Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 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)
commita2c8e7ed0a394b713e8a7e1bf0532389539eca97 (patch)
tree7affb77f544b6c736ab06874721e9ba063f9799d
parenta4fe57d04da5cc9a10288cecaa7a1718d9113ca0 (diff)
added tooltips, fixed category needed for save, and added loads of comments
-rw-r--r--pyclic.py112
1 files changed, 85 insertions, 27 deletions
diff --git a/pyclic.py b/pyclic.py
index 3e71eba..df42477 100644
--- a/pyclic.py
+++ b/pyclic.py
@@ -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)