def makeProjectMenu(self): importsMenu = Menu(self.mainMenu, tearoff=False) importsMenu.add_command(label='Fasta Sequence',command=self.importFastaSeq) importsMenu.add_command(label='NMR-STAR 2.1.1', command=self.importNmrStar211) importsMenu.add_command(label='NMR-STAR 3.1', command=self.importNmrStar31) importsMenu.add_command(label='PDB 3.20',command=self.importPdb) importsMenu.add_command(label='PDB Coords',command=self.importPdbCoords) #importsMenu.add_command(label='CNS Distance Restraints',command=self.importCnsDistance) exportsMenu = Menu(self.mainMenu, tearoff=False) exportsMenu.add_command(label='NMR-STAR 3.1', command=self.eciFrame.exportNmrStar31) exportsMenu.add_command(label='PDB Coords',command=self.eciFrame.exportPdb) #exportsMenu.add_command(label='CNS Distance Restraints',command=self.eciFrame.exportCnsDistance) # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call menu.add_command(label='New', shortcut='N', command=self.newProject) menu.add_command(label='Open', shortcut='O', command=self.openProject) menu.add_command(label='Close', shortcut='C', command=self.closeProject) menu.add_command(label='Save', shortcut='S', command=self.saveProject) menu.add_command(label='Save As', shortcut='A', command=self.saveAsProject) menu.add_cascade(label='Import', shortcut='I', menu=importsMenu) menu.add_cascade(label='Export', shortcut='E', menu=exportsMenu) menu.add_command(label='Quit', shortcut='Q', command=self.quit) menu.add_command(label='Version', shortcut='V', command=self.showVersion) self.mainMenu.add_cascade(label='Project', shortcut='P', menu=menu) menu.options = ['New','Open','Close','Save','Save As','Import','Export','Quit','Version'] return menu
def makeOtherMenu(self): # The fonts menu is a pre-created widget fontsMenu = FontMenu(self.mainMenu, self.setFont, sizes=(8,10,12), doItalic=0, doBoldItalic=0, tearoff=0) # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Only Fonts option so far menu.add_cascade(label='Fonts', shortcut='F', menu=fontsMenu) self.mainMenu.add_cascade(label='Options', shortcut='O', menu=menu) menu.options = ['Fonts',] return menu
def makeAppearanceMenu(self): # The fonts menu is a pre-created widget fontsMenu = FontMenu(self.mainMenu, self.setFont, sizes=(8,10,12), doItalic=0, doBoldItalic=0, tearoff=0) # Plot color schemes colorMenu = Menu(self.mainMenu, tearoff=0) colorMenu.add_radiobutton(label='Red', command=self.colorSchemeRed,) colorMenu.add_radiobutton(label='Rainbow', command=self.colorSchemeRainbow,) #colorMenu.add_radiobutton(label='Black', shortcut='B', command=self.colorSchemeBlack) #colorMenu.add_radiobutton(label='White', shortcut='W', command=self.colorSchemeWhite) # Submenu of the main menu menu = Menu(self.mainMenu, tearoff=0) # Only Fonts option so far menu.add_cascade(label='Plot Colour Scheme',shortcut='C', menu=colorMenu) menu.add_cascade(label='Fonts', shortcut='F', menu=fontsMenu) self.mainMenu.add_cascade(label='Appearance', shortcut='A', menu=menu) menu.options = ['Plot Colour Scheme','Fonts'] return menu
class DataFileImportGui(BasePopup): # TODO CHANGE help_url = 'http://www.ebi.ac.uk/pdbe' def __init__(self, root): self.root = root self.font = DEFAULT_FONT # Application object needed to store application-specific data with project self.application = Application(name=PROGRAM_NAME) self.versionInfo = VERSION ccpnProjectName = askString( "CCPN project name", 'Please give a name to this import session:') self.fcWrapper = FormatConverterWrapper( ccpnProjectName=ccpnProjectName, guiRoot=self) self.project = self.fcWrapper.formatConversion.ccpnProject # Application popup is a superclass of memops.editor.BasePoup BasePopup.__init__(self, parent=root, title=PROGRAM_NAME, location='+100+100', class_=self.application.name) self.setTitle(PROGRAM_NAME) def body(self, guiParent): self.geometry('600x350') # Ensure that the first row and column in popup expand guiParent.expandGrid(0, 0) self.importFrame = DataFileImportFrame(guiParent, basePopup=self, grid=(0, 0)) # Dictionary to store popups opened by this application - e.g. need to close upon quit self.popups = {} # Default font self.font = DEFAULT_FONT # Closing the window from the desktop environment calls the proper quit self.protocol('WM_DELETE_WINDOW', self.quit) self.mainMenu = Menu(self) self.projectMenu = self.makeProjectMenu() self.mainMenu.add_command(label='Formats', shortcut='F', command=self.importFrame.showFormats) self.mainMenu.add_command( label='Help', shortcut='H', command=self.importFrame.showMainInstructions) # Put the main menu self.config(menu=self.mainMenu) self.setMenuState() def makeProjectMenu(self): # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) menu.add_command(label='Save', shortcut='S', command=self.saveProject) menu.add_command(label='Save As', shortcut='A', command=self.saveAsProject) menu.add_command(label='Quit', shortcut='Q', command=self.quit) menu.add_command(label='Version', shortcut='V', command=self.showVersion) self.mainMenu.add_cascade(label='Project', shortcut='P', menu=menu) menu.options = ['Save', 'Save As', 'Quit', 'Version'] return menu def saveProject(self): self.saveFile() def saveAsProject(self): self.askSaveFile() def showVersion(self): showInfo('Version', 'Version ' + self.versionInfo, parent=self) def setMenuState(self): state = Tkinter.NORMAL for option in ('Save', 'Save As', 'Quit', 'Version'): i = self.projectMenu.options.index(option) self.projectMenu.entryconfig(i, state=state) def askSaveFile(self): popup = self.openPopup('save_project', SaveProjectPopup) popup.refresh() def modalAskSaveFile(self): popup = SaveProjectPopup(self, project=self.project, dismiss_text='Cancel Quit', modal=True) did_save = popup.did_save popup.destroy() return did_save def quitSaveProject(self): if (self.project.activeRepositories): return self.saveFile() else: return self.modalAskSaveFile() """ def destroyPopups(self): for key in self.popups.keys(): popup = self.popups[key] popup.destroy() self.popups = {} """ def saveFile(self): if not self.project: return False try: saveProject(self.project, createFallback=True) print 'successfully saved project' return True except IOError, e: showError('Saving file', str(e), parent=self) return False
class DangleGui(BasePopup): """ **A Bayesian inferential prediction method for protein backbone dihedral angles** DANGLE (Dihedral ANgles from Global Likelihood Estimates) predicts protein backbone Phi and Psi angles and secondary structure assignments solely from amino acid sequence information, experimental chemical shifts and a database of known protein structures and their associated shifts. This approach uses Bayesian inferential logic to analyse the likelihood of conformations throughout Ramachandran space, paying explicit attention to the population distributions expected for different amino acid residue types. Simple filtering procedures can identify the most "predictable" residues, yielding 92% of all Phi and Psi predictions accurate to within +/-30 degrees. In contrast to previous approaches, more than 80% of Phi or Psi predictions for glycine and pre-proline are reliable. Furthermore, DANGLE provides meaningful upper and lower bounds for the predictions which are shown to represent the precision of the prediction. Over 90% of the experimental dihedral angles in the set of test proteins are within the boundary ranges suggested by DANGLE. At a lower resolution level, the program correctly assigns each residue to one of three secondary structure states (H, E or C) in 85% of cases. DANGLE also provides an indication of the degeneracy in the relationship between shift measurements and conformation at each site. For more documentation see the `DANGLE web site`_ at SourceForge. .. _`DANGLE web site`: http://dangle.sourceforge.net/ **Reference** *Ming-Sin Cheung, Mahon L. Maguire, Tim J. Stevens, and R. William Broadhurst. "DANGLE: A Bayesian inferential method for predicting protein backbone dihedral angles and secondary structure." Journal of Magnetic Resonance Volume 202, Issue 2, February 2010, Pages 223-233* """ def __init__(self, root, programName=PROGRAM_NAME, **kw): self.parent = root self.programName = programName # Application object needed to store application-specific data with project self.application = Application(name=PROGRAM_NAME) self.versionInfo = 'Version ' + VERSION self.graphPopup = None self.analysisProfile = None # Application popup is a superclass of memops.editor.BasePoup BasePopup.__init__(self, parent=root, title=PROGRAM_NAME, location='+100+100', class_=self.application.name, **kw) def body(self, guiParent): # Ensure that the first row and column in popup expand guiParent.grid_rowconfigure(1, weight=1) guiParent.grid_columnconfigure(0, weight=1, minsize=200) frame = Frame(guiParent) # Body widgets can be put in this frame frame.grid(row=1, column=0, sticky='nsew') frame.grid_rowconfigure(0, weight=1) frame.grid_columnconfigure(0, weight=1, minsize=200) self.dangleFrame = DangleFrame(frame, self, project=self.project) self.dangleFrame.grid(row=0, column=0, sticky='nsew') # Dictionary to store popups opened by this application - e.g. need to close upon quit self.popups = {} # Default font self.font = 'Helvetica 10' # Closing the window from the desktop environment calls the proper quit self.protocol('WM_DELETE_WINDOW', self.quit) self.mainMenu = Menu(self) self.projectMenu = self.makeProjectMenu() self.viewMenu = self.viewFileMenu() self.otherMenu = self.makeAppearanceMenu() # Put the main menu self.config(menu=self.mainMenu) self.initProject() def makeProjectMenu(self): # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call menu.add_command(label='New', shortcut='N', command=self.newProject, tipText='Make a new, blank CCPN project. Closes any existing project') menu.add_command(label='Open', shortcut='O', command=self.openProject, tipText='Open a new CCPN project from disk, closing any existing project') menu.add_command(label='Close', shortcut='C', command=self.closeProject, tipText='Close the current CCPN project') menu.add_command(label='Save', shortcut='S', command=self.saveProject, tipText='Save the current CCPN prjoject at its pre-specified location') menu.add_command(label='Save As', shortcut='A', command=self.saveAsProject, tipText='Save the current CCPN project at a new location') menu.add_command(label='Backup', shortcut='B', command=self.backupProject, tipText='Manage options for automatic CCPN project backup') menu.add_command(label='Quit', shortcut='Q', command=self.quit, tipText='Exit from the DANGLE program') menu.add_command(label='Version', shortcut='V', command=self.showVersion) self.mainMenu.add_cascade(label='Project', shortcut='P', menu=menu) menu.options = ['New','Open','Close','Save','Save As','Backup','Quit','Version'] return menu def viewFileMenu(self): # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call menu.add_command(label='Prediction Graph', shortcut='G', command=self.viewGraph, tipText='Show a graphical view of the poredicted backbone dihedral angles') self.mainMenu.add_cascade(label='View', shortcut='V', menu=menu) menu.options = ['Prediction Graph'] return menu def makeAppearanceMenu(self): # The fonts menu is a pre-created widget fontsMenu = FontMenu(self.mainMenu, self.setFont, sizes=(8,10,12), doItalic=0, doBoldItalic=0, tearoff=0) # Plot color schemes colorMenu = Menu(self.mainMenu, tearoff=0) colorMenu.add_radiobutton(label='Red', command=self.colorSchemeRed,) colorMenu.add_radiobutton(label='Rainbow', command=self.colorSchemeRainbow,) #colorMenu.add_radiobutton(label='Black', shortcut='B', command=self.colorSchemeBlack) #colorMenu.add_radiobutton(label='White', shortcut='W', command=self.colorSchemeWhite) # Submenu of the main menu menu = Menu(self.mainMenu, tearoff=0) # Only Fonts option so far menu.add_cascade(label='Plot Colour Scheme',shortcut='C', menu=colorMenu) menu.add_cascade(label='Fonts', shortcut='F', menu=fontsMenu) self.mainMenu.add_cascade(label='Appearance', shortcut='A', menu=menu) menu.options = ['Plot Colour Scheme','Fonts'] return menu def colorSchemeRed(self): self.dangleFrame.colorScheme = 'red' def colorSchemeRainbow(self): self.dangleFrame.colorScheme = 'rainbow' def colorSchemeBlack(self): self.dangleFrame.colorScheme = 'black' def colorSchemeWhite(self): self.dangleFrame.colorScheme = 'white' def viewGraph(self): phiData, psiData = self.dangleFrame.getPhiPsiPredictions() if self.graphPopup: self.graphPopup.open() else: self.graphPopup = DangleGraphPopup(self) dangleChain = self.dangleFrame.dangleChain good = [] med = [] bad = [] if dangleChain: resNum = 0 # In case no residues for dResidue in dangleChain.dangleResidues: resNum = dResidue.residue.seqCode nIslands = dResidue.numIslands if nIslands < 2: good.append((resNum, nIslands)) elif nIslands < 4: med.append((resNum, nIslands)) else: bad.append((resNum, nIslands)) good.append((resNum, 0)) # To bias the graph islandData = [good, med, bad] self.graphPopup.update(phiData,psiData,islandData) def newProject(self): if self.project: # Project already present if not self.closeProject(): # If we don't close the current project do nothing return name = askString(title='Project name', prompt='Enter project name:',parent=self) if name: # Make the API Project object project = Implementation.MemopsRoot(name=name) nmrProject = project.newNmrProject(name = project.name) self.initProject(project) def openProject(self): if self.project: if not self.closeProject(): return self.openPopup('open_project', OpenProjectPopup, callback=self.initProject) def openPopup(self, popup_name, clazz, *args, **kw): popup = self.popups.get(popup_name) if popup: popup.open() else: if self.analysisProfile: transient = self.analysisProfile.transientWindows else: transient = True # Below automatically opens popup popup = self.popups[popup_name] = clazz(self, project=self.project, transient=transient, *args, **kw) return popup def closeProject(self, queryClose=True, querySave=True): if queryClose: if (not showYesNo('Close project', 'Close current project?')): return False if querySave: if (not self.checkSaving()): return False self.destroyPopups() self.initProject() return True def saveProject(self): #if (self.project.isStored): self.saveFile() #else: # self.askSaveFile() def saveAsProject(self): self.askSaveFile() def backupProject(self): pass #self.openPopup('backup_project', BackupProjectPopup) def showVersion(self): showInfo('Version', self.versionInfo, parent=self) def setFont(self, fontName=None, popup=None): if fontName is None: if self.analysisProfile: # Get font specification saved as project application data self.font = self.analysisProfile.font else: self.font = fontName if self.analysisProfile: # Set font specification as project application data self.analysisProfile.font = fontName if not popup: popup = self childList = popup.children.values() classes = [Tkinter.Button, Tkinter.Label, Tkinter.Menu, Tkinter.Entry, Tkinter.Checkbutton, Tkinter.Radiobutton] for child in childList: for clazz in classes: if isinstance(child, clazz): if hasattr(child, 'font'): if not child.font: child.config( font=self.font) else: child.config( font=self.font ) break if hasattr(child, 'children'): childList.extend( child.children.values() ) def initProject(self, project=None): if project: self.project = project else: project = self.project self.setTitle(self.programName) if project: self.project.application = self.application self.setFont() self.dangleFrame.updateProject(project) self.setupSoftware() if not project.currentAnalysisProfile: analysisProfiles = project.sortedAnalysisProfiles() if analysisProfiles: project.currentAnalysisProfile = analysisProfiles[0] else: project.newAnalysisProfile(name=project.name) self.analysisProfile = project.currentAnalysisProfile self.setMenuState() def setupSoftware(self): project = self.project methodStore = project.currentMethodStore or \ project.findFirstMethodStore() or \ project.newMethodStore(name=project.name) software = methodStore.findFirstSoftware(name=PROGRAM_NAME, version=VERSION) if not software: software = methodStore.newSoftware(name=PROGRAM_NAME, version=VERSION) #software.vendorName = 'Nicole Cheung' #software.vendorAddress = '' #software.vendorWebAddress = 'http:' #software.details = '' def setMenuState(self): if self.project: state = Tkinter.NORMAL else: state = Tkinter.DISABLED # Disable bits of the project menu if there's no project for option in ('Save','Save As','Backup','Close'): i = self.projectMenu.options.index(option) self.projectMenu.entryconfig(i, state=state) # Disable bits of the project menu if not stand-alone if hasattr(self.parent, 'project'): for option in ('New','Open','Close'): i = self.projectMenu.options.index(option) self.projectMenu.entryconfig(i, state=Tkinter.DISABLED) # Disable other manus and view menu if there's no project for menu in [self.otherMenu,self.viewMenu]: # Include more menus in this list for i in range(len(menu.options)): menu.entryconfig(i, state=state) def askSaveFile(self): popup = self.openPopup('save_project', SaveProjectPopup) def modalAskSaveFile(self): popup = SaveProjectPopup(self, project=self.project, dismiss_text='Cancel Quit', modal=True) did_save = popup.did_save popup.destroy() return did_save def quitSaveProject(self): if self.project.activeRepositories: return self.saveFile() else: return self.modalAskSaveFile() def destroyPopups(self): for key in self.popups.keys(): popup = self.popups[key] popup.destroy() self.popups = {} def saveFile(self): if (not self.project): return False try: self.project.saveModified() print 'Successfully saved project' return True except IOError, e: showError('Saving file', str(e)) return False
class ApplicationPopup(BasePopup): help_url = 'http://www.ccpn.ac.uk' def __init__(self, root, programName='Ccpn Workflow Management System'): self.programName = programName self.font = DEFAULT_FONT # Application object needed to store application-specific data with project self.application = Application(name=PROGRAM_NAME) self.versionInfo = 'Version ' + VERSION self.ariaProjectFile = None self.username = None # what do these do?? self.updateFuncs = [] self.projButtons = [] # may need these in the end self.ariaPaths = [] self.isdPaths = [] # FIXME JMCI # hard code this for now. this should be initialised from file # read during GUI login and then extended using the menu options # should set a placeholder. In fact, this placeholder will also have # a default user (guest) so that there is always a structure to # extend should the user wish to start from scratch and not log in self.repList = RepositoryList() self.currentTask = None # going to stick in shortcuts to frames for quick access self.frameShortcuts = {} # Application popup is a superclass of memops.editor.BasePoup BasePopup.__init__(self, parent=root, title=PROGRAM_NAME, location='+100+100', class_=self.application.name) self.setTitle(PROGRAM_NAME) def body(self, guiParent): self.geometry('700x600') # Ensure that the first row and column in popup expand guiParent.grid_rowconfigure(0, weight=1) guiParent.grid_columnconfigure(0, weight=1, minsize=200) frame = Frame(guiParent) # Body widgets can be put in this frame frame.grid() # this is going to set up the options on the tabs. Really we need # stronger bookeeping between the options and the frames. it # might make sense to define a master dictionary with option_name # => index. We can use this dictionary to build up the software # options and can also use it to define any refreshes etc (although # these would be better done through notifiers) softwareOpts = [ 'Repository', 'Project', 'Process', 'Client Tasks', 'Server Tasks', 'Data Exchange', 'Workflow', 'Protocols', 'User' ] # FIXME JMCI # we should have a tidier tabbed frame. ned to discuss rules with # tjs but it would seem to make sense to have the tabs stretch # across the entire top of the frame. Check the existing options # first, though self.tabbedFrame = TabbedFrame(guiParent, options=softwareOpts, toggleOff=False, selected=0) self.tabbedFrame.grid(row=0, column=0, sticky='nsew') frames = self.tabbedFrame.frames # Logos ccpnDir = getTopDirectory() imageDir = os.path.join(ccpnDir, 'python', 'extendNmr', 'images') imageFile = os.path.join(imageDir, 'CcpnLogo.gif') self.ccpnLogo = Tkinter.PhotoImage(file=imageFile) # Dictionary to store popups opened by this application - e.g. need to close upon quit self.popups = {} # Default font self.font = 'Helvetica 10' # Closing the window from the desktop environment calls the proper quit self.protocol('WM_DELETE_WINDOW', self.quit) # jmci we are going to have to change these drastically self.mainMenu = Menu(self) self.userMenu = self.makeUserMenu() self.repositoryMenu = self.makeRepositoryMenu() self.otherMenu = self.makeOtherMenu() # Put the top level menu self.config(menu=self.mainMenu) self.initRepository(frames[0]) self.initProjectFrame(frames[1]) self.initWms(frames[2]) self.initTasks(frames[3]) self.initDataExch(frames[5]) self.initWorkflow(frames[6]) self.initProtocol(frames[7]) self.initUserFrame(frames[8]) self.initProject() if not self.project: for button in self.projButtons: button.disable() # the main client side daemon. This is going to run in the background # and control the task processing self.taskDaemon = TaskManager(self) self.taskDaemon.active = False self.taskDaemon.start() ## THE TABBED FRAMES ## def initRepository(self, frame): frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) repositoryFrame = RepositoryFrame(frame, basePopup=self) repositoryFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(repositoryFrame.updateAll) def initProjectFrame(self, frame): frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) self.projectFrame = ProjectFrame(frame, basePopup=self) self.projectFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(self.projectFrame.updateAll) def initWms(self, frame): frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) extendNmrFrame = ExtendNmrFrame(frame, basePopup=self) extendNmrFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(extendNmrFrame.updateAll) def initTasks(self, frame): frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) tasksFrame = TasksFrame(frame, self) tasksFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(tasksFrame.updateAll) def initDataExch(self, frame): row = 0 frame.config(bg='#E6E6E6') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) dataExchFrame = DataExchFrame(frame, basePopup=self) dataExchFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(dataExchFrame.updateAll) def initWorkflow(self, frame): row = 0 frame.config(bg='#FFFFFF') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) workflowFrame = WorkflowFrame(frame, basePopup=self) workflowFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(workflowFrame.updateAll) def initProtocol(self, frame): row = 0 frame.config(bg='#FFFFFF') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) protocolFrame = ProtocolFrame(frame, basePopup=self) protocolFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(protocolFrame.updateAll) def initUserFrame(self, frame): frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(1, weight=1) row = 0 frame.config(bg='#FFFFFF') userFrame = UserFrame(frame, basePopup=self) userFrame.grid(row=1, column=0, sticky='nsew') self.updateFuncs.append(userFrame.updateAll) ## The Menu ## def makeUserMenu(self): menu = Menu(self.mainMenu, tearoff=0) menu.add_command(label='Log In', shortcut='I', command=self.openLoginPopup) menu.add_command(label='Log Out', shortcut='O', command=self.logout) menu.add_command(label='Save Profile', shortcut='S', command=self.tmpCall) menu.add_command(label='View Profile', shortcut='V', command=self.tmpCall) menu.add_command(label='Create Profile', shortcut='C', command=self.tmpCall) menu.add_command(label='Edit Profile', shortcut='E', command=self.tmpCall) self.mainMenu.add_cascade(label='User', shortcut='U', menu=menu) menu.options = [ 'Log In', 'Log Out', 'Save Profile', 'View Profile', 'Create Profile', 'Edit Profile' ] return menu def makeRepositoryMenu(self): self.repMenu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call self.repMenu.add_command(label='Manager', shortcut='M', command=self.tmpCall) self.repMenu.add_command(label='Connect', shortcut='C', command=self.openRepository) # doesn't really work to have a disconnect; we do not have a list # of repositories and so would it refer to? Better to do this from # within the RepositoryFrame self.repMenu.add_command(label='Disconnect', shortcut='D', command=self.tmpCall) # again, this is functionality that would make sense but which it is hard to put # in the top level menu because it is not obvious which repository it refers # to self.repMenu.add_command(label='Import Project', shortcut='I', command=self.tmpCall) self.repMenu.add_command(label='Export Project', shortcut='E', command=self.tmpCall) # FIXME JMCI # the quit option needs to be tied to a dialogue box that asks whether # the current connection state should be saved. This will have to be # secured and so means that the GUI should have a login itself (beyond # the logins for the various resources). self.repMenu.add_command(label='Quit', shortcut='Q', command=self.quit) self.mainMenu.add_cascade(label='Repository', shortcut='R', menu=self.repMenu) self.repMenu.options = [ 'Connect', 'Disconnect', 'Import Project', 'Export Project', 'Quit' ] return self.repMenu def makeProjectMenu(self): # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call menu.add_command(label='New', shortcut='N', command=self.newProject) menu.add_command(label='Open', shortcut='O', command=self.openProject) menu.add_command(label='Close', shortcut='C', command=self.closeProject) menu.add_command(label='Save', shortcut='S', command=self.saveProject) menu.add_command(label='Save As', shortcut='A', command=self.saveAsProject) menu.add_command(label='Quit', shortcut='Q', command=self.quit) menu.add_command(label='Version', shortcut='V', command=self.showVersion) self.mainMenu.add_cascade(label='Project', shortcut='P', menu=menu) menu.options = [ 'New', 'Open', 'Close', 'Save', 'Save As', 'Quit', 'Version' ] return menu def makeOtherMenu(self): # The fonts menu is a pre-created widget fontsMenu = FontMenu(self.mainMenu, self.setFont, sizes=(8, 10, 12), doItalic=0, doBoldItalic=0, tearoff=0) # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Only Fonts option so far menu.add_cascade(label='Fonts', shortcut='F', menu=fontsMenu) self.mainMenu.add_cascade(label='Options', shortcut='O', menu=menu) menu.options = [ 'Fonts', ] return menu def makeCcpNmrMenu(self): try: from ccpnmr.analysis.AnalysisPopup import AnalysisPopup haveAnalysis = True except ImportError: haveAnalysis = False try: from ccpnmr.format.gui.FormatConverter import FormatConverter from ccpnmr.format.gui.DataShifter import DataShifter haveFormatConv = True except ImportError: haveFormatConv = False menu = Menu(self.mainMenu, tearoff=0) if haveAnalysis: menu.add_command(label='Analysis', shortcut='A', command=self.ccpNmrAnalysis) else: menu.add_command(label='Analysis ** NOT INSTALLED **', shortcut='A', command=None) if haveFormatConv: menu.add_command(label='Format Converter', shortcut='F', command=self.ccpNmrFormatConverter) menu.add_command(label='Data Shifter', shortcut='D', command=self.ccpNmrDataShifter) else: menu.add_command(label='Format Converter ** NOT INSTALLED **', shortcut='F', command=None) menu.add_command(label='Data Shifter ** NOT INSTALLED **', shortcut='D', command=None) self.mainMenu.add_cascade(label='CcpNmr', shortcut='C', menu=menu) menu.options = ['Analysis', 'Format Converter', 'Data Shifter'] return menu def ccpNmrAnalysis(self, cacheSize=64): from ccpnmr.analysis.AnalysisPopup import AnalysisPopup analysis = AnalysisPopup(self, cache_size=cacheSize, glDirect=None) analysis.update_idletasks() # fast if self.project: analysis.initProject(self.project) def ccpNmrFormatConverter(self): from ccpnmr.format.gui.FormatConverter import FormatConverter fc = FormatConverter(self, threading=False, project=self.project) fc.open() if self.project: fc.initProject(self.project) def ccpNmrDataShifter(self): from ccpnmr.format.gui.DataShifter import DataShifter ds = DataShifter(self) ds.open() def newProject(self): if self.project: # Project already present if not self.closeProject(): # If we don't close the current project do nothing return name = askString(title='Project name', prompt='Enter project name:', parent=self) if name: # Make the API Project object project = Implementation.MemopsRoot(name=name) nmrProject = project.newNmrProject(name=name) self.initProject(project) # placeholder method until we write code def tmpCall(self): return def openProject(self): if self.project: if not self.closeProject(): return self.openPopup('open_project', OpenProjectPopup, callback=self.initProject) def openLoginPopup(self): # at the moment we do this through methods in the popup. It # would be much more sensible to do this through some # sort of callback. login_popup = LoginPopup(self) # really we want to imoblise the rest. how to do? def setRepository(self, rep): self.repList.currentRepository = rep if self.frameShortcuts.has_key('Repository'): self.frameShortcuts['Repository'].drawFrame() if self.frameShortcuts.has_key('Tasks'): self.frameShortcuts['Tasks'].drawFrame() #for ff in self.tabbedFrame.frames[0].children.values(): # ff.draw() #for ff in self.tabbedFrame.frames[3].children.values(): # ff.draw() for ff in self.tabbedFrame.frames[8].children.values(): ff.draw() def openRepository(self): rep_popup = RepositoryPropertiesPopup(self) def closeRepository(self): pass def logout(self): self.setUsername(None) self.repList = RepositoryList() print 'in logout ', self.repList print '#########################' print self.tabbedFrame.frames[0].__dict__ print '#########################' if self.frameShortcuts.has_key('Repository'): self.frameShortcuts['Repository'].drawFrame() #for ff in self.tabbedFrame.frames[0].children.values(): # ff.draw() for ff in self.tabbedFrame.frames[8].children.values(): ff.draw() def openPopup(self, popup_name, clazz, oldStyle=False, *args, **kw): popup = self.popups.get(popup_name) if (popup): popup.open() else: if self.project: analysisProfile = self.analysisProfile else: analysisProfile = None if analysisProfile: transient = analysisProfile.transientDialogs else: transient = True name = popup_name if (oldStyle): popup = self.popups[popup_name] = clazz(self, transient=transient, *args, **kw) else: popup = self.popups[popup_name] = clazz(self, project=self.project, popup_name=name, transient=transient, *args, **kw) # above automatically opens popup return popup def closeProject(self, queryClose=True, querySave=True): if queryClose: if not showYesNo( 'Close project', 'Close current project?', parent=self): return False if querySave: if not self.checkSaving(): return False self.destroyPopups() self.initProject() return True def saveProject(self): self.saveFile() # NBNB Rasmus 22/8/08 changed to fit AnalysisPopup (and removed 'isStored' bug) #if (self.project.isStored): # self.saveFile() #else: # self.askSaveFile() def saveAsProject(self): self.askSaveFile() def showVersion(self): showInfo('Version', self.versionInfo, parent=self) def changeFont(self, analysisProfile): if analysisProfile is self.analysisProfile: if self.font != analysisProfile.font: self.font = analysisProfile.font or DEFAULT_FONT self.setFont() def selectFont(self, font): # Only called from main menu option if self.project: self.analysisProfile.font = font def setFont(self, font=None, popup=None): if font is None: font = self.font or DEFAULT_FONT else: self.font = font if not popup: popup = self childList = popup.children.values() classes = [ Tkinter.Button, Tkinter.Label, Tkinter.Menu, Tkinter.Entry, Tkinter.Checkbutton, Tkinter.Radiobutton ] for child in childList: for clazz in classes: if isinstance(child, clazz): if hasattr(child, 'font'): if not child.font: child.config(font=font) else: child.config(font=font) break if isinstance(child, Tkinter.Frame): child.font = font elif isinstance(child, ScrolledMatrix): child.setFont(font) if hasattr(child, 'children'): childList.extend(child.children.values()) def initProject(self, project=None): self.project = project if project: self.initTopObjects(self.project) self.project.application = self.application self.setFont() webBrowser = ProjectWebBrowser(self.top, popup=self, project=project) #self.helpButton.config(command = lambda url=self.help_url: webBrowser.open(url) ) for i, func in enumerate(self.updateFuncs): func(project) for button in self.projButtons: button.enable() self.setupSoftware() else: for button in self.projButtons: button.disable() self.setMenuState() def setUsername(self, name): self.username = name print 'set username ', self.username # jmci FIXME # need to look into this carefully and analyse the possible # states def setMenuState(self): if self.project: state = Tkinter.NORMAL else: state = Tkinter.DISABLED # Disable bits of the project menu if there's no project #for option in ('Save','Save As','Close'): # i = self.projectMenu.options.index(option) # self.projectMenu.entryconfig(i, state=state) # Disable other manus if there's no project #for menu in [self.otherMenu,]: # Include more menus in this list # for i in range(len(menu.options)): # menu.entryconfig(i, state=state) def setupSoftware(self): project = self.project methodStore = project.currentMethodStore or \ project.findFirstMethodStore() or \ project.newMethodStore(name=project.name) software = methodStore.findFirstSoftware(name=PROGRAM_NAME, version=VERSION) if not software: software = methodStore.newSoftware(name=PROGRAM_NAME, version=VERSION) #software.vendorName = 'PDBe & CCPN' #software.vendorAddress = '' #software.vendorWebAddress = 'http:' #software.details = '' def askSaveFile(self): popup = self.openPopup('save_project', SaveProjectPopup) popup.refresh() def modalAskSaveFile(self): popup = SaveProjectPopup(self, project=self.project, dismiss_text='Cancel Quit', modal=True) did_save = popup.did_save popup.destroy() return did_save def quitSaveProject(self): if (self.project.activeRepositories): return self.saveFile() else: return self.modalAskSaveFile() def destroyPopups(self): for key in self.popups.keys(): popup = self.popups[key] popup.destroy() self.popups = {} ## WMS methods # should maybe merge this with setUsername # this will read a config file that stores user setups. How this # is done TBD so hack for now and just return def readConfig(self, userName): # this should return the full RepositoryList structure. In reality this # will parse from file. set it by hand from here for now for speed repList = RepositoryList(userName) rep1 = repList.newRepository('remote', 'localhost:8080/HalxService', 'ccpn', 'remote') repList.currentRepository = rep1 # should these be directory objects? repList.current_export_dir = '/home/jionides/work/CCPN/test_JMCI_data' repList.current_import_dir = '/home/jionides/work/CCPN/test_EXP_data' self.repList = repList print 'in readconfig ' self.setRepository(rep1) # really should be done through notifiers if self.frameShortcuts.has_key('Repository'): self.frameShortcuts['Repository'].drawFrame() if self.frameShortcuts.has_key('Tasks'): self.frameShortcuts['Tasks'].drawFrame() if self.frameShortcuts.has_key('DataExch'): self.frameShortcuts['DataExch'].drawFrame() for ff in self.tabbedFrame.frames[8].children.values(): ff.draw() # want to update the top menu. The idea should be to add a bar item # and then to list all the repositories underneath. Clicking on a given # repository will set the home repository as current. That seems to # be a good sensible way of simplifying the interface in a expected # way. We could, alternatively, use tabs. opts = {} self.repMenu.add('separator', **opts) for rep in repList.repositories: item = { 'command': lambda rep=rep: self.setRepository(rep), 'label': rep.name } self.repMenu.add('comman', **item) self.repMenu.config() ## end WMS methods def copyModifiedStorages(self): modifiedStorages = [ storage for storage in self.project.storages if storage.isModified ] if (self.project.isModified): modifiedStorages.append(self.project) for storage in modifiedStorages: self.copyStorage(storage) def saveFile(self): if not self.project: return False try: saveProject(self.project, createFallback=True) print 'successfully saved project' return True except IOError, e: showError('Saving file', str(e), parent=self) return False
class EntryCompletionGui(BasePopup): ''' The standalone version of CcpNmr Entry Completion Interface (ECI). With it, you can complete all the necessary information required for PDB and BMRB data depositions by adding an "Entry" object to your CCPN project. An "Entry" object contains all the information that you wish to deposit with your submission. You can also select chemical shift lists, peak lists, structural restraints, ensembles, etc. and all at the click of a button. In addition, you can add all the meta data that is required for submissions to the PDB and BMRB. This can be done securely on your desktop computer over the duration of your NMR project. ''' help_url = 'http://www.ccpn.ac.uk' def __init__(self, root): self.root = root self.font = DEFAULT_FONT # Application object needed to store application-specific data with project self.application = Application(name=PROGRAM_NAME) self.versionInfo = VERSION # Application popup is a superclass of memops.editor.BasePoup BasePopup.__init__(self, parent=root, title=PROGRAM_NAME, location='+100+100', class_=self.application.name) #self.setTitle(PROGRAM_NAME) def body(self, guiParent): self.geometry('900x750') # Ensure that the first row and column in popup expand guiParent.expandGrid(0,0) self.eciFrame = EntryCompletionFrame(guiParent, basePopup=self, grid=(0,0)) # Add help, close buttons #buttonList = UtilityButtonList(self.eciFrame.tabbedFrame.sideFrame, # grid=(0,0), sticky='e') # Dictionary to store popups opened by this application - e.g. need to close upon quit self.popups = {} # Default font self.font = 'Helvetica 10' # Closing the window from the desktop environment calls the proper quit self.protocol('WM_DELETE_WINDOW', self.quit) self.mainMenu = Menu(self) self.projectMenu = self.makeProjectMenu() self.ccpNmrMenu = self.makeCcpNmrMenu() self.otherMenu = self.makeOtherMenu() # Put the main menu self.config(menu=self.mainMenu) self.initProject() def makeProjectMenu(self): importsMenu = Menu(self.mainMenu, tearoff=False) importsMenu.add_command(label='Fasta Sequence',command=self.importFastaSeq) importsMenu.add_command(label='NMR-STAR 2.1.1', command=self.importNmrStar211) importsMenu.add_command(label='NMR-STAR 3.1', command=self.importNmrStar31) importsMenu.add_command(label='PDB 3.20',command=self.importPdb) importsMenu.add_command(label='PDB Coords',command=self.importPdbCoords) #importsMenu.add_command(label='CNS Distance Restraints',command=self.importCnsDistance) exportsMenu = Menu(self.mainMenu, tearoff=False) exportsMenu.add_command(label='NMR-STAR 3.1', command=self.eciFrame.exportNmrStar31) exportsMenu.add_command(label='PDB Coords',command=self.eciFrame.exportPdb) #exportsMenu.add_command(label='CNS Distance Restraints',command=self.eciFrame.exportCnsDistance) # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call menu.add_command(label='New', shortcut='N', command=self.newProject) menu.add_command(label='Open', shortcut='O', command=self.openProject) menu.add_command(label='Close', shortcut='C', command=self.closeProject) menu.add_command(label='Save', shortcut='S', command=self.saveProject) menu.add_command(label='Save As', shortcut='A', command=self.saveAsProject) menu.add_cascade(label='Import', shortcut='I', menu=importsMenu) menu.add_cascade(label='Export', shortcut='E', menu=exportsMenu) menu.add_command(label='Quit', shortcut='Q', command=self.quit) menu.add_command(label='Version', shortcut='V', command=self.showVersion) self.mainMenu.add_cascade(label='Project', shortcut='P', menu=menu) menu.options = ['New','Open','Close','Save','Save As','Import','Export','Quit','Version'] return menu def makeOtherMenu(self): # The fonts menu is a pre-created widget fontsMenu = FontMenu(self.mainMenu, self.setFont, sizes=(8,10,12), doItalic=0, doBoldItalic=0, tearoff=0) # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Only Fonts option so far menu.add_cascade(label='Fonts', shortcut='F', menu=fontsMenu) self.mainMenu.add_cascade(label='Options', shortcut='O', menu=menu) menu.options = ['Fonts',] return menu def makeCcpNmrMenu(self): try: from ccpnmr.analysis.AnalysisPopup import AnalysisPopup haveAnalysis = True except ImportError: haveAnalysis = False try: from ccpnmr.format.gui.FormatConverter import FormatConverter from ccpnmr.format.gui.DataShifter import DataShifter haveFormatConv = True except ImportError: haveFormatConv = False menu = Menu(self.mainMenu, tearoff=0) if haveAnalysis: menu.add_command(label='Analysis', shortcut='A', command=self.ccpNmrAnalysis) else: menu.add_command(label='Analysis ** NOT INSTALLED **', shortcut='A', command=None) if haveFormatConv: menu.add_command(label='Format Converter', shortcut='F', command=self.ccpNmrFormatConverter) menu.add_command(label='Data Shifter', shortcut='D', command=self.ccpNmrDataShifter) else: menu.add_command(label='Format Converter ** NOT INSTALLED **', shortcut='F', command=None) menu.add_command(label='Data Shifter ** NOT INSTALLED **', shortcut='D', command=None) self.mainMenu.add_cascade(label='CcpNmr', shortcut='C', menu=menu) menu.options = ['Analysis','Format Converter','Data Shifter'] return menu def ccpNmrAnalysis(self, cacheSize=64): from ccpnmr.analysis.AnalysisPopup import AnalysisPopup analysis = AnalysisPopup(self, cache_size=cacheSize, glDirect=None) analysis.update_idletasks() # fast if self.project: analysis.initProject(self.project) def ccpNmrFormatConverter(self): from ccpnmr.format.gui.FormatConverter import FormatConverter fc = FormatConverter(self,threading=False,project=self.project) fc.open() if self.project: fc.initProject(self.project) def ccpNmrDataShifter(self): from ccpnmr.format.gui.DataShifter import DataShifter ds = DataShifter(self) ds.open() def newProject(self): if self.project: # Project already present if not self.closeProject(): # If we don't close the current project do nothing return name = askString(title='Project name', prompt='Enter project name:',parent=self) if name: # Make the API Project object project = Implementation.MemopsRoot(name=name) nmrProject = project.newNmrProject(name=name) self.initProject(project) def openProject(self): if self.project: if not self.closeProject(): return self.openPopup('open_project', OpenProjectPopup, callback=self.initProject) def openPopup(self, popup_name, clazz, oldStyle=False, *args, **kw): popup = self.popups.get(popup_name) if (popup): popup.open() else: if self.project: analysisProfile = self.analysisProfile else: analysisProfile = None if analysisProfile: transient = analysisProfile.transientDialogs else: transient = True name = popup_name if (oldStyle): popup = self.popups[popup_name] = clazz(self, transient=transient, *args, **kw) else: popup = self.popups[popup_name] = clazz(self, project=self.project, popup_name=name, transient=transient, *args, **kw) # above automatically opens popup return popup def closeProject(self, queryClose = True, querySave = True): if queryClose: if not showYesNo('Close project', 'Close current project?', parent=self): return False if querySave: if not self.checkSaving(): return False self.destroyPopups() self.initProject() return True def saveProject(self): self.saveFile() def saveAsProject(self): self.askSaveFile() def importNmrStar211(self): if not self.project: showWarning('Failure','Please create a new CCPN project.', parent=self) return fileTypes = [ FileType('STAR', ['*.str']), FileType('All', ['*'])] fileSelectPopup = FileSelectPopup(self, file_types=fileTypes, title='Import NMR-STAR 2.1.1 file', dismiss_text='Cancel', selected_file_must_exist=True, multiSelect=False,) fileName = fileSelectPopup.getFile() if not os.path.exists(fileName): showWarning('Failure','No such file.', parent=self) return if fileName: nmrStarObj = NmrStarFormat(self.project, self, verbose=True) nmrStarObj.readProject(fileName, minimalPrompts=True, version='2.1.1') self.eciFrame.updateAll() return nmrStarObj def importNmrStar31(self): if not self.project: showWarning('Failure','Please create a new CCPN project.', parent=self) return fileTypes = [ FileType('STAR', ['*.str']), FileType('All', ['*'])] fileSelectPopup = FileSelectPopup(self, file_types=fileTypes, title='Import NMR-STAR 3.1 file', dismiss_text='Cancel', selected_file_must_exist=True, multiSelect=False,) fileName = fileSelectPopup.getFile() if not os.path.exists(fileName): showWarning('Failure','No such file.', parent=self) return if fileName: nmrStarObj = NmrStarFormat(self.project, self, verbose=True) nmrStarObj.readProject(fileName, minimalPrompts=True, version='3.1') self.eciFrame.updateAll() return nmrStarObj def importPdb(self): if not self.project: showWarning('Failure','Please create a new CCPN project.', parent=self) return fileTypes = [ FileType('PDB', ['*.pdb']), FileType('PDB Entry', ['*.ent']), FileType('All', ['*']) ] fileSelectPopup = FileSelectPopup(self, file_types=fileTypes, title='Import PDB 3.20 file', dismiss_text='Cancel', selected_file_must_exist=True, multiSelect=False,) fileName = fileSelectPopup.getFile() if not os.path.exists(fileName): showWarning('Failure','No such file.', parent=self) return if fileName: name = os.path.split(fileName)[1] if '.' in name: name = name.split('.')[0] pdbObj = ReadPdb(fileName, self.project, 'PDB_'+ name, self) self.eciFrame.updateAll() return pdbObj def importCnsDistance(self): if not self.project: showWarning('Failure','Please create a new CCPN project.', parent=self) return fileTypes = [ FileType('CNS', ['*.tbl']), FileType('All', ['*']) ] fileSelectPopup = FileSelectPopup(self, file_types=fileTypes, title='Import CNS distance restraints file', dismiss_text='Cancel', selected_file_must_exist=True, multiSelect=False,) fileName = fileSelectPopup.getFile() if not os.path.exists(fileName): showWarning('Failure','No such file.', parent=self) return if fileName: name = os.path.split(fileName)[1] if '.' in name: name = name.split('.')[0] cnsObj = CnsFormat(self.project, self, verbose=True) cnsObj.readDistanceConstraints(fileName, minimalPrompts=True) self.eciFrame.updateAll() return cnsObj def importFastaSeq(self): if not self.project: showWarning('Failure','Please create a new CCPN project.', parent=self) return fileTypes = [ FileType('Fasta', ['*.fsa']), FileType('All', ['*']) ] fileSelectPopup = FileSelectPopup(self, file_types=fileTypes, title='Import Fasta sequence file', dismiss_text='Cancel', selected_file_must_exist=True, multiSelect=False,) fileName = fileSelectPopup.getFile() if not os.path.exists(fileName): showWarning('Failure','No such file.', parent=self) return if fileName: name = os.path.split(fileName)[1] if '.' in name: name = name.split('.')[0] fastaObj = FastaFormat(self.project, self, verbose=True) fastaObj.readSequence(fileName, minimalPrompts=True) self.eciFrame.updateAll() return fastaObj def importPdbCoords(self): if not self.project: showWarning('Failure','Please create a new CCPN project.', parent=self) return fileTypes = [ FileType('PDB', ['*.pdb']), FileType('PDB Entry', ['*.ent']), FileType('All', ['*']) ] fileSelectPopup = FileSelectPopup(self, file_types=fileTypes, title='Import PDB coordinates file', dismiss_text='Cancel', selected_file_must_exist=True, multiSelect=False,) fileName = fileSelectPopup.getFile() if not os.path.exists(fileName): showWarning('Failure','No such file.', parent=self) return if fileName: name = os.path.split(fileName)[1] if '.' in name: name = name.split('.')[0] pdbObj = PseudoPdbFormat(self.project, self, verbose=True) pdbObj.readCoordinates(fileName, minimalPrompts=True) self.eciFrame.updateAll() return pdbObj def showVersion(self): showInfo('Version', 'Version ' + self.versionInfo, parent=self) def changeFont(self, analysisProfile): if analysisProfile is self.analysisProfile: if self.font != analysisProfile.font: self.font = analysisProfile.font or DEFAULT_FONT self.setFont() def selectFont(self, font): # Only called from main menu option if self.project: self.analysisProfile.font = font def setFont(self, font=None, popup=None): if font is None: font = self.font or DEFAULT_FONT else: self.font = font if not popup: popup = self childList = popup.children.values() classes = [Tkinter.Button, Tkinter.Label, Tkinter.Menu, Tkinter.Entry, Tkinter.Checkbutton, Tkinter.Radiobutton] for child in childList: for clazz in classes: if isinstance(child, clazz): if hasattr(child, 'font'): if not child.font: child.config( font=font) else: child.config( font=font ) break if isinstance(child, Tkinter.Frame): child.font = font elif isinstance(child, ScrolledMatrix): child.setFont(font) if hasattr(child, 'children'): childList.extend( child.children.values() ) def initProject(self, project=None): self.project = project if project: self.initTopObjects(self.project) self.project.application = self.application self.setFont() webBrowser = ProjectWebBrowser(self.top, popup=self, project=project) self.setupSoftware() self.eciFrame.updateAll(project) self.setMenuState() def setupSoftware(self): project = self.project methodStore = project.currentMethodStore or \ project.findFirstMethodStore() or \ project.newMethodStore(name=project.name) software = methodStore.findFirstSoftware(name=PROGRAM_NAME, version=VERSION) if not software: software = methodStore.newSoftware(name=PROGRAM_NAME, version=VERSION) software.vendorName = 'PDBe & CCPN' #software.vendorAddress = '' software.vendorWebAddress = 'http://www.ebi.ac.uk/pdbe/' software.details = 'The PDBe & CCPN Entry Completion Interface' software.tasks = ['data deposition'] def setMenuState(self): if self.project: state = Tkinter.NORMAL else: state = Tkinter.DISABLED # Disable bits of the project menu if there's no project for option in ('Close','Save','Save As',): i = self.projectMenu.options.index(option) self.projectMenu.entryconfig(i, state=state) # Disable other menus if there's no project for menu in [self.otherMenu,]: # Include more menus in this list for i in range(len(menu.options)): menu.entryconfig(i, state=state) def askSaveFile(self): popup = self.openPopup('save_project', SaveProjectPopup) popup.refresh() def modalAskSaveFile(self): popup = SaveProjectPopup(self, project=self.project, dismiss_text='Cancel Quit', modal=True) did_save = popup.did_save popup.destroy() return did_save def quitSaveProject(self): if (self.project.activeRepositories): return self.saveFile() else: return self.modalAskSaveFile() def destroyPopups(self): for key in self.popups.keys(): popup = self.popups[key] popup.destroy() self.popups = {} def copyModifiedStorages(self): modifiedStorages = [storage for storage in self.project.storages if storage.isModified] if (self.project.isModified): modifiedStorages.append(self.project) for storage in modifiedStorages: self.copyStorage(storage) def saveFile(self): if not self.project: return False try: saveProject(self.project, createFallback=True) print 'successfully saved project' return True except IOError, e: showError('Saving file', str(e), parent=self) return False
def setProjectMenu(self): ProjectMenu = 'Project' # Imports submenu importsMenu = Menu(self.menubar, tearoff=False) importsMenu.add_command(label='Via Format Converter', shortcut='F', command=self.runFormatConverter) importsMenu.add_command(label='NMR-STAR 2.1.1', command=self.importNmrStar211) importsMenu.add_command(label='NMR-STAR 3.1', shortcut='N', command=self.importNmrStar31) importsMenu.add_command(label='PDB 3.20', shortcut='P', command=self.importPdb) importsMenu.add_command(label='Coordinates (PDB-style)', shortcut='C', command=self.importCoordinates) # Preferences submenu fontsMenu = FontMenu(self.menubar, self.selectFont, sizes=(8, 10, 12), doItalic=False, doBoldItalic=False, tearoff=0) prefsMenu = Menu(self.menubar, tearoff=False) prefsMenu.add_cascade( label='Fonts', shortcut='F', image=self.iconFont, compound='left', menu=fontsMenu, tipText='Select font to use in the graphical interface') prefsMenu.add_command(label='Colour Schemes', image=self.iconTable, compound='left', shortcut='C', tipText='Edit and create colour schemes', command=self.editColorSchemes) prefsMenu.add_command( label='Residue Codes', image=self.iconTable, compound='left', shortcut='R', tipText= 'User-specified codes that override the standard residue names', command=self.editResidueCodes) prefsMenu.add_command(label='User Options', image=self.iconTable, compound='left', shortcut='U', tipText='General options for Analysis behaviour', command=self.editProfiles) # menu = Menu(self.menubar, tearoff=0) menu.add_command( label='New', shortcut='N', image=self.iconNewWindow, compound='left', command=self.newProject, tipText='Create a new, blank CCPN project (closes any open project)' ) menu.add_command( label='Open Project', shortcut='O', image=self.iconOpen, compound='left', command=self.openProject, tipText= 'Open a new CCPN project by selecting a project directory on disk') menu.add_command( label='Open Spectra', shortcut='p', image=self.iconOpenFile, compound='left', command=self.openSpectrum, tipText= 'Open spectrum data fom disk, creating a default CCPN project if needed' ) menu.add_command(label='Save', shortcut='S', image=self.iconSave, compound='left', command=self.saveProject, tipText='Save the current CCPN project on disk') menu.add_command( label='Save As', shortcut='A', image=self.iconSaveAs, compound='left', command=self.saveAsProject, tipText= 'Save the current CCPN project under a different name (project directory)' ) menu.add_cascade(label='Import', shortcut='I', image=self.iconImport, compound='left', menu=importsMenu) menu.add_command(label='Close', shortcut='C', image=self.iconClose, compound='left', command=self.closeProject, tipText='Close the current CCPN project') menu.add_command( label='Quit', shortcut='Q', image=self.iconQuit, compound='left', command=self.quit, tipText='Quit Extend-NMR, closing any open CCPN project') menu.add_separator() menu.add_cascade(label='Preferences', shortcut='P', image=self.iconPrefs, compound='left', menu=prefsMenu) menu.add_command( label='Validate', shortcut='V', image=self.iconTool, compound='left', command=self.validateProject, tipText= 'Check the current CCPN project for data model consistency errors') menu.add_command( label='Backup', shortcut='B', image=self.iconTool, compound='left', command=self.backupProject, tipText='Setup options for automated backup of CCPN project data') menu.add_command( label='Archive', shortcut='r', image=self.iconTool, compound='left', command=self.archiveProject, tipText= 'Save the current CCPN project in an archived form, e.g. tar gzipped' ) self.menubar.add_cascade(label=ProjectMenu, shortcut='j', menu=menu) self.menus[ProjectMenu] = menu self.menu_items[ProjectMenu] = [ 'New', 'Open Project', 'Open Spectra', 'Save', 'Save As', 'Import', 'Close', 'Quit', 'Preferences', 'Validate', 'Backup', 'Archive', ] # Menus that area ctive in absence of a project #for ii in (0,1,2,7,13,15): for ii in ( 0, 1, 2, 7, ): self.fixedActiveMenus[(ProjectMenu, ii)] = True
def body(self, guiParent): self.menus = {} self.menu_items = {} self.fixedActiveMenus = {} self.popups = {} self.callbacksDict = {} self.selected_objects = [] self.menubar = menubar = Menu(guiParent) self.font = DEFAULT_FONT self.setProjectMenu() # menu = Menu(self.menubar, tearoff=0) menu.bind('<Button>', self.printAnalysisCommandLineInfo) self.menubar.add_cascade(label='CcpNmr Analysis', shortcut='C', menu=menu) self.menubar.add_command(label='FormatConverter', shortcut='F', command=self.runFormatConverter) self.menubar = menu self.initProject() self.setPeaksMenu() self.setMoleculeMenu() self.setAssignMenu() self.setResonanceMenu() self.setDataMenu() self.setStructureMenu() self.setChartMenu() self.setMacroMenu() self.setOtherMenu() self.setMenuState() # need to do it again because of OtherMenu state # Help Submenu helpMenu = Menu(self.menubar, tearoff=0) helpMenu.add_command(label='Version', shortcut='V', command=self.showVersion) helpMenu.add_command(label='About', shortcut='A', command=self.showAbout) helpMenu.add_command(label='Help', shortcut='H', command=self.showHelp) menu.add_separator() menu.add_command(label='CCPN Updates', shortcut='U', image=self.iconRefresh, compound='left', command=self.updateAnalysis, tipText='Get any new patches and updates to CcpNmr') menu.add_cascade(label='CCPN Help', shortcut='H', image=self.iconHelp, compound='left', menu=helpMenu) self.config(menu=menubar) # Ensure that the first row and column in popup expand guiParent.grid_rowconfigure(0, weight=1) guiParent.grid_columnconfigure(0, weight=1, minsize=200) frame = Frame(guiParent) # Body widgets can be put in this frame frame.grid() softwareOpts = [ 'Extend-NMR', 'ARIA 2', 'Auremol', 'CING', ' ECI ', 'HADDOCK', ' ISD ', 'PRODECOMP' ] self.tabbedFrame = TabbedFrame(guiParent, options=softwareOpts, toggleOff=False, selected=0, callback=self.toggleTab) self.tabbedFrame.grid(row=0, column=0, sticky='nsew') frames = self.tabbedFrame.frames # Logos ccpnDir = getTopDirectory() imageDir = os.path.join(ccpnDir, 'python', 'extendNmr', 'images') imageFile = os.path.join(imageDir, 'Fp6Logo.gif') self.fp6Logo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'CingLogo.gif') self.cingLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'AriaLogo.gif') self.ariaLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'IsdLogo.gif') self.isdLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'HaddockLogo.gif') self.haddockLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'AuremolLogo.gif') self.auremolLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'CcpnLogo.gif') self.ccpnLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'ProdecompLogo.gif') self.prodecompLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'MddLogo.gif') self.mddLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'BrukerLogo.gif') self.brukerLogo = Tkinter.PhotoImage(file=imageFile) imageFile = os.path.join(imageDir, 'MsdLogo.gif') self.msdLogo = Tkinter.PhotoImage(file=imageFile) self.initExtendNmr(frames[0]) self.initAria(frames[1]) self.initAuremol(frames[2]) self.initCing(frames[3]) self.initEci(frames[4]) self.initHaddock(frames[5]) self.initIsd(frames[6]) self.initProdecomp(frames[7]) self.initProject(self.project) if not self.project: for button in self.projButtons: button.disable() self.geometry('680x670')
class EntryCompletionGui(BasePopup): help_url = 'http://www.ccpn.ac.uk' def __init__(self, root): self.font = DEFAULT_FONT # Application object needed to store application-specific data with project self.application = Application(name=PROGRAM_NAME) self.versionInfo = VERSION # Application popup is a superclass of memops.editor.BasePoup BasePopup.__init__(self, parent=root, title=PROGRAM_NAME, location='+100+100', class_=self.application.name) #self.setTitle(PROGRAM_NAME) def body(self, guiParent): self.geometry('800x750') # Ensure that the first row and column in popup expand guiParent.expandGrid(0,0) self.eciFrame = EntryCompletionFrame(guiParent, basePopup=self, grid=(0,0)) # Add help, close buttons #buttonList = UtilityButtonList(self.eciFrame.tabbedFrame.sideFrame, # grid=(0,0), sticky='e') # Dictionary to store popups opened by this application - e.g. need to close upon quit self.popups = {} # Default font self.font = 'Helvetica 10' # Closing the window from the desktop environment calls the proper quit self.protocol('WM_DELETE_WINDOW', self.quit) self.mainMenu = Menu(self) self.projectMenu = self.makeProjectMenu() self.ccpNmrMenu = self.makeCcpNmrMenu() self.otherMenu = self.makeOtherMenu() # Put the main menu self.config(menu=self.mainMenu) self.initProject() def makeProjectMenu(self): # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call menu.add_command(label='New', shortcut='N', command=self.newProject) menu.add_command(label='Open', shortcut='O', command=self.openProject) menu.add_command(label='Close', shortcut='C', command=self.closeProject) menu.add_command(label='Save', shortcut='S', command=self.saveProject) menu.add_command(label='Save As', shortcut='A', command=self.saveAsProject) menu.add_command(label='Quit', shortcut='Q', command=self.quit) menu.add_command(label='Version', shortcut='V', command=self.showVersion) self.mainMenu.add_cascade(label='Project', shortcut='P', menu=menu) menu.options = ['New','Open','Close','Save','Save As','Quit','Version'] return menu def makeOtherMenu(self): # The fonts menu is a pre-created widget fontsMenu = FontMenu(self.mainMenu, self.setFont, sizes=(8,10,12), doItalic=0, doBoldItalic=0, tearoff=0) # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Only Fonts option so far menu.add_cascade(label='Fonts', shortcut='F', menu=fontsMenu) self.mainMenu.add_cascade(label='Options', shortcut='O', menu=menu) menu.options = ['Fonts',] return menu def makeCcpNmrMenu(self): try: from ccpnmr.analysis.AnalysisPopup import AnalysisPopup haveAnalysis = True except ImportError: haveAnalysis = False try: from ccpnmr.format.gui.FormatConverter import FormatConverter from ccpnmr.format.gui.DataShifter import DataShifter haveFormatConv = True except ImportError: haveFormatConv = False menu = Menu(self.mainMenu, tearoff=0) if haveAnalysis: menu.add_command(label='Analysis', shortcut='A', command=self.ccpNmrAnalysis) else: menu.add_command(label='Analysis ** NOT INSTALLED **', shortcut='A', command=None) if haveFormatConv: menu.add_command(label='Format Converter', shortcut='F', command=self.ccpNmrFormatConverter) menu.add_command(label='Data Shifter', shortcut='D', command=self.ccpNmrDataShifter) else: menu.add_command(label='Format Converter ** NOT INSTALLED **', shortcut='F', command=None) menu.add_command(label='Data Shifter ** NOT INSTALLED **', shortcut='D', command=None) self.mainMenu.add_cascade(label='CcpNmr', shortcut='C', menu=menu) menu.options = ['Analysis','Format Converter','Data Shifter'] return menu def ccpNmrAnalysis(self, cacheSize=64): from ccpnmr.analysis.AnalysisPopup import AnalysisPopup analysis = AnalysisPopup(self, cache_size=cacheSize, glDirect=None) analysis.update_idletasks() # fast if self.project: analysis.initProject(self.project) def ccpNmrFormatConverter(self): from ccpnmr.format.gui.FormatConverter import FormatConverter fc = FormatConverter(self,threading=False,project=self.project) fc.open() if self.project: fc.initProject(self.project) def ccpNmrDataShifter(self): from ccpnmr.format.gui.DataShifter import DataShifter ds = DataShifter(self) ds.open() def newProject(self): if self.project: # Project already present if not self.closeProject(): # If we don't close the current project do nothing return name = askString(title='Project name', prompt='Enter project name:',parent=self) if name: # Make the API Project object project = Implementation.MemopsRoot(name=name) nmrProject = project.newNmrProject(name=name) self.initProject(project) def openProject(self): if self.project: if not self.closeProject(): return self.openPopup('open_project', OpenProjectPopup, callback=self.initProject) def openPopup(self, popup_name, clazz, oldStyle=False, *args, **kw): popup = self.popups.get(popup_name) if (popup): popup.open() else: if self.project: analysisProfile = self.analysisProfile else: analysisProfile = None if analysisProfile: transient = analysisProfile.transientDialogs else: transient = True name = popup_name if (oldStyle): popup = self.popups[popup_name] = clazz(self, transient=transient, *args, **kw) else: popup = self.popups[popup_name] = clazz(self, project=self.project, popup_name=name, transient=transient, *args, **kw) # above automatically opens popup return popup def closeProject(self, queryClose = True, querySave = True): if queryClose: if not showYesNo('Close project', 'Close current project?', parent=self): return False if querySave: if not self.checkSaving(): return False self.destroyPopups() self.initProject() return True def saveProject(self): self.saveFile() def saveAsProject(self): self.askSaveFile() def showVersion(self): showInfo('Version', 'Version ' + self.versionInfo, parent=self) def changeFont(self, analysisProfile): if analysisProfile is self.analysisProfile: if self.font != analysisProfile.font: self.font = analysisProfile.font or DEFAULT_FONT self.setFont() def selectFont(self, font): # Only called from main menu option if self.project: self.analysisProfile.font = font def setFont(self, font=None, popup=None): if font is None: font = self.font or DEFAULT_FONT else: self.font = font if not popup: popup = self childList = popup.children.values() classes = [Tkinter.Button, Tkinter.Label, Tkinter.Menu, Tkinter.Entry, Tkinter.Checkbutton, Tkinter.Radiobutton] for child in childList: for clazz in classes: if isinstance(child, clazz): if hasattr(child, 'font'): if not child.font: child.config( font=font) else: child.config( font=font ) break if isinstance(child, Tkinter.Frame): child.font = font elif isinstance(child, ScrolledMatrix): child.setFont(font) if hasattr(child, 'children'): childList.extend( child.children.values() ) def initProject(self, project=None): self.project = project if project: self.initTopObjects(self.project) self.project.application = self.application self.setFont() webBrowser = ProjectWebBrowser(self.top, popup=self, project=project) self.setupSoftware() self.eciFrame.updateAll(project) self.setMenuState() def setupSoftware(self): project = self.project methodStore = project.currentMethodStore or \ project.findFirstMethodStore() or \ project.newMethodStore(name=project.name) software = methodStore.findFirstSoftware(name=PROGRAM_NAME, version=VERSION) if not software: software = methodStore.newSoftware(name=PROGRAM_NAME, version=VERSION) software.vendorName = 'PDBe & CCPN' #software.vendorAddress = '' software.vendorWebAddress = 'http://www.ebi.ac.uk/pdbe/' software.details = 'The PDBe & CCPN Entry Completion Interface' software.tasks = ['data deposition'] def setMenuState(self): if self.project: state = Tkinter.NORMAL else: state = Tkinter.DISABLED # Disable bits of the project menu if there's no project for option in ('Close','Save','Save As',): i = self.projectMenu.options.index(option) self.projectMenu.entryconfig(i, state=state) # Disable other menus if there's no project for menu in [self.otherMenu,]: # Include more menus in this list for i in range(len(menu.options)): menu.entryconfig(i, state=state) def askSaveFile(self): popup = self.openPopup('save_project', SaveProjectPopup) popup.refresh() def modalAskSaveFile(self): popup = SaveProjectPopup(self, project=self.project, dismiss_text='Cancel Quit', modal=True) did_save = popup.did_save popup.destroy() return did_save def quitSaveProject(self): if (self.project.activeRepositories): return self.saveFile() else: return self.modalAskSaveFile() def destroyPopups(self): for key in self.popups.keys(): popup = self.popups[key] popup.destroy() self.popups = {} def copyModifiedStorages(self): modifiedStorages = [storage for storage in self.project.storages if storage.isModified] if (self.project.isModified): modifiedStorages.append(self.project) for storage in modifiedStorages: self.copyStorage(storage) def saveFile(self): if not self.project: return False try: saveProject(self.project, createFallback=True) print 'successfully saved project' return True except IOError, e: showError('Saving file', str(e), parent=self) return False
class ApplicationPopup(BasePopup): help_url = 'http://www.ccpn.ac.uk' def __init__(self, root, programName='ApplicationTemplate'): self.programName = programName # Application object needed to store application-specific data with project self.application = Application(name=programName) self.versionInfo = 'Version 0.00a' # Application popup is a superclass of memops.editor.BasePoup BasePopup.__init__(self, parent=root, title=programName, location='+100+100', class_=self.application.name) def body(self, guiParent): # Ensure that the first row and column in popup expand guiParent.grid_rowconfigure(0, weight=1) guiParent.grid_columnconfigure(0, weight=1, minsize=200) frame = Frame(guiParent) # Body widgets can be put in this frame frame.grid() buttons = createDismissHelpButtonList(frame, dismiss_text='Quit', dismiss_cmd=self.quit, help_url=self.help_url, expands=1) buttons.grid(row=0, column=0, sticky=Tkinter.NSEW) self.helpButton = buttons.buttons[-1] self.helpButtonCommand = self.helpButton.buttonCommand # the command with no project # Dictionary to store popups opened by this application - e.g. need to close upon quit self.popups = {} # Default font self.font = 'Helvetica 10' # Closing the window from the desktop environment calls the proper quit self.protocol('WM_DELETE_WINDOW', self.quit) self.mainMenu = Menu(self) self.projectMenu = self.makeProjectMenu() self.otherMenu = self.makeOtherMenu() # Put the main menu self.config(menu=self.mainMenu) self.initProject() def makeProjectMenu(self): # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Add various options to the menu and state the functions they call menu.add_command(label='New', shortcut='N', command=self.newProject) menu.add_command(label='Open', shortcut='O', command=self.openProject) menu.add_command(label='Close', shortcut='C', command=self.closeProject) menu.add_command(label='Save', shortcut='S', command=self.saveProject) menu.add_command(label='Save As', shortcut='A', command=self.saveAsProject) menu.add_command(label='Quit', shortcut='Q', command=self.quit) menu.add_command(label='Version', shortcut='V', command=self.showVersion) self.mainMenu.add_cascade(label='Project', shortcut='P', menu=menu) menu.options = [ 'New', 'Open', 'Close', 'Save', 'Save As', 'Quit', 'Version' ] return menu def makeOtherMenu(self): # The fonts menu is a pre-created widget fontsMenu = FontMenu(self.mainMenu, self.setFont, sizes=(8, 10, 12), doItalic=0, doBoldItalic=0, tearoff=0) # Submenu of the min menu menu = Menu(self.mainMenu, tearoff=0) # Only Fonts option so far menu.add_command(label='Popup Template', shortcut='P', command=self.popupTemplate) menu.add_cascade(label='Fonts', shortcut='F', menu=fontsMenu) self.mainMenu.add_cascade(label='Other', shortcut='O', menu=menu) menu.options = ['Popup Template', 'Fonts'] return menu def popupTemplate(self): popup = self.openPopup('popup_template', PopupTemplate) def newProject(self): if self.project: # Project already present if not self.closeProject(): # If we don't close the current project do nothing return name = askString(title='Project name', prompt='Enter project name:', parent=self) if name: # Make the API Project object project = Implementation.MemopsRoot(name=name) nmrProject = Nmr.NmrProject(project, name=project.name) self.initProject(project) def openProject(self): if self.project: if not self.closeProject(): return self.openPopup('open_project', OpenProjectPopup, callback=self.initProject) def openPopup(self, popup_name, clazz, *args, **kw): popup = self.popups.get(popup_name) if popup: popup.open() else: transient = getAreDialogsTransient(self.project) # Below automatically opens popup popup = self.popups[popup_name] = clazz(self, project=self.project, transient=transient, *args, **kw) return popup def closeProject(self, queryClose=True, querySave=True): if queryClose: if (not showYesNo('Close project', 'Close current project?')): return False if querySave: if (not self.checkSaving()): return False self.helpButton.config(command=self.helpButtonCommand) self.destroyPopups() self.initProject() return True def saveProject(self): self.saveFile() #if (self.project.isStored): # self.saveFile() #else: # self.askSaveFile() def saveAsProject(self): self.askSaveFile() def showVersion(self): showInfo('Version', self.versionInfo, parent=self) def setFont(self, fontName=None, popup=None): if fontName is None: if self.project: # Get font specification saved as project application data self.font = getProjectFont(self.project) else: self.font = fontName if self.project: # Set font specification as project application data setProjectFont(self.project, self.font) if not popup: popup = self childList = popup.children.values() classes = [ Tkinter.Button, Tkinter.Label, Tkinter.Menu, Tkinter.Entry, Tkinter.Checkbutton, Tkinter.Radiobutton ] for child in childList: for clazz in classes: if isinstance(child, clazz): if hasattr(child, 'font'): if not child.font: child.config(font=self.font) else: child.config(font=self.font) break if hasattr(child, 'children'): childList.extend(child.children.values()) def initProject(self, project=None): self.project = project self.setTitle(self.programName) if project: self.project.application = self.application self.setFont() webBrowser = ProjectWebBrowser(self.top, popup=self, project=project) self.helpButton.config( command=lambda url=self.help_url: webBrowser.open(url)) self.setMenuState() def setMenuState(self): if self.project: state = Tkinter.NORMAL else: state = Tkinter.DISABLED # Disable bits of the project menu if there's no project for option in ('Save', 'Save As', 'Quit'): i = self.projectMenu.options.index(option) self.projectMenu.entryconfig(i, state=state) # Disable other manus if there's no project for menu in [ self.otherMenu, ]: # Include more menus in this list for i in range(len(menu.options)): menu.entryconfig(i, state=state) def askSaveFile(self): popup = self.openPopup('save_project', SaveProjectPopup) popup.refresh() def modalAskSaveFile(self): popup = SaveProjectPopup(self, project=self.project, dismiss_text='Cancel Quit', modal=True) did_save = popup.did_save popup.destroy() return did_save def quitSaveProject(self): if (self.project.activeRepositories): return self.saveFile() else: return self.modalAskSaveFile() def destroyPopups(self): for key in self.popups.keys(): popup = self.popups[key] popup.destroy() self.popups = {} def copyModifiedStorages(self): modifiedStorages = [ storage for storage in self.project.storages if storage.isModified ] if (self.project.isModified): modifiedStorages.append(self.project) for storage in modifiedStorages: self.copyStorage(storage) def saveFile(self): if (not self.project): return False try: self.copyModifiedStorages() self.project.saveModified() print 'Successfully saved project' return True except IOError, e: showError('Saving file', str(e)) return False