class SaveLoadTab(object): """The tab that lets the user FileSelect a file to open or to save. """ def __init__(self, parent, frame): """Init. args: parent: the guiElement that this tab is part of. frame: the frame this part of the GUI lives in. """ self.guiParent = parent self.frame = frame self.project = parent.project self.nmrProject = parent.nmrProject self.loadAndSaveButtons = None self.fileselectionBox = None self.body() def body(self): """Setting up the body of this view.""" frame = self.frame file_types = [FileType("pyc", ["*.pyc"])] self.fileselectionBox = FileSelect(frame, multiSelect=False, file_types=file_types) self.fileselectionBox.grid(row=0, column=0, columnspan=6, sticky="nsew") texts = ["Load", "Save"] commands = [self.loadDataFromPyc, self.saveDataToPyc] self.loadAndSaveButtons = ButtonList(frame, commands=commands, texts=texts) self.loadAndSaveButtons.grid(row=1, column=0, sticky="nsew") frame.grid_rowconfigure(0, weight=1) frame.grid_columnconfigure(0, weight=1) def saveDataToPyc(self): """Save the data to the selected file.""" if self.guiParent.connector.results: fileName = self.fileselectionBox.getFile() self.guiParent.connector.saveDataToPyc(fileName) self.fileselectionBox.updateFileList() else: string = """There are no results to save, """ """the algorithm has not run yet.""" showWarning("No Results to Save", string, parent=self.guiParent) def loadDataFromPyc(self): """Load the data from the selected file.""" fileName = self.fileselectionBox.getFile() self.guiParent.connector.loadDataFromPyc(fileName) self.guiParent.resultsTab.update()
class OpenProjectPopup(BasePopup): def __init__(self, parent, title='Project : Open', callback=None, help_msg='', help_url='', load_project=None, *args, **kw): self.callback = callback self.help_msg = help_msg self.help_url = help_url self.project = None if not load_project: askdir = lambda title, prompt, initial_value: askDir( title, prompt, initial_value, parent=self, extra_dismiss_text='Skip') askfile = lambda title, prompt, initial_value: askFile( title, prompt, initial_value, parent=self, extra_dismiss_text='Skip') load_project = lambda path: loadProject( path, showWarning=showWarning, askDir=askdir, askFile=askfile) self.load_project = load_project BasePopup.__init__(self, parent=parent, title=title, *args, **kw) def body(self, master): self.geometry('600x500') master.grid_rowconfigure(1, weight=1) master.grid_columnconfigure(0, weight=1) label = Label(master, text='Select Project Directory') label.grid(row=0, column=0, sticky=Tkinter.W) file_types = [FileType('Project', ['*.xml']), FileType('All', ['*'])] self.file_select = FileSelect(master, file_types=file_types, show_file=False, double_callback=self.ok, getRowColor=self.getEntryColor, getExtraCell=self.getProjectFileText, extraHeadings=('Status', ), extraJustifies=('left', )) self.file_select.grid(row=1, column=0, sticky=Tkinter.NSEW) texts = ['Open'] commands = [self.ok] buttons = createDismissHelpButtonList(master, texts=texts, commands=commands, dismiss_text='Cancel', help_msg=self.help_msg, help_url=self.help_url) buttons.grid(row=2, column=0, sticky=Tkinter.EW) self.ok_button = buttons.buttons[0] def getEntryColor(self, fileName): # this function returns background color for entry if doesRepositoryContainProject(fileName): color = '#C0FFC0' # green elif getPossibleProjectFiles(fileName): color = '#FFFFC0' # yellow else: color = None # default return color def getProjectFileText(self, fileName): if doesRepositoryContainProject(fileName): tt = time.localtime(os.path.getmtime(fileName)) tt = '%4d-%02d-%02d %02d:%02d:%02d' % tt[:6] data = 'OK (%s)' % tt else: files = getPossibleProjectFiles(fileName) nfiles = len(files) if nfiles == 1: data = '%s' % os.path.basename(files[0]) elif nfiles: data = '%d possible' % nfiles else: data = None data = (data, ) return data def disableOk(self): self.file_select.double_callback = None self.ok_button.config(state=Tkinter.DISABLED) def enableOk(self): self.file_select.double_callback = self.ok self.ok_button.config(state=Tkinter.NORMAL) def apply(self): # protect against repeated double-clicking if (self.project): return False path = self.file_select.getDirectory() if not doesRepositoryContainProject( path) and not getPossibleProjectFiles(path): self.file_select.changeDir(path) return False self.disableOk() self.project = None if not path: showError('No path', 'Need to select path', self) self.enableOk() return False try: self.project = self.load_project(path) except ApiError, e: showError('Loading project', e.error_msg, self) self.enableOk() return False except IOError, e: showError('Loading project', str(e), self) self.enableOk() return False
class FormatFilePopup(BasePopup): def __init__(self, parent, file=None, files=None, component=None, selectionText='Select', title=None, format=None, multiSelect=False): # # Also get format (from self?) # self.file = None # Use this to return single file info, for backward compat if not multiSelect and file: self.files = [file] elif files: self.files = files else: self.files = [] if self.files: for i in range(len(self.files)): self.files[i] = normalisePath(self.files[i]) self.component = component self.fileSelected = False self.selectionText = selectionText self.format = format self.multiSelect = multiSelect if not title: title = 'Select %s file' % component BasePopup.__init__(self, parent=parent, title=title, modal=True, transient=True) def body(self, master): master.grid_columnconfigure(0, weight=1) master.grid_rowconfigure(0, weight=1) master.grid_rowconfigure(1, weight=1) self.geometry('500x500') fileNames = [] # All files have to be in same directory! if self.files and self.files[0].find(dirsep) > -1: (path, fileName) = splitPath(self.files[0]) directory = path fileNames.append(fileName) for file in self.files[1:]: (path, fileName) = splitPath(file) fileNames.append(fileName) else: path = None directory = normalisePath(os.path.abspath(os.curdir)) fileNames = [] #print directory #print fileName file_types = [] if fileTypeDict.has_key(self.component): if self.format and fileTypeDict[self.component].has_key( self.format): file_types.extend([ FileType(self.format, fileTypeDict[self.component][self.format]) ]) if fileTypeDict[self.component].has_key('generic'): file_types.extend([ FileType('generic', fileTypeDict[self.component]['generic']) ]) file_types.extend([FileType('All', ['*'])]) self.file_select = FileSelect(master, file_types=file_types, directory=directory, double_callback=self.ok, multiSelect=self.multiSelect) if self.multiSelect: self.file_select.setFiles(fileNames) else: if fileNames: fileName = fileNames[0] else: fileName = '' self.file_select.setFile(fileName) self.file_select.grid(row=0, column=0, sticky=Tkinter.NSEW) texts = [self.selectionText] commands = [self.ok] buttons = createDismissHelpButtonList(master, texts=texts, commands=commands) buttons.grid(row=1, column=0, sticky=Tkinter.EW) def apply(self): if not self.multiSelect: file = self.file_select.getFile() if file: files = [file] else: files = [] else: files = self.file_select.getFiles() if (not files): self.files = None return False self.fileSelected = True self.files = [] # Handle symbolic links in Linux/unix for file in files: symbolicLinkIndex = string.find(file, '->') if symbolicLinkIndex != -1: self.files.append(file[symbolicLinkIndex + 3:]) else: self.files.append(file) # For single files, set self.file for backward compat if not self.multiSelect: self.file = self.files[0] return True
class SaveLoadTab(object): '''The tab that lets the user FileSelect a file to open or to save. ''' def __init__(self, parent, frame): '''Init. args: parent: the guiElement that this tab is part of. frame: the frame this part of the GUI lives in. ''' self.guiParent = parent self.frame = frame self.project = parent.project self.nmrProject = parent.nmrProject self.loadAndSaveButtons = None self.fileselectionBox = None self.body() def body(self): '''Setting up the body of this view.''' frame = self.frame file_types = [FileType('pyc', ['*.pyc'])] self.fileselectionBox = FileSelect(frame, multiSelect=False, file_types=file_types) self.fileselectionBox.grid(row=0, column=0, columnspan=6, sticky='nsew') texts = ['Load', 'Save'] commands = [self.loadDataFromPyc, self.saveDataToPyc] self.loadAndSaveButtons = ButtonList(frame, commands=commands, texts=texts) self.loadAndSaveButtons.grid(row=1, column=0, sticky='nsew') frame.grid_rowconfigure(0, weight=1) frame.grid_columnconfigure(0, weight=1) def saveDataToPyc(self): '''Save the data to the selected file.''' if self.guiParent.connector.results: fileName = self.fileselectionBox.getFile() self.guiParent.connector.saveDataToPyc(fileName) self.fileselectionBox.updateFileList() else: string = ('''There are no results to save, ''' '''the algorithm has not run yet.''') showWarning('No Results to Save', string, parent=self.guiParent) def loadDataFromPyc(self): '''Load the data from the selected file.''' fileName = self.fileselectionBox.getFile() self.guiParent.connector.loadDataFromPyc(fileName) self.guiParent.resultsTab.update()
class ArchiveProjectPopup(BasePopup): """ **Archive the Project** This popup window enables the user to archive the CCPN Project into a gzipped tar file. By default it only includes the *.xml files which reside in the project directory. If the "Include *.xml.bak files" check button is checked then it will also include the *.xml.bak files which reside in the project directory. If the "Include data files which are in the project directory" check button is checked then it will also include the binary data files which reside in the project directory. **Caveats & Tips** The archive excludes the reference data *.xml files (quite sensibly). """ def __init__(self, parent, project, title='Project : Archive', callback=None, help_msg='', help_url='', dismiss_text='', *args, **kw): self.callback = callback self.help_msg = help_msg self.help_url = help_url self.dismiss_text = dismiss_text BasePopup.__init__(self, parent=parent, project=project, title=title, *args, **kw) def body(self, guiParent): now = datetime.date.today().strftime('%y%m%d') filePrefix = '%s_%s' % (self.project.name, now) projDir = getUserDataPath(self.project) directory = os.path.dirname(projDir) guiParent.grid_rowconfigure(0, weight=1) guiParent.grid_columnconfigure(1, weight=1) row = 0 label = Label(guiParent, text='Archive File:') label.grid(row=row, column=0, sticky=Tkinter.E) tipText = 'File name (excluding .tgz ending) for archive' self.fileEntry = Entry(guiParent, text=filePrefix, tipText=tipText) self.fileEntry.grid(row=row, column=1, sticky=Tkinter.EW) label = Label(guiParent, text='.tgz (automatically appended)') label.grid(row=row, column=2, sticky=Tkinter.W) row = row + 1 self.backupCheck = CheckButton( guiParent, text='Include *.xml.bak files', tipText='If checked include *.xml.bak files') self.backupCheck.grid(row=row, column=1, columnspan=2, sticky=Tkinter.W) row = row + 1 self.dataCheck = CheckButton( guiParent, text='Include data files which are in project directory', tipText= 'If checked include data files if they are located in project directory' ) self.dataCheck.grid(row=row, column=1, columnspan=2, sticky=Tkinter.W) row = row + 1 labelFrame = LabelFrame(guiParent, text='Archive Location') labelFrame.grid(row=row, column=0, columnspan=3, sticky=Tkinter.NSEW) labelFrame.grid_rowconfigure(0, weight=1) labelFrame.grid_columnconfigure(0, weight=1) self.dirSelect = FileSelect(labelFrame, directory=directory, show_file=False) self.dirSelect.grid(row=0, column=0, sticky=Tkinter.NSEW) guiParent.grid_rowconfigure(row, weight=1) row = row + 1 texts = ['Save'] tipTexts = ['Create archive file'] commands = [self.save] buttons = createDismissHelpButtonList(guiParent, texts=texts, tipTexts=tipTexts, commands=commands, help_msg=self.help_msg, help_url=self.help_url, dismiss_text=self.dismiss_text, expands=True) buttons.grid(row=row, column=0, columnspan=3, sticky=Tkinter.EW) def save(self): filePrefix = self.fileEntry.get() directory = self.dirSelect.getDirectory() filePrefix = joinPath(directory, filePrefix) fileName = filePrefix + '.tgz' if os.path.exists(fileName): if not showYesNo('File exists', 'File "%s" exists, overwrite?' % fileName, parent=self): return includeBackups = self.backupCheck.isSelected() includeData = self.dataCheck.isSelected() packageProject(self.project, filePrefix, includeBackups, includeData)
class FileSelectPopup(BasePopup): def __init__(self, parent, file_types=None, directory=None, multiSelect=False, title='Browse files', prompt=None, show_file=True, file='', dismiss_text='Close', extra_dismiss_text='', selected_file_must_exist=False, default_dir=None, *args, **kw): self.file_types = file_types self.directory = directory self.prompt = prompt self.show_file = show_file self.dismiss_text = dismiss_text self.extra_dismiss_text = extra_dismiss_text self.initial_file = file self.selected_file_must_exist = selected_file_must_exist self.default_dir = default_dir self.multiSelect = multiSelect kw['title'] = title kw['transient'] = True kw['modal'] = True BasePopup.__init__(self, parent=parent, *args, **kw) def body(self, master): self.geometry('600x400') master.grid_rowconfigure(0, weight=1) master.grid_columnconfigure(0, weight=1) self.result = '' self.file_select = FileSelect(master, file_types=self.file_types, directory=self.directory, prompt=self.prompt, show_file=self.show_file, file=self.initial_file, multiSelect=self.multiSelect, default_dir=self.default_dir) self.file_select.grid(row=0, column=0, sticky=Tkinter.NSEW) texts = ['Ok'] commands = [self.ok] if (self.extra_dismiss_text): texts.append(self.extra_dismiss_text) commands.append(self.extra) buttons = createDismissHelpButtonList(master, texts=texts, commands=commands, dismiss_text=self.dismiss_text) buttons.grid(row=1, column=0, sticky=Tkinter.EW) def apply(self): self.result = '' file = self.file_select.getFile() if (self.selected_file_must_exist and not os.path.exists(file)): showError('No file', 'File does not exist', self) return False self.result = file return True def extra(self): self.result = None self.close() def getFile(self): if (self.result): return self.file_select.getFile() else: return self.result def getDirectory(self): if (self.result): return self.file_select.getDirectory() else: return self.result def open(self, file=''): if (file): self.setFile(file) BasePopup.open(self) def __getattr__(self, name): try: return getattr(self.__dict__['file_select'], name) except: raise AttributeError, "%s instance has no attribute '%s'" % ( self.__class__.__name__, name)
class OpenMacroPopup(BasePopup): """ **Locate Python Macro Scripts On Disk** This popup is used to locate a Python file and function definition on disk so that it can be loaded into Analysis as a "Macro". The top table is a file browser that the user can navigate to the location of the Python file (typically sending in ".py"). When a Python file is selected in the upper table the system will look through the contents of the file to find any macro functions that are defined within. Note that a macro function is defined by the normal Python "def" keyword but must take "argSever" as its first input argument. Any macro functions in the selected file will be displayed in the lower table. Clicking on the name of a function in this table selects it for opening. The user may edit the name of the macro for display purposes within Analysis. Finally clicking [Load Macro] will add it to the CCPN project, stored in a user-specific way inside the current Analysis profile. Once loaded into the project the new macro will appear in the main macro table (the "Macros" tab of `User Options`_) .. _`User Options`: EditProfilesPopup.html """ def __init__(self, parent, **kw): # TBD: properly transient = True BasePopup.__init__(self, parent=parent, title='Open macro', transient=transient, **kw) def body(self, guiParent): guiParent.grid_columnconfigure(1,weight=1) row = 0 file_types = [ FileType('Python', ['*.py']), FileType('All', ['*']) ] self.file_select = FileSelect(guiParent, file_types=file_types, single_callback=self.chooseFile, double_callback=self.chooseFile) self.file_select.grid(row=row, column=0, columnspan=2, sticky='nsew') row = row + 1 headingList=('Function',) self.scrolledMatrix = ScrolledMatrix(guiParent, initialRows=4, headingList=headingList, callback=self.selectFunction) self.scrolledMatrix.grid(row=row, column=0, columnspan=2, sticky='nsew') guiParent.grid_rowconfigure(row,weight=1) row = row + 1 self.moduleLabel1 = Label(guiParent, text='Module: ') self.moduleLabel1.grid(row=row, column=0, sticky='nw') self.moduleLabel2 = Label(guiParent, text=' ') self.moduleLabel2.grid(row=row, column=1, sticky='nw') row = row + 1 self.functionLabel1 = Label(guiParent, text='Function: ') self.functionLabel1.grid(row=row, column=0, sticky='nw') self.functionLabel2 = Label(guiParent, text=' ') self.functionLabel2.grid(row=row, column=1, sticky='nw') row = row + 1 self.nameLabel = Label(guiParent, text='Name: ') self.nameLabel.grid(row=row, column=0, sticky='nw') self.nameEntry = Entry(guiParent, text=' ', width=40) self.nameEntry.grid(row=row, column=1, sticky='nw') row = row + 1 texts = [ 'Load Macro' ] commands = [ self.loadMacro ] buttons = UtilityButtonList(guiParent, texts=texts, commands=commands, helpUrl=self.help_url) buttons.grid(row=row, column=0, columnspan=2, sticky='ew') self.loadButton = buttons.buttons[0] self.loadButton.disable() self.path = None self.module = None self.function = None def selectFunction(self, function, row, col): if function: self.loadButton.enable() self.function = function self.functionLabel2.set(function) self.nameEntry.set(function) def updateFunctions(self, file): self.loadButton.disable() functions = [] fileHandle = open(file, 'r') line = fileHandle.readline() textMatrix = [] while line : match = re.match('\s*def\s+(\w+)\s*\(.*argServer',line) if match: function = match.group(1) functions.append(function) textMatrix.append( [function,] ) line = fileHandle.readline() self.scrolledMatrix.update(objectList=functions,textMatrix=textMatrix) def chooseFile(self, file): fullPath =self.file_select.getFile() if not os.path.isdir(fullPath) and file: (self.path, module) = splitPath(fullPath) module = re.sub('\..+?$','',module) self.module = module self.moduleLabel2.set(module) self.updateFunctions(file) def loadMacro(self): if self.module and self.function and self.path: name = self.nameEntry.get() if not name: name = self.function analysisProfile = self.analysisProfile m1 = analysisProfile.newMacro(name=name,path=self.path, function=self.function, module=self.module,ordering=1) self.close()
class SaveProjectFrame(Frame): def __init__(self, guiParent, project, callback=None, help_msg='', help_url='', dismiss_text='', modal=False, *args, **kw): self.project = project self.callback = callback self.help_msg = help_msg self.help_url = help_url self.dismiss_text = dismiss_text self.modal = modal self.did_save = False Frame.__init__(self, guiParent, *args, **kw) projDir = Io.getUserDataPath(self.project) guiParent.grid_columnconfigure(1, weight=1) row = 0 label = Label(guiParent, text='Project Name:') label.grid(row=row, column=0, sticky=Tkinter.E) self.proj_name_entry = Entry( guiParent, text=self.project.name, returnCallback=self.updateInfo, leaveCallback=self.updateInfo, tipText='The name used for the project save directory') self.proj_name_entry.grid(row=row, column=1, sticky=Tkinter.EW) row = row + 1 label = Label(guiParent, text='Project Directory:') label.grid(row=row, column=0, sticky=Tkinter.E) label = self.proj_dir_label = Label(guiParent, text=projDir) label.grid(row=row, column=1, sticky=Tkinter.W) row = row + 1 label = Label( guiParent, text='Note: Project Directory = Save Location + Project Name') label.grid(row=row, column=1, sticky=Tkinter.W) text = 'Save binary data with project' tipText = 'Copy data files (e.g. for spectra) into new project directory if not already in current project directory: careful, this can take some time' row = row + 1 self.dataCheckButton = CheckButton(guiParent, text=text, tipText=tipText) self.dataCheckButton.grid(row=row, column=0, columnspan=2, sticky=Tkinter.W) row = row + 1 guiParent.grid_rowconfigure(row, weight=1) labelFrame = LabelFrame(guiParent, text='Save Location') labelFrame.grid(row=row, column=0, columnspan=2, sticky=Tkinter.NSEW) labelFrame.grid_rowconfigure(0, weight=1) labelFrame.grid_columnconfigure(0, weight=1) directory = os.path.dirname(projDir) self.proj_dir_select = FileSelect( labelFrame, directory=directory, select_dir_callback=self.selectDir, change_dir_callback=self.updateInfo, should_change_dir_callback=self.shouldChangeDir, getRowColor=self.getEntryColor, show_file=False) self.proj_dir_select.grid(row=0, column=0, sticky=Tkinter.NSEW) row = row + 1 texts = ['Save'] tipTexts = ['Save project with specified name in specified directory'] commands = [self.save] buttons = createDismissHelpButtonList(guiParent, texts=texts, tipTexts=tipTexts, commands=commands, help_msg=self.help_msg, help_url=self.help_url, dismiss_text=self.dismiss_text, expands=True) buttons.grid(row=row, column=0, columnspan=2, sticky=Tkinter.EW) def save(self): projName = self.proj_name_entry.get() directory = self.proj_dir_select.getDirectory() directory = joinPath(directory, projName) if self.isProjectDirectory(directory): if not showOkCancel('Overwrite directory', 'Overwrite existing project directory?', parent=self): return self.updateInfo() self.did_save = False changeDataLocations = self.dataCheckButton.isSelected() done = False try: done = Io.saveProject(self.project, newPath=directory, newProjectName=projName, createFallback=True, showYesNo=showYesNo, changeDataLocations=changeDataLocations, showWarning=showWarning) if done: showInfo('Project saved', 'Project saved successfully') self.did_save = True if self.callback: self.callback(self.project) elif self.modal: return # give another chance except Implementation.ApiError, e: showError('Save project', e.error_msg) except IOError, e: showError('Save project', str(e))
class OpenSpectrumPopup(BasePopup): r""" **Locate Spectrum Data for Use in CCPN Project** This popup window enables the user to locate spectrum data within a file system and associate the files (typically binary) with an experiment and spectrum name so that it may be visualised and accessed within the current CCPN project. Spectra of many different origins and file formats may be loaded, which currently includes Bruker, Varian, Felix, NMRPipe, NmrView, SPARKY/UCSF, Azara and the factorised shape format "USF3". Depending upon the file format of the spectrum, data loaded the user may be required to either select a parameter file which then refers to the actual spectrum intensity data; this is true for Bruker "procs" and AZARA ".par" files, or alternatively a spectrum data file itself that contains referencing information; this is the case for SPARKY/UCSF, NmrView and NMRPipe spectra. The layout of the popup involved two sections; the upper of which is for navigating to and selecting the spectrum or parameter files within the file-system, and the lower is for specifying how each spectrum is loaded into the CCPN project. It should be noted that when spectrum parameters are read the first time, the relevant information is copied into the CCPN project, where it may be adjusted independently of the original file information. No copies of the spectrum intensity data are made, the CCPN project merely refers to the spectrum data on disk, although the data file for a loaded spectrum may subsequently be moved or replaced. In normal operation the user first selects the kind of spectrum file format that will be loaded via the upper "File format" pulldown menu and then checks that the "File type" pulldown (toward the bottom of the file browser) is set to detect the appropriate kinds of filename; if a helpful file name filter is not available the user can add one via the "Manual Select" field, taking care to add any wild-card symbols, like the asterisk in "\*.ft3". Next the spectrum data or parameter files, appropriate to the selected format, are located by navigating within the file-system browser. When the required spectrum files are visible the user selects one *or more* to load. Multiple file selections may be made using left-click with <Ctrl> (toggle selection) or <Shift> (select range). It should be noted that when selecting Bruker files, when using the standard Bruker directory structure, the user only needs to navigate to the numbered spectrum directory; by default the "procs" file two levels down is searched for, e.g. "123/pdata/1/procs" is shown in the directory containing the "123" directory. When spectrum or parameter files are selected in the file table, the lower "Spectra To Open" table is filled to reflect the selection. The user should then be mindful of the settings within this table and may choose to edit various things by double-clicking on the appropriate cell. Typically the user just adjusts the name of the independent "Experiment" and "Spectrum" records. These names are usually concatenated like "expName:specName" in CCPN graphical displays so there is no need to repeat a name in both fields; this only takes up more space. The Experiment, which is a record of *what was done experimentally*, commonly has a short name like "HNCA" or "HSQC_298K" so the user readily knows how to interpret the experimental data. The Spectrum, which is a record of *the data that was collected*, commonly has a short name to identify the spectrum number or file name. An Experiment record may contain several Spectrum records, so the spectrum's name need minimally only identify it amongst others from the same experiment. The Shift List value may be changed if the user knows that the experiment represents a distinct set of conditions, with different spectrum peak/resonance positions, to existing or other experiments being entered. Each shift list will be curated separately, to give separate chemical shift values for assignments made under different conditions (even when relating to the same atoms). The shift list that an experiment uses may also be changed at any time after loading. When all spectra and options are specified the [Open Spectrum] button will load the relevant data into the CCPN project. If the "Skip verification dialogs" option is set it is assumed that all of the spectrum point to frequency referencing information, and any data file references, are correct. Otherwise, the user will be prompted to confirm the file details and referencing information for each spectrum in turn. Finally, after loading the user is asked to set the type of NMR experiment, in terms of general magnetisation transfer pathway, that was performed. **Caveats & Tips** If the name of an Experiment that is *already within the CCPN project* is used, then the loaded spectrum will (assuming it is compatible) be entered under that existing experiment record; no new experiment entity will be defined. The user may legitimately use this feature to load several spectra that relate to the same experiment; typically where spectra are different projections. To facilitate this the "Use shared experiment" option can be selected. Although experiments and spectra may be renamed after loading, a spectrum record may not be placed under a different experiment once created; deletion and re-loading is the only mans of achieving this, and care must be taken in transferring any assignments. """ def __init__(self, parent, *args, **kw): self.experiment = None self.currentObject = None #self.currentObjects = [] # looks obsolete BasePopup.__init__(self, parent=parent, title='Experiment : Open Spectra', **kw) def open(self): self.message() BasePopup.open(self) def body(self, guiFrame): self.fileSelect = None names, objects = self.getShiftLists() self.shiftListPulldown = PulldownList(self, callback=self.setShiftList, texts=names, objects=objects) self.windowPulldown = PulldownList(self, texts=WINDOW_OPTS, callback=self.setWindow) self.experimentEntry = Entry(self, width=16, returnCallback=self.setExperiment) self.spectrumEntry = Entry(self, width=16, returnCallback=self.setSpectrum) guiFrame.grid_columnconfigure(0, weight=1) guiFrame.grid_rowconfigure(0, weight=1) guiFrame.grid_rowconfigure(1, weight=1) leftFrame = LabelFrame(guiFrame, text='File Selection') leftFrame.grid(row=0, column=0, sticky='nsew') leftFrame.grid_columnconfigure(3, weight=1) row = 0 label = Label(leftFrame, text='File format:') label.grid(row=row, column=0, sticky='w') tipText = 'Selects which kind of spectrum file is being loaded; what its data matrix format is' self.formatPulldown = PulldownList(leftFrame, callback=self.chooseFormat, texts=file_formats, tipText=tipText, grid=(row, 1)) self.detailsLabel = Label(leftFrame, text='Show details:') tipText = 'Whether to show an annotation that describes the spectrum in the file selection; currently only uses comment fields from Bruker spectra' self.detailsSelect = CheckButton(leftFrame, selected=False, callback=self.showDetails, tipText=tipText) self.titleRow = row self.detailsSelected = False row = row + 1 leftFrame.grid_rowconfigure(row, weight=1) file_types = [FileType('All', ['*'])] self.fileSelect = FileSelect(leftFrame, multiSelect=True, file_types=file_types, single_callback=self.chooseFiles, extraHeadings=('Details', ), extraJustifies=('left', ), displayExtra=False, getExtraCell=self.getDetails, manualFileFilter=True) self.fileSelect.grid(row=row, column=0, columnspan=6, sticky='nsew') rightFrame = LabelFrame(guiFrame, text='Spectra To Open') rightFrame.grid(row=1, column=0, sticky='nsew') rightFrame.grid_columnconfigure(3, weight=1) row = 0 label = Label(rightFrame, text='Skip verification dialogs:', grid=(row, 0)) tipText = 'Whether to allow the user to check file interpretation and referencing information before the spectrum is loaded' self.verifySelect = CheckButton(rightFrame, selected=False, grid=(row, 1), tipText=tipText) label = Label(rightFrame, text='Use shared experiment:', grid=(row, 2)) tipText = 'When selecting multiple spectrum files, whether the loaded spectra will all belong to (derive from) the same experiment; useful for projection spectra etc.' self.sharedExpSelect = CheckButton(rightFrame, selected=False, tipText=tipText, callback=self.useShared, grid=(row, 3)) row = row + 1 rightFrame.grid_rowconfigure(row, weight=1) tipTexts = [ 'A short textual name for the experiment record that the loaded spectrum will belong to; may be a new experiment or the name of an existing one', 'A short textual name to identify the spectrum within its experiment; typically a few characters or spectrum number, rather than a repeat of the experiment name', 'The location of the file, relative to the current directory, that the spectrum data will be loaded from', 'Sets which window or windows the spectrum will initially appear within once loaded', 'Sets which shift list the experiment (and hence loaded spectrum) will use to curate chemical shift information; can be changed after load time' ] headingList = [ 'Experiment', 'Spectrum', 'File', 'Windows', 'Shift List' ] editWidgets = [ self.experimentEntry, self.spectrumEntry, None, self.windowPulldown, self.shiftListPulldown ] editGetCallbacks = [ self.getExperiment, self.getSpectrum, None, self.getWindow, self.getShiftList ] editSetCallbacks = [ self.setExperiment, self.setSpectrum, None, self.setWindow, self.setShiftList ] self.scrolledMatrix = ScrolledMatrix(rightFrame, headingList=headingList, callback=self.selectCell, editWidgets=editWidgets, multiSelect=True, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, tipTexts=tipTexts, grid=(row, 0), gridSpan=(1, 4)) row = row + 1 tipTexts = [ 'Load spectrum or spectra into the CCPN project using the selected file(s)', ] texts = ['Open Spectrum'] commands = [self.openSpectra] bottomButtons = UtilityButtonList(guiFrame, texts=texts, tipTexts=tipTexts, doClone=False, commands=commands, helpUrl=self.help_url) bottomButtons.grid(row=row, column=0, columnspan=1, sticky='ew') self.openButton = bottomButtons.buttons[0] self.chooseFormat('Azara') self.message() def message(self): if not self.project or len(self.nmrProject.experiments) < 1: pass #self.parent.ticker.setMessage('Choose spectrum files to open.... ') def showDetails(self, isSelected): self.detailsSelected = isSelected self.fileSelect.updateDisplayExtra(isSelected) # below is so that when Details column is toggled on it will actually # be seen without having to use the scrollbar self.fileSelect.fileList.refreshSize() def useShared(self, isSelected): self.chooseFiles(forceUpdate=True) #if isSelected: #objects = self.scrolledMatrix.objectList #if len(objects) > 1: # self.currentObject = objects[0] # text = objects[0][0] # self.chooseFiles() # for oo in objects[1:]: # oo[0] = text # if self.project: # self.experiment = self.nmrProject.findFirstExperiment(name=text) #self.update() def gridDetails(self, bool): if bool: self.detailsLabel.grid(row=self.titleRow, column=2, sticky='w') self.detailsSelect.grid(row=self.titleRow, column=3, sticky='w') self.fileSelect.updateDisplayExtra(self.detailsSelected) else: self.detailsLabel.grid_forget() self.detailsSelect.grid_forget() self.fileSelect.updateDisplayExtra(False) def openSpectra(self): noVerify = self.verifySelect.getSelected() # tracks if 'add to existing experiment' has already ben OK'ed self.okExpSet = set() directory = self.fileSelect.getDirectory() spectra = [] specIndex = 0 for obj in self.scrolledMatrix.objectList: fileName = uniIo.joinPath(directory, obj.fileName) spectrum = self.openSpectrum(obj.exptName, obj.specName, fileName, obj.window, obj.shiftListName) specIndex += 1 if (spectrum): # check endianness if we are not verifying spectra.append(spectrum) if noVerify: isBigEndian = isSpectrumBigEndian( spectrum) # according to data in file if isBigEndian is not None: isBigEndianCurr = getIsSpectrumBigEndian( spectrum) # according to data model setIsSpectrumBigEndian(spectrum, isBigEndian) if isBigEndian != isBigEndianCurr: if isBigEndian: s = 'big' else: s = 'little' print 'WARNING: swapped endianess of spectrum to %s endian' % s # del self.okExpSet if noVerify and len(spectra) > 1 and self.sharedExpSelect.getSelected( ): # if we are using a shared experiment and not verifying, # set referencing to match first spectrum for all # get reference spectrum and set up data structure # use most recent pre-existing spectrum, otherwise first new one refSpec = spectra[0] for spec in spectra[0].experiment.sortedDataSources(): if spec in spectra: break else: refSpec = spec ddrLists = {} refDdrs = [] for dataDim in refSpec.sortedDataDims(): for ddr in dataDim.dataDimRefs: ddrLists[ddr.expDimRef] = [] refDdrs.append(ddr) # get dataDimRefs, store by ExpDimRef, # checking that all spectra have data dim refs for same set of xdr nTotal = len(ddrLists) for spec in spectra: nFound = 0 for dataDim in spec.sortedDataDims(): for ddr in dataDim.dataDimRefs: xdr = ddr.expDimRef ll = ddrLists.get(xdr) if ll is None: # something did not match - do nothing break else: ll.append(ddr) nFound += 1 else: if nFound == nTotal: # we are OK. Do next spectrum continue # something did not match - do nothing break else: # all spectra matched. Now reset O1 references to match reference if refSpec is spectra[0]: startAt = 1 else: startAt = 0 for refDdr in refDdrs: dataDim = refDdr.dataDim centrePoint = dataDim.numPointsOrig / 2 - dataDim.pointOffset + 1 refValue = refDdr.pointToValue(centrePoint) xdr = refDdr.expDimRef for ddr in ddrLists[xdr][startAt:]: dataDim = ddr.dataDim centrePoint = dataDim.numPointsOrig / 2 - dataDim.pointOffset + 1 ddr.refPoint = centrePoint ddr.refValue = refValue # set refExperiment if there is only one possibility experiments = [] ignoreSet = set() showPopup = False for spectrum in spectra: experiment = spectrum.experiment if experiment not in ignoreSet: ignoreSet.add(experiment) if not experiment.refExperiment: experiments.append(spectrum.experiment) if noVerify: resetCategory = False if not hasattr(experiment, 'category'): if (hasattr(experiment, 'pulProgName') and hasattr(experiment, 'pulProgType')): # this is first time we get here, and we have external name and source # use external source to set fullType experiment.category = 'use external' resetCategory = True refExperiments = getRefExperiments(experiment) if resetCategory and not refExperiments: # no refExperiments match external source. # unset 'use external' category del experiment.category if len(refExperiments) == 1: # only one possibility, just set it setRefExperiment(experiment, refExperiments[0]) # wb104: 20 Oct 2014: do not popup Experiment types dialog if noVerify #else: # showPopup = True # Pop up refExperiment verification if experiments and (showPopup or not noVerify): self.parent.initRefExperiments(experiments) # set up internal Analysis data for spectrum in spectra: self.parent.finishInitSpectrum(spectrum) print 'finished opening spectrum', spectrum.experiment.name, spectrum.name def chooseFiles(self, forceUpdate=False, *file): directory = self.fileSelect.getDirectory() fileNames = self.fileSelect.fileList.currentObjects fullFileNames1 = [uniIo.joinPath(directory, x) for x in fileNames] fullFileNames2 = [x.fileName for x in self.scrolledMatrix.objectList] fullFileNames2 = [uniIo.joinPath(directory, x) for x in fullFileNames2] if fullFileNames1 == fullFileNames2 and not forceUpdate: return objectList = [] textMatrix = [] format = self.formatPulldown.getText() shiftListName = self.getShiftLists()[0][0] windowOpt = WINDOW_OPTS[1] oneUp = os.path.dirname if format == 'Bruker': if self.sharedExpSelect.getSelected(): nameTemplate = 'Bruker_%d' next = self.getNextExpNum(nfiles=len(fileNames), nameTemplate=nameTemplate) exptName = nameTemplate % (next) for i, fileName in enumerate(fileNames): fullFileName = fullFileNames1[i] specName = os.path.basename( oneUp(oneUp(oneUp(fullFileName)))) datum = (exptName, specName, fileName, windowOpt, shiftListName) dataObj = RowObject(*datum) textMatrix.append(datum) objectList.append(dataObj) else: for i, fileName in enumerate(fileNames): fullFileName = fullFileNames1[i] try: # below should not fail ss1 = oneUp(fullFileName) specName = os.path.basename(ss1) ss2 = os.path.basename(oneUp(oneUp(ss1))) exptName = 'Bruker_' + ss2 except: # just put in something ss = os.path.basename(fullFileName) exptName = 'Bruker_' + ss specName = ss datum = (exptName, specName, fileName, windowOpt, shiftListName) dataObj = RowObject(*datum) textMatrix.append(datum) objectList.append(dataObj) else: next = self.getNextExpNum(nfiles=len(fileNames)) if self.sharedExpSelect.getSelected(): exptName = 'Expt_%d' % (next) for i, fileName in enumerate(fileNames): specName = re.sub('\.\w+$', '', fileName) datum = (exptName, specName, fileName, windowOpt, shiftListName) dataObj = RowObject(*datum) textMatrix.append(datum) objectList.append(dataObj) else: for i, fileName in enumerate(fileNames): exptName = 'Expt_%d' % (next + i) specName = re.sub('\.\w+$', '', fileName) datum = (exptName, specName, fileName, windowOpt, shiftListName) dataObj = RowObject(*datum) textMatrix.append(datum) objectList.append(dataObj) if len(fileNames) > 1: self.openButton.config(text='Open Spectra') else: self.openButton.config(text='Open Spectrum') self.scrolledMatrix.update(objectList=objectList, textMatrix=textMatrix) def getNextExpNum(self, nfiles=0, nameTemplate='Expt_%d'): """ get suitable free integer to use for exp names """ next = 1 if self.project: nmrProject = self.nmrProject ii = len(nmrProject.experiments) # find first exp number that is not taken # NBNB TBD could consider expname = specname, specname = proc dir next = ii + 1 if nfiles: while ii < next + nfiles: ii += 1 if nmrProject.findFirstExperiment(name=nameTemplate % ii): next = ii + 1 # return next def getDetails(self, fullfile): details = '' if os.path.isfile(fullfile): format = self.formatPulldown.getText() detailsDir = os.path.dirname(fullfile) detailsFile = uniIo.joinPath(detailsDir, details_file_dict[format]) if os.path.exists(detailsFile): fp = open(detailsFile) details = fp.read().strip().replace('\n', ' ').replace('\r', ' ') fp.close() return (details, ) def update(self): objectList = self.scrolledMatrix.objectList textMatrix = [(obj.exptName, obj.specName, obj.fileName, obj.window, obj.shiftListName) for obj in objectList] self.scrolledMatrix.update(objectList=objectList, textMatrix=textMatrix) def selectCell(self, obj, row, col): self.currentObject = obj if self.project: self.experiment = self.nmrProject.findFirstExperiment( name=obj.exptName) else: self.experiment = None def getWindow(self, obj): if obj: self.windowPulldown.set(obj.window) def setWindow(self, opt): if isinstance(opt, RowObject): self.currentObject.window = opt.window else: self.currentObject.window = opt self.update() def setShiftList(self, obj=None): if self.project: project = self.project shiftList = self.shiftListPulldown.getObject() if shiftList is None: shiftList = newShiftList(project, unit='ppm') if self.experiment and shiftList and ( shiftList is not self.experiment.shiftList): setExperimentShiftList(self.experiment, shiftList) self.currentObject.shiftListName = shiftList.name self.update() def getShiftList(self, object): names, shiftLists = self.getShiftLists() if names: self.shiftListPulldown.setup(names, shiftLists, 0) if self.experiment and self.experiment.shiftList: name = self.experiment.shiftList.name else: name = object.shiftListName if name is not None: self.shiftListPulldown.set(name) def getShiftLists(self): if self.project: names = [] objects = getShiftLists(self.nmrProject) for shiftList in objects: if not shiftList.name: shiftList.name = 'ShiftList %d' % shiftList.serial names.append(shiftList.name) objects.append(None) names.append('<New>') else: objects = [ None, ] names = [ 'ShiftList 1', ] return names, objects def chooseFormat(self, format): if format in ('Bruker', 'Varian'): self.gridDetails(True) else: self.gridDetails(False) file_types = [] file_type = file_type_dict.get(format) if (file_type): file_types.extend([file_type]) file_types.append(FileType('All', ['*'])) file_types.append(self.fileSelect.manualFilter) self.fileSelect.setFileTypes(file_types) def getSpectrum(self, obj): if obj: self.spectrumEntry.set(obj.specName) def setSpectrum(self, *event): if self.currentObject: text = self.spectrumEntry.get() if text and text != ' ': for data in self.scrolledMatrix.objectList: if data is self.currentObject: continue if (data.specName == text) and (data.exptName == self.currentObject.exptName): showWarning( 'Repeated name', 'Spectrum name (%s) already in use for experiment (%s)' % (data.specName, data.exptName), parent=self) return elif (self.experiment) and ( self.experiment.findFirstDataSource(name=text)): showWarning( 'Repeated name', 'Spectrum name (%s) already in use for experiment (%s)' % (data.specName, data.exptName), parent=self) return self.currentObject.specName = text self.update() def getExperiment(self, obj): if obj: self.experimentEntry.set(obj.exptName) def setExperiment(self, *event): if self.currentObject: text = self.experimentEntry.get() if text and text != ' ': if self.sharedExpSelect.getSelected(): # share one experiment for all rows for oo in self.scrolledMatrix.objectList: oo.exptName = text else: #separate experiments self.currentObject.exptName = text if self.project: self.experiment = self.nmrProject.findFirstExperiment( name=text) self.update() def updateShiftLists(self): if self.project: name = self.expt_entry.get() e = self.nmrProject.findFirstExperiment(name=name) else: e = None names, objects = self.getShiftLists() if e and e.shiftList: index = objects.index(e.shiftList) else: index = 0 self.shiftListPulldown.setup(names, objects, index) def openSpectrum(self, exptName, specName, file, windowOpt=WINDOW_OPTS[2], shiftListName='<New>', extraData=None): # input checks if not file: showError('No file', 'Need to enter file', parent=self) return None if not exptName: showError('Experiment', 'Need to enter experiment name', parent=self) return None if not specName: showError('Spectrum', 'Need to enter spectrum name', parent=self) return None # get or set up project project = self.project if not project: self.project = project = defaultProject() self.parent.initProject(project) self.nmrProject = self.parent.nmrProject self.analysisProject = self.parent.analysisProject #Default ShiftList with name 'ShiftList 1' created # set up shift list if shiftListName == '<New>': shiftList = None else: shiftList = self.nmrProject.findFirstMeasurementList( className='ShiftList', name=shiftListName) # read params format = self.formatPulldown.getText() clazz = params_class_dict[format] try: params = clazz(file, extraData=extraData) except Implementation.ApiError, e: showError('Reading params file', 'Fatal error: ' + e.error_msg, parent=self) return None dim = params.pseudoDataDim() if dim is not None: if format == 'NMRPipe': popup = NmrPipePseudoPopup(self, params, dim, file) popup.destroy() elif format == 'Bruker': popup = BrukerPseudoPopup(self, params, dim) popup.destroy() # get or set up experiment experiment = self.nmrProject.findFirstExperiment(name=exptName) if experiment: expIsNew = False if experiment.findFirstDataSource(name=specName): showError('Duplicate name', 'Duplicate spectrum name "%s" in experiment %s' % (specName, experiment.name), parent=self) return None elif (experiment.dataSources and experiment not in self.okExpSet): if showOkCancel('Multiple Spectra Warning', 'Really put multiple ' 'spectra into existing experiment %s?' % experiment.name, parent=self): self.okExpSet.add(experiment) else: return else: expIsNew = True try: # Will also work for shiftList == None experiment = Nmr.Experiment(self.nmrProject, name=exptName, numDim=params.ndim, shiftList=shiftList) except Implementation.ApiError, experiment: showError('Experiment', experiment.error_msg, parent=self) return None