diff options
author | David Van Assche <nubae@big-nubae.local.lan> | 2009-09-08 21:49:30 (GMT) |
---|---|---|
committer | David Van Assche <nubae@big-nubae.local.lan> | 2009-09-08 21:49:30 (GMT) |
commit | a2c8e7ed0a394b713e8a7e1bf0532389539eca97 (patch) | |
tree | 7affb77f544b6c736ab06874721e9ba063f9799d | |
parent | a4fe57d04da5cc9a10288cecaa7a1718d9113ca0 (diff) |
added tooltips, fixed category needed for save, and added loads of comments
-rw-r--r-- | pyclic.py | 112 |
1 files changed, 85 insertions, 27 deletions
@@ -329,6 +329,8 @@ class PyClicAdmin: #Now add to the xml document xml_document.documentElement.appendChild(questions_element) + #This is the main xml saver... basicallt it leads to xml_save, which does the heavy parsing work. Comparatitvaly + #its far easier to open a document than save one. def xml_save_to_file(self, widget): """Save the current post to xml_file @param xml_file - string - path to file that @@ -338,9 +340,9 @@ class PyClicAdmin: #Init return value success = False - #Get the available DOM Implementation + #Get the available DOM Implementation, in this case, the XML parser impl = minidom.getDOMImplementation() - #Create the document, with PyClicAdmin as to base node + #Create the document, with PyClicAdmin as base node xml_document = impl.createDocument(None, PyClicCommon._xml_tags[MAIN_TAG], None) #Save the questions into the xml self.xml_save(xml_document) @@ -349,7 +351,9 @@ class PyClicAdmin: save_file = open(self.xml_file, 'w') #write the xml document to disc xml_document.documentElement.writexml(save_file) + #Close the file after writing to it save_file.close() + #print exception errors except IOError, (errno, strerror): self.show_error_dlg( "Error saving quiz(%s): %s" % (errno, strerror)) @@ -360,33 +364,50 @@ class PyClicAdmin: return success - # open image file self.chooser with filter for just image types + # open image file self.chooser with filter for just png. We use just png because thats what cairo likes + # though it would be possible to create a pixbuf from any image and feed that to cairo instead. Would + # require quite some restructuring of code. def open_image(self,widget): + #create a chooser dialog and give it the base file open dialog with cancel and ok buttons self.chooser = gtk.FileChooserDialog(title="Open Image",action=gtk.FILE_CHOOSER_ACTION_OPEN,buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + #add a file filter filter = gtk.FileFilter() + #set the file filter name to Images filter.set_name("Images") + #set the filters mime type. You can add more underneath for more filetypes filter.add_mime_type("image/png") + #set the actual pattern were searching for, in this case png. filter.add_pattern("*.png") + #add the filter to the chooser dialog self.chooser.add_filter(filter) + #set response to whatever is returned from self.chooser response = self.chooser.run() + #If user clicks on ok, then get the image and create a cairo surface object. It is here that cairo will only + #accept pngs. We also put in a scale image function, in case the image is not the right size. We should probably + #tell the user what size to use approximately so the image looks at its best. if response == gtk.RESPONSE_OK: self.image=self.image.create_from_png(self.chooser.get_filename()) self.image_scale(self.image) self.image_filename=self.chooser.get_filename() self.image=self.image.create_from_png(self.chooser.get_filename()) + #expose the changes to X and let it redraw the screen self.darea.queue_draw() + #user has cancelled if it comes to here elif response == gtk.RESPONSE_CANCEL: print 'Closed, no files selected' + #kill the chooser dialog object self.chooser.destroy() + #A relatively simple function to scale an image by getting its height and width, and doing some funky stuff + #with a cairo matrix. def image_scale(self,image): self.width=self.image.get_width() self.height=self.image.get_height() imgpat = cairo.SurfacePattern(self.image) scaler = cairo.Matrix() - #image width/640*100,image height/480 + #image width/640,image height/480 scaler.scale(self.width/640.0,self.height/480.0) imgpat.set_matrix(scaler) @@ -398,18 +419,22 @@ class PyClicAdmin: ctx.paint() canvas.write_to_png(self.chooser.get_filename()) - + #this function grabs the mouse coordinates and appends them to the coordinates list. def grab_click(self,widget,event): x, y = event.get_coords() self.coordinates.append((x,y)) gc = widget.window.new_gc() widget.queue_draw() + #we send the x,y values to expose for drawing the filled circle + #We add a label to the right hand vertical box, with the contents of the mouse click number. + #could have just start an iterator here, but we got the amount of clicks instead... kinda cooler. self.label=gtk.Label(self.coordinates.index((x,y))+1) self.label_list.append(self.label) + #pack the label in the 2nd vbox self.vbox2.pack_start(self.label,False,False,0) self.label.show() - + #Also add an entry box for every click self.entry=gtk.Entry(max=30) self.entry_list.append(self.entry) @@ -417,29 +442,39 @@ class PyClicAdmin: self.entry.show() + #This function does the hardcore Cairo drawing part with the circle and pango and stuff... def expose(self, widget, event): self.cr = widget.window.cairo_create() self.cr.set_source_surface(self.image) self.cr.paint() + #set pango details for drawing in circle self.cr.select_font_face("Arial",cairo.FONT_SLANT_NORMAL,cairo.FONT_WEIGHT_BOLD) self.cr.set_font_size(16) + #for each entry in self.coordinates, in other words, for every mouse click position stored for x,y in self.coordinates: - + #set the colour split into its R, G, B components self.cr.set_source_rgb(self.colorred,self.colorgreen,self.colorblue) + #draw the respective circle self.cr.arc(x,y,14,0,2 * math.pi) + #give the circle an edge self.cr.stroke + #make it a filled circle self.cr.fill() + #define whats going in the circle, basically the mouseclick number self.string="%s" %(self.coordinates.index((x,y))+1) + #where do we put it self.cr.move_to(x-4,y+5) + #what colour do we make the pango object self.cr.set_source_rgb(1, 1, 1) - + #show the pango object self.cr.show_text(self.string) - + #needed function to get the active text from the combo box, as gtk doesnt have that built in. found on the web + #some place def get_active_text(combobox): model = combobox.get_model() active = combobox.get_active() @@ -447,31 +482,35 @@ class PyClicAdmin: return None return model[active][0] + #function to encode in base64 the image so we can transport the XML document easily, especially across xmpp tubes. def encode64(self,filew): try: response = open(filew) data = response.read() - + #give us the exception error if it doesnt work except IOError, (errno, strerror): self.show_error_dlg("Error saving quiz(%s): %s" % (errno, strerror)) - + #return the base64 encoded object return data.encode('base64') + #File save function that gets called when all elements have been collected and xml file needs to be openned. def on_file_save(self, widget): """This function saves the current Quiz as an XML file using sub functions""" - # Let the user browse for the save location and name + # Let the user browse for the save location and name of XML file if (self.xml_file == None): self.xml_file = self.pcc.file_browse(gtk.FILE_CHOOSER_ACTION_SAVE) #If we have a xml_file if (self.xml_file): + #If we can actually send to the xml_save_to_file function if (self.xml_save_to_file(self.xml_file)): - #Allright it all worked! Set the Title + #Allright it all worked! Set the Title of the window self.pcc.set_window_title_from_file(self.xml_file,self.window) - self.on_info(self.window) + #Give a success notice of saving the file + self.on_save_notice(self.window) - - def on_info(self,window): + #success notice for file save + def on_save_notice(self,window): dialog = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, "File saved successfully") @@ -479,6 +518,14 @@ class PyClicAdmin: dialog.run() dialog.destroy() + #warning notice that category is missing + def on_items_missing(self,window): + dialog = gtk.MessageDialog(self.window, + gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, "You must have a category selected to save") + dialog.set_title("Too few details") + dialog.run() + dialog.destroy() def on_file_save_as(self, widget): @@ -497,10 +544,13 @@ class PyClicAdmin: self.xml_file = xml_file PyClicCommon.set_window_title_from_file(self.xml_file) + #simple little function to grab combobox changed value for category def on_changed(self,widget): self.Category = widget.get_active_text() + #function to collect data and make sure category is selected def save_details(self,widget): + self.Cat=self.cb_category.get_active_text() self.Title = self.title_entry.get_text() self.Author = self.author_entry.get_text() # save image to base64 @@ -509,9 +559,13 @@ class PyClicAdmin: self.Entries=[] for entry in self.entry_list: self.Entries.append(entry.get_text()) - - self.on_file_save(file) + if self.Cat==None: + print "Category missing" + self.on_items_missing(self.window) + else: + self.on_file_save(file) + #function to clear all data and all elements def on_file_new(self,widget): for entry in self.entry_list: self.vbox2.remove(entry) @@ -527,6 +581,7 @@ class PyClicAdmin: self.entry="" self.window.queue_draw() + #function to call color selector and set the individual colours to their respective numbers def on_clicked(self, widget): cdia = gtk.ColorSelectionDialog("Select color") response = cdia.run() @@ -541,6 +596,7 @@ class PyClicAdmin: cdia.destroy() self.window.queue_draw() + #Start the main constructor of our class, where the magic happens, kinda... not really... def __init__(self): # create the main window, and attach delete_event signal to terminating # the application @@ -553,6 +609,7 @@ class PyClicAdmin: print e.message sys.exit(1) + #instantiate the pycliccomon class which we imported... yay... now I know what instantiate means :-) self.pcc=PyClicCommon() self.window.connect("delete_event", self.pcc.close_application) @@ -561,7 +618,7 @@ class PyClicAdmin: self.vbox2 = gtk.VBox(False, 2) - + #set an empty xml file on program start self.xml_file=None @@ -614,17 +671,23 @@ class PyClicAdmin: vbox = gtk.VBox(False, 2) vbox.pack_start(mb,False,False,0) - #Insert Toolbar with open,save and exit + #Insert Toolbar with several options, and icons taken from stock library, toolbar only contains icons. toolbar = gtk.Toolbar() toolbar.set_style(gtk.TOOLBAR_ICONS) - newtb = gtk.ToolButton(gtk.STOCK_CLEAR) + newtb = gtk.ToolButton(gtk.STOCK_CLEAR) + newtb.set_tooltip_text("Clear the screan / start new quiz") opentb = gtk.ToolButton(gtk.STOCK_OPEN) + opentb.set_tooltip_text("Open a PyQClic quiz") savetb = gtk.ToolButton(gtk.STOCK_SAVE) + savetb.set_tooltip_text("Save a PyQClic Quiz with .gpx extension") colortb = gtk.ToolButton(gtk.STOCK_SELECT_COLOR) + colortb.set_tooltip_text("Change round label color") importtb = gtk.ToolButton(gtk.STOCK_ORIENTATION_PORTRAIT) + importtb.set_tooltip_text("Import/Open image for labeling") sep = gtk.SeparatorToolItem() quittb = gtk.ToolButton(gtk.STOCK_QUIT) + quittb.set_tooltip_text("Quit the Program, C u l8r") toolbar.insert(newtb, 0) toolbar.insert(opentb, 1) @@ -634,12 +697,7 @@ class PyClicAdmin: toolbar.insert(sep, 5) toolbar.insert(quittb, 6) - quittb.connect("clicked", gtk.main_quit) - newtb.connect("clicked", self.on_file_new) - opentb.connect("clicked", self.on_file_open) - savetb.connect("clicked", self.save_details) - colortb.connect("clicked", self.on_clicked) - importtb.connect("clicked",self.open_image) + vbox.pack_start(toolbar, False, False, 0) |