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

# Source Code for Module nMOLDYN.GUI.AnimationDialog

      1  """This modules implements I{View-->Animation} dialog.
      2
      3  Classes:
      4      * AnimationDialog: creates I{View-->Animation} dialog used to view an animation of a trajectory.
      5  """
      6
      7  # The python distribution modules
      8  import os
      9  import sys
     10
     11  # The Tcl/Tk modules
     12  from tkFileDialog import askopenfilename
     13  from Tkinter import *
     14
     15  # The ScientificPython modules
     16
     17  # The MMTK distribution modules
     18  from MMTK.Trajectory import Trajectory
     19  from MMTK.Visualization import definePDBViewer, viewTrajectory
     20
     21  # The nMOLDYN modules
     22  from nMOLDYN.Core.Error import Error
     23  from nMOLDYN.Core.Logger import LogMessage
     24  from nMOLDYN.Core.Preferences import PREFERENCES
     25  from nMOLDYN.GUI.Widgets import ComboFileBrowser, ComboIntegerEntry, ComboRadiobutton
     26
     27 -class AnimationDialog(Toplevel):
     28      """Sets up a dialog used to visualize a loaded trajectory.
     29
     30      @note: if a trajectory has been previously loaded in nMOLDYN for simulation purposes this will be the one
     31      proposed for visualization by default. Otherwise, the user can still choose a trajectory to visualize from
     32      the dialog.
     33      """
     34
     35 -    def __init__(self, parent, title = None, trajectory = None):
     36          """The constructor.
     37
     38          @param parent: the parent widget.
     39
     40          @param title: a string specifying the title of the dialog.
     41          @type title: string
     42
     43          @param trajectory: an opened MMTK trajectory.
     44          @type trajectory: an instance of MMTK.Trajectory.Trajectory class.
     45          """
     46
     47          Toplevel.__init__(self, parent)
     48          self.transient(parent)
     49
     50          if title:
     51              self.title(title)
     52
     53          self.parent = parent
     54
     55          # If a trajectory has been loaded in nMOLDYN for simulation purposes (e.g. MSD ...) then it is proposed by default for
     56          # visualization.
     57          if isinstance(trajectory, Trajectory):
     58              self.trajectory = trajectory
     59
     60          else:
     61              self.trajectory = None
     62
     63          body = Frame(self)
     64          self.initial_focus = self.body(body)
     65          body.grid(row = 0, column = 0, sticky = EW)
     66
     67          self.buttonbox()
     68
     69          self.grab_set()
     70
     71          if not self.initial_focus:
     72              self.initial_focus = self
     73
     74          self.protocol("WM_DELETE_WINDOW", self.cancel)
     75
     76          self.resizable(width = NO, height = NO)
     77
     78          self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
     79
     80          self.initial_focus.focus_set()
     81
     82          self.wait_window(self)
     83
     84 -    def body(self, master):
     85          """
     86          Create dialog body. Return widget that should have initial focus.
     87          """
     88
     89          settingsFrame = LabelFrame(master, text = 'Settings', bd = 2, relief = GROOVE)
     90          settingsFrame.grid(row = 0, column = 0, sticky = EW, padx = 3, pady = 3)
     91          settingsFrame.grid_columnconfigure(0, weight = 1)
     92
     93          # The combo widget for the file browser.
     94          self.fileBrowser = ComboFileBrowser(settingsFrame,\
     95                                              frameLabel = "MMTK Trajectory file",\
     96                                              tagName = 'animation_mmtk_trajectory_file',\
     97                                              contents = '',\
     98                                              save = False,\
     99                                              command = self.openTrajectory)
    100          self.fileBrowser.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = EW)
    101          self.fileBrowser.grid_columnconfigure(0, weight = 1)
    102          self.fileBrowser.entry.bind('<Return>', self.openTrajectory)
    103
    104          # The combo widget for the first step setting.
    105          self.firstStepEntry = ComboIntegerEntry(settingsFrame,\
    106                                                  frameLabel = 'First step',\
    107                                                  tagName = 'animation_first_step')
    108          self.firstStepEntry.grid(row = 1, column = 0, sticky = EW, padx = 2, pady = 2)
    109          self.firstStepEntry.grid_columnconfigure(0, weight = 1)
    110
    111          # The combo widget for the last step setting.
    112          self.lastStepEntry = ComboIntegerEntry(settingsFrame,\
    113                                                 frameLabel = 'Last step',\
    114                                                 tagName = 'animation_last_step')
    115          self.lastStepEntry.grid(row = 2, column = 0, sticky = EW, padx = 2, pady = 2)
    116          self.lastStepEntry.grid_columnconfigure(0, weight = 1)
    117
    118          # The combo widget for the skip step setting.
    119          self.skipStepEntry = ComboIntegerEntry(settingsFrame,\
    120                                                 frameLabel = 'Skip step',\
    121                                                 tagName = 'animation_skip_test')
    122          self.skipStepEntry.grid(row = 3, column = 0, sticky = EW, padx = 2, pady = 2)
    123          self.skipStepEntry.grid_columnconfigure(0, weight = 1)
    124
    125          if self.trajectory is not None:
    126              # The control variables are updated with the informations coming from the loaded trajectory.
    127              self.fileBrowser.setValue(self.trajectory.filename)
    128              self.firstStepEntry.setValue(1)
    129              self.lastStepEntry.setValue(1)
    130              self.skipStepEntry.setValue(1)
    131
    132          return None
    133
    134 -    def buttonbox(self):
    135          """
    136          Add standard button box.
    137          """
    138
    139          # The frame that contains the 'Cancel' and 'OK' buttons.
    140          box = LabelFrame(self, text = 'Actions', bd = 2, relief = GROOVE)
    141          box.grid(row = 1, column = 0, sticky = EW, padx = 3, pady = 3)
    142          box.grid_columnconfigure(0, weight = 1)
    143
    144          w = Button(box, text = "Cancel", width=10, command = self.cancel)
    145          w.grid(row = 0, column = 0, sticky = E)
    146          w = Button(box, text = "OK", width=10, command = self.ok, default=ACTIVE)
    147          w.grid(row = 0, column = 1, sticky = E)
    148
    149          self.bind("<Return>", self.ok)
    150          self.bind("<Escape>", self.cancel)
    151
    152      # Standard button semantics.
    153 -    def ok(self, event = None):
    154
    155          if not self.validate():
    156              self.initial_focus.focus_set()
    157              return
    158
    159          self.withdraw()
    160          self.update_idletasks()
    161
    162          self.apply()
    163
    164          self.cancel()
    165
    166 -    def cancel(self, event=None):
    167
    168          # Put focus back to the parent window
    169          self.parent.focus_set()
    170          self.destroy()
    171
    172      # Command hooks
    173 -    def validate(self):
    174
    175          if not self.trajectory:
    176              raise Error('No MMTK trajectory file loaded for animation.')
    177
    178          if self.trajectory.filename != self.fileBrowser.getValue():
    179              raise Error('Mismatch between the loaded trajectory and the displayed MMTK trajectory file name.\
    180  You should validate that file by pressing Return on its corresponding entry.')
    181
    182          self.viewableAtoms = self.trajectory.universe.atomsWithDefinedPositions()
    183
    184          if not self.firstStepEntry.getValue():
    185              self.first = 0
    186              LogMessage('warning', 'First frame undefined. Frame 1 will be taken by default.', ['gui'])
    187          else:
    188              self.first = self.firstStepEntry.getValue() - 1
    189
    190          if self.first < 0:
    191              raise Error('First frame not within [1,%d].' % len(self.trajectory))
    192
    193          if not self.lastStepEntry.getValue():
    194              self.last = 1
    195              LogMessage('warning', 'Last frame undefined. Frame 1 will be taken by default.', ['gui'])
    196          else:
    197              self.last = self.lastStepEntry.getValue()
    198
    199          if self.last > len(self.trajectory):
    200              raise Error('Last frame not within [1,%d].' % len(self.trajectory))
    201
    202          if not self.skipStepEntry.getValue():
    203              self.skip = 1
    204              LogMessage('warning', 'Frame skip undefined. 1 will be taken by default.', ['gui'])
    205          else:
    206              self.skip = self.skipStepEntry.getValue()
    207
    208          if (self.skip < 1) or (self.skip >= len(self.trajectory)):
    209              raise Error('Last frame not within [1,%d[.' % len(self.trajectory))
    210
    211          return True
    212
    213 -    def apply(self):
    214
    215          try:
    216              if os.path.exists(PREFERENCES.vmd_path):
    217                  definePDBViewer('vmd', PREFERENCES.vmd_path)
    218              else:
    219                  raise
    220          except:
    221              raise Error('Error when defining VMD molecular viewer from %s path.' % PREFERENCES.vmd_path)
    222
    223          try:
    224              # This MMTK function calls VMD to visualize the trajectory.
    225              viewTrajectory(trajectory = self.trajectory, first = self.first, last = self.last, skip = self.skip,\
    226                             subset = self.viewableAtoms)
    227          except:
    228              raise Error('Error when animating the trajectory.')
    229
    230 -    def openTrajectory(self, event = None):
    231          """
    232          The method is called when the user clicks on the 'Browse' button of the trajectory visualization dialog.
    233          It opens a file browser. After the file selection some of the dialog widgets are updated with the informations
    234          coming from the loaded trajectory.
    235
    236          Arguments:
    237              - event: Tkinter event.
    238          """
    239
    240          # Case where the user enters a file name directly in the entry widget without using the browser.
    241          if event is not None:
    242              if event.widget == self.fileBrowser.entry:
    243                  filename = self.fileBrowser.getValue()
    244              else:
    245                  return
    246
    247          else:
    248              # The name of the NetCDF file to load.
    249              filename = askopenfilename(parent = self,\
    250                                         filetypes = [('NetCDF file','*.nc')],\
    251                                         initialdir = PREFERENCES.trajfile_path)
    252
    253          # The file must exist.
    254          if filename:
    255              try:
    256                  # The trajectory is loaded.
    257                  self.trajectory = Trajectory(None, filename, 'r')
    258
    259              except IOError:
    260                  LogMessage('warning', 'Problem when reading the trajectory.',['gui'])
    261                  self.fileBrowser.setValue('')
    262                  self.firstStepEntry.setValue('')
    263                  self.lastStepEntry.setValue('')
    264                  self.skipStepEntry.setValue('')
    265
    266              else:
    267                  # The control variables are updated with the informations about the loaded trajectory.
    268                  self.fileBrowser.setValue(filename)
    269                  self.firstStepEntry.setValue(1)
    270                  self.lastStepEntry.setValue(1)
    271                  self.skipStepEntry.setValue(1)
    272
    273          return 'break'
    274