Package nMOLDYN :: Package GUI :: Module SelectionDialog |
[hide private]
[frames] | no frames]

# Source Code for Module nMOLDYN.GUI.SelectionDialog

      1  """This modules implements the atom selection dialog used in almost all nMOLDYN analysis.
      2
      3  The atom selection can be performed for various purposes such as selection of atoms for the simulation, selection
      4  of hydrogen atoms to deuterate or selection of several group of atoms on which an analysis will be performed
      5  collectively.
      6
      7  Classes:
      8      * SelectionDialog: sets up a selection dialog in the scope of an analysis dialog.
      9  """
     10
     11  # The python distribution modules
     12  import copy
     13  import os
     14  import sys
     15
     16  # The Tcl/Tk modules
     17  import Dialog
     18  from Tkinter import *
     19  from tkFileDialog import askopenfilename
     20
     21  # The nMOLDYN modules
     22  from nMOLDYN.Core.Logger import LogMessage
     23  from nMOLDYN.GUI.Widgets import ComboFileBrowser, ComboFrame, ComboListbox, ComboRadiobutton, ComboText
     24
     25 -class SelectionDialog(Toplevel):
     26      """Sets up a dialog from which the user can perform an atom selection.
     27      """
     28
     29 -    def __init__(self, parent, selectionType, univContents):
     30          """The constructor.
     31
     32          @param parent: the parent widget.
     33
     34          @param selectionType: a string being one of 'subset', 'deuteration' or 'group' specifying the
     35              atom selection type thatwill be performed.
     36          @type selectionType: string
     37
     38          @param univContents: a dictionnary that contains the universe contents.
     39          @type univContents: dict
     40          """
     41
     42          Toplevel.__init__(self, parent)
     43          self.transient(parent)
     44
     45          self.title('%s selection dialog' % selectionType)
     46
     47          self.parent = parent
     48
     49          # A local copy of the 'selectionType' argument. One of 'subset', 'deuteration', 'group'.
     50          self.selectionType = selectionType
     51
     52          # A local copy of the 'univContents' argument.
     53          self.univContents = copy.deepcopy(univContents)
     54
     55          # Create a set of all the possible keywords found in the universe contents. It will be used to tag those keywords
     56          # in the 'Selection preview' text widget.
     57          self.keywords = set()
     58          for v in self.univContents.values():
     59              self.keywords.update(v.keys())
     60
     61          # The selection dictionnary.
     62          self.selection = {}
     63
     64          # The dictionnary that stores the keywords and values currently selected.
     65          self.currentSelection = {}
     66
     67          # The selection string is set to its default value that is the entry value the ComboButton.
     68          # The selection prefix i also set. It is used especially for 'group' selection
     69          # types where it introducesand group1, group2 ...For 'subset' and 'deuteration' selection types,
     70          # this is respectively 'subset' and 'deuteration' even in these cases the prefix will be omitted in
     71          # the final selection string.
     72          if self.selectionType == 'group':
     73              self.selectionString = self.parent.widgets['group'].getValue()
     74              self.selectedPrefixName = None
     75
     76          elif self.selectionType == 'triplet':
     77              self.selectionType = 'group'
     78              self.selectionString = self.parent.widgets['triplet'].getValue()
     79              self.selectedPrefixName = None
     80
     81          elif self.selectionType == 'bond':
     82              self.selectionType = 'group'
     83              self.selectionString = self.parent.widgets['bond'].getValue()
     84              self.selectedPrefixName = None
     85
     86          elif self.selectionType == 'subset':
     87              self.selectionString = self.parent.widgets['subset'].getValue()
     88              self.selectedPrefixName = self.selectionType
     89
     90          elif self.selectionType == 'deuteration':
     91              self.selectionString = self.parent.widgets['deuteration'].getValue()
     92              self.selectedPrefixName = self.selectionType
     93
     94          # The object name currently selected.
     95          self.selectedObjectName = None
     96
     97          # The selection keyword currently selected.
     98          self.selectedKeyword = None
     99
    100          body = Frame(self)
    101          self.initial_focus = self.body(body)
    102          body.grid(row = 0, column = 0, sticky = EW)
    103
    104          self.buttonbox()
    105
    106          self.grab_set()
    107
    108          if not self.initial_focus:
    109              self.initial_focus = self
    110
    111          self.protocol("WM_DELETE_WINDOW", self.cancel)
    112
    113          self.resizable(width = NO, height = NO)
    114
    115          self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
    116
    117          self.initial_focus.focus_set()
    118
    119          self.wait_window(self)
    120
    121 -    def body(self, master):
    122          """Create dialog body. Return widget that should have initial focus.
    123          """
    124
    125          self.settingsFrame = LabelFrame(master, text = 'Settings', bd = 2, relief = GROOVE)
    126          self.settingsFrame.grid(row = 0, column = 0, sticky = EW, padx = 3, pady = 3)
    127          self.settingsFrame.grid_columnconfigure(0, weight = 1)
    128
    129          self.selectionMediasRadio = ComboRadiobutton(self.settingsFrame,\
    130                                                       frameLabel = "Selection media",\
    131                                                       contents = ["from a selection file",\
    132                                                                   "from the loaded trajectory",\
    133                                                                   "from an expression string"],\
    134                                                      layout = (1,3),\
    135                                                      default = 1)
    136          [r.config(width = 22, command = self.changeSelectionMedia) for r in self.selectionMediasRadio.radio]
    137          self.selectionMediasRadio.grid(row = 0, column = 0, padx = 2, pady = 5, sticky = EW)
    138
    139          # The frame that will host the selection browsers specific to the selected selection type.
    140          self.selectionFrame = Frame(self.settingsFrame, bd = 2, relief = GROOVE, width = 1000, height = 300)
    141          self.selectionFrame.grid(row = 1, column = 0, padx = 3, pady = 3, sticky = 'NEW')
    142          self.selectionFrame.grid_propagate(0)
    143          self.selectionFrame.grid_columnconfigure(0, weight = 1)
    144          self.selectionFrame.grid_rowconfigure(10, weight = 1)
    145
    146          # The selection browser for a selection from a selection file.
    147          self.fileBrowser = ComboFileBrowser(self.selectionFrame,\
    148                                              frameLabel = 'Selection from a selection file',\
    149                                              command = self.selectFromFile)
    150          self.fileBrowser.entry.config(width = 100)
    151          self.fileBrowser.entry.bind('<Return>', self.selectFromFile)
    152
    153          # The selection browser for a selection from the loaded trajectory. This is the one displayed by default.
    154          self.objectBrowser = ComboFrame(self.selectionFrame, frameLabel = 'Selection from the loaded trajectory')
    155          self.objectBrowser.grid(row = 0, column = 0, padx = 3, pady = 3, sticky = EW)
    156          self.objectBrowser.grid_columnconfigure(0, weight = 1)
    157          self.objectBrowser.grid_columnconfigure(1, weight = 1)
    158          self.objectBrowser.grid_columnconfigure(2, weight = 1)
    159
    160          if self.selectionType == 'group':
    161              self.objectBrowser.grid_columnconfigure(3, weight = 1)
    162              self.objectBrowser.grid_columnconfigure(4, weight = 1)
    163
    164              f = Frame(self.objectBrowser, bd = 0)
    165              f.grid(row = 0, column = 0, sticky = EW)
    166              # The 'Object type' listbox for the selection of a given object type.
    167              self.prefixName = ComboListbox(f, frameLabel = 'Group number', contents = ['group1'])
    168              self.prefixName.lb.config(width = 8, height = 8, exportselection = 0, selectmode = SINGLE)
    169
    170              Button(f, width = 6, text = 'New group', command = self.createNewGroup).grid(row = 1, column = 0, padx = 2, pady = 2, sticky = EW)
    171
    172              f.grid_rowconfigure(0, weight = 1)
    173
    174              self.prefixName.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = EW)
    175              self.prefixName.grid_columnconfigure(0, weight = 1)
    176              self.prefixName.lb.bind('<ButtonRelease-1>', self.selectPrefixName)
    177              self.prefixName.lb.bind('<Double-1>', self.deletePrefixName)
    178
    179              colNum = 1
    180
    181          else:
    182              colNum = 0
    183
    184          # The 'Object type' listbox for the selection of a given object type.
    185          self.objectName = ComboListbox(self.objectBrowser,\
    186                                         frameLabel = 'Object name',\
    187                                         contents = sorted(self.univContents.keys()))
    188          self.objectName.grid(row = 0, column = colNum, padx = 2, pady = 2, sticky = EW)
    189          self.objectName.grid_columnconfigure(0, weight = 1)
    190          self.objectName.lb.config(width = 20, exportselection = 0, selectmode = SINGLE)
    191
    192          self.objectName.lb.bind('<ButtonRelease-1>', self.selectObjectName)
    193          self.objectName.lb.bind('<Double-1>', self.deleteObjectName)
    194
    195          if self.selectionType == 'group':
    196              # The 'Selection keyword' listbox for the selection of a given selection keyword.
    197              self.groupingLevel = ComboListbox(self.objectBrowser,'Grouping level')
    198              self.groupingLevel.grid(row = 0, column = colNum+1, padx = 2, pady = 2, sticky = EW)
    199              self.groupingLevel.grid_columnconfigure(0, weight = 1)
    200              self.groupingLevel.lb.config(width = 20, exportselection = 0, selectmode = SINGLE)
    201              self.groupingLevel.lb.bind('<ButtonRelease-1>', self.selectGroupingLevel)
    202              colNum += 1
    203
    204          # The 'Selection keyword' listbox for the selection of a given selection keyword.
    205          self.selectionKeyword = ComboListbox(self.objectBrowser, 'Selection keyword')
    206          self.selectionKeyword.grid(row = 0, column = colNum+1, padx = 2, pady = 2, sticky = EW)
    207          self.selectionKeyword.grid_columnconfigure(0, weight = 1)
    208          self.selectionKeyword.lb.config(width = 20, exportselection = 0, selectmode = SINGLE)
    209          self.selectionKeyword.lb.bind('<ButtonRelease-1>', self.selectKeyword)
    210
    211          # The 'Selection value' listbox for the selection of a given selection value.
    212          self.selectionValue = ComboListbox(self.objectBrowser, 'Selection value')
    213          self.selectionValue.grid(row = 0, column = colNum+2, padx = 2, pady = 2, sticky = EW)
    214          self.selectionValue.grid_columnconfigure(0, weight = 1)
    215          self.selectionValue.lb.config(width = 40, exportselection = 0, selectmode = MULTIPLE)
    216          self.selectionValue.lb.bind('<ButtonRelease-1>', self.selectValue)
    217          self.selectionValue.lb.bind('<Control-a>', self.selectValue)
    218
    219          # The frame that will host the button used to build the regular selection expression.
    220          selectionButtons = ComboFrame(self.objectBrowser, frameLabel = 'Linkers')
    221          selectionButtons.grid(row = 1, column = 0, columnspan = 5, padx = 2, pady = 2, sticky = EW)
    222
    223          # The five buttons that allow to the construction of the selection patterns.
    224          Button(selectionButtons, text = 'Clear', width = 4, command = self.clear).grid(row = 0, column = 0)
    225          Button(selectionButtons, text = '('   , width = 4, command = lambda : self.appendLinker('(')).grid(row = 0, column = 1)
    226          Button(selectionButtons, text = ')'   , width = 4, command = lambda : self.appendLinker(')')).grid(row = 0, column = 2)
    227          Button(selectionButtons, text = 'AND' , width = 4, command = lambda : self.appendLinker('AND')).grid(row = 0, column = 3)
    228          Button(selectionButtons, text = 'OR'  , width = 4, command = lambda : self.appendLinker('OR')).grid(row = 0, column = 4)
    229
    230          # The selection browser for a selection from an expression string.
    231          self.expressionBrowser = ComboText(self.selectionFrame, 'Selection from an expression string')
    232          self.expressionBrowser.text.config(height = 10, state = NORMAL)
    233          self.expressionBrowser.text.bind('<Return>', self.selectFromExpression)
    234
    235          self.selectionPreview = ComboText(self.settingsFrame, 'Selection preview')
    236          self.selectionPreview.grid(row = 2, column = 0, padx = 3, pady = 3, sticky = EW)
    237          self.selectionPreview.grid_columnconfigure(0, weight = 1)
    238          self.selectionPreview.text.config(height = 10, font = ('Courier', '12'))
    239          self.selectionPreview.text.tag_config('prefix'    , foreground = 'pink'  , font = ('Courier','12','bold'))
    240          self.selectionPreview.text.tag_config('italic'    , foreground = 'black' , font = ('Courier','12','normal', 'italic'))
    241          self.selectionPreview.text.tag_config('bold'      , foreground = 'black' , font = ('Courier','12','bold'))
    242          self.selectionPreview.text.tag_config('objectname', foreground = 'red'   , font = ('Courier','12','bold'))
    243          self.selectionPreview.text.tag_config('filename'  , foreground = 'blue'  , font = ('Courier','12','bold'))
    244          self.selectionPreview.text.tag_config('expression', foreground = 'green' , font = ('Courier','12','bold'))
    245          self.selectionPreview.text.tag_config('()'        , foreground = 'black' , font = ('Courier','12','bold'))
    246          self.selectionPreview.text.tag_config('AND'       , foreground = 'purple', font = ('Courier','12','bold'))
    247          self.selectionPreview.text.tag_config('OR'        , foreground = 'purple', font = ('Courier','12','bold'))
    248
    249          self.displaySelectionString()
    250
    251          return None
    252
    253 -    def buttonbox(self):
    254          """Add standard button box.
    255          """
    256
    257          # The frame that contains the 'Cancel' and 'OK' buttons.
    258          box = LabelFrame(self, text = 'Actions', bd = 2, relief = GROOVE)
    259          box.grid(row = 1, column = 0, sticky = EW, padx = 3, pady = 3)
    260          box.grid_columnconfigure(0, weight = 1)
    261
    262          w = Button(box, text = "Cancel", width=10, command = self.cancel)
    263          w.grid(row = 0, column = 0, sticky = E)
    264          w = Button(box, text = "OK", width=10, command = self.ok, default=ACTIVE)
    265          w.grid(row = 0, column = 1, sticky = E)
    266
    267          self.bind("<Return>", self.ok)
    268          self.bind("<Escape>", self.cancel)
    269
    270      # Standard button semantics.
    271 -    def ok(self, event = None):
    272          """This method is called when the user clicks on the 'OK' button of the selection editor
    273          dialog. It closes the selection editor dialog and build the selection string.
    274          """
    275
    276          if not self.validate():
    277              self.initial_focus.focus_set()
    278              return
    279
    280          self.withdraw()
    281          self.update_idletasks()
    282
    283          self.apply()
    284
    285          # Put focus back to the parent window
    286          self.parent.focus_set()
    287          self.destroy()
    288
    289 -    def cancel(self, event = None):
    290          """Cancel the selection setting up the selection string to a selection type-dependant value.
    291          """
    292
    293          if self.selectionType == 'group':
    294              self.selectionString = 'all'
    295
    296          elif self.selectionType == 'subset':
    297              self.selectionString = 'all'
    298
    299          elif self.selectionType == 'deuteration':
    300              self.selectionString = 'no'
    301
    302          # Put focus back to the parent window
    303          self.parent.focus_set()
    304          self.destroy()
    305
    306 -    def validate(self):
    307          return True
    308
    309 -    def apply(self):
    310          """Performs a last checking of the selection string before closing the selection dialog.
    311          """
    312
    313          # The selection string built from tke loaded universe are checked for trailing 'AND' or 'OR' that may
    314          # fool the selection string parser.
    315          for key in self.selection.keys():
    316
    317              # Selection strings coming from file and expression medias do not need to be checked.
    318              if key in ['filename','expression']:
    319                  return
    320
    321              for subkey in self.selection[key].keys():
    322                  if self.selection[key][subkey]:
    323                      if self.selection[key][subkey][-1] in ['AND', 'OR']:
    324                          del self.selection[key][subkey][-1]
    325                          if not self.selection[key][subkey]:
    326                              del self.selection[key][subkey]
    327                  else:
    328                      del self.selection[key][subkey]
    329
    330          if not self.selection:
    331              return
    332
    333          # Build the selection string out of the self.selection dictionnary.
    334          self.buildSelectionString()
    335
    336 -    def getValue(self):
    337          """This method returns the self.selectionString class attributes.
    338
    339          Thanks to this method, the selection dialog can be used like any other ComboWidget for which the getValue
    340          allows to fetch their contents.
    341          """
    342          return self.selectionString
    343
    344 -    def setDefaultSelectionString(self):
    345          """Sets the selection string to its default value. This value depends on the the selection type.
    346          """
    347
    348          if self.selectionType == 'group':
    349              self.selectionString = 'all'
    350
    351          elif self.selectionType == 'subset':
    352              self.selectionString = 'all'
    353
    354          elif self.selectionType == 'deuteration':
    355              self.selectionString = 'no'
    356
    357 -    def changeSelectionMedia(self):
    358          """Changes the 'media' from which the selection will be performed.
    359
    360          It can be either from a selection file, either from the loaded trajectory or from an expression string.
    361          When changing selection media, the previous selection is cleared.
    362          """
    363
    364          self.clear()
    365
    366          selectionMedia = self.selectionMediasRadio.getValue()
    367
    368          for w in self.selectionFrame.winfo_children():
    369              w.grid_forget()
    370
    371          if selectionMedia == 'from a selection file':
    372              self.fileBrowser.grid(row = 0, column = 0, padx = 3, pady = 3, sticky = EW)
    373              self.fileBrowser.grid_columnconfigure(0, weight = 1)
    374
    375          elif selectionMedia == 'from the loaded trajectory':
    376              self.objectBrowser.grid(row = 0, column = 0, padx = 3, pady = 3, sticky = EW)
    377              self.objectBrowser.grid_columnconfigure(0, weight = 1)
    378              self.objectBrowser.grid_columnconfigure(1, weight = 1)
    379              self.objectBrowser.grid_columnconfigure(2, weight = 1)
    380
    381          elif selectionMedia == 'from an expression string':
    382              self.expressionBrowser.grid(row = 0, column = 0, padx = 3, pady = 3, sticky = EW)
    383              self.expressionBrowser.grid_columnconfigure(0, weight = 1)
    384
    385 -    def clear(self):
    386          """This methods clears all the listboxes of the 'Selection from the loaded trajectory' browser.
    387          It resets the selection listboxes and their associated variables, it resets the selection
    388          string, and updates the 'Selection preview' text widget.
    389          """
    390
    391          self.selectedPrefixName = self.selectionType
    392          if self.selectionType == 'group':
    393              self.prefixName.lb.selection_clear(0, END)
    394              self.groupingLevel.lb.selection_clear(0, END)
    395
    396          self.selection = {}
    397
    398          self.selectedObjectName = None
    399
    400          # The 'Object name' listbox selection is cleared.
    401          self.objectName.lb.selection_clear(0, END)
    402
    403          self.selectedKeyword = None
    404          self.selectionKeyword.cleanup()
    405
    406          self.currentSelection = {}
    407          self.selectionValue.cleanup()
    408
    409          # Build the selection string out of the self.selection dictionnary.
    410          self.buildSelectionString()
    411
    412          # Displays the selection string on the 'Selection preview' text widget.
    413          self.displaySelectionString()
    414
    415 -    def buildSelectionString(self):
    416          """This method actually build the selection string out of the |self.selection| dictionnary.
    417          """
    418
    419          # In case of a selection from a file, the selection string just contain the keyword 'filename'
    420          # followed by the name of the file.
    421          if self.selection.has_key('filename'):
    422              self.selectionString = 'filename %s' % self.selection['filename']
    423
    424          elif self.selection.has_key('expression'):
    425              self.selectionString = 'expression %s' % self.selection['expression']
    426
    427          else:
    428              self.selectionString = ''
    429              for prefix in sorted(self.selection.keys()):
    430                  # In case of 'subset' and 'deuteration' selection types, the prefix are not included in
    431                  # the selection string.
    432                  if prefix not in ['subset', 'deuteration']:
    433                      self.selectionString += prefix + ' '
    434
    435                      if self.selectionType == 'group':
    436                          self.selectionString += 'groupinglevel %s ' % self.groupingLevel.lb.get(int(self.groupingLevel.lb.curselection()[0]))
    437
    438                  sortedObjectNames = sorted(self.selection[prefix].keys())
    439                  for index1 in range(len(sortedObjectNames)):
    440                      objectName = sortedObjectNames[index1]
    441                      objectSelection = self.selection[prefix][objectName]
    442
    443                      if objectSelection:
    444                          self.selectionString += 'objectname %s ' % objectName
    445
    446                          for objSel in objectSelection:
    447                              if isinstance(objSel,dict):
    448                                  sortedKeywords = sorted(objSel.keys())
    449                                  for index in range(len(sortedKeywords)):
    450                                      keyword = sortedKeywords[index]
    451                                      value = objSel[keyword]
    452                                      self.selectionString += '%s %s ' % (keyword, ','.join(value))
    453                                      if index < len(sortedKeywords) - 1:
    454                                          self.selectionString += 'OR '
    455                              else:
    456                                  self.selectionString += objSel + ' '
    457                          if index1 < len(sortedObjectNames) - 1:
    458                              self.selectionString += 'OR '
    459
    460              # The string is stripped.
    461              self.selectionString = self.selectionString.strip()
    462
    463 -    def displaySelectionString(self):
    464          """Displays in the 'Selection preview' textwidget the selection string under process.
    465          """
    466
    467          # First the 'Selection preview' text widget is cleaned up.
    468          self.selectionPreview.cleanup()
    469
    470          # If the selection string is empty, do nothing.
    471          if not self.selectionString:
    472              return
    473
    474          # The selection string is inserted in the 'Selection preview' text widget.
    475          self.selectionPreview.insert(contents = self.selectionString)
    476
    477          # The prefixes are tagged.
    478          for k in self.selection.keys():
    479              self.selectionPreview.tag(k,'prefix')
    480
    481          # The selection keywords are tagged.
    482          for k in self.keywords:
    483              self.selectionPreview.tag(k,'italic')
    484
    485          # The word 'objectname' is tagged.
    486          self.selectionPreview.tag('objectname','objectname')
    487          # The word 'filename' is tagged.
    488          self.selectionPreview.tag('filename','filename')
    489          # The word 'filename' is tagged.
    490          self.selectionPreview.tag('expression','expression')
    491
    492          # The linker are tagged.
    493          self.selectionPreview.tag('(','()')
    494          self.selectionPreview.tag(')','()')
    495          self.selectionPreview.tag('AND','AND')
    496          self.selectionPreview.tag('OR','OR')
    497
    498 -    def selectFromExpression(self, event):
    499          """This callback performs a selection from a expression string by writing the expression in its corresponding text
    500          widget.
    501
    502          The expression must be a set of valid ;-separated python instructions the last one being 'selection = ...'
    503          as the selection string parser will search for the selection variables when executing the expression string.
    504
    505          To refer to the universe just use the variable 'self.universe'.
    506          """
    507
    508          if not self.expressionBrowser.text.get('0.0', END).strip():
    509              return
    510
    511          # Update the self.selection dictionnary.
    512          self.selection = {'expression' : self.expressionBrowser.text.get('0.0', END).strip()}
    513
    514          # Build the selection string out of the self.selection dictionnary.
    515          self.buildSelectionString()
    516
    517          # Displays the selection string on the 'Selection preview' text widget.
    518          self.displaySelectionString()
    519
    520          return 'break'
    521
    522 -    def selectFromFile(self, event = None):
    523          """This method/callback performs a selection from a file by selection the file from a browser.
    524          """
    525
    526          # If the method is called as a callback using the Return button on the entry of the file browser.
    527          if event:
    528              # Is there already a file name in the file browser entry ? There can be one if the methid is used as a
    529              # callback when pressing Return on the entry of the filebrowser.
    530              filename = self.fileBrowser.getValue()
    531
    532          # There is no file name so open a browser for the file selection.
    533          else:
    534              # The name of the NetCDF file to load.
    535              filename = askopenfilename(parent = self, filetypes = [('NMS file','.nms'), ('Python file', '.py'), ('All files', '.*')])
    536
    537          # Checks that the file name is not an empty string.
    538          if not filename:
    539              self.fileBrowser.setValue('')
    540              return
    541
    542          # Checks that the file exists.
    543          if not os.path.exists(filename):
    544              self.fileBrowser.setValue('')
    545              return
    546
    547          # Update the entry of the file browser.
    548          self.fileBrowser.setValue(filename)
    549
    550          # Update the self.selection dictionnary.
    551          self.selection = {'filename' : filename}
    552
    553          # Build the selection string out of the self.selection dictionnary.
    554          self.buildSelectionString()
    555
    556          # Displays the selection string on the 'Selection preview' text widget.
    557          self.displaySelectionString()
    558
    559          return 'break'
    560
    561      # The following methods all intervene when performing the selection from the loaded trajectory.
    562 -    def selectPrefixName(self, event):
    563          """This callback is called when the user clicks on one item of the 'Group number' listbox of the selection editor.
    564          """
    565
    566          # The selected object is reset.
    567          self.selectedObjectName = None
    568
    569          # The 'Object name' listbox selection is cleared.
    570          self.objectName.lb.selection_clear(0, END)
    571
    572          # The 'Selection keyword' listbox contents is suppressed.
    573          self.selectionKeyword.cleanup()
    574
    575          # The 'Selection value' listbox contents is suppressed.
    576          self.selectionValue.cleanup()
    577
    578          # The self.currentSelection dictionnary is reset.
    579          self.currentSelection = {}
    580
    581          # If no prefix was selected in the listbox, do nothing.
    582          if not self.prefixName.lb.curselection():
    583              self.selectedPrefixName = None
    584          else:
    585              # The self.selectedPrefixName attribute is updated.
    586              self.selectedPrefixName = self.prefixName.lb.get(int(self.prefixName.lb.curselection()[0]))
    587
    588 -    def deletePrefixName(self, event):
    589          """This callback will remove the selection string associated to the selected prefix name.
    590          """
    591
    592          # If no prefix was selected in the listbox, do nothing.
    593          if not self.prefixName.lb.curselection():
    594              return
    595
    596          # The selected prefix.
    597          sel = self.prefixName.lb.get(int(self.prefixName.lb.curselection()[0]))
    598
    599          # The entry of the self.selection dictionnary corresponding to the selected prefix is removed.
    600          if self.selection.has_key(sel):
    601              del self.selection[sel]
    602
    603          # Build the selection string out of the self.selection dictionnary.
    604          self.buildSelectionString()
    605
    606          # Displays the selection string on the 'Selection preview' text widget.
    607          self.displaySelectionString()
    608
    609 -    def createNewGroup(self):
    610          """This callback will create a new group entry in the 'Group number' listbox.
    611          """
    612
    613          # If the selection type is not 'group', do nothing.
    614          if self.selectionType != 'group':
    615              return
    616
    617          # A new entry is inserted at the end of the 'Group number' listbox.
    618          self.prefixName.lb.insert(END, 'group' + str(len(self.prefixName.lb.get(0, END))+1))
    619
    620 -    def selectObjectName(self, event):
    621          """This callback is called when the user clicks on one item of the 'Object name' listbox of the
    622          selection editor. It will display into the 'Selection keyword' listbox all the selection keywords
    623          corresponding to the selected object type.
    624          """
    625
    626          # If there is no prefix selected, do nothing.
    627          if not self.selectedPrefixName:
    628              return
    629
    630          # If the self.selection dictionnary does not have the selected prefix name as key, create it.
    631          if not self.selection.has_key(self.selectedPrefixName):
    632              self.selection[self.selectedPrefixName] = {}
    633
    634          # If no object was selected in the 'Object name' listbox, do nothing.
    635          if not self.objectName.lb.curselection():
    636              return
    637
    638          # The MMTK object type.
    639          self.selectedObjectName = self.objectName.lb.get(int(self.objectName.lb.curselection()[0]))
    640
    641          # If the self.selection dictionnary does not have the selected object name as subkey, set it with an empty
    642          # list that will contain the linker and selection dictionnaries.
    643          if not self.selection[self.selectedPrefixName].has_key(self.selectedObjectName):
    644              self.selection[self.selectedPrefixName][self.selectedObjectName] = []
    645
    646          if self.selectionType == 'group':
    647              # Clean and then updates the 'Selection keyword' listbox.
    648              self.groupingLevel.cleanup()
    649              for gl in sorted(self.univContents[self.selectedObjectName]['groupinglevel'][1]):
    650                  self.groupingLevel.lb.insert(END, gl)
    651              self.groupingLevel.lb.selection_set(self.univContents[self.selectedObjectName]['groupinglevel'][0])
    652
    653          # Clean and then updates the 'Selection keyword' listbox.
    654          self.selectionKeyword.cleanup()
    655          for k in sorted(self.univContents[self.selectedObjectName].keys()):
    656              if k in ['number','objectclass', 'groupinglevel']:
    657                  continue
    658
    659              self.selectionKeyword.lb.insert(END, k)
    660
    661          # The 'Selection values' listbox is cleaned up.
    662          self.selectionValue.cleanup()
    663
    664          # The current selection is cleaned up.
    665          self.currentSelection = {}
    666
    667 -    def selectGroupingLevel(self, event):
    668          """
    669          """
    670          if self.selectionString:
    671              # Build the selection string out of the self.selection dictionnary.
    672              self.buildSelectionString()
    673
    674              # Displays the selection string on the 'Selection preview' text widget.
    675              self.displaySelectionString()
    676
    677 -    def selectKeyword(self, event):
    678          """This callback is called whenever the user clicks on one item of the 'Selection keyword' listbox.
    679          It will display in the 'Selection value' listbox the selection values available for the
    680          selected keyword.
    681          """
    682
    683          # If no keyword was selected in the 'Selection keyword' listbox, do nothing.
    684          if not self.selectionKeyword.lb.curselection():
    685              return
    686
    687          # The selected selection keyword.
    688          self.selectedKeyword = self.selectionKeyword.lb.get(int(self.selectionKeyword.lb.curselection()[0]))
    689
    690          # The 'Selection value' listbox is cleaned.
    691          self.selectionValue.cleanup()
    692
    693          # List of the values available for the the selected selection keyword.
    694          values = self.univContents[self.selectedObjectName][self.selectedKeyword]
    695
    696          # The selection values corresponding to the selected selection keyword are displayed in the 'Selection value' listbox.
    697          self.selectionValue.insert(values)
    698
    699          # Activate the 'Selected value' listbox entries that are currently under process.
    700          for index in range(len(values)):
    701              value = values[index]
    702              try:
    703                  # If the selection keyword is present in the current selection then it is selected in the listbox
    704                  # by default
    705                  if value in self.currentSelection[self.selectedKeyword]:
    706                      self.selectionValue.lb.selection_set(index)
    707              except KeyError:
    708                  continue
    709
    710 -    def deleteObjectName(self, event):
    711          """This method will delete the object name from the selection string if it was previously selected.
    712          """
    713
    714          # If no object name was selected in the 'Object name' listbox, do nothing.
    715          if not self.objectName.lb.curselection():
    716              return
    717
    718          # The selected object name.
    719          objectName = self.objectName.lb.get(int(self.objectName.lb.curselection()[0]))
    720
    721          # Delete the self.selection dictionnary subkeys that matches the selected object name.
    722          for k in self.selection.keys():
    723              if self.selection[k].has_key(objectName):
    724                  del self.selection[k][objectName]
    725
    726          # Build the selection string out of the self.selection dictionnary.
    727          self.buildSelectionString()
    728
    729          # Displays the selection string on the 'Selection preview' text widget.
    730          self.displaySelectionString()
    731
    732 -    def selectValue(self, event):
    733          """This callback is called whenever the user clicks on one entry of the 'Selection value' listbox.
    734          It will update the current selection.
    735          """
    736
    737          # If the event is Ctrl-a, select everything.
    738          if event.keysym == 'a':
    739              self.selectionValue.lb.selection_set(0, END)
    740
    741          # If some values were selected in the 'Selected value' listbox, updates the self.currentSelection
    742          # dictionnary with the selected values.
    743          if self.selectionValue.lb.curselection():
    744              selectedValues = [self.selectionValue.lb.get(int(v)) for v in self.selectionValue.lb.curselection()]
    745              self.currentSelection[self.selectedKeyword] = selectedValues
    746
    747          # Else, update the self.currentSelection dictionnary by removing the key corresponding to the
    748          # selected keyword for which no values have been selected.
    749          else:
    750              if self.currentSelection.has_key(self.selectedKeyword):
    751                  del self.currentSelection[self.selectedKeyword]
    752              else:
    753                  return
    754
    755          # The selected prefix name.
    756          prefixName = self.selectedPrefixName
    757
    758          # The selected object name.
    759          objectName = self.selectedObjectName
    760
    761          # The selection list is updated.
    762          if not self.selection[prefixName][objectName]:
    763              if self.currentSelection:
    764                  # If it is empty, the current expression is automatically appended.
    765                  self.selection[prefixName][objectName].append(self.currentSelection)
    766          else:
    767              # It if is not empty and the last element is already a selection expression then replaces it.
    768              if isinstance(self.selection[prefixName][objectName][-1],dict):
    769                  if self.currentSelection:
    770                      self.selection[prefixName][objectName][-1] = self.currentSelection
    771                  else:
    772                      del self.selection[prefixName][objectName][-1]
    773              # It if is not empty and the last element is a linker then append the current expression.
    774              else:
    775                  if self.currentSelection:
    776                      self.selection[prefixName][objectName].append(self.currentSelection)
    777
    778          reset = True
    779          for k in self.selection.keys():
    780              for kk in self.selection[k].keys():
    781                  if self.selection[k][kk]:
    782                      reset = False
    783          else:
    784              if reset:
    785                  self.clear()
    786
    787          # Build the selection string out of the self.selection dictionnary.
    788          self.buildSelectionString()
    789
    790          # Displays the selection string on the 'Selection preview' text widget.
    791          self.displaySelectionString()
    792
    793 -    def appendLinker(self, linker):
    794          """
    795          This method is called when the user press the '(', ')', 'AND' or 'OR' buttons of the atom selection
    796          dialog. It:
    797              - checks whether the selected linker can be actually be appended
    798              - appends the linker if so.
    799          """
    800
    801          # If no object name is selected, do nothing.
    802          if self.selectedObjectName is None:
    803              return
    804
    805          # Some basic checkings to prevent user from badly formatting a selection pattern string.
    806          # May not be sufficient but should throw most of the errors.
    807
    808          # The linker must be one of '(', ')', 'AND', 'OR'.
    809          if linker not in ['(',')','AND','OR']:
    810              return
    811
    812          selList = self.selection[self.selectedPrefixName][self.selectedObjectName]
    813
    814          # If the selection pattern is empty, then the only possible linker to append is '('.
    815          if not selList:
    816              if linker != '(':
    817                  return
    818          else:
    819              # Case of '('. Must follow '(', 'AND' or 'OR'.
    820              if linker == '(':
    821                  if selList[-1] not in ['AND','OR','(']:
    822                      return
    823              # Case of ')'.
    824              #   -Should always be less ')' than '('.
    825              #   -Must not follow '(', 'AND' or 'OR'.
    826              elif linker == ')':
    827                  if selList.count('(') <= selList.count(')'):
    828                      return
    829                  if selList[-1] in ['AND', 'OR', '(']:
    830                      return
    831              # Case of 'AND'. Must not follow '(', 'AND' or 'OR'.
    832              elif linker == 'AND':
    833                  if selList[-1] in ['AND','OR','(']:
    834                      return
    835              # Case of 'OR'. Must not follow '(', 'AND' or 'OR'.
    836              elif linker == 'OR':
    837                  if selList[-1] in ['AND','OR','(']:
    838                      return
    839
    840          # Everything seems OK, the linker can be appended.
    841          selList.append(linker)
    842
    843          # The 'Selection value' listbox is cleaned up.
    844          self.selectionValue.lb.selection_clear(0, END)
    845
    846          # The current selection is reinitiliazed.
    847          self.currentSelection = {}
    848
    849          # Build the selection string out of the self.selection dictionnary.
    850          self.buildSelectionString()
    851
    852          # Displays the selection string on the 'Selection preview' text widget.
    853          self.displaySelectionString()
    854