class App(Frame, GUI_help): """Data pipe GUI for importing and fitting of raw data. This class uses ekin provided an automated pipeline for fitting raw text data files and propagating errors. Uses a config file to store the pipeline settings""" def __init__(self, parent=None, rawfile=None, conffile=None): self.parent=parent if not self.parent: Frame.__init__(self) self.main=self.master else: self.main=Toplevel() self.master=self.main self.main.title('DNATool Desktop') self.main.protocol('WM_DELETE_WINDOW',self.quit) self.defaultprefs = {'rememberwindowsize':0,'orientation':'horizontal', 'alignmenttool':'clustal','clustalpath':'clustalw'} self.defaultopts = [('rememberwindowsize','checkbutton',1,'Remember window size'), ('orientation','menu',('horizontal','vertical'), 'Default sideframe orientation'), ('alignmenttool','menu',('clustal','muscle','needle'), 'External alignment tool'), ('clustalpath','entry','','Path to Clustal')] self.loadPrefs() self.setGeometry() self.P = Project() self.primerdb = PrimerDatabase() self.setupApps() self.setupGUI() self.sidepane.selectpage('PrimerDB') return def setGeometry(self): if self.rememberwindowsize == 1 and self.preferences.has_key('lastwindowsize'): lastwindowsize = self.preferences.get('lastwindowsize') self.winsize = lastwindowsize #self.w = int(lastwindowsize.split('x')[0]) else: self.winsize = self.getBestGeometry() self.main.geometry(self.winsize) return def getBestGeometry(self): """Calculate optimal geometry from screen size""" ws = self.main.winfo_screenwidth() hs = self.main.winfo_screenheight() self.w=w=ws/1.3; h=500 x = (ws/2)-(w/2); y = (hs/2)-(h/2) g = '%dx%d+%d+%d' % (w,h,x,y) return g def saveGeometry(self): """Save current geometry before quitting""" g = self.main.geometry() self.preferences.set('lastwindowsize', g) return def setupApps(self): """Creates a dict of classes so that GUI frames like primer design can be dynamically added without explicit methods for each""" self.apps = {'Primer Design': PrimerDesignGUI, 'ORF Overview': ORFOverview, 'Sequence Analysis': SequenceAnalysis, 'Sequence Alignment Tool': SequenceAlignmentTool, 'Restriction Digest Summary': RestrictionDigestSummary, 'Blast Interface':BlastInterface, 'NotePad': TextEditor} return def loadPrefs(self): """Load prefs from a preferences instance""" self.preferences = Preferences('DNATool2',{}) temp = {} for key in self.defaultprefs: if not key in self.preferences.prefs: self.preferences.set(key, self.defaultprefs[key]) temp[key] = self.preferences.get(key) self.applyPrefs(temp) return def savePrefs(self): """Save prefs to a preferences instance""" self.applyPrefs(self.prefsdialog.getValues()) self.preferences = Preferences('DNATool2',{}) for key in self.defaultprefs: self.preferences.set(key, self.__dict__[key]) return def applyPrefs(self, prefs=None): """Apply prefs from a given dict""" if prefs == None: prefs=self.defaultprefs for key in prefs: self.__dict__[key] = prefs[key] return def setupGUI(self): """Do GUI elements""" self.visibleapps = {} #bottom panel bottom = Frame(self.main,height=50) bottom.pack(side=BOTTOM,fill=BOTH,pady=1) #status bar sb = self.addStatusBar(bottom) tb = self.addWindowToolBar(bottom) tb.pack(side=LEFT,anchor='e',expand=1) self.m = PanedWindow(self.main, orient=self.orientation, sashwidth=2, showhandle=True) self.m.pack(side=TOP,fill=BOTH,pady=2,expand=1) sc = self.sc = SequenceCanvas(self.m,parentapp=self, width=900,height=800) sc.pack(side=TOP,fill=BOTH,pady=2) self.m.add(sc) self.m.paneconfigure(sc,sticky='news',min=200) self.createMenuBar() self.createToolBar() self.createSidePane() if self.orientation == 'vertical': self.m.paneconfigure(self.sidepane, min=200) self.createPrimerDBGUI() self.createChildFrame(name='NotePad') return def createMenuBar(self): """Create the menu bar for the application. """ self.menu=Menu(self.main) self.file_menu={'01Open Project':{'cmd':self.openProject}, '02Open Sequence':{'cmd':self.openSequence}, '05Quit':{'cmd':self.quit}} self.file_menu=self.create_pulldown(self.menu,self.file_menu) self.menu.add_cascade(label='File',menu=self.file_menu['var']) self.edit_menu={'01Undo':{'cmd':self.undo}, '02Copy':{'cmd':self.copy}, '03Select All':{'cmd':self.sc.selectAll}, '04Configure Restriction Enzymes':{'cmd':self.restrictionEnzymesDialog}} self.edit_menu=self.create_pulldown(self.menu,self.edit_menu) self.menu.add_cascade(label='Edit',menu=self.edit_menu['var']) self.primer_menu={'01Primer DB':{'cmd':self.createPrimerDBGUI}} self.primer_menu=self.create_pulldown(self.menu,self.primer_menu) self.menu.add_cascade(label='Primer Tools',menu=self.primer_menu['var']) self.seqanal_menu={'01x':{'cmd':self.openSequence}} self.seqanal_menu=self.create_pulldown(self.menu,self.seqanal_menu) self.menu.add_cascade(label='Sequence Analysis',menu=self.seqanal_menu['var']) self.view_menu=Menu(self.menu) self.menu.add_cascade(label='Tools',menu=self.view_menu) self.appsvars = {} for i in self.apps.keys(): self.appsvars[i] = IntVar() def func(args): def new(): self.toggleApps(args) return new self.view_menu.add_checkbutton(label=i, onvalue=True, offvalue=False, command=func(i), variable=self.appsvars[i]) self.help_menu={ '01Online Help':{'cmd': self.help}, '02About':{'cmd': self.about},} self.help_menu=self.create_pulldown(self.menu,self.help_menu) self.menu.add_cascade(label='Help',menu=self.help_menu['var']) self.main.config(menu=self.menu) return def createSidePane(self, width=200): """Side panel for various dialogs is tabbed notebook that can hold multiple dialogs at once """ self.closeSidePane() self.sidepane = Frame(self.m, bd=1,relief=RAISED) self.sidepane = Pmw.NoteBook(self.m) self.sidepane.component('hull').configure(relief='sunken', borderwidth=1) self.m.paneconfigure(self.sidepane, width=width, sticky='news') self.m.add(self.sidepane) self.sidepane.setnaturalsize() return self.sidepane def closeSidePane(self): """Destroy sidepine""" if hasattr(self, 'sidepane'): self.m.forget(self.sidepane) self.sidepane.destroy() return def createChildFrame(self, sidepane=True, width=400, name=None): """Create a child frame in sidepane notebook or as toplevel""" geometry = '600x400+500+250' if sidepane == True: cframe = self.sidepane.add(name) self.sidepane.tab(name).configure(font='fixed 8',anchor='w') self.sidepane.selectpage(name) else: cframe = Toplevel() if name == None: title = 'default' else: title = name cframe.title(title) self.__dict__[name] = cframe #if name is a pre-defined app we load fetch the class if self.apps.has_key(name): cls = self.apps[name] inst = cls(cframe, parentapp=self) inst.pack(fill=BOTH,expand=1) self.appsvars[name].set(1) if hasattr(inst, 'geometry'): geometry = inst.geometry if sidepane == False: cframe.geometry(geometry) #bind frame close def func(evt): if hasattr(self, name): del self.__dict__[name] if name in self.appsvars: self.appsvars[name].set(0) cframe.bind("<Destroy>", func) return cframe def closeChildFrame(self): """Close sidepane frame""" name = self.sidepane.getcurselection() self.sidepane.delete(name) return def detachChildFrame(self): """Since we cannot actually detach frames in Tkinter, we remove the frame in the sidepane make a new toplevel window""" name = self.sidepane.getcurselection() self.sidepane.delete(name) if name == 'PrimerDB': fr = self.createPrimerDBGUI(sidepane=False) else: fr = self.createChildFrame(sidepane=False, name=name) return fr def toggleApps(self, name): """Remove or add apps from view""" print name if self.appsvars[name].get() == 1: if not hasattr(self, name): fr = self.createChildFrame(sidepane=True, name=name) else: if hasattr(self, name): if name in self.sidepane.pagenames(): self.sidepane.delete(name) else: self.__dict__[name].destroy() del self.__dict__[name] return def createToolBar(self): """Toolbar""" self.toolbar = ToolBar(self.main, self) self.toolbar.pack(side=TOP,fill=X,pady=1,before=self.m) img = Images.openproject() hlptxt="Open Project from file" self.toolbar.addButton('Open Project', self.openProject, img, hlptxt) img = Images.saveproject() hlptxt="Save Project" self.toolbar.addButton('Save Project', self.openProject, img, hlptxt) img = Images.undo() hlptxt="Undo" self.toolbar.addButton('Save Project', self.openProject, img, hlptxt) img = Images.zoomout() hlptxt="Zoom Out" self.toolbar.addButton('Save Project', self.sc.zoomOut, img, hlptxt) img = Images.zoomin() hlptxt="Zoom In" self.toolbar.addButton('Save Project', self.sc.zoomIn, img, hlptxt) img = Images.windowprefs() hlptxt="Seqeuence display preferences" self.toolbar.addButton('Seqeuence display preferences', self.sc.showPrefs, img, hlptxt) img = Images.prefs() hlptxt="Preferences" self.toolbar.addButton('Preferences', self.globalPrefsDialog, img, hlptxt) return def addWindowToolBar(self, parent): """Toolbar for changing frame views""" toolbar = ToolBar(parent, self) img = Images.closeframe() hlptxt="Close current sideframe" toolbar.addButton('tile vertical', self.closeChildFrame, img, hlptxt) img = Images.detachframe() hlptxt="Detach current sideframe as seperate window" toolbar.addButton('tile vertical', self.detachChildFrame, img, hlptxt) img = Images.tilevertical() hlptxt="Tile frames vertically" toolbar.addButton('x', self.tileVertical, img, hlptxt) img = Images.tilehorizontal() hlptxt="Tile frames horizontally" toolbar.addButton('tile horizontal', self.tileHorizontal, img, hlptxt) return toolbar def addStatusBar(self, parent): fr = Frame(parent, width=100) Label(fr,text='status stuff').pack() fr.pack(fill=X,side=LEFT,anchor='w') return def removeAll(self): """Remove all widgets""" for w in self.main.children.values(): w.destroy() return def tileHorizontal(self): """Re-arrange paned widgets horizontally""" if self.orientation == 'horizontal': return self.removeAll() self.orientation = 'horizontal' self.setupGUI() return def tileVertical(self): """Re-arrange paned widgets vertically""" if self.orientation == 'vertical': return self.removeAll() self.orientation = 'vertical' self.setupGUI() return def openSequence(self): """Load a sequence""" seq = Sequence() self.sc.loadSequence(seq) return def openProject(self, filename=None): """Load a project""" if filename == None: filename = Dialogs.openFilename(parent=self, ext='dtp') if not filename: return self.P.load(filename) #open sequence seq = self.P.DNAseq #print self.P.used_enzymes, self.P.cut_pos self.sc.project = self.P self.sc.update() #update primer db self.primerdb = PrimerDatabase(self.P.data['primer_dict']) self.pdbwin.database = self.primerdb self.pdbwin.update() return def copy(self): self.sc.copySequence() return def undo(self): return def createPrimerDBGUI(self, sidepane=True): """We create this individually to avoid confusion""" if hasattr(self, 'PrimerDB'): self.PrimerDB.lift() return fr = self.createChildFrame(name='PrimerDB',sidepane=sidepane) self.pdbwin = PrimerDBGUI(fr, database=self.primerdb) self.pdbwin.update() self.pdbwin.pack(fill=BOTH,expand=1) #bind window closing so it's automatically recreated in the sidepane if sidepane == False: def func(evt): self.createPrimerDBGUI() self.pdbwin.bind("<Destroy>", func) return fr def applyRestrSiteSettings(self): if hasattr(self, 'restrsitedialog'): vals = self.restrsitedialog.getValues() self.sc.update() return def restrictionEnzymesDialog(self, sidepane=True): defaults = {'uniquesitesonly':1,'showonlyenzymescutmax':50, 'ignorecutpos':1,'minlengthrecseq':5,'excludepromiscuous':1} options = [('uniquesitesonly','checkbutton',1,'Show unique sites only'), ('showonlyenzymescutmax','scale',(1,100),'Show only enzymes that cut max'), ('ignorecutpos','checkbutton',1,'Ignore cut position when finding isoschiziomers'), ('minlengthrecseq','scale',(1,10),'Min length of recognition sequence'), ('excludepromiscuous','checkbutton',1,'Exclude promiscuous enzymes')] geometry = '400x250+500+250' fr = self.createChildFrame(name='Configure Restriction Enzymes',sidepane=sidepane) self.restrsitedialog = Dialogs.GenericDialog(fr, options, defaults) defaults = {'uniquesitesonly':1,'showonlyenzymescutmax':50, 'ignorecutpos':1,'minlengthrecseq':5,'excludepromiscuous':1} self.restrsitedialog.pack(fill=BOTH,expand=1) return def applySettings(self): self.applyPrefs(self.prefsdialog.getValues()) #self.removeAll() #self.setupGUI() #self.globalPrefsDialog() return def globalPrefsDialog(self, sidepane=True): curr = {} for key in self.defaultprefs: curr[key] = self.__dict__[key] fr = self.createChildFrame(name='Global settings', sidepane=sidepane) self.prefsdialog = Dialogs.PrefsDialog(fr, self, self.defaultopts, curr, self.applySettings) self.prefsdialog.pack(fill=BOTH,expand=1) return def help(self): import webbrowser link='http://code.google.com/p/peat/wiki/DNAtool' webbrowser.open(link,autoraise=1) return def about(self): win=Toplevel() win.geometry('+500+350') win.title('About DNATool') win.maxsize(width=400,height=400) logo = Images.logo() label = Label(win,image=logo) label.image = logo label.pack(fill=BOTH,padx=4,pady=4) text="""DNATool App, Version 2 is a python desktop application for DNA sequence manipulation. Released under GPL v3 (C) Copyright 2012- Damien Farrell """ text=text.replace('\t','') text= ' '.join(text.split()) Label(win,text=text,wraplength=400).pack(fill=Y,side=TOP,pady=4) return def quit(self): if self.rememberwindowsize == 1: self.saveGeometry() self.main.destroy() if not self.parent: sys.exit() return
class App(Frame, GUI_help): """Data pipe GUI for importing and fitting of raw data. This class uses ekin provided an automated pipeline for fitting raw text data files and propagating errors. Uses a config file to store the pipeline settings""" def __init__(self, parent=None, rawfile=None, conffile=None): self.parent = parent if not self.parent: Frame.__init__(self) self.main = self.master else: self.main = Toplevel() self.master = self.main self.main.title('DNATool Desktop') self.main.protocol('WM_DELETE_WINDOW', self.quit) self.defaultprefs = { 'rememberwindowsize': 0, 'orientation': 'horizontal', 'alignmenttool': 'clustal', 'clustalpath': 'clustalw' } self.defaultopts = [ ('rememberwindowsize', 'checkbutton', 1, 'Remember window size'), ('orientation', 'menu', ('horizontal', 'vertical'), 'Default sideframe orientation'), ('alignmenttool', 'menu', ('clustal', 'muscle', 'needle'), 'External alignment tool'), ('clustalpath', 'entry', '', 'Path to Clustal') ] self.loadPrefs() self.setGeometry() self.P = Project() self.primerdb = PrimerDatabase() self.setupApps() self.setupGUI() self.sidepane.selectpage('PrimerDB') return def setGeometry(self): if self.rememberwindowsize == 1 and self.preferences.has_key( 'lastwindowsize'): lastwindowsize = self.preferences.get('lastwindowsize') self.winsize = lastwindowsize #self.w = int(lastwindowsize.split('x')[0]) else: self.winsize = self.getBestGeometry() self.main.geometry(self.winsize) return def getBestGeometry(self): """Calculate optimal geometry from screen size""" ws = self.main.winfo_screenwidth() hs = self.main.winfo_screenheight() self.w = w = ws / 1.3 h = 500 x = (ws / 2) - (w / 2) y = (hs / 2) - (h / 2) g = '%dx%d+%d+%d' % (w, h, x, y) return g def saveGeometry(self): """Save current geometry before quitting""" g = self.main.geometry() self.preferences.set('lastwindowsize', g) return def setupApps(self): """Creates a dict of classes so that GUI frames like primer design can be dynamically added without explicit methods for each""" self.apps = { 'Primer Design': PrimerDesignGUI, 'ORF Overview': ORFOverview, 'Sequence Analysis': SequenceAnalysis, 'Sequence Alignment Tool': SequenceAlignmentTool, 'Restriction Digest Summary': RestrictionDigestSummary, 'Blast Interface': BlastInterface, 'NotePad': TextEditor } return def loadPrefs(self): """Load prefs from a preferences instance""" self.preferences = Preferences('DNATool2', {}) temp = {} for key in self.defaultprefs: if not key in self.preferences.prefs: self.preferences.set(key, self.defaultprefs[key]) temp[key] = self.preferences.get(key) self.applyPrefs(temp) return def savePrefs(self): """Save prefs to a preferences instance""" self.applyPrefs(self.prefsdialog.getValues()) self.preferences = Preferences('DNATool2', {}) for key in self.defaultprefs: self.preferences.set(key, self.__dict__[key]) return def applyPrefs(self, prefs=None): """Apply prefs from a given dict""" if prefs == None: prefs = self.defaultprefs for key in prefs: self.__dict__[key] = prefs[key] return def setupGUI(self): """Do GUI elements""" self.visibleapps = {} #bottom panel bottom = Frame(self.main, height=50) bottom.pack(side=BOTTOM, fill=BOTH, pady=1) #status bar sb = self.addStatusBar(bottom) tb = self.addWindowToolBar(bottom) tb.pack(side=LEFT, anchor='e', expand=1) self.m = PanedWindow(self.main, orient=self.orientation, sashwidth=2, showhandle=True) self.m.pack(side=TOP, fill=BOTH, pady=2, expand=1) sc = self.sc = SequenceCanvas(self.m, parentapp=self, width=900, height=800) sc.pack(side=TOP, fill=BOTH, pady=2) self.m.add(sc) self.m.paneconfigure(sc, sticky='news', min=200) self.createMenuBar() self.createToolBar() self.createSidePane() if self.orientation == 'vertical': self.m.paneconfigure(self.sidepane, min=200) self.createPrimerDBGUI() self.createChildFrame(name='NotePad') return def createMenuBar(self): """Create the menu bar for the application. """ self.menu = Menu(self.main) self.file_menu = { '01Open Project': { 'cmd': self.openProject }, '02Open Sequence': { 'cmd': self.openSequence }, '05Quit': { 'cmd': self.quit } } self.file_menu = self.create_pulldown(self.menu, self.file_menu) self.menu.add_cascade(label='File', menu=self.file_menu['var']) self.edit_menu = { '01Undo': { 'cmd': self.undo }, '02Copy': { 'cmd': self.copy }, '03Select All': { 'cmd': self.sc.selectAll }, '04Configure Restriction Enzymes': { 'cmd': self.restrictionEnzymesDialog } } self.edit_menu = self.create_pulldown(self.menu, self.edit_menu) self.menu.add_cascade(label='Edit', menu=self.edit_menu['var']) self.primer_menu = {'01Primer DB': {'cmd': self.createPrimerDBGUI}} self.primer_menu = self.create_pulldown(self.menu, self.primer_menu) self.menu.add_cascade(label='Primer Tools', menu=self.primer_menu['var']) self.seqanal_menu = {'01x': {'cmd': self.openSequence}} self.seqanal_menu = self.create_pulldown(self.menu, self.seqanal_menu) self.menu.add_cascade(label='Sequence Analysis', menu=self.seqanal_menu['var']) self.view_menu = Menu(self.menu) self.menu.add_cascade(label='Tools', menu=self.view_menu) self.appsvars = {} for i in self.apps.keys(): self.appsvars[i] = IntVar() def func(args): def new(): self.toggleApps(args) return new self.view_menu.add_checkbutton(label=i, onvalue=True, offvalue=False, command=func(i), variable=self.appsvars[i]) self.help_menu = { '01Online Help': { 'cmd': self.help }, '02About': { 'cmd': self.about }, } self.help_menu = self.create_pulldown(self.menu, self.help_menu) self.menu.add_cascade(label='Help', menu=self.help_menu['var']) self.main.config(menu=self.menu) return def createSidePane(self, width=200): """Side panel for various dialogs is tabbed notebook that can hold multiple dialogs at once """ self.closeSidePane() self.sidepane = Frame(self.m, bd=1, relief=RAISED) self.sidepane = Pmw.NoteBook(self.m) self.sidepane.component('hull').configure(relief='sunken', borderwidth=1) self.m.paneconfigure(self.sidepane, width=width, sticky='news') self.m.add(self.sidepane) self.sidepane.setnaturalsize() return self.sidepane def closeSidePane(self): """Destroy sidepine""" if hasattr(self, 'sidepane'): self.m.forget(self.sidepane) self.sidepane.destroy() return def createChildFrame(self, sidepane=True, width=400, name=None): """Create a child frame in sidepane notebook or as toplevel""" geometry = '600x400+500+250' if sidepane == True: cframe = self.sidepane.add(name) self.sidepane.tab(name).configure(font='fixed 8', anchor='w') self.sidepane.selectpage(name) else: cframe = Toplevel() if name == None: title = 'default' else: title = name cframe.title(title) self.__dict__[name] = cframe #if name is a pre-defined app we load fetch the class if self.apps.has_key(name): cls = self.apps[name] inst = cls(cframe, parentapp=self) inst.pack(fill=BOTH, expand=1) self.appsvars[name].set(1) if hasattr(inst, 'geometry'): geometry = inst.geometry if sidepane == False: cframe.geometry(geometry) #bind frame close def func(evt): if hasattr(self, name): del self.__dict__[name] if name in self.appsvars: self.appsvars[name].set(0) cframe.bind("<Destroy>", func) return cframe def closeChildFrame(self): """Close sidepane frame""" name = self.sidepane.getcurselection() self.sidepane.delete(name) return def detachChildFrame(self): """Since we cannot actually detach frames in Tkinter, we remove the frame in the sidepane make a new toplevel window""" name = self.sidepane.getcurselection() self.sidepane.delete(name) if name == 'PrimerDB': fr = self.createPrimerDBGUI(sidepane=False) else: fr = self.createChildFrame(sidepane=False, name=name) return fr def toggleApps(self, name): """Remove or add apps from view""" print name if self.appsvars[name].get() == 1: if not hasattr(self, name): fr = self.createChildFrame(sidepane=True, name=name) else: if hasattr(self, name): if name in self.sidepane.pagenames(): self.sidepane.delete(name) else: self.__dict__[name].destroy() del self.__dict__[name] return def createToolBar(self): """Toolbar""" self.toolbar = ToolBar(self.main, self) self.toolbar.pack(side=TOP, fill=X, pady=1, before=self.m) img = Images.openproject() hlptxt = "Open Project from file" self.toolbar.addButton('Open Project', self.openProject, img, hlptxt) img = Images.saveproject() hlptxt = "Save Project" self.toolbar.addButton('Save Project', self.openProject, img, hlptxt) img = Images.undo() hlptxt = "Undo" self.toolbar.addButton('Save Project', self.openProject, img, hlptxt) img = Images.zoomout() hlptxt = "Zoom Out" self.toolbar.addButton('Save Project', self.sc.zoomOut, img, hlptxt) img = Images.zoomin() hlptxt = "Zoom In" self.toolbar.addButton('Save Project', self.sc.zoomIn, img, hlptxt) img = Images.windowprefs() hlptxt = "Seqeuence display preferences" self.toolbar.addButton('Seqeuence display preferences', self.sc.showPrefs, img, hlptxt) img = Images.prefs() hlptxt = "Preferences" self.toolbar.addButton('Preferences', self.globalPrefsDialog, img, hlptxt) return def addWindowToolBar(self, parent): """Toolbar for changing frame views""" toolbar = ToolBar(parent, self) img = Images.closeframe() hlptxt = "Close current sideframe" toolbar.addButton('tile vertical', self.closeChildFrame, img, hlptxt) img = Images.detachframe() hlptxt = "Detach current sideframe as seperate window" toolbar.addButton('tile vertical', self.detachChildFrame, img, hlptxt) img = Images.tilevertical() hlptxt = "Tile frames vertically" toolbar.addButton('x', self.tileVertical, img, hlptxt) img = Images.tilehorizontal() hlptxt = "Tile frames horizontally" toolbar.addButton('tile horizontal', self.tileHorizontal, img, hlptxt) return toolbar def addStatusBar(self, parent): fr = Frame(parent, width=100) Label(fr, text='status stuff').pack() fr.pack(fill=X, side=LEFT, anchor='w') return def removeAll(self): """Remove all widgets""" for w in self.main.children.values(): w.destroy() return def tileHorizontal(self): """Re-arrange paned widgets horizontally""" if self.orientation == 'horizontal': return self.removeAll() self.orientation = 'horizontal' self.setupGUI() return def tileVertical(self): """Re-arrange paned widgets vertically""" if self.orientation == 'vertical': return self.removeAll() self.orientation = 'vertical' self.setupGUI() return def openSequence(self): """Load a sequence""" seq = Sequence() self.sc.loadSequence(seq) return def openProject(self, filename=None): """Load a project""" if filename == None: filename = Dialogs.openFilename(parent=self, ext='dtp') if not filename: return self.P.load(filename) #open sequence seq = self.P.DNAseq #print self.P.used_enzymes, self.P.cut_pos self.sc.project = self.P self.sc.update() #update primer db self.primerdb = PrimerDatabase(self.P.data['primer_dict']) self.pdbwin.database = self.primerdb self.pdbwin.update() return def copy(self): self.sc.copySequence() return def undo(self): return def createPrimerDBGUI(self, sidepane=True): """We create this individually to avoid confusion""" if hasattr(self, 'PrimerDB'): self.PrimerDB.lift() return fr = self.createChildFrame(name='PrimerDB', sidepane=sidepane) self.pdbwin = PrimerDBGUI(fr, database=self.primerdb) self.pdbwin.update() self.pdbwin.pack(fill=BOTH, expand=1) #bind window closing so it's automatically recreated in the sidepane if sidepane == False: def func(evt): self.createPrimerDBGUI() self.pdbwin.bind("<Destroy>", func) return fr def applyRestrSiteSettings(self): if hasattr(self, 'restrsitedialog'): vals = self.restrsitedialog.getValues() self.sc.update() return def restrictionEnzymesDialog(self, sidepane=True): defaults = { 'uniquesitesonly': 1, 'showonlyenzymescutmax': 50, 'ignorecutpos': 1, 'minlengthrecseq': 5, 'excludepromiscuous': 1 } options = [('uniquesitesonly', 'checkbutton', 1, 'Show unique sites only'), ('showonlyenzymescutmax', 'scale', (1, 100), 'Show only enzymes that cut max'), ('ignorecutpos', 'checkbutton', 1, 'Ignore cut position when finding isoschiziomers'), ('minlengthrecseq', 'scale', (1, 10), 'Min length of recognition sequence'), ('excludepromiscuous', 'checkbutton', 1, 'Exclude promiscuous enzymes')] geometry = '400x250+500+250' fr = self.createChildFrame(name='Configure Restriction Enzymes', sidepane=sidepane) self.restrsitedialog = Dialogs.GenericDialog(fr, options, defaults) defaults = { 'uniquesitesonly': 1, 'showonlyenzymescutmax': 50, 'ignorecutpos': 1, 'minlengthrecseq': 5, 'excludepromiscuous': 1 } self.restrsitedialog.pack(fill=BOTH, expand=1) return def applySettings(self): self.applyPrefs(self.prefsdialog.getValues()) #self.removeAll() #self.setupGUI() #self.globalPrefsDialog() return def globalPrefsDialog(self, sidepane=True): curr = {} for key in self.defaultprefs: curr[key] = self.__dict__[key] fr = self.createChildFrame(name='Global settings', sidepane=sidepane) self.prefsdialog = Dialogs.PrefsDialog(fr, self, self.defaultopts, curr, self.applySettings) self.prefsdialog.pack(fill=BOTH, expand=1) return def help(self): import webbrowser link = 'http://code.google.com/p/peat/wiki/DNAtool' webbrowser.open(link, autoraise=1) return def about(self): win = Toplevel() win.geometry('+500+350') win.title('About DNATool') win.maxsize(width=400, height=400) logo = Images.logo() label = Label(win, image=logo) label.image = logo label.pack(fill=BOTH, padx=4, pady=4) text = """DNATool App, Version 2 is a python desktop application for DNA sequence manipulation. Released under GPL v3 (C) Copyright 2012- Damien Farrell """ text = text.replace('\t', '') text = ' '.join(text.split()) Label(win, text=text, wraplength=400).pack(fill=Y, side=TOP, pady=4) return def quit(self): if self.rememberwindowsize == 1: self.saveGeometry() self.main.destroy() if not self.parent: sys.exit() return
class TablesApp(Frame): """ Tables app """ def __init__(self,parent=None,data=None,datafile=None): "Initialize the application." self.parent=parent #If there is data to be loaded, show the dialog first if not self.parent: Frame.__init__(self) self.tablesapp_win=self.master else: self.tablesapp_win=Toplevel() # Get platform into a variable import platform self.currplatform=platform.system() if not hasattr(self,'defaultsavedir'): self.defaultsavedir = os.getcwd() self.preferences=Preferences('TablesApp',{'check_for_update':1}) self.loadprefs() self.tablesapp_win.title('Tables Application') self.tablesapp_win.geometry('+200+200') self.x_size=800 self.y_size=600 self.createMenuBar() self.apptoolBar = ToolBar(self.tablesapp_win, self) self.apptoolBar.pack(fill=BOTH, expand=NO) #add find bar #self.createSearchBar() if data != None: self.data = data self.new_project(data) elif datafile != None: self.open_project(datafile) else: self.new_project() self.tablesapp_win.protocol('WM_DELETE_WINDOW',self.quit) return def createMenuBar(self): """Create the menu bar for the application. """ self.menu=Menu(self.tablesapp_win) self.proj_menu={'01New':{'cmd':self.new_project}, '02Open':{'cmd':self.open_project}, '03Close':{'cmd':self.close_project}, '04Save':{'cmd':self.save_project}, '05Save As':{'cmd':self.save_as_project}, '06Preferences..':{'cmd':self.showPrefsDialog}, '08Quit':{'cmd':self.quit}} if self.parent: self.proj_menu['08Return to Database']={'cmd':self.return_data} self.proj_menu=self.create_pulldown(self.menu,self.proj_menu) self.menu.add_cascade(label='Project',menu=self.proj_menu['var']) self.records_menu={'01Add Row':{'cmd':self.add_Row}, '02Delete Row':{'cmd':self.delete_Row}, '03Add Column':{'cmd':self.add_Column}, '04Delete Column':{'cmd':self.delete_Column}, '05Auto Add Rows':{'cmd':self.autoAdd_Rows}, '06Auto Add Columns':{'cmd':self.autoAdd_Columns}, '07Find':{'cmd':self.createSearchBar}, } self.records_menu=self.create_pulldown(self.menu,self.records_menu) self.menu.add_cascade(label='Records',menu=self.records_menu['var']) self.sheet_menu={'01Add Sheet':{'cmd':self.add_Sheet}, '02Remove Sheet':{'cmd':self.delete_Sheet}, '03Copy Sheet':{'cmd':self.copy_Sheet}, '04Rename Sheet':{'cmd':self.rename_Sheet}, } self.sheet_menu=self.create_pulldown(self.menu,self.sheet_menu) self.menu.add_cascade(label='Sheet',menu=self.sheet_menu['var']) self.IO_menu={'01Import from csv file':{'cmd':self.import_cvs}, '02Export to csv file':{'cmd':self.export_cvs}, } self.IO_menu=self.create_pulldown(self.menu,self.IO_menu) self.menu.add_cascade(label='Import/Export',menu=self.IO_menu['var']) self.view_menu = Menu(self.menu, tearoff=0) self.view_menu.add_radiobutton(label="Normal View", state=ACTIVE,command=self.normal_view) self.view_menu.add_radiobutton(label="Page View", command=self.page_view) self.menu.add_cascade(label='View',menu=self.view_menu) # # Help menu # self.help_menu={'01Online Help':{'cmd':self.online_documentation}, '02About':{'cmd':self.about_Tables}} self.help_menu=self.create_pulldown(self.menu,self.help_menu) self.menu.add_cascade(label='Help',menu=self.help_menu['var']) self.tablesapp_win.config(menu=self.menu) return def create_pulldown(self,menu,dict): # # Create a pulldown in var from the info in dict # var=Menu(menu,tearoff=0) items=dict.keys() items.sort() for item in items: if item[-3:]=='sep': var.add_separator() else: # # Do we have a command? # command=None if dict[item].has_key('cmd'): command=dict[item]['cmd'] # # Put the command in there # if dict[item].has_key('sc'): var.add_command(label='%-25s %9s' %(item[2:],dict[item]['sc']),command=command) else: var.add_command(label='%-25s' %(item[2:]),command=command) dict['var']=var return dict def createSearchBar(self, event=None): """Add a find entry box""" frame = Frame(self.tablesapp_win) row=0 def close(): frame.destroy() self.findtext=StringVar() self.findbox=Entry(frame,textvariable=self.findtext,width=30,bg='white') self.findbox.grid(row=row,column=1,sticky='news',columnspan=2,padx=2,pady=2) self.findbox.bind('<Return>',self.do_find_text) Label(frame,text='Find:').grid(row=row,column=0,sticky='ew') self.findagainbutton=Button(frame,text='Find Again', command=self.do_find_again) self.findagainbutton.grid(row=row,column=3,sticky='news',padx=2,pady=2) self.cbutton=Button(frame,text='Close', command=close) self.cbutton.grid(row=row,column=4,sticky='news',padx=2,pady=2) frame.pack(fill=BOTH, expand=NO) return def loadprefs(self): """Setup default prefs file if any of the keys are not present""" defaultprefs = {'textsize':14, 'windowwidth': 800 ,'windowheight':600} for prop in defaultprefs.keys(): try: self.preferences.get(prop) except: self.preferences.set(prop, defaultprefs[prop]) return def showPrefsDialog(self): self.prefswindow = self.currenttable.showtablePrefs() return def new_project(self, data=None): """Create a new table, with model and add the frame""" if hasattr(self,'currenttable'): self.notebook.destroy() self.currenttable.destroy() #Create the sheets dict self.sheets = {} self.notebook = Pmw.NoteBook(self.tablesapp_win, raisecommand=self.setcurrenttable) self.notebook.pack(fill='both', expand=1, padx=4, pady=4) if data !=None: for s in data.keys(): sdata = data[s] try: self.add_Sheet(s ,sdata) except: print 'skipping' else: #do the table adding stuff for the initial sheet self.add_Sheet('sheet1') self.notebook.setnaturalsize() return def open_project(self, filename=None): if filename == None: filename=tkFileDialog.askopenfilename(defaultextension='.tbleprj"', initialdir=os.getcwd(), filetypes=[("Pickle file","*.tbleprj"), ("All files","*.*")], parent=self.tablesapp_win) if os.path.isfile(filename): fd=open(filename) data=pickle.load(fd) fd.close() self.new_project(data) self.filename=filename return def save_project(self): if not hasattr(self, 'filename'): self.save_as_project() elif self.filename == None: self.save_as_project() else: self.do_save_project(self.filename) return def save_as_project(self): """Save as a new filename""" filename=tkFileDialog.asksaveasfilename(parent=self.tablesapp_win, defaultextension='.tblprj', initialdir=self.defaultsavedir, filetypes=[("TableApp project","*.tblprj"), ("All files","*.*")]) if not filename: print 'Returning' return self.filename=filename self.do_save_project(self.filename) return def do_save_project(self, filename): """Get model dicts and write all to pickle file""" data={} for s in self.sheets.keys(): currtable = self.sheets[s] model = currtable.getModel() data[s] = model.getData() fd=open(filename,'w') pickle.dump(data,fd) fd.close() return def close_project(self): if hasattr(self,'currenttable'): #self.notebook.destroy() self.currenttable.destroy() return def import_cvs(self): importer = TableImporter() #datafile = importer.open_File(self.tablesapp_win) #just use the dialog to load and import the file importdialog = importer.import_Dialog(self.tablesapp_win) self.tablesapp_win.wait_window(importdialog) model = TableModel() model.importDict(importer.data) sheetdata = {} sheetdata['sheet1'] = model.getData() self.new_project(sheetdata) return def export_cvs(self): exporter = TableExporter() exporter.ExportTableData(self.currenttable) return def add_Sheet(self, sheetname=None, sheetdata=None): """Add a new sheet - handles all the table creation stuff""" def checksheet_name(name): if name == '': tkMessageBox.showwarning("Whoops", "Name should not be blank.") return 0 if self.sheets.has_key(name): tkMessageBox.showwarning("Name exists", "Sheet name already exists!") return 0 noshts = len(self.notebook.pagenames()) if sheetname == None: sheetname = tkSimpleDialog.askstring("New sheet name?", "Enter sheet name:", initialvalue='sheet'+str(noshts+1)) checksheet_name(sheetname) page = self.notebook.add(sheetname) #Create the table and model if data present if sheetdata != None: model = TableModel(sheetdata) self.currenttable = MyTable(page, model) else: self.currenttable = MyTable(page) #Load preferences into table self.currenttable.loadPrefs(self.preferences) #This handles all the canvas and header in the frame passed to constructor self.currenttable.createTableFrame() #add the table to the sheet dict self.sheets[sheetname] = self.currenttable self.saved = 0 return sheetname def delete_Sheet(self): """Delete a sheet""" s = self.notebook.getcurselection() self.notebook.delete(s) del self.sheets[s] return def copy_Sheet(self, newname=None): """Copy a sheet""" newdata = self.currenttable.getModel().getData().copy() if newname==None: self.add_Sheet(None, newdata) else: self.add_Sheet(newname, newdata) return def rename_Sheet(self): """Rename a sheet""" s = self.notebook.getcurselection() newname = tkSimpleDialog.askstring("New sheet name?", "Enter new sheet name:", initialvalue=s) if newname == None: return self.copy_Sheet(newname) self.delete_Sheet() return def setcurrenttable(self, event): """Set the currenttable so that menu items work with visible sheet""" try: s = self.notebook.getcurselection() self.currenttable = self.sheets[s] except: pass return def add_Row(self): """Add a new row""" self.currenttable.add_Row() self.saved = 0 return def delete_Row(self): """Delete currently selected row""" self.currenttable.delete_Row() self.saved = 0 return def add_Column(self): """Add a new column""" self.currenttable.add_Column() self.saved = 0 return def delete_Column(self): """Delete currently selected column in table""" self.currenttable.delete_Column() self.saved = 0 return def autoAdd_Rows(self): """Auto add x rows""" self.currenttable.autoAdd_Rows() self.saved = 0 return def autoAdd_Columns(self): """Auto add x rows""" self.currenttable.autoAdd_Columns() self.saved = 0 return def findValue(self): self.currenttable.findValue() return def do_find_text(self, event=None): """Find the text in the table""" if not hasattr(self,'currenttable'): return import string if string.strip(self.findtext.get())=='': return searchstring=self.findtext.get() if self.currenttable!=None: self.currenttable.findValue(searchstring) return def do_find_again(self, event=None): """Find again""" if not hasattr(self,'currenttable'): return searchstring=self.findtext.get() if self.currenttable!=None: self.currenttable.findValue(searchstring, findagain=1) return def plot(self, event=None): self.currenttable.plot_Selected() return def plotSetup(self, event=None): self.currenttable.plotSetup() return def normal_view(self,event=None): self.currenttable.paging_Off() return def page_view(self,event=None): self.currenttable.paging = 1 self.currenttable.redrawTable() return def about_Tables(self): self.ab_win=Toplevel() self.ab_win.geometry('+100+350') self.ab_win.title('About TablesApp') import Table_images logo = Table_images.tableapp_logo() label = Label(self.ab_win,image=logo) label.image = logo label.grid(row=0,column=0,sticky='news',padx=4,pady=4) text=['Tables Sample App ','Shows the use of Tablecanvas class for tkinter', 'Copyright (C) Damien Farrell 2008', 'This program is free software; you can redistribute it and/or', 'modify it under the terms of the GNU General Public License', 'as published by the Free Software Foundation; either version 2', 'of the License, or (at your option) any later version.'] row=1 for line in text: tmp=Label(self.ab_win,text=line) tmp.grid(row=row,column=0,sticky='news',padx=4) row=row+1 return def online_documentation(self,event=None): """Open the online documentation""" import webbrowser link='http://sourceforge.net/projects/tkintertable/' webbrowser.open(link,autoraise=1) return def quit(self): self.tablesapp_win.destroy() return
class SequenceCanvas(Pmw.ScrolledCanvas): """Canvas for drawing all graphical elements, sequences and restrictions sites""" def __init__(self, parent=None, parentapp=None, width=400, height=400, bg='white', **kwargs): Pmw.ScrolledCanvas.__init__(self, parent, canvasmargin=2) self.parent = parent self.parentapp = parentapp self.project = None self.platform = platform.system() self.width = width self.height = height self.canvas = self.component('canvas') self.canvas.configure(bg='#f6f9f6', height=height, width=width) self.createBindings() self.defaultprefs = { 'seqfont': 'Courier', 'seqfontsize': 13, 'fontstyle': 'bold', 'basescale': 15, 'restrfont': 'Arial', 'backgrcolor': '#f6f9f6', 'seqcoloroption': 2 } fonts = ['Courier', 'Arial', 'Fixed', 'Tahoma', 'Times', 'Verdana'] #we use the following to create the prefs dialog #list of tuples of the form name,type,default,label self.defaultopts = [ ('seqfont', 'menu', fonts, 'Sequence font'), ('seqfontsize', 'scale', (6, 30), 'Sequence font size'), ('fontstyle', 'menu', ['normal', 'bold', 'italic'], 'Font style'), ('basescale', 'scale', (8, 50), 'Base scale'), ('restrfont', 'menu', fonts, 'Restr site font'), ('backgrcolor', 'color', '#f6f9f6', 'Background color') ] self.loadPrefs() self.baserow = self.height / 2 self.seqstart = 80 self.siterowstart = 70 self.orfoffset = 15 self.yscale = 1.1 #self.sequence = Utilities.createDummySequence(100) self.alignedsequences = [] self.update() return def createBindings(self): """Bindings""" c = self.canvas c.bind("<Button-1>", self.handleLeftClick) c.bind("<B1-Motion>", self.handleLeftMotion) c.bind("<Button-3>", self.handleRightClick) c.bind_all("<Control-KeyPress-c>", self.copySequence) #c.bind("<ButtonRelease-3>",self.handleRightRelease) '''c.bind("<ButtonRelease-1>",self.handle_left_release) c.bind("<Shift-Button-1>", self.handle_left_shift_click) c.bind("<Shift-ButtonRelease-1>", self.handle_left_shift_release) c.bind("<B3-Motion>", self.handle_right_motion) c.bind_all("<Control-KeyPress-x>",self.cut_DNA) c.bind_all("<Control-KeyPress-v>",self.paste_DNA) c.bind_all("<Delete>",self.delete_DNA) ''' return def loadPrefs(self): """Load prefs from a preferences instance""" self.preferences = Preferences('DNATool2', {}) temp = {} for key in self.defaultprefs: if not key in self.preferences.prefs: self.preferences.set(key, self.defaultprefs[key]) temp[key] = self.preferences.get(key) self.applyPrefs(temp) return def savePrefs(self): """Save prefs to a preferences instance""" self.preferences = Preferences('DNATool2', {}) for key in self.defaultprefs: self.preferences.set(key, self.__dict__[key]) return def applyPrefs(self, prefs=None): """Apply prefs from a given dict""" if prefs == None: prefs = self.defaultprefs for key in prefs: self.__dict__[key] = prefs[key] return def handleLeftClick(self, evt): """Handle left click""" if hasattr(self, 'rightmenu'): self.rightmenu.destroy() c = self.canvas if len(c.gettags(CURRENT)) == 0: return self.markPosition(evt) x = evt.x y = evt.y items = c.find_closest(evt.x, evt.y, halo=14) x1, y1, x2, y2 = c.bbox(CURRENT) self.selecteditems = c.find_enclosed(x1 - 1, y1 - 1, x2 + 1, y2 + 1) return def handleLeftMotion(self, evt): c = self.canvas items = self.selecteditems current = c.gettags(CURRENT) if 'sitelabel' in current: self.dragMove(evt, items) elif 'sequence' in current: self.setSequenceSelection(evt) return def selectSequence(self, seq): """Select sequence just from seq values""" self.highlightSequence(seq) self.selectedrange = seq return def selectAll(self): sel = range(0, len(self.sequence)) self.selectSequence(sel) return def setSequenceSelection(self, evt): """Select sequence from mouse action""" c = self.canvas x = self.oldx x2 = c.canvasx(evt.x) height = self.basescale / 1.1 y = self.baserow + height / 2 c.delete(c.find_withtag('seqselection')) rect = c.create_rectangle(x, y, x2, y - height, width=0, tag=('seqselection'), fill='yellow') x1, y1, x2, y2 = c.bbox(rect) items = c.find_overlapping(x1 + 2, y1, x2 - 2, y2) seq = range(self.getSeqPositionFromCoords(x), self.getSeqPositionFromCoords(x2)) self.selectSequence(seq) return def highlightSequence(self, sequence): """Highlight section of sequence in different color""" self.colorSequence() c = self.canvas height = self.basescale / 1.1 y = self.baserow + height / 2 ignore = set(['seqbackground', 'seqselection']) for s in sequence: x = self.getBasePosition(s) items = c.find_overlapping(x - 2, y - 2, x, y + 2) for i in items: if len(set(c.gettags(i)) & ignore) > 0: continue c.itemconfig(i, fill='red') c.lift(i) return def getSeqPositionFromCoords(self, x): """From X and Y coordinate, return the DNA base number""" #if abs(y-self.baserow)>5: # return None pos = int(float(x - self.seqstart + 4.0) / self.basescale) return pos def markPosition(self, evt): c = self.canvas self.oldx = c.canvasx(evt.x) self.oldy = c.canvasy(evt.y) self.selectedtags = c.gettags(CURRENT) return def dragMove(self, evt, items=None, tags=None): """Handle mouse drag""" c = self.canvas x = c.canvasx(evt.x) y = c.canvasy(evt.y) diffx = x - self.oldx diffy = y - self.oldy self.oldx = x self.oldy = y name = c.gettags(CURRENT)[0] for i in items: c.move(i, diffx, diffy) self.drawSiteConnector(x, y, name, move=True) return def handleRightClick(self, evt): self.rightmenu = self.popupMenu(evt) return def popupMenu(self, evt): """Right click shows popup menu""" popupmenu = Menu(self.canvas, tearoff=0) def popupFocusOut(evt): popupmenu.unpost() popupmenu.add_command(label="Show Prefs", command=self.showPrefs) popupmenu.add_command(label="Zoom in", command=self.zoomIn) popupmenu.add_command(label="Zoom out", command=self.zoomOut) popupmenu.bind("<FocusOut>", popupFocusOut) popupmenu.focus_set() popupmenu.post(evt.x_root, evt.y_root) return popupmenu def addSequences(self, sequences): self.alignedsequences = sequences return def update(self, sequence=None, enzymes=None, cutpos=None): """Update display of the current sequence(s)""" if sequence == None: X = self.getDatafromProject() if X == None: return else: sequence, enzymes, cutpos = X #remove previous self.clear() self.calculateScaling() self.drawDefaultLabels() #update sequence self.showSequence(sequence) self.colorSequence() self.drawSeqBackground() #if self.ORFselected == True: self.showAA3Seq(sequence) #draw restr sites if enzymes != None: self.showRestrictionSites(enzymes, cutpos) #update primers if selected #self.showPrimers() self.canvas.configure(bg=self.backgrcolor) return def getDatafromProject(self): if self.project != None: P = self.project if P.DNAseq == '': return else: return sequence = P.DNAseq enzymes = P.used_enzymes cutpos = P.cut_pos return sequence, enzymes, cutpos def clear(self): """Clear all""" c = self.canvas c.delete(ALL) return def calculateScaling(self): """Calculate font size dependant y-scaling to prevent crowding""" self.yscale = self.seqfontsize / 10.0 self.yscale = pow(self.yscale, 0.05) return def getCurrentFont(self): """Generate current font from settings""" fontsize = self.seqfontsize fontstyle = self.fontstyle #create a font object if fontstyle != 'italic': seqfont = tkFont.Font(family=self.seqfont, size=fontsize, weight=fontstyle) else: seqfont = tkFont.Font(family=self.seqfont, size=fontsize, slant="italic") return seqfont def showSequence(self, sequence=None, row=None, tag=None): """Show sequence""" if sequence == None: return if row == None: row = self.baserow c = self.canvas seqfont = self.getCurrentFont() #dna sequence self.sequence = sequence #print sequence for i in range(len(sequence)): pos = self.getBasePosition(i) item = c.create_text(pos, row, font=seqfont, text=sequence[i], fill='black', anchor='w', tag=('seqtext', 'sequence')) if tag != None: c.itemconfig(i, tag=tag) self.seqend = self.getBasePosition(len(sequence)) - self.seqstart self.canvas.configure(scrollregion=(0, 0, self.seqend + 100, self.height)) self.centerPage() return def showMultiple(self, aligned=None, direction='up'): """Show multiple sequences aligned to the base one""" #print self.alignedsequences if aligned == None: aligned = self.alignedsequences self.clearMultiple() if len(aligned) == 0: return #move restr sites up self.clearRestrictionSites() if direction == 'up': inc = -15 else: inc = 15 row = self.baserow + inc print len(aligned) for s in aligned[:55]: self.showSequence(s, row, tag='aligned') row += inc self.height += 20 return def clearMultiple(self): """Clear multiple sequences""" c = self.canvas c.delete('aligned') self.update() return def showAASeq(self): return def showAA3Seq(self, sequence=None): """Show 3 letter code amino acid sequence""" if sequence == None: return c = self.canvas seqfont = self.getCurrentFont() y = (self.baserow + self.orfoffset) * self.yscale frame = 0 AAseqs3, AAseqs1 = Mutation.translate(sequence) aaseq = AAseqs3[frame] #print aaseq for i in range(len(aaseq)): pos = self.getAAPosition(i) #,frame+1) c.create_text(pos, y, font=seqfont, text=aaseq[i], fill='black', tag=('aasequence')) for i in range(len(aaseq)): if i % 5 != 0: continue pos = self.getAAPosition(i) c.create_text(pos, y + 45, font='Courier 11', text=i, fill='black', tag=('aasequence')) c.create_line(pos, y + 35, pos, y + 20, fill='red', width=2) return def colorSequence(self): """Color the dna sequence""" c = self.canvas items = c.find_withtag('seqtext') option = 2 count = 0 clr = '#66CC00' for i in items: if option == 1: c.itemconfig(i, fill=clr) elif option == 2: if count % 3 == 0 and clr == '#66CC00': clr = '#999900' elif count % 3 == 0 and clr == '#999900': clr = '#66CC00' c.itemconfig(i, fill=clr) count = count + 1 return def drawDefaultLabels(self): """Draw objects that are permanent""" c = self.canvas item = c.create_text(5, self.baserow, font='Courier 10', text='DNA seq', fill='darkgreen', anchor='w') y = (self.baserow + self.orfoffset) * self.yscale item = c.create_text(5, y, font='Courier 10', text='ORF', fill='black', anchor='w') item = c.create_text(5, y + 45, font='Courier 10', text='AA no.', fill='gray', anchor='w') return def drawSeqBackground(self, color='white'): """Draw a background for a sequence""" c = self.canvas x = self.seqstart height = self.basescale y = self.baserow + height / 2 end = self.seqend rect = c.create_rectangle(x, y, x + end, y - height, width=0, tag=('seqbackground', 'sequence'), fill=color) c.tag_lower(rect) return rect def drawRestrictionSite(self, name, positions): """Draw restriction site(s) for a single enzyme""" c = self.canvas font = restrfont = str( self.restrfont) + ' ' + str(self.seqfontsize - 2) done = [] if len(positions) == 1: #font = font+' underline' fill = '#FF9999' else: fill = '#F6FCE1' for pos in positions: uid = name + str(pos[0]) self.restrictionsites[uid] = pos[0] if pos[0] in done: continue done.append(pos[0]) x = self.getBasePosition(pos[0]) y = self.baserow - self.siterowstart text = self.create_text(x, y, text=name, tags=(uid, 'sitelabel', 'restrsite'), font=font, anchor='nw') x1, y1, x2, y2 = box = c.bbox(text) rect = c.create_rectangle(box, fill=fill, outline='gray', tags=(uid, 'rect', 'restrsite')) items = c.find_withtag(uid) overlapping = c.find_overlapping(x1, y1, x2, y2)[:-2] #print pos, items, overlapping inc = -10 while len(overlapping) > 1: for i in items: c.move(i, 0, inc) x1, y1, x2, y2 = c.bbox(i) overlapping = c.find_overlapping(x1, y1, x2, y2)[:-2] y = y + inc c.lift(text) self.drawSiteConnector(x, y, uid) return text def drawSiteConnector(self, x2, y2, uid, move=False): """Draw line connecting site label to sequence""" c = self.canvas pos = self.restrictionsites[uid] x1 = self.getBasePosition(pos) y1 = self.baserow - 15 if move == True: old = list(set(c.find_withtag(uid)) & set(c.find_withtag('line'))) for i in old: c.delete(i) line = c.create_line(x1, y1, x1, y2, fill='blue', width=2, stipple='gray25', tag=(uid, 'line', 'restrsite')) c.tag_lower(line) line = c.create_line(x1, y2, x2, y2, fill='blue', width=2, stipple='gray25', tag=(uid, 'line', 'restrsite')) c.tag_lower(line) return def moveItemByName(self, name, y): c = self.canvas items = c.find_withtag(name) for i in items: c.move(i, 0, y) return def showRestrictionSites(self, enzymes=None, cutpos=None): """Draw all restriction sites""" if enzymes == None: return self.restrictionsites = {} c = self.canvas for e in enzymes: if cutpos.has_key(e): positions = cutpos[e] r = self.drawRestrictionSite(e, positions) return def clearRestrictionSites(self): """Clear all restriction sites""" c = self.canvas #print c.find_withtag('restrsite') c.delete('restrsite') return def getBasePosition(self, pos): """Return the x position of the nth base on the canvas""" return self.seqstart + float(pos) * self.basescale def getAAPosition(self, pos, frame=None): pos = pos * 3 + 1 #+float(frame) return self.getBasePosition(pos) def showPrimers(self): """Draw primers""" return def centerPage(self): """Center canvas on sequence after redraw""" top, bottom = self.yview() size = bottom - top if size == 0: size = 0.4 middle = size * 0.4 self.yview('moveto', middle) #print top, bottom #print middle return def zoomIn(self): """Zoom in by enlarging all elements""" c = self.canvas x1, x2 = self.xview() y1, y2 = self.yview() self.basescale = self.basescale * 1.1 self.seqfontsize = self.seqfontsize + 1 self.update() return def zoomOut(self): """Zoom out by reducing all elements""" if self.seqfontsize < 7: return self.basescale = self.basescale / 1.1 self.seqfontsize = self.seqfontsize - 1 self.update() return def copySequence(self, evt=None): """Copy sequence text""" seqdata = ''.join([self.sequence[i] for i in self.selectedrange]) self.parent.clipboard_clear() self.parent.clipboard_append(seqdata) return def showPrefs(self, evt=None): """Show preferences window""" fr = Toplevel(self.parent) fr.title('Sequence window preferences') def func(): self.applyPrefs(self.prefsdialog.getValues()) self.update() curr = {} for key in self.defaultprefs: curr[key] = self.__dict__[key] dlg = self.prefsdialog = Dialogs.PrefsDialog(fr, self, options=self.defaultopts, defaults=curr, callback=func) dlg.pack(fill=BOTH, expand=1) fr.geometry(dlg.geometry) fr.grab_set() fr.transient(self.parent) return
class TablesApp(Frame): """ Tables app """ def __init__(self, parent=None, data=None, datafile=None): "Initialize the application." self.parent = parent #If there is data to be loaded, show the dialog first if not self.parent: Frame.__init__(self) self.tablesapp_win = self.master else: self.tablesapp_win = Toplevel() # Get platform into a variable import platform self.currplatform = platform.system() if not hasattr(self, 'defaultsavedir'): self.defaultsavedir = os.getcwd() self.preferences = Preferences('TablesApp', {'check_for_update': 1}) self.loadprefs() self.tablesapp_win.title('Tables Application') self.tablesapp_win.geometry('+200+200') self.x_size = 800 self.y_size = 600 self.createMenuBar() self.apptoolBar = ToolBar(self.tablesapp_win, self) self.apptoolBar.pack(fill=BOTH, expand=NO) #add find bar #self.createSearchBar() if data != None: self.data = data self.new_project(data) elif datafile != None: self.open_project(datafile) else: self.new_project() self.tablesapp_win.protocol('WM_DELETE_WINDOW', self.quit) return def createMenuBar(self): """Create the menu bar for the application. """ self.menu = Menu(self.tablesapp_win) self.proj_menu = { '01New': { 'cmd': self.new_project }, '02Open': { 'cmd': self.open_project }, '03Close': { 'cmd': self.close_project }, '04Save': { 'cmd': self.save_project }, '05Save As': { 'cmd': self.save_as_project }, '06Preferences..': { 'cmd': self.showPrefsDialog }, '08Quit': { 'cmd': self.quit } } if self.parent: self.proj_menu['08Return to Database'] = {'cmd': self.return_data} self.proj_menu = self.create_pulldown(self.menu, self.proj_menu) self.menu.add_cascade(label='Project', menu=self.proj_menu['var']) self.records_menu = { '01Add Row': { 'cmd': self.add_Row }, '02Delete Row': { 'cmd': self.delete_Row }, '03Add Column': { 'cmd': self.add_Column }, '04Delete Column': { 'cmd': self.delete_Column }, '05Auto Add Rows': { 'cmd': self.autoAdd_Rows }, '06Auto Add Columns': { 'cmd': self.autoAdd_Columns }, '07Find': { 'cmd': self.createSearchBar }, } self.records_menu = self.create_pulldown(self.menu, self.records_menu) self.menu.add_cascade(label='Records', menu=self.records_menu['var']) self.sheet_menu = { '01Add Sheet': { 'cmd': self.add_Sheet }, '02Remove Sheet': { 'cmd': self.delete_Sheet }, '03Copy Sheet': { 'cmd': self.copy_Sheet }, '04Rename Sheet': { 'cmd': self.rename_Sheet }, } self.sheet_menu = self.create_pulldown(self.menu, self.sheet_menu) self.menu.add_cascade(label='Sheet', menu=self.sheet_menu['var']) self.IO_menu = { '01Import from csv file': { 'cmd': self.import_cvs }, '02Export to csv file': { 'cmd': self.export_cvs }, } self.IO_menu = self.create_pulldown(self.menu, self.IO_menu) self.menu.add_cascade(label='Import/Export', menu=self.IO_menu['var']) self.view_menu = Menu(self.menu, tearoff=0) self.view_menu.add_radiobutton(label="Normal View", state=ACTIVE, command=self.normal_view) self.view_menu.add_radiobutton(label="Page View", command=self.page_view) self.menu.add_cascade(label='View', menu=self.view_menu) # # Help menu # self.help_menu = { '01Online Help': { 'cmd': self.online_documentation }, '02About': { 'cmd': self.about_Tables } } self.help_menu = self.create_pulldown(self.menu, self.help_menu) self.menu.add_cascade(label='Help', menu=self.help_menu['var']) self.tablesapp_win.config(menu=self.menu) return def create_pulldown(self, menu, dict): # # Create a pulldown in var from the info in dict # var = Menu(menu, tearoff=0) items = dict.keys() items.sort() for item in items: if item[-3:] == 'sep': var.add_separator() else: # # Do we have a command? # command = None if dict[item].has_key('cmd'): command = dict[item]['cmd'] # # Put the command in there # if dict[item].has_key('sc'): var.add_command(label='%-25s %9s' % (item[2:], dict[item]['sc']), command=command) else: var.add_command(label='%-25s' % (item[2:]), command=command) dict['var'] = var return dict def createSearchBar(self, event=None): """Add a find entry box""" frame = Frame(self.tablesapp_win) row = 0 def close(): frame.destroy() self.findtext = StringVar() self.findbox = Entry(frame, textvariable=self.findtext, width=30, bg='white') self.findbox.grid(row=row, column=1, sticky='news', columnspan=2, padx=2, pady=2) self.findbox.bind('<Return>', self.do_find_text) Label(frame, text='Find:').grid(row=row, column=0, sticky='ew') self.findagainbutton = Button(frame, text='Find Again', command=self.do_find_again) self.findagainbutton.grid(row=row, column=3, sticky='news', padx=2, pady=2) self.cbutton = Button(frame, text='Close', command=close) self.cbutton.grid(row=row, column=4, sticky='news', padx=2, pady=2) frame.pack(fill=BOTH, expand=NO) return def loadprefs(self): """Setup default prefs file if any of the keys are not present""" defaultprefs = { 'textsize': 14, 'windowwidth': 800, 'windowheight': 600 } for prop in defaultprefs.keys(): try: self.preferences.get(prop) except: self.preferences.set(prop, defaultprefs[prop]) return def showPrefsDialog(self): self.prefswindow = self.currenttable.showtablePrefs() return def new_project(self, data=None): """Create a new table, with model and add the frame""" if hasattr(self, 'currenttable'): self.notebook.destroy() self.currenttable.destroy() #Create the sheets dict self.sheets = {} self.notebook = Pmw.NoteBook(self.tablesapp_win, raisecommand=self.setcurrenttable) self.notebook.pack(fill='both', expand=1, padx=4, pady=4) if data != None: for s in data.keys(): sdata = data[s] try: self.add_Sheet(s, sdata) except: print 'skipping' else: #do the table adding stuff for the initial sheet self.add_Sheet('sheet1') self.notebook.setnaturalsize() return def open_project(self, filename=None): if filename == None: filename = tkFileDialog.askopenfilename( defaultextension='.tbleprj"', initialdir=os.getcwd(), filetypes=[("Pickle file", "*.tbleprj"), ("All files", "*.*")], parent=self.tablesapp_win) if os.path.isfile(filename): fd = open(filename) data = pickle.load(fd) fd.close() self.new_project(data) self.filename = filename return def save_project(self): if not hasattr(self, 'filename'): self.save_as_project() elif self.filename == None: self.save_as_project() else: self.do_save_project(self.filename) return def save_as_project(self): """Save as a new filename""" filename = tkFileDialog.asksaveasfilename( parent=self.tablesapp_win, defaultextension='.tblprj', initialdir=self.defaultsavedir, filetypes=[("TableApp project", "*.tblprj"), ("All files", "*.*")]) if not filename: print 'Returning' return self.filename = filename self.do_save_project(self.filename) return def do_save_project(self, filename): """Get model dicts and write all to pickle file""" data = {} for s in self.sheets.keys(): currtable = self.sheets[s] model = currtable.getModel() data[s] = model.getData() fd = open(filename, 'w') pickle.dump(data, fd) fd.close() return def close_project(self): if hasattr(self, 'currenttable'): #self.notebook.destroy() self.currenttable.destroy() return def import_cvs(self): importer = TableImporter() #datafile = importer.open_File(self.tablesapp_win) #just use the dialog to load and import the file importdialog = importer.import_Dialog(self.tablesapp_win) self.tablesapp_win.wait_window(importdialog) model = TableModel() model.importDict(importer.data) sheetdata = {} sheetdata['sheet1'] = model.getData() self.new_project(sheetdata) return def export_cvs(self): exporter = TableExporter() exporter.ExportTableData(self.currenttable) return def add_Sheet(self, sheetname=None, sheetdata=None): """Add a new sheet - handles all the table creation stuff""" def checksheet_name(name): if name == '': tkMessageBox.showwarning("Whoops", "Name should not be blank.") return 0 if self.sheets.has_key(name): tkMessageBox.showwarning("Name exists", "Sheet name already exists!") return 0 noshts = len(self.notebook.pagenames()) if sheetname == None: sheetname = tkSimpleDialog.askstring("New sheet name?", "Enter sheet name:", initialvalue='sheet' + str(noshts + 1)) checksheet_name(sheetname) page = self.notebook.add(sheetname) #Create the table and model if data present if sheetdata != None: model = TableModel(sheetdata) self.currenttable = MyTable(page, model) else: self.currenttable = MyTable(page) #Load preferences into table self.currenttable.loadPrefs(self.preferences) #This handles all the canvas and header in the frame passed to constructor self.currenttable.createTableFrame() #add the table to the sheet dict self.sheets[sheetname] = self.currenttable self.saved = 0 return sheetname def delete_Sheet(self): """Delete a sheet""" s = self.notebook.getcurselection() self.notebook.delete(s) del self.sheets[s] return def copy_Sheet(self, newname=None): """Copy a sheet""" newdata = self.currenttable.getModel().getData().copy() if newname == None: self.add_Sheet(None, newdata) else: self.add_Sheet(newname, newdata) return def rename_Sheet(self): """Rename a sheet""" s = self.notebook.getcurselection() newname = tkSimpleDialog.askstring("New sheet name?", "Enter new sheet name:", initialvalue=s) if newname == None: return self.copy_Sheet(newname) self.delete_Sheet() return def setcurrenttable(self, event): """Set the currenttable so that menu items work with visible sheet""" try: s = self.notebook.getcurselection() self.currenttable = self.sheets[s] except: pass return def add_Row(self): """Add a new row""" self.currenttable.add_Row() self.saved = 0 return def delete_Row(self): """Delete currently selected row""" self.currenttable.delete_Row() self.saved = 0 return def add_Column(self): """Add a new column""" self.currenttable.add_Column() self.saved = 0 return def delete_Column(self): """Delete currently selected column in table""" self.currenttable.delete_Column() self.saved = 0 return def autoAdd_Rows(self): """Auto add x rows""" self.currenttable.autoAdd_Rows() self.saved = 0 return def autoAdd_Columns(self): """Auto add x rows""" self.currenttable.autoAdd_Columns() self.saved = 0 return def findValue(self): self.currenttable.findValue() return def do_find_text(self, event=None): """Find the text in the table""" if not hasattr(self, 'currenttable'): return import string if string.strip(self.findtext.get()) == '': return searchstring = self.findtext.get() if self.currenttable != None: self.currenttable.findValue(searchstring) return def do_find_again(self, event=None): """Find again""" if not hasattr(self, 'currenttable'): return searchstring = self.findtext.get() if self.currenttable != None: self.currenttable.findValue(searchstring, findagain=1) return def plot(self, event=None): self.currenttable.plot_Selected() return def plotSetup(self, event=None): self.currenttable.plotSetup() return def normal_view(self, event=None): self.currenttable.paging_Off() return def page_view(self, event=None): self.currenttable.paging = 1 self.currenttable.redrawTable() return def about_Tables(self): self.ab_win = Toplevel() self.ab_win.geometry('+100+350') self.ab_win.title('About TablesApp') import Table_images logo = Table_images.tableapp_logo() label = Label(self.ab_win, image=logo) label.image = logo label.grid(row=0, column=0, sticky='news', padx=4, pady=4) text = [ 'Tables Sample App ', 'Shows the use of Tablecanvas class for tkinter', 'Copyright (C) Damien Farrell 2008', 'This program is free software; you can redistribute it and/or', 'modify it under the terms of the GNU General Public License', 'as published by the Free Software Foundation; either version 2', 'of the License, or (at your option) any later version.' ] row = 1 for line in text: tmp = Label(self.ab_win, text=line) tmp.grid(row=row, column=0, sticky='news', padx=4) row = row + 1 return def online_documentation(self, event=None): """Open the online documentation""" import webbrowser link = 'http://sourceforge.net/projects/tkintertable/' webbrowser.open(link, autoraise=1) return def quit(self): self.tablesapp_win.destroy() return
class LabbookApp(Frame, GUI_help): """ Labbook app """ appname = 'Labbook client' def __init__(self, parent=None, peatinfo=None, title=None, data=None, datafile=None): "Initialize the application." self.parent = parent #If there is data to be loaded, show the dialog first if self.parent == None: Frame.__init__(self) self.labbook_win = self.master self.peatinfo = None else: self.labbook_win = Toplevel() self.master = self.labbook_win self.peatinfo = peatinfo #reference to peat protein/field self.DB = self.parent.DB #ref to peat if title != None: self.title = 'subtable_' + title else: self.title = 'Labbook Tool' self.ID = 'Labbook' # Get platform into a variable import platform self.currplatform = platform.system() if not hasattr(self, 'defaultsavedir'): self.defaultsavedir = os.getcwd() self.preferences = Preferences('Labbook', {'check_for_update': 1}) #self.loadprefs() if self.peatinfo: protein = self.peatinfo['record'] field_name = self.peatinfo['column'] self.labbook_win.title('Labbook: ' + protein + '_' + field_name) else: self.labbook_win.title(self.title) self.labbook_win.geometry('+200+100') self.x_size = 1000 self.y_size = 500 self.createMenuBar() self.apptoolBar = ToolBar(self.labbook_win, self) self.apptoolBar.pack(fill=BOTH, expand=NO) #add find bar #self.createSearchBar() if data != None: self.data = data self.new_project(data) elif datafile != None: self.open_project(filename=datafile) else: self.new_project() #add return to main PEAT db button if self.parent: Button(self.labbook_win, text="Return to Database", command=self.return_data).pack() self.labbook_win.protocol('WM_DELETE_WINDOW', self.quit) self.createBindings() self.clipboard = None return def createBindings(self): """Bind keys""" self.labbook_win.bind("<Control-n>", self.new_project) self.labbook_win.bind("<Control-o>", self.open_project) self.labbook_win.bind("<Control-s>", self.save_project) self.labbook_win.bind("<Control-q>", self.quit) self.labbook_win.bind("<Control-i>", self.import_csv) self.labbook_win.bind("<Control-e>", self.export_csv) return def createMenuBar(self): """Create the menu bar for the application. """ self.menu = Menu(self.labbook_win) self.proj_menu = { '01New': { 'cmd': self.new_project }, '02Open': { 'cmd': self.open_project }, '03Close': { 'cmd': self.close_project }, '04Save': { 'cmd': self.save_project }, '05Save As': { 'cmd': self.save_as_project }, '06Preferences..': { 'cmd': self.showPrefsDialog }, '08Quit': { 'cmd': self.quit } } if self.parent: self.proj_menu['08Return to Database'] = {'cmd': self.return_data} self.proj_menu = self.create_pulldown(self.menu, self.proj_menu) self.menu.add_cascade(label='Project', menu=self.proj_menu['var']) self.edit_menu = { '01Copy': { 'cmd': self.copy }, '02Paste': { 'cmd': self.paste }, '03Copy Columns': { 'cmd': self.copyColumns }, '04Paste Columns': { 'cmd': self.pasteColumns } } self.edit_menu = self.create_pulldown(self.menu, self.edit_menu) self.menu.add_cascade(label='Edit', menu=self.edit_menu['var']) self.records_menu = { '01Add Row': { 'cmd': self.add_Row }, '02Delete Row': { 'cmd': self.delete_Row }, '03Add Column': { 'cmd': self.add_Column }, '04Delete Column': { 'cmd': self.delete_Column }, '05Auto Add Rows': { 'cmd': self.autoAdd_Rows }, '06Auto Add Columns': { 'cmd': self.autoAdd_Columns }, '07Find Cell': { 'cmd': self.createSearchBar }, '08Filter': { 'cmd': self.showFilteringBar } } self.records_menu = self.create_pulldown(self.menu, self.records_menu) self.menu.add_cascade(label='Records', menu=self.records_menu['var']) self.sheet_menu = { '01Add Sheet': { 'cmd': self.add_Sheet }, '02Remove Sheet': { 'cmd': self.delete_Sheet }, '03Copy Sheet': { 'cmd': self.copy_Sheet }, '04Rename Sheet': { 'cmd': self.rename_Sheet }, '05Merge Sheet': { 'cmd': self.merge_Sheet }, } self.sheet_menu = self.create_pulldown(self.menu, self.sheet_menu) self.menu.add_cascade(label='Sheet', menu=self.sheet_menu['var']) self.IO_menu = { '01Import from csv file': { 'cmd': self.import_csv }, '02Export to csv file': { 'cmd': self.export_csv }, '03Import external fileset': { 'cmd': self.import_fileset }, } self.IO_menu = self.create_pulldown(self.menu, self.IO_menu) self.menu.add_cascade(label='Import/Export', menu=self.IO_menu['var']) self.view_menu = Menu(self.menu, tearoff=0) self.view_menu.add_radiobutton(label="Normal View", state=ACTIVE, command=self.normal_view) self.view_menu.add_radiobutton(label="Page View", command=self.page_view) self.view_menu.add_command(label="Show All", command=self.showAll) self.menu.add_cascade(label='View', menu=self.view_menu) # # Help menu # self.help_menu = { '01Online Help': { 'cmd': self.online_documentation }, '02About': { 'cmd': self.about_Labbook } } self.help_menu = self.create_pulldown(self.menu, self.help_menu) self.menu.add_cascade(label='Help', menu=self.help_menu['var']) self.labbook_win.config(menu=self.menu) return def createSearchBar(self, event=None): """Add a find entry box""" frame = Frame(self.labbook_win) row = 0 def close(): frame.destroy() self.findtext = StringVar() self.findbox = Entry(frame, textvariable=self.findtext, width=30, bg='white') self.findbox.grid(row=row, column=1, sticky='news', columnspan=2, padx=2, pady=2) self.findbox.bind('<Return>', self.do_find_text) Label(frame, text='Find:').grid(row=row, column=0, sticky='ew') self.findagainbutton = Button(frame, text='Find Again', command=self.do_find_again) self.findagainbutton.grid(row=row, column=3, sticky='news', padx=2, pady=2) self.cbutton = Button(frame, text='Close', command=close) self.cbutton.grid(row=row, column=4, sticky='news', padx=2, pady=2) frame.pack(fill=BOTH, expand=NO) return def showFilteringBar(self): s = self.notebook.getcurselection() page = self.notebook.page(s) if not hasattr(self.currenttable, 'filterframe') or self.currenttable.filterframe == None: frame = self.currenttable.createFilteringBar(page) frame.grid(row=5, column=0, columnspan=3) return def showAll(self): """Show all recs""" self.currenttable.showAll() return def loadprefs(self): """Setup default prefs file if any of the keys are not present""" defaultprefs = { 'textsize': 14, 'windowwidth': 800, 'windowheight': 600 } for prop in defaultprefs.keys(): try: self.preferences.get(prop) except: self.preferences.set(prop, defaultprefs[prop]) print self.preferences.get('textsize') return def showPrefsDialog(self): self.prefswindow = self.currenttable.showtablePrefs() return def new_project(self, data=None): """Create a new table, with model and add the frame""" if hasattr(self, 'currenttable'): self.notebook.destroy() self.currenttable.destroy() #Create the sheets dict self.sheets = {} self.notebook = Pmw.NoteBook(self.labbook_win, raisecommand=self.setcurrenttable) self.notebook.pack(fill='both', expand=1, padx=4, pady=4) if data != None: for s in data.keys(): sdata = data[s] #try: self.add_Sheet(s, sdata) #except: # print 'skipping' else: #do the table adding stuff for the initial sheet self.add_Sheet('sheet1') self.notebook.setnaturalsize() self.setcurrenttable() return def open_project(self, event=None, filename=None): import os if filename == None: import tkFileDialog filename = tkFileDialog.askopenfilename( defaultextension='.labbook', initialdir=os.getcwd(), filetypes=[("Pickle file", "*.labbook"), ("All files", "*.*")], parent=self.labbook_win) if os.path.isfile(filename): fd = open(filename) import pickle data = pickle.load(fd) fd.close() self.new_project(data) self.filename = filename return def save_project(self, event=None): if not hasattr(self, 'filename'): self.save_as_project() elif self.filename == None: self.save_as_project() else: self.do_save_project(self.filename) return def save_as_project(self): """Save as a new filename""" import tkFileDialog, os filename = tkFileDialog.asksaveasfilename( parent=self.labbook_win, defaultextension='.labbook', initialdir=self.defaultsavedir, filetypes=[("Labbook project", "*.labbook"), ("All files", "*.*")]) if not filename: print 'Returning' return self.filename = filename self.do_save_project(self.filename) return def do_save_project(self, filename): """Get model dicts and write all to pickle file""" data = {} for s in self.sheets.keys(): currtable = self.sheets[s] model = currtable.getModel() data[s] = model.getData() fd = open(filename, 'w') import pickle pickle.dump(data, fd) fd.close() return def close_project(self): if hasattr(self, 'currenttable'): #self.notebook.destroy() self.currenttable.destroy() return def import_csv(self): importer = TableImporter() #just use the dialog to load and import the file importdialog = importer.import_Dialog(self.labbook_win) self.labbook_win.wait_window(importdialog) modeldata = importer.modeldata self.add_Sheet(sheetdata=modeldata) return def export_csv(self): exporter = TableExporter() exporter.ExportTableData(self.currenttable) return def import_fileset(self): """Import a series of external files in a folder""" if self.parent == None: import tkMessageBox tkMessageBox.showwarning( "Not available", "You can't use this feature outside PEAT.") return from Extfile import FileHandler fh = FileHandler(parent=self) fh.importFileset(DB=self.DB, callback=self.currenttable.redrawTable) return def add_Sheet(self, sheetname=None, sheetdata=None, model=None): """Add a new sheet - handles all the table creation stuff""" def checksheet_name(name): if name == '': tkMessageBox.showwarning("Whoops", "Name should not be blank.") return 0 if self.sheets.has_key(name): tkMessageBox.showwarning("Name exists", "Sheet name already exists!") return 0 noshts = len(self.notebook.pagenames()) if sheetname == None: sheetname = tkSimpleDialog.askstring("New sheet name?", "Enter sheet name:", initialvalue='sheet' + str(noshts + 1), parent=self.labbook_win) checksheet_name(sheetname) page = self.notebook.add(sheetname) #Create the model if none provided if model == None: if sheetdata != None: model = LabbookTableModel(sheetdata) else: model = LabbookTableModel(rows=10, columns=5) #create the table: we pass the parent instance of peat #and peat row/col if present self.currenttable = LabbookTable(parent=page, model=model, sheetname=sheetname, peat=self.parent, peatinfo=self.peatinfo) #Load preferences into table self.currenttable.loadPrefs(self.preferences) #This handles all the canvas and header in the frame passed to constructor self.currenttable.createTableFrame() #add the table to the sheet dict self.sheets[sheetname] = self.currenttable self.saved = 0 return sheetname def delete_Sheet(self, s=None): """Delete a sheet""" if s == None: s = self.notebook.getcurselection() print s self.notebook.delete(s) del self.sheets[s] return def copy_Sheet(self, newname=None): """Copy a sheet""" newdata = self.currenttable.getModel().getData().copy() if newname == None: self.add_Sheet(None, newdata) else: self.add_Sheet(newname, newdata) return def rename_Sheet(self): """Rename a sheet""" s = self.notebook.getcurselection() newname = tkSimpleDialog.askstring("New sheet name?", "Enter new sheet name:", initialvalue=s) if newname == None: return self.copy_Sheet(newname) self.delete_Sheet() return def merge_Sheet(self): """Merge 2 sheets""" if len(self.sheets) < 2: return def domerge(): name = shs.getvalue()[0] newmodel = self.sheets[name].model curr.model.merge(newmodel) self.currenttable.redrawTable() return s = self.notebook.getcurselection() curr = self.sheets[s] fr = Toplevel() fr.title('Select sheet to merge') self.set_centered_geometry(self.labbook_win, fr) shs = self.sheetsSelector(fr) Button(fr, text='Merge', command=domerge).pack(side=TOP) return def setcurrenttable(self, event=None): """Set the currenttable so that menu items work with visible sheet""" try: s = self.notebook.getcurselection() self.currenttable = self.sheets[s] except: pass return def add_Row(self): """Add a new row""" self.currenttable.add_Row() self.saved = 0 return def delete_Row(self): """Delete currently selected row""" self.currenttable.delete_Row() self.saved = 0 return def add_Column(self): """Add a new column""" self.currenttable.add_Column() self.saved = 0 return def delete_Column(self): """Delete currently selected column in table""" self.currenttable.delete_Column() self.saved = 0 return def autoAdd_Rows(self): """Auto add x rows""" self.currenttable.autoAdd_Rows() self.saved = 0 return def autoAdd_Columns(self): """Auto add x rows""" self.currenttable.autoAdd_Columns() self.saved = 0 return def copy(self): """Copy current selection to internal clipboard""" T = self.currenttable self.clipboard = T.copyCell() return def paste(self): print self.clipboard return def copyColumns(self): """Copy columns""" self.currenttable.getSelectedColumn() self.clipboard = self.currenttable.copyColumns() return def pasteColumns(self): """Paste columns""" self.currenttable.pasteColumns(self.clipboard) return def findValue(self): self.currenttable.findValue() return def do_find_text(self, event=None): """Find the text in the table""" if not hasattr(self, 'currenttable'): return import string if string.strip(self.findtext.get()) == '': return searchstring = self.findtext.get() if self.currenttable != None: self.currenttable.findValue(searchstring) return def do_find_again(self, event=None): """Find again""" if not hasattr(self, 'currenttable'): return searchstring = self.findtext.get() if self.currenttable != None: self.currenttable.findValue(searchstring, findagain=1) return def plot(self, event=None): self.currenttable.plot_Selected() return def plotSetup(self, event=None): self.currenttable.plotSetup() return def normal_view(self, event=None): self.currenttable.paging_Off() return def page_view(self, event=None): self.currenttable.paging = 1 self.currenttable.redrawTable() return def return_data(self, event=None): """Return the data to PEAT""" returndata = {} for s in self.sheets.keys(): currtable = self.sheets[s] model = currtable.getModel() returndata[s] = model.getData() self.parent.templabbookdata = returndata.copy() self.quit() return def sheetsSelector(self, frame): """Show list of sheets""" names = self.sheets.keys() labbooklist = Pmw.ScrolledListBox(frame, labelpos='nw', label_text='Sheets', listbox_height=8) labbooklist.pack(fill=BOTH, expand=1) labbooklist.setlist(names) return labbooklist def about_Labbook(self): self.ab_win = Toplevel() self.ab_win.geometry('+100+350') self.ab_win.title('About Labbook') import PEAT_images logo = PEAT_images.labbook_logo() label = Label(self.ab_win, image=logo) label.image = logo label.grid(row=0, column=0, sticky='news', padx=4, pady=4) text = [ 'Labbook ', 'Part of Protein Engineering and Analysis Tool', 'A spreadsheet-like table for PEAT.' ] row = 1 for line in text: tmp = Label(self.ab_win, text=line) tmp.grid(row=row, column=0, sticky='news', padx=4) row = row + 1 return def online_documentation(self, event=None): """Open the online documentation""" import webbrowser link = 'http://enzyme.ucd.ie/PEAT/' webbrowser.open(link, autoraise=1) return def quit(self, event=None): self.labbook_win.destroy() return
class SequenceCanvas(Pmw.ScrolledCanvas): """Canvas for drawing all graphical elements, sequences and restrictions sites""" def __init__(self, parent=None, parentapp=None, width=400, height=400, bg='white', **kwargs): Pmw.ScrolledCanvas.__init__(self, parent, canvasmargin=2) self.parent = parent self.parentapp = parentapp self.project = None self.platform = platform.system() self.width=width self.height=height self.canvas = self.component('canvas') self.canvas.configure(bg='#f6f9f6',height=height, width=width) self.createBindings() self.defaultprefs = {'seqfont':'Courier', 'seqfontsize':13, 'fontstyle':'bold', 'basescale':15, 'restrfont':'Arial', 'backgrcolor':'#f6f9f6','seqcoloroption':2} fonts = ['Courier','Arial','Fixed','Tahoma','Times','Verdana'] #we use the following to create the prefs dialog #list of tuples of the form name,type,default,label self.defaultopts = [('seqfont','menu',fonts,'Sequence font'), ('seqfontsize','scale',(6,30), 'Sequence font size'), ('fontstyle','menu',['normal','bold','italic'],'Font style'), ('basescale','scale',(8,50), 'Base scale'), ('restrfont','menu',fonts,'Restr site font'), ('backgrcolor','color','#f6f9f6','Background color')] self.loadPrefs() self.baserow = self.height/2 self.seqstart = 80 self.siterowstart = 70 self.orfoffset = 15 self.yscale = 1.1 #self.sequence = Utilities.createDummySequence(100) self.alignedsequences = [] self.update() return def createBindings(self): """Bindings""" c = self.canvas c.bind("<Button-1>", self.handleLeftClick) c.bind("<B1-Motion>", self.handleLeftMotion) c.bind("<Button-3>", self.handleRightClick) c.bind_all("<Control-KeyPress-c>", self.copySequence) #c.bind("<ButtonRelease-3>",self.handleRightRelease) '''c.bind("<ButtonRelease-1>",self.handle_left_release) c.bind("<Shift-Button-1>", self.handle_left_shift_click) c.bind("<Shift-ButtonRelease-1>", self.handle_left_shift_release) c.bind("<B3-Motion>", self.handle_right_motion) c.bind_all("<Control-KeyPress-x>",self.cut_DNA) c.bind_all("<Control-KeyPress-v>",self.paste_DNA) c.bind_all("<Delete>",self.delete_DNA) ''' return def loadPrefs(self): """Load prefs from a preferences instance""" self.preferences = Preferences('DNATool2',{}) temp = {} for key in self.defaultprefs: if not key in self.preferences.prefs: self.preferences.set(key, self.defaultprefs[key]) temp[key] = self.preferences.get(key) self.applyPrefs(temp) return def savePrefs(self): """Save prefs to a preferences instance""" self.preferences = Preferences('DNATool2',{}) for key in self.defaultprefs: self.preferences.set(key, self.__dict__[key]) return def applyPrefs(self, prefs=None): """Apply prefs from a given dict""" if prefs == None: prefs=self.defaultprefs for key in prefs: self.__dict__[key] = prefs[key] return def handleLeftClick(self, evt): """Handle left click""" if hasattr(self, 'rightmenu'): self.rightmenu.destroy() c = self.canvas if len(c.gettags(CURRENT))==0: return self.markPosition(evt) x=evt.x; y=evt.y items = c.find_closest(evt.x, evt.y, halo=14) x1,y1,x2,y2 = c.bbox(CURRENT) self.selecteditems = c.find_enclosed(x1-1, y1-1, x2+1, y2+1) return def handleLeftMotion(self, evt): c = self.canvas items = self.selecteditems current = c.gettags(CURRENT) if 'sitelabel' in current: self.dragMove(evt, items) elif 'sequence' in current: self.setSequenceSelection(evt) return def selectSequence(self, seq): """Select sequence just from seq values""" self.highlightSequence(seq) self.selectedrange = seq return def selectAll(self): sel = range(0,len(self.sequence)) self.selectSequence(sel) return def setSequenceSelection(self, evt): """Select sequence from mouse action""" c = self.canvas x = self.oldx x2 = c.canvasx(evt.x) height = self.basescale/1.1 y = self.baserow+height/2 c.delete(c.find_withtag('seqselection')) rect = c.create_rectangle(x,y, x2, y-height, width=0, tag=('seqselection'),fill='yellow') x1,y1,x2,y2 = c.bbox(rect) items = c.find_overlapping(x1+2, y1, x2-2, y2) seq = range(self.getSeqPositionFromCoords(x),self.getSeqPositionFromCoords(x2)) self.selectSequence(seq) return def highlightSequence(self, sequence): """Highlight section of sequence in different color""" self.colorSequence() c = self.canvas height = self.basescale/1.1 y = self.baserow+height/2 ignore = set(['seqbackground','seqselection']) for s in sequence: x = self.getBasePosition(s) items = c.find_overlapping(x-2, y-2, x, y+2) for i in items: if len(set(c.gettags(i)) & ignore) > 0: continue c.itemconfig(i,fill='red') c.lift(i) return def getSeqPositionFromCoords(self,x): """From X and Y coordinate, return the DNA base number""" #if abs(y-self.baserow)>5: # return None pos = int(float(x-self.seqstart+4.0)/self.basescale) return pos def markPosition(self, evt): c = self.canvas self.oldx = c.canvasx(evt.x) self.oldy = c.canvasy(evt.y) self.selectedtags = c.gettags(CURRENT) return def dragMove(self, evt, items=None, tags=None): """Handle mouse drag""" c = self.canvas x = c.canvasx(evt.x) y = c.canvasy(evt.y) diffx = x - self.oldx diffy = y - self.oldy self.oldx = x self.oldy = y name = c.gettags(CURRENT)[0] for i in items: c.move(i, diffx, diffy) self.drawSiteConnector(x, y, name, move=True) return def handleRightClick(self, evt): self.rightmenu = self.popupMenu(evt) return def popupMenu(self, evt): """Right click shows popup menu""" popupmenu = Menu(self.canvas, tearoff = 0) def popupFocusOut(evt): popupmenu.unpost() popupmenu.add_command(label="Show Prefs", command= self.showPrefs) popupmenu.add_command(label="Zoom in", command= self.zoomIn) popupmenu.add_command(label="Zoom out", command= self.zoomOut) popupmenu.bind("<FocusOut>", popupFocusOut) popupmenu.focus_set() popupmenu.post(evt.x_root, evt.y_root) return popupmenu def addSequences(self, sequences): self.alignedsequences = sequences return def update(self, sequence=None, enzymes=None, cutpos=None): """Update display of the current sequence(s)""" if sequence == None: X = self.getDatafromProject() if X == None: return else: sequence, enzymes, cutpos = X #remove previous self.clear() self.calculateScaling() self.drawDefaultLabels() #update sequence self.showSequence(sequence) self.colorSequence() self.drawSeqBackground() #if self.ORFselected == True: self.showAA3Seq(sequence) #draw restr sites if enzymes != None: self.showRestrictionSites(enzymes, cutpos) #update primers if selected #self.showPrimers() self.canvas.configure(bg=self.backgrcolor) return def getDatafromProject(self): if self.project != None: P = self.project if P.DNAseq == '': return else: return sequence = P.DNAseq enzymes = P.used_enzymes cutpos = P.cut_pos return sequence, enzymes, cutpos def clear(self): """Clear all""" c = self.canvas c.delete(ALL) return def calculateScaling(self): """Calculate font size dependant y-scaling to prevent crowding""" self.yscale = self.seqfontsize/10.0 self.yscale=pow(self.yscale,0.05) return def getCurrentFont(self): """Generate current font from settings""" fontsize = self.seqfontsize fontstyle = self.fontstyle #create a font object if fontstyle != 'italic': seqfont = tkFont.Font (family=self.seqfont, size=fontsize, weight=fontstyle) else: seqfont = tkFont.Font (family=self.seqfont, size=fontsize, slant="italic") return seqfont def showSequence(self, sequence=None, row=None, tag=None): """Show sequence""" if sequence == None: return if row == None: row = self.baserow c = self.canvas seqfont = self.getCurrentFont() #dna sequence self.sequence = sequence #print sequence for i in range(len(sequence)): pos = self.getBasePosition(i) item = c.create_text(pos,row, font=seqfont,text=sequence[i], fill='black',anchor='w',tag=('seqtext','sequence')) if tag != None: c.itemconfig(i, tag=tag) self.seqend = self.getBasePosition(len(sequence))-self.seqstart self.canvas.configure(scrollregion=(0,0,self.seqend+100,self.height)) self.centerPage() return def showMultiple(self, aligned=None, direction='up'): """Show multiple sequences aligned to the base one""" #print self.alignedsequences if aligned == None: aligned = self.alignedsequences self.clearMultiple() if len(aligned) == 0: return #move restr sites up self.clearRestrictionSites() if direction == 'up': inc = -15 else: inc = 15 row = self.baserow + inc print len(aligned) for s in aligned[:55]: self.showSequence(s, row, tag='aligned') row+=inc self.height+=20 return def clearMultiple(self): """Clear multiple sequences""" c = self.canvas c.delete('aligned') self.update() return def showAASeq(self): return def showAA3Seq(self, sequence=None): """Show 3 letter code amino acid sequence""" if sequence == None: return c = self.canvas seqfont = self.getCurrentFont() y = (self.baserow+self.orfoffset)*self.yscale frame = 0 AAseqs3,AAseqs1 = Mutation.translate(sequence) aaseq = AAseqs3[frame] #print aaseq for i in range(len(aaseq)): pos = self.getAAPosition(i)#,frame+1) c.create_text(pos,y, font=seqfont,text=aaseq[i], fill='black',tag=('aasequence')) for i in range(len(aaseq)): if i%5!=0: continue pos = self.getAAPosition(i) c.create_text(pos,y+45, font='Courier 11',text=i, fill='black',tag=('aasequence')) c.create_line(pos,y+35,pos,y+20,fill='red',width=2) return def colorSequence(self): """Color the dna sequence""" c = self.canvas items = c.find_withtag('seqtext') option = 2 count=0 clr = '#66CC00' for i in items: if option == 1: c.itemconfig(i, fill=clr) elif option == 2: if count % 3 == 0 and clr == '#66CC00': clr='#999900' elif count % 3 == 0 and clr=='#999900': clr='#66CC00' c.itemconfig(i, fill=clr) count=count+1 return def drawDefaultLabels(self): """Draw objects that are permanent""" c = self.canvas item = c.create_text(5,self.baserow,font='Courier 10',text='DNA seq', fill='darkgreen',anchor='w') y = (self.baserow+self.orfoffset)*self.yscale item = c.create_text(5,y,font='Courier 10',text='ORF', fill='black',anchor='w') item = c.create_text(5,y+45,font='Courier 10',text='AA no.', fill='gray',anchor='w') return def drawSeqBackground(self, color='white'): """Draw a background for a sequence""" c = self.canvas x = self.seqstart height = self.basescale y = self.baserow+height/2 end = self.seqend rect = c.create_rectangle(x,y, x+end, y-height, width=0,tag=('seqbackground','sequence'),fill=color) c.tag_lower(rect) return rect def drawRestrictionSite(self, name, positions): """Draw restriction site(s) for a single enzyme""" c = self.canvas font = restrfont = str(self.restrfont)+' '+str(self.seqfontsize-2) done=[] if len(positions) == 1: #font = font+' underline' fill = '#FF9999' else: fill = '#F6FCE1' for pos in positions: uid = name+str(pos[0]) self.restrictionsites[uid] = pos[0] if pos[0] in done: continue done.append(pos[0]) x = self.getBasePosition(pos[0]) y = self.baserow-self.siterowstart text = self.create_text(x,y,text=name,tags=(uid,'sitelabel','restrsite'), font=font,anchor='nw') x1,y1,x2,y2 = box = c.bbox(text) rect = c.create_rectangle(box,fill=fill,outline='gray', tags=(uid,'rect','restrsite')) items = c.find_withtag(uid) overlapping = c.find_overlapping(x1,y1,x2,y2)[:-2] #print pos, items, overlapping inc=-10 while len(overlapping) > 1: for i in items: c.move(i,0,inc) x1,y1,x2,y2 = c.bbox(i) overlapping = c.find_overlapping(x1,y1,x2,y2)[:-2] y=y+inc c.lift(text) self.drawSiteConnector(x,y,uid) return text def drawSiteConnector(self,x2,y2,uid,move=False): """Draw line connecting site label to sequence""" c = self.canvas pos = self.restrictionsites[uid] x1 = self.getBasePosition(pos) y1 = self.baserow-15 if move==True: old = list(set(c.find_withtag(uid))&set(c.find_withtag('line'))) for i in old: c.delete(i) line = c.create_line(x1,y1,x1,y2, fill='blue', width=2,stipple='gray25', tag=(uid,'line','restrsite')) c.tag_lower(line) line = c.create_line(x1,y2,x2,y2, fill='blue', width=2,stipple='gray25', tag=(uid,'line','restrsite')) c.tag_lower(line) return def moveItemByName(self, name, y): c = self.canvas items = c.find_withtag(name) for i in items: c.move(i, 0, y) return def showRestrictionSites(self, enzymes=None, cutpos=None): """Draw all restriction sites""" if enzymes==None: return self.restrictionsites = {} c = self.canvas for e in enzymes: if cutpos.has_key(e): positions = cutpos[e] r = self.drawRestrictionSite(e, positions) return def clearRestrictionSites(self): """Clear all restriction sites""" c = self.canvas #print c.find_withtag('restrsite') c.delete('restrsite') return def getBasePosition(self, pos): """Return the x position of the nth base on the canvas""" return self.seqstart + float(pos) * self.basescale def getAAPosition(self, pos, frame=None): pos = pos*3+1 #+float(frame) return self.getBasePosition(pos) def showPrimers(self): """Draw primers""" return def centerPage(self): """Center canvas on sequence after redraw""" top, bottom = self.yview() size = bottom - top if size==0: size=0.4 middle = size * 0.4 self.yview('moveto', middle) #print top, bottom #print middle return def zoomIn(self): """Zoom in by enlarging all elements""" c = self.canvas x1,x2 = self.xview() y1,y2 = self.yview() self.basescale = self.basescale*1.1 self.seqfontsize = self.seqfontsize+1 self.update() return def zoomOut(self): """Zoom out by reducing all elements""" if self.seqfontsize<7: return self.basescale = self.basescale/1.1 self.seqfontsize = self.seqfontsize-1 self.update() return def copySequence(self, evt=None): """Copy sequence text""" seqdata = ''.join([self.sequence[i] for i in self.selectedrange]) self.parent.clipboard_clear() self.parent.clipboard_append(seqdata) return def showPrefs(self, evt=None): """Show preferences window""" fr = Toplevel(self.parent) fr.title('Sequence window preferences') def func(): self.applyPrefs(self.prefsdialog.getValues()) self.update() curr = {} for key in self.defaultprefs: curr[key] = self.__dict__[key] dlg = self.prefsdialog = Dialogs.PrefsDialog(fr, self, options=self.defaultopts, defaults=curr, callback=func) dlg.pack(fill=BOTH,expand=1) fr.geometry(dlg.geometry) fr.grab_set() fr.transient(self.parent) return