From fb0ee90d778c1c5a7bf4fe87c4d030157520ba3d Mon Sep 17 00:00:00 2001 From: David Van Assche Date: Wed, 09 Sep 2009 15:49:27 +0000 Subject: added pyclicuser.py --- diff --git a/pyclicuser.py b/pyclicuser.py new file mode 100644 index 0000000..d2ac301 --- /dev/null +++ b/pyclicuser.py @@ -0,0 +1,798 @@ +#!/usr/bin/python + +# PyqClicAdmin application, Administration interface. User loads an image, then places lables on them with circled +# numbers in colour of their choice (application has colour changing ability), then user writes meanings of labels on +# right hand side, and stores all this in an XML file. XML file contains tags as listed in pylic-common.py file, +# along with base 64 encoded image. This is for transportability reasons, specifically, transporting across xmpp +# tubes for collaboration. Application uses cairo and pango libraries for drawing and labeling image. It uses the +# minidom library for xml importing/exporting. + +import pygtk +pygtk.require('2.0') +import gtk +import cairo +import math +from xml.dom import minidom +import os +import sys +from pyclic_common import * + +class PyClicAdmin: + + #function to open xml file, though parsing of file happens in xml_load_from_file() function. + def on_file_open(self, widget): + # use file_browse function to open file + xml_file = self.pcc.file_browse(gtk.FILE_CHOOSER_ACTION_OPEN) + # Check to see if we have a xml_file + if (xml_file): + if (self.xml_load_from_file(xml_file)): + """Allright it all worked! save the current file and + set the title.""" + self.xml_file = xml_file + # set window title to the name of loaded quiz + self.pcc.set_window_title_from_file(self.xml_file,self.window) + + #Another in between file in the process of opening xml, basically this checks to see its really an xml document + #and can be parsed by minidom, if not it will fail and tell user why. If successful sends it through to + #xml_load which does the heavy parsing. + def xml_load_from_file(self, xml_file): + """Load a quiz from an xml file + @param xml_file - string - path to file that + we will load. + @returns boolean - True success. False failure + """ + #Init return value + success = False + + #Load the xml_file to a document, show error if it fails + try: + xml_document = minidom.parse(xml_file) + if (xml_document): + success = ((self.xml_load(xml_document))) + except IOError, (errno, strerror): + #show error if not xml file or doesnt load. + self.show_error_dlg( + "Error loading quiz file(%s): %s" % (errno, strerror)) + return success + + # Heavy duty xml file parser. Stores false or true for all loaded objects, though currently unused in program + # for anything. Title, Category, Author, Colours, Coordinates, Questions and Image are pulled in, parsed and placed + # in their respective positions + def xml_load(self, xml_document): + """Load the current quiz from an xml document. + @param xml_document - xml.dom.minidom.Document object - + The xml document that we will load the quiz from. + @returns boolean True - success. False - Failure.""" + + title_loaded = False + category_loaded = False + question_loaded = False + author_loaded = False + image_loaded = False + coordinates_loaded = False + entries_loaded = False + questions_loaded = False + colors_loaded = False + self.answers_list=[] + # reset all values before loading document, make sure data is clean, and drawing area is clean + self.on_file_new(self) + #Loop through all child nodes of the root. + for node in xml_document.documentElement.childNodes: + #We are looking for the quiz Node, which will contain all the subelements title, author, category + #buttons color, and image. Basically this is seperated as such because it needs to do just one + #iteration per quiz document. + if (node.nodeName == PyClicCommon._xml_tags[QUIZ_TAG]): + # Now loop through the quiz nodes children + for item_node in node.childNodes: + if (item_node.nodeName == PyClicCommon._xml_tags[TITLE_TAG]): + """Set the title, the firstChild in this case is + the actual title text that we saved.""" + + #Make sure it's not a blank string + if (item_node.firstChild): + self.title_entry.set_text(item_node.firstChild.nodeValue) + else: + print "Tag not loaded, probably empty" + title_loaded = True + # Title Tag loaded at this point and placed by self.title_entry.set_text + elif (item_node.nodeName == PyClicCommon._xml_tags[CATEGORY_TAG]): + """Set the category, the firstChild in this case is + the actual category that we saved.""" + #Make sure it's not a blank string + if (item_node.firstChild): + #we make quite a hacky loop through the listbox, since gtk + #doesnt have very nice manipulation of listboxes, and uses + #just number indexing. + if item_node.firstChild.nodeValue=="Geography": + catindex=0 + elif item_node.firstChild.nodeValue=="Science": + catindex=1 + elif item_node.firstChild.nodeValue=="ICT": + catindex=2 + elif item_node.firstChild.nodeValue=="Languages": + catindex=3 + elif item_node.firstChild.nodeValue=="Maths": + catindex=4 + elif item_node.firstChild.nodeValue=="Music": + catindex=5 + elif item_node.firstChild.nodeValue=="History": + catindex=6 + elif item_node.firstChild.nodeValue=="Business": + catindex=7 + elif item_node.firstChild.nodeValue=="Art": + catindex=8 + #we set the active listbox element to category it found + self.cb_category.set_active(catindex) + else: + print "Tag not loaded, probably empty" + category_loaded = True + #At this point we have found category and title and have placed them in their + #their corresponding positions + elif (item_node.nodeName == PyClicCommon._xml_tags[AUTHOR_TAG]): + """Set the author, the firstChild in this case is + the actual author that we saved. This tag is not really that important + and in fact was put in as an after though just in case its wanted""" + #Make sure it's not a blank string + if (item_node.firstChild): + self.author_entry.set_text(item_node.firstChild.nodeValue) + else: + print "Tag not loaded, probably empty" + author_loaded = True + #At this point category, title and author have been loaded and placed in the document + elif (item_node.nodeName == PyClicCommon._xml_tags[IMAGE_TAG]): + """Set the image, the firstChild in this case is + the image that we saved. Then decode from base64""" + #Make sure it's not a blank string + if (item_node.firstChild): + #we set self.image equal to the decoding of the bin64 image, then + #issue a queue draw to let X redraw the drawing area. + self.image = self.pcc.decode64(item_node.firstChild.nodeValue) + self.window.queue_draw() + else: + print "Tag not loaded, probably empty" + image_loaded = True + #Weve now loaded the image, the category, the title and the author and placed + #them in their corresponding positions. + elif (item_node.nodeName == PyClicCommon._xml_tags[COLOR_TAG]): + """Set the image, the firstChild in this case is + the image that we saved. Then decode from base64""" + #Make sure it's not a blank string + if (item_node.firstChild): + #since weve saved the colors as a string, as its xml, and + #all xml elements must be strings, we need to pull out those + #values and make them proper floats to get exact colour values + #aswell as split into the 3 corresponsding R, G and B. First we + #split the values at the , + self.colourred,self.colourgreen,self.colourblue = item_node.firstChild.nodeValue.split(",") + #now we replace the [ with nothing as that got pulled in on save on + #conversion of list to string + self.colorred=self.colourred.replace('[', '') + self.colorred=float(self.colorred) + self.colorgreen=float(self.colourgreen) + #we do the same replacement for the outer bracket, and now have a + # proper list again, split into its R, G, B components, as floats + self.colorblue=self.colourblue.replace(']', '') + self.colorblue=float(self.colorblue) + #we send the color values to X to be redrawn. + self.window.queue_draw() + else: + print "Tag not loaded, probably empty" + colors_loaded = True + #We've now loaded all the QUIZ tag elements, the ones that require just one iteration. + #We are looking for the questions Node, which contains all the iterrable values, that is to say + #values for each question found. + elif (node.nodeName == PyClicCommon._xml_tags[QUESTIONS_TAG]): + # Now loop through the question nodes children + for item_node in node.childNodes: + self.entradas=[] + #we look for entry tag + if (item_node.nodeName == PyClicCommon._xml_tags[ENTRY_TAG]): + """Grab all the entries.""" + #Make sure it's not a blank string + if (item_node.firstChild): + #iterate through entries + self.entradas.append(item_node.firstChild.nodeValue) + # now pull out values and place them in entry boxes, generating + # an entry box for each value + for entry in self.entradas: + self.answers_list.append(item_node.firstChild.nodeValue) + self.label=gtk.Label("("+str(len(item_node.firstChild.nodeValue))+" letras)") + self.entry=gtk.Entry(max=30) + self.entry_list.append(self.entry) + # the below adds the text to the entry boxes + self.vbox2.pack_start(self.label,False,False,0) + self.vbox2.pack_start(self.entry,False,False,0) + self.label.show() + self.entry.show() + else: + print "Tag not loaded, probably empty" + entries_loaded = True + #We create an empty questions list to iterate through and place items in + #self.questions_list=[] + #we look for the question tag + #if (item_node.nodeName == PyClicCommon._xml_tags[QUESTION_TAG]): + """Grab all the questions.""" + #Make sure it's not a blank string + # if (item_node.firstChild): + #for each question, append it to the questions_list + # self.questions_list.append(item_node.firstChild.nodeValue) + #now generate the questions labels show it + #for question in self.questions_list: + # self.label=self.get_label(answer) + # self.label_list.append(self.label) + # self.vbox2.pack_start(self.label,False,False,0) + # self.label.show() + # else: + # print "Tag not loaded, probably empty" + # question_loaded = True + #create empty self.coordinate list to place coordinates into + self.coordinate=[] + # Look for coordinates tag + if (item_node.nodeName == PyClicCommon._xml_tags[COORDINATES_TAG]): + """Grab all the coordinates.""" + #Make sure it's not a blank string + if (item_node.firstChild): + #add all coordinates to list + self.coordinate.append(item_node.firstChild.nodeValue) + # but split x and y and turn into proper floats and point to proper + # coordinates list, coordinate, is just used for iteration here. + for coordinate in self.coordinate: + x,y = coordinate.split(",") + self.coordinates.append((float(x),float(y))) + # Get X to place or coordinates in the drawin area + self.window.queue_draw() + else: + print "Tag not loaded, probably empty" + coordinates_loaded = True + # At this point all our question labels and coordinates + # have been loaded and placed. We create a entries + #iterator list called entradas. + + break + # break out of topmost loop since we are finished loading items from XML document. + # also return all loaded values as true, which is curerntly unused, but might serve some + # purpose at some point. + return (title_loaded and category_loaded and author_loaded and image_loaded and entries_loaded and question_loaded and colors_loaded and coordinates_loaded) + + + #function to save quiz to xml document, way simpler than loading the xml file. In this case we simply + #generate all the tags, and place the respectve elements inside. + def xml_save(self, xml_document): + """Save the current quiz to an xml document. + @param xml_document - xml.dom.minidom.Document object - + The xml document that we will save the post to.""" + + #create + quiz_element = xml_document.createElement(PyClicCommon._xml_tags[QUIZ_TAG]) + #create + category_element = xml_document.createElement(PyClicCommon._xml_tags[CATEGORY_TAG]) + #Create category + category_element.appendChild(xml_document.createTextNode(self.Category)) + #Creates + image_element = xml_document.createElement(PyClicCommon._xml_tags[IMAGE_TAG]) + #Create image + image_element.appendChild(xml_document.createTextNode(self.Image)) + #Creates + title_element = xml_document.createElement(PyClicCommon._xml_tags[TITLE_TAG]) + #Creates title + title_element.appendChild(xml_document.createTextNode(self.Title)) + #Creates + author_element = xml_document.createElement(PyClicCommon._xml_tags[AUTHOR_TAG]) + #Creates author + author_element.appendChild(xml_document.createTextNode(self.Author)) + #Creates + color_element = xml_document.createElement(PyClicCommon._xml_tags[COLOR_TAG]) + #Create colorvalues list, and add R,G,B values to it (we should really strip the brackets on string + #conversion here taking out the []), but we do that on load instead. Reason = this function was created + #before the load function + colourvalues = [] + colourvalues.append(self.colorred) + colourvalues.append(self.colorgreen) + colourvalues.append(self.colorblue) + #Creates colorValues and turns into string + color_element.appendChild(xml_document.createTextNode(str(colourvalues))) + #appends all elements to quiz tagged XML object + quiz_element.appendChild(category_element) + quiz_element.appendChild(title_element) + quiz_element.appendChild(image_element) + quiz_element.appendChild(author_element) + quiz_element.appendChild(color_element) + #Now add all quiz subelements to xml document, these are the non recursive elements of the quiz document, + # there is only one of each. + xml_document.documentElement.appendChild(quiz_element) + #create + questions_element = xml_document.createElement(PyClicCommon._xml_tags[QUESTIONS_TAG]) + #Setup iteration + Iterate = 0 + #Set questions here, no point in saving values before hand, in fact, come to think of it, we dont really even + #need to save this, as it is quite clear we have questions going up in number starting at 1. But for + #clarity of XML document we do it that way. + question = 1 + # while there are coordinates in the self.coordinates list, iterate through and save stuff + while Iterate < len(self.coordinates): + #Create + question_element = xml_document.createElement(PyClicCommon._xml_tags[QUESTION_TAG]) + #create question and turn to string (XML requires it) + question_element.appendChild(xml_document.createTextNode(str(question))) + c = self.coordinates[Iterate] + #Create + coordinates_element = xml_document.createElement(PyClicCommon._xml_tags[COORDINATES_TAG]) + #create x,y, and turn into strings. This method is better than doing a str + # as no bracets are saved, just value,value for each set of x,y coordinates. + coordinates_element.appendChild(xml_document.createTextNode("%d,%d" % (c[0],c[1]))) + #Create + entry_element = xml_document.createElement(PyClicCommon._xml_tags[ENTRY_TAG]) + #create entry and append each entry via the iterator + entry_element.appendChild(xml_document.createTextNode(self.Entries[Iterate])) + + #Add above to + questions_element.appendChild(question_element) + questions_element.appendChild(coordinates_element) + questions_element.appendChild(entry_element) + Iterate=Iterate+1 + question=question+1 + #Now add to the xml document + xml_document.documentElement.appendChild(questions_element) + + #This is the main xml saver... basically 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 + we will save the xml to. + @returns boolean - True success. False failure + """ + #Init return value + success = False + + #Get the available DOM Implementation, in this case, the XML parser + impl = minidom.getDOMImplementation() + #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) + #Now actually try to save the file + try: + 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)) + else: + #Allright it all worked! Set the return value + success = True + + return success + + #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,image height/480 + scaler.scale(self.width/640.0,self.height/480.0) + imgpat.set_matrix(scaler) + + #set resampling filter + imgpat.set_filter(cairo.FILTER_BEST) + canvas = cairo.ImageSurface(cairo.FORMAT_ARGB32,640,480) + ctx = cairo.Context(canvas) + ctx.set_source(imgpat) + ctx.paint() + canvas.write_to_png(self.chooser.get_filename()) + + #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() + if active < 0: + 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 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 of the window + self.pcc.set_window_title_from_file(self.xml_file,self.window) + #Give a success notice of saving the file + self.on_save_notice(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") + dialog.set_title("Save Successful") + 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): + """Let the user save the current file to a new location.""" + + xml_file = "Untitled" + if (self.xml_file != None): + xml_file = os.path.basename(self.xml_file) + + xml_file = self.file_browse(gtk.FILE_CHOOSER_ACTION_SAVE, xml_file) + #If we have a xml_file + if (xml_file): + if (self.xml_save_to_file(xml_file)): + """Allright it all worked! save the current file and + set the title.""" + 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 + self.Image = self.encode64(self.image_filename) + # function to grab entries from entry list + self.Entries=[] + for entry in self.entry_list: + self.Entries.append(entry.get_text()) + if self.Cat==None: + print "Category missing" + self.on_items_missing(self.window) + else: + self.on_file_save(file) + + #function to check answers against entry list. + def on_check_answers(self,widget): + iterate=1 + for entry in self.entry_list: + self.Entries.append(entry.get_text()) + while iterate < len(self.Entries): + if self.Entries[iterate]==self.answers_list[iterate]: + print self.Entries[iterate]+" is the right answer" + else: + print "wrong!" + iterate=iterate+1 +# self.label.set_text(answers) +# self.window.queue_draw() + + def on_set_label(self,answer): + on_check_answers(self,widget) + return answer + + #function to clear all data and all elements + def on_file_new(self,widget): + for entry in self.entry_list: + self.vbox2.remove(entry) + for label in self.label_list: + self.vbox2.remove(label) + self.entry_list=[] + self.Entries=[] + self.coordinates=[] + self.author_entry.set_text("") + self.title_entry.set_text("") + self.question_list=[] + self.xml_file = None + 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() + + if response == gtk.RESPONSE_OK: + colorsel = cdia.colorsel + self.colour = colorsel.get_current_color() + #assign the colours as values pycairo understands + self.colorred = self.colour.red/65535.0 + self.colorgreen = self.colour.green/65535.0 + self.colorblue = self.colour.blue/65535.0 + + cdia.destroy() + #queue the drawing to X + 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 + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + + #set icon for app (set at 48x48 pixels) + try: + self.window.set_icon_from_file("pyclicicon.png") + except Exception, e: + print e.message + sys.exit(1) + + #instantiate the pycliccomon class which we imported... yay... now I know what instantiate means :-) + self.pcc=PyClicCommon() + #add the delete_event handler to pyclic common close application method + self.window.connect("delete_event", self.pcc.close_application) + #set size for window + self.window.set_size_request(775,544) + #set the window to have no border + self.window.set_border_width(0) + + + #set an empty xml file on program start + self.xml_file=None + + + #Insert menubar containing 2 columns, file and About or help + #create menu bar + mb = gtk.MenuBar() + #create file menu + filemenu = gtk.Menu() + #add File menu item + filem = gtk.MenuItem("File") + #add a submenu to the file menu, basically everything that shows up below file + filem.set_submenu(filemenu) + #An about menu suboption, linked by the activate handler to the about_program function + aboutm = gtk.MenuItem("About PyClicAdmin") + aboutm.connect("activate",self.pcc.about_program) + #add it to the filemenu + filemenu.append(aboutm) + #Create a new quiz or clear the screen. This basically deletes all the variable contents + #so you have a clean page. Connect it via the activate handler to the on_file_new function + newquiz = gtk.MenuItem("New File / Clear") + newquiz.connect("activate",self.on_file_new) + #add it to the filemenu + filemenu.append(newquiz) + #create open quiz menu item + openquiz = gtk.MenuItem("Open Quiz") + #connect the openquiz activator to on_file_open + openquiz.connect("activate",self.on_file_open) + #add openquiz to filemenu + filemenu.append(openquiz) + + #create save option + save = gtk.MenuItem("Save Quiz") + #connect the activate handler to the save_details function + save.connect("activate",self.save_details) + #add save to the filemenu + filemenu.append(save) + #create exit option + exit = gtk.MenuItem("Exit") + #connect handler to integrated gtk.quit function + exit.connect("activate",gtk.main_quit) + #add exit to the filemenu + filemenu.append(exit) + + #create options submenu + optionsmenu = gtk.Menu() + #create options option + options = gtk.MenuItem("Options") + #set optionsmenu as a submenu + options.set_submenu(optionsmenu) + #create open image option +# openimage = gtk.MenuItem("Open Image") + #add activate handler to open_image function +# openimage.connect("activate",self.open_image) + #add open to the optionsmenu +# optionsmenu.append(openimage) + #create change color option +# colormenu = gtk.MenuItem("Change Color") + #add activate handler to on_clicked function +# colormenu.connect("activate", self.on_clicked) + #add color option to optionsmenu +# optionsmenu.append(colormenu) + #add filemenu and options to menubar + mb.append(filem) + mb.append(options) + + #Insert Toolbar with several options, and icons taken from stock library, + #toolbar only contains icons. Add tooltips to iconic toolbar too. + toolbar = gtk.Toolbar() + toolbar.set_style(gtk.TOOLBAR_ICONS) + + 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") + sep = gtk.SeparatorToolItem() + quittb = gtk.ToolButton(gtk.STOCK_QUIT) + quittb.set_tooltip_text("Quit the Program, C u l8r") + + #place positions of toolbar options in toolbar + toolbar.insert(newtb, 0) + toolbar.insert(opentb, 1) + toolbar.insert(savetb, 2) + toolbar.insert(sep, 3) + toolbar.insert(quittb, 4) + + #connect toolbar handlers to their functions on click + 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) + + #create a drawing area where we will place the image + self.darea=gtk.DrawingArea() + #introduce a startup image called pyclic.png which gives usage instructions + self.image = cairo.ImageSurface.create_from_png("pyclic.png") + #make initial image filename pyclic.png + self.image_filename="pyclic.png" + #connect the drawing area to the expose_event handler via the expose function. + #Expose makes X draw everything, so one needs to call this function whenever + #one needs to add something new to the canvas. This is done using the queue_draw + #function, found in several places in this program. + self.darea.connect("expose_event", self.expose) + #create the events mask, in this case a button click + self.darea.set_events(gtk.gdk.BUTTON_PRESS_MASK) + #add another handler on button_press_event to the grab_click function which takes + #care of grabbing x,y coordinates +# self.darea.connect("button_press_event",self.grab_click) + #set the drawing area size + self.darea.set_size_request(606,540) + #define empty coordinates list + + self.coordinates=[] + #define empty text entries list + self.entry_list=[] + #define empty labels list + self.label_list=[] + #define empty question list + self.question_list=[] + + #define color values for question circle + self.colorred=0 + self.colorblue=0 + self.colorgreen=0 + + # Generate Layout + #create vertical box + vbox = gtk.VBox(False, 2) + #add the menubar to the vertical box + vbox.pack_start(mb,False,False,0) + #add toolbar to vertical box + vbox.pack_start(toolbar, False, False, 0) + #add the vertical box to the window + self.window.add(vbox) + #create a horizontal box under the menu and toolbar + self.hbox = gtk.HBox(False, 2) + #add the horizontal box to the vertical box + vbox.add(self.hbox) + #create a fixed area for the drawing area + fix = gtk.Fixed() + #add the fixed area to the horizontal box + self.hbox.add(fix) + #add the drawing area to fixed area at position 0,0, that is to say top left + #corner + fix.put(self.darea,0,0) + #add second vertical box + self.vbox2 = gtk.VBox(False, 2) + + + # Add a title label + title_label=gtk.Label("Title") + self.vbox2.pack_start(title_label,False,False,0) + #Add a Title entry box + self.title_entry=gtk.Entry(max=50) + self.vbox2.pack_start(self.title_entry,False,False,0) + #Add an author label + author_label=gtk.Label("Author") + self.vbox2.pack_start(author_label,False,False,0) + #Add an author entry box + self.author_entry=gtk.Entry(max=50) + self.vbox2.pack_start(self.author_entry,False,False,0) + #Add a Category label + title_category=gtk.Label("Category") + self.vbox2.pack_start(title_category,False,False,0) + #Add a combobox called category to the right hand side and connect changed + #handler to on_changed, which captures the category selected + self.cb_category=gtk.combo_box_new_text() + self.cb_category.connect("changed", self.on_changed) + self.cb_category.append_text("Geography") + self.cb_category.append_text("Science") + self.cb_category.append_text("ICT") + self.cb_category.append_text("Languages") + self.cb_category.append_text("Maths") + self.cb_category.append_text("Music") + self.cb_category.append_text("History") + self.cb_category.append_text("Business") + self.cb_category.append_text("Art") + self.vbox2.pack_start(self.cb_category,False,False,0) + + #submit button for entries + submit_button=gtk.Button("Submit") + self.vbox2.pack_start(submit_button,False,False,0) + #add an event handler to submit button via save_details function + submit_button.set_events(gtk.gdk.BUTTON_PRESS_MASK) + submit_button.connect("clicked",self.on_check_answers) + #add event handler to clear button via on_file_new function + clear_button=gtk.Button("Clear") + self.vbox2.pack_start(clear_button,False,False,0) + clear_button.set_events(gtk.gdk.BUTTON_PRESS_MASK) + clear_button.connect("clicked",self.on_file_new) + #make a scrolledwindow and connect to vertical box 2 + self.scrollw = gtk.ScrolledWindow() + self.scrollw.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC) + self.hbox.pack_start(self.scrollw) + self.scrollw.add_with_viewport(self.vbox2) + + #show all the showable items + self.window.show_all() + +#initiate main loop +def main(): + gtk.main() + return 0 + +#instantiate pyclicadmin class +if __name__ == "__main__": + PyClicAdmin() + main() + -- cgit v0.9.1