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

# Source Code for Module nMOLDYN.GUI.NetCDFToASCIIConversionDialog

      1  """This modules implements I{File-->Convert NetCDF to ASCII} dialog.
      2
      3  Classes:
      4      * NetCDFToASCIIConversionDialog: creates I{File-->Convert NetCDF to ASCII} dialog used to
      5        convert a file in NetCDF format to a file in ASCII format.
      6  """
      7
      8  # The python distribution modules
      9  import copy
     10  import inspect
     11  import os
     12  import re
     13  import sys
     14
     15  # The Tcl/Tk modules
     16  from tkFileDialog import askopenfilename
     17  from Tkinter import *
     18
     19  # The ScientificPython modules
     20  from Scientific import N as Num
     21  from Scientific.IO.NetCDF import _NetCDFFile, NetCDFFile
     22
     23  from MMTK.Trajectory import Trajectory
     24
     25  # The nMOLDYN modules
     26  from nMOLDYN.Core.Error import Error
     27  from nMOLDYN.Core.IOFiles import convertNetCDFToASCII
     28  from nMOLDYN.Core.Logger import LogMessage
     29  from nMOLDYN.Core.Preferences import PREFERENCES
     30  from nMOLDYN.GUI.Widgets import *
     31
     32 -class NetCDFToASCIIConversionDialog(Toplevel):
     33      """Sets up a dialog that allows the conversion of any numeric variables present in a
     34      NetCDF file into an ASCII file.
     35      """
     36
     37 -    def __init__(self, parent, title = None, netcdf = None):
     38          """The constructor.
     39
     40          @param parent: the parent widget.
     41
     42          @param title: a string specifying the title of the dialog.
     43          @type title: string
     44          """
     45
     46          Toplevel.__init__(self, parent)
     47          self.transient(parent)
     48
     49          if title:
     50              self.title(title)
     51
     52          self.parent = parent
     53
     54          try:
     55              if isinstance(netcdf, _NetCDFFile):
     56                  self.netcdf = netcdf
     57                  self.netcdf_filename = re.findall('<open netCDF file \'(.*)\',.*', str(netcdf))[0]
     58
     59              elif isinstance(netcdf, Trajectory):
     60                  self.netcdf = NetCDFFile(netcdf.filename, 'r')
     61                  self.netcdf_filename = netcdf.filename
     62
     63              else:
     64                  raise
     65
     66          except:
     67              self.netcdf = None
     68              self.netcdf_filename = None
     69
     70          body = Frame(self)
     71          self.initial_focus = self.body(body)
     72          body.grid(row = 0, column = 0, sticky = EW)
     73
     74          self.buttonbox()
     75
     76          self.grab_set()
     77
     78          if not self.initial_focus:
     79              self.initial_focus = self
     80
     81          self.protocol("WM_DELETE_WINDOW", self.cancel)
     82
     83          self.resizable(width = NO, height = NO)
     84
     85          self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
     86
     87          self.initial_focus.focus_set()
     88
     89          self.wait_window(self)
     90
     91 -    def body(self, master):
     92          """
     93          Create dialog body. Return widget that should have initial focus.
     94          """
     95
     96          settingsFrame = LabelFrame(master, text = 'Settings', bd = 2, relief = GROOVE)
     97          settingsFrame.grid(row = 0, column = 0, sticky = EW, padx = 3, pady = 3)
     98          settingsFrame.grid_columnconfigure(0, weight = 1)
     99
    100          # The combo widget for the file browser.
    101          self.inputFileBrowser = ComboFileBrowser(settingsFrame,\
    102                                                   frameLabel = "NetCDF input file",\
    103                                                   tagName = 'convert_netcdf_to_ascii_netcdf_input_file',\
    104                                                   contents = '',\
    105                                                   save = False,\
    106                                                   command = self.openNetCDFFile,\
    107                                                   filetypes = [("NetCDF file", ".nc"),])
    108          self.inputFileBrowser.entry.bind('<Return>', self.openNetCDFFile)
    109          self.inputFileBrowser.grid(row = 0, column = 0, sticky = EW, padx = 2, pady = 2)
    110          self.inputFileBrowser.grid_columnconfigure(0, weight = 1)
    111
    112          self.variablesInfo = ComboText(settingsFrame,\
    113                                         frameLabel = 'Available variables',\
    114                                         tagName = 'convert_netcdf_to_ascii_available_variables')
    115          self.variablesInfo.grid(row = 1, column = 0, columnspan = 2, sticky = EW, padx = 2, pady = 2)
    116          self.variablesInfo.grid_columnconfigure(0, weight = 1)
    117          self.variablesInfo.text.config({'height' : 10, 'width' : 68})
    118
    119          self.variablesInfo.text.window_create('1.0',\
    120                                                window = Label(self.variablesInfo.text,
    121                                                               text = 'Select',\
    122                                                               width = 13,\
    123                                                               bg = 'Grey'))
    124
    125          self.variablesInfo.text.window_create('1.1',\
    126                                                window = Label(self.variablesInfo.text,
    127                                                               text = 'NetCDF Variable',\
    128                                                               width = 50,\
    129                                                               anchor = W,\
    130                                                               bg = 'white'))
    131
    132          # The combo widget for the float precision.
    133          self.floatPrecisionEntry = ComboIntegerEntry(settingsFrame,\
    134                                                       frameLabel = 'Float precision',\
    135                                                       tagName = 'convert_netcdf_to_ascii_float_precision',\
    136                                                       contents = 9)
    137          self.floatPrecisionEntry.grid(row = 2, column = 0, sticky = EW, padx = 2, pady = 2)
    138          self.floatPrecisionEntry.grid_columnconfigure(0, weight = 1)
    139
    140          # The combo widget for the double precision.
    141          self.doublePrecisionEntry = ComboIntegerEntry(settingsFrame,\
    142                                                        frameLabel = 'Double precision',\
    143                                                        tagName = 'convert_netcdf_to_ascii_double_precision',\
    144                                                        contents = 17)
    145          self.doublePrecisionEntry.grid(row = 3, column = 0, sticky = EW, padx = 2, pady = 2)
    146          self.doublePrecisionEntry.grid_columnconfigure(0, weight = 1)
    147
    148          # The combo widget for the file browser.
    149          self.outputFileBrowser = ComboFileBrowser(settingsFrame,\
    150                                                    frameLabel = "ASCII/CDL output file",\
    151                                                    tagName = 'convert_netcdf_to_ascii_ascii_output_file',\
    152                                                    contents = '',\
    153                                                    filetypes = [("CDL file", ".cdl"),],\
    154                                                    save = True)
    155          self.outputFileBrowser.grid(row = 4, column = 0, sticky = EW, padx = 2, pady = 2)
    156          self.outputFileBrowser.grid_columnconfigure(0, weight = 1)
    157
    158          if self.netcdf is not None:
    159              # The control variables are updated with the informations coming from the loaded trajectory.
    160              self.inputFileBrowser.setValue(self.netcdf_filename)
    161              self.displayNetCDFContents()
    162              self.outputFileBrowser.setValue(os.path.splitext(self.netcdf_filename)[0] + '.cdl')
    163          else:
    164              self.outputFileBrowser.setValue('ASCII.cdl')
    165
    166 -    def buttonbox(self):
    167          """
    168          Add standard button box.
    169          """
    170
    171          # The frame that contains the 'Cancel' and 'OK' buttons.
    172          box = LabelFrame(self, text = 'Actions', bd = 2, relief = GROOVE)
    173          box.grid(row = 1, column = 0, sticky = EW, padx = 3, pady = 3)
    174          box.grid_columnconfigure(0, weight = 1)
    175
    176          w = Button(box, text = "Cancel", width=10, command = self.cancel)
    177          w.grid(row = 0, column = 0, sticky = E)
    178          w = Button(box, text = "OK", width=10, command = self.ok, default=ACTIVE)
    179          w.grid(row = 0, column = 1, sticky = E)
    180
    181          self.bind("<Return>", self.ok)
    182          self.bind("<Escape>", self.cancel)
    183
    184      # Standard button semantics.
    185 -    def ok(self, event = None):
    186
    187          if not self.validate():
    188              self.initial_focus.focus_set()
    189              return
    190
    191          self.update_idletasks()
    192
    193          self.apply()
    194
    195 -    def cancel(self, event=None):
    196
    197          # Put focus back to the parent window
    198          self.parent.focus_set()
    199          self.destroy()
    200
    201      # Command hooks
    202 -    def validate(self):
    203
    204          # An input file must have been set.
    205          self.inputFile = self.inputFileBrowser.getValue()
    206          if not self.inputFile:
    207              raise Error('Please enter a NetCDF input file.')
    208
    209          # The float precision entry is checked and stored.
    210          self.floatPrecision = self.floatPrecisionEntry.getValue()
    211          if self.floatPrecision <= 0:
    212              raise Error('The float precision must > 0.')
    213
    214          # The double precision entry is checked and stored.
    215          self.doublePrecision = self.doublePrecisionEntry.getValue()
    216          if self.doublePrecision <= 0:
    217              raise Error('The Double precision must > 0.')
    218
    219          # An output file must have been set.
    220          self.outputFile = self.outputFileBrowser.getValue()
    221          if not self.outputFile:
    222              raise Error('Please enter an ASCII output file.')
    223
    224          # The extension '.cdl' is appended to the output file name if necessary.
    225          if self.outputFile[-4:] != '.cdl':
    226              self.outputFile += '.cdl'
    227
    228          # The selected variables are stored.
    229          self.selectedVariables = []
    230          for k, v in self.variables.items():
    231              if v.get():
    232                  self.selectedVariables.append(k)
    233
    234          if not self.selectedVariables:
    235              raise Error('No NetCDF variables selected for conversion.')
    236
    237          return True
    238
    239      # Command hooks
    240 -    def apply(self):
    241          """
    242          This method is called when the user clicks on the OK button of the conversion dialog. It performs the
    243          conversion from the loaded NetCDF file to the selected ASCII/CDL file.
    244          """
    245
    246          convertNetCDFToASCII(inputFile = self.inputFile,\
    247                               outputFile = self.outputFile,\
    248                               variables = self.selectedVariables,\
    249                               floatPrecision = self.floatPrecision,\
    250                               doublePrecision = self.doublePrecision)
    251
    252          LogMessage('info', 'Conversion successful', ['gui'])
    253
    254
    255 -    def openNetCDFFile(self, event = None):
    256          """
    257          This method opens a NetCDF file and updates the dialog with the data read from that file.
    258          Arguments:
    259              -event: Tkinter event.
    260          """
    261
    262          self.variablesInfo.text.config(state = NORMAL)
    263          self.variablesInfo.text.delete('2.0', END)
    264          self.variablesInfo.text.config(state = DISABLED)
    265
    266          # Case where the user enters a file name directly in the entry widget without using the browser.
    267          if event is not None:
    268              if event.widget == self.inputFileBrowser.entry:
    269                  filename = self.inputFileBrowser.getValue()
    270              else:
    271                  return
    272
    273          else:
    274
    275              # The name of the NetCDF file to load.
    276              filename = askopenfilename(parent = self,\
    277                                         filetypes = [('NetCDF file','*.nc')],\
    278                                         initialdir = PREFERENCES.outputfile_path)
    279
    280          # The file must exist otherwise do nothing.
    281          if filename:
    282              self.netcdf = NetCDFFile(filename, 'r')
    283
    284              self.displayNetCDFContents()
    285
    286              # The filebrowser entry is updated with the loaded filename.
    287              self.inputFileBrowser.setValue(filename)
    288
    289              # A default filename for the output ASCII file is built.
    290              self.outputFileBrowser.setValue(os.path.splitext(filename)[0] + '.cdl')
    291
    292          return 'break'
    293
    294 -    def selectVariable(self):
    295
    296          for k, v in self.variables.items():
    297              if v.get():
    298                  self.textVariables[k].set('selected')
    299
    300              else:
    301                  self.textVariables[k].set('unselected')
    302
    303
    304 -    def displayNetCDFContents(self):
    305          """
    306          This method display the variables found in the NetCDF file.
    307          """
    308
    309          self.variables = {}
    310          self.textVariables = {}
    311
    312          self.variablesInfo.text.config(state = NORMAL)
    313          self.variablesInfo.text.delete('2.0', END)
    314          self.variablesInfo.text.config(state = DISABLED)
    315
    316          comp = 0
    317          for varName in sorted(self.netcdf.variables.keys()):
    318              self.variables[varName] = BooleanVar()
    319              self.variables[varName].set(True)
    320
    321              self.textVariables[varName] = StringVar()
    322              self.textVariables[varName].set('selected')
    323
    324              self.variablesInfo.insert(END, '\n')
    325
    326              self.variablesInfo.text.window_create(str(comp + 2)+'.0',\
    327                                                    window = Checkbutton(self.variablesInfo.text,\
    328                                                                         variable = self.variables[varName],\
    329                                                                         textvariable = self.textVariables[varName],\
    330                                                                         command = self.selectVariable,\
    331                                                                         anchor = W,\
    332                                                                         justify = LEFT,\
    333                                                                         bd = 1,\
    334                                                                         width = 10,\
    335                                                                         bg = 'Grey'))
    336
    337              self.variablesInfo.text.window_create(str(comp + 2)+'.1',\
    338                                                    window = Label(self.variablesInfo.text,\
    339                                                                   text = varName,\
    340                                                                   width = 50,\
    341                                                                   anchor = W,\
    342                                                                   bg = 'white'))
    343              comp += 1
    344