Exemple #1
0
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()
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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()
Exemple #5
0
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)
Exemple #7
0
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()
Exemple #8
0
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))
Exemple #9
0
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