Package diffpy :: Package pdfgui :: Package gui :: Module temperatureseriespanel
[hide private]
[frames] | no frames]

Source Code for Module diffpy.pdfgui.gui.temperatureseriespanel

  1  #!/usr/bin/env python 
  2  # -*- coding: ISO-8859-1 -*- 
  3  ############################################################################## 
  4  # 
  5  # PDFgui            by DANSE Diffraction group 
  6  #                   Simon J. L. Billinge 
  7  #                   (c) 2006 trustees of the Michigan State University. 
  8  #                   All rights reserved. 
  9  # 
 10  # File coded by:    Chris Farrow 
 11  # 
 12  # See AUTHORS.txt for a list of people who contributed. 
 13  # See LICENSE.txt for license information. 
 14  # 
 15  ############################################################################## 
 16   
 17  # generated by wxGlade 0.4.1 on Tue Nov 21 12:33:37 2006 
 18   
 19  import sys 
 20  import os.path 
 21  import re 
 22  import wx 
 23  from diffpy.pdfgui.control.pdfguimacros import makeTemperatureSeries 
 24  from diffpy.pdfgui.gui.pdfpanel import PDFPanel 
 25  from diffpy.pdfgui.gui.tooltips import temperatureseriespanel as toolTips 
 26  from diffpy.pdfgui.gui.wxExtensions.listctrls import AutoWidthListCtrl 
 27  from diffpy.pdfgui.utils import numericStringSort 
 28   
29 -class TemperatureSeriesPanel(wx.Panel, PDFPanel):
30 - def __init__(self, *args, **kwds):
31 PDFPanel.__init__(self) 32 # begin wxGlade: TemperatureSeriesPanel.__init__ 33 kwds["style"] = wx.TAB_TRAVERSAL 34 wx.Panel.__init__(self, *args, **kwds) 35 self.instructionsLabel = wx.StaticText(self, -1, "Select a fit from the tree on the left then add datasets and assign\ntemperatues below. If you have not set up a fit to be the template\nfor the series, hit cancel and rerun this macro once a fit has been\ncreated.") 36 self.listCtrlFiles = AutoWidthListCtrl(self, -1, style=wx.LC_REPORT|wx.LC_EDIT_LABELS|wx.SUNKEN_BORDER) 37 self.buttonUp = wx.BitmapButton(self, -1, wx.NullBitmap) 38 self.buttonDown = wx.BitmapButton(self, -1, wx.NullBitmap) 39 self.buttonAdd = wx.Button(self, wx.ID_ADD, "Add") 40 self.buttonDelete = wx.Button(self, wx.ID_DELETE, "Delete") 41 self.static_line_1 = wx.StaticLine(self, -1) 42 self.goButton = wx.Button(self, wx.ID_OK, "OK") 43 self.cancelButton = wx.Button(self, wx.ID_CANCEL, "Cancel") 44 45 self.__set_properties() 46 self.__do_layout() 47 48 self.Bind(wx.EVT_LIST_COL_CLICK, self.onColClick, self.listCtrlFiles) 49 self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.onEndLabelEdit, self.listCtrlFiles) 50 self.Bind(wx.EVT_BUTTON, self.onUp, self.buttonUp) 51 self.Bind(wx.EVT_BUTTON, self.onDown, self.buttonDown) 52 self.Bind(wx.EVT_BUTTON, self.onAdd, id=wx.ID_ADD) 53 self.Bind(wx.EVT_BUTTON, self.onDelete, id=wx.ID_DELETE) 54 self.Bind(wx.EVT_BUTTON, self.onOK, id=wx.ID_OK) 55 self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL) 56 # end wxGlade 57 self.buttonUp.SetBitmapLabel(wx.ArtProvider.GetBitmap(wx.ART_GO_UP)) 58 self.buttonDown.SetBitmapLabel(wx.ArtProvider.GetBitmap(wx.ART_GO_DOWN)) 59 self.__customProperties()
60
61 - def __set_properties(self):
62 # begin wxGlade: TemperatureSeriesPanel.__set_properties 63 self.instructionsLabel.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "")) 64 self.buttonUp.SetSize(self.buttonUp.GetBestSize()) 65 self.buttonDown.SetSize(self.buttonDown.GetBestSize()) 66 # end wxGlade 67 self.setToolTips(toolTips)
68
69 - def __do_layout(self):
70 # begin wxGlade: TemperatureSeriesPanel.__do_layout 71 sizer_1 = wx.BoxSizer(wx.VERTICAL) 72 sizer_3 = wx.BoxSizer(wx.HORIZONTAL) 73 grid_sizer_1 = wx.GridSizer(1, 2, 10, 10) 74 sizer_2 = wx.BoxSizer(wx.VERTICAL) 75 sizer_4 = wx.BoxSizer(wx.HORIZONTAL) 76 sizer_5 = wx.BoxSizer(wx.VERTICAL) 77 sizer_1.Add(self.instructionsLabel, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5) 78 sizer_4.Add(self.listCtrlFiles, 1, wx.ALL|wx.EXPAND, 5) 79 sizer_5.Add((0, 0), 1, wx.ADJUST_MINSIZE, 0) 80 sizer_5.Add(self.buttonUp, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) 81 sizer_5.Add(self.buttonDown, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) 82 sizer_5.Add((0, 0), 1, wx.ADJUST_MINSIZE, 0) 83 sizer_4.Add(sizer_5, 0, wx.EXPAND, 0) 84 sizer_2.Add(sizer_4, 1, wx.EXPAND, 0) 85 sizer_1.Add(sizer_2, 1, wx.EXPAND, 0) 86 grid_sizer_1.Add(self.buttonAdd, 0, wx.ADJUST_MINSIZE, 0) 87 grid_sizer_1.Add(self.buttonDelete, 0, wx.ADJUST_MINSIZE, 0) 88 sizer_1.Add(grid_sizer_1, 0, wx.ALL, 5) 89 sizer_1.Add(self.static_line_1, 0, wx.EXPAND, 0) 90 sizer_3.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) 91 sizer_3.Add(self.goButton, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) 92 sizer_3.Add(self.cancelButton, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) 93 sizer_1.Add(sizer_3, 0, wx.EXPAND, 0) 94 self.SetAutoLayout(True) 95 self.SetSizer(sizer_1) 96 sizer_1.Fit(self) 97 sizer_1.SetSizeHints(self)
98 # end wxGlade 99
100 - def __customProperties(self):
101 """Set the custom properties.""" 102 self.fit = None 103 self.reverse = False # Reverse the sort? 104 self.fullpath = '.' 105 self.datasets = [] # Contains (temperature, filename) tuples 106 # temperature is a float and comes first for easy sorting 107 108 self.listCtrlFiles.InsertColumn(0, "Temperature") 109 self.listCtrlFiles.InsertColumn(1, "Data Set") 110 self.listCtrlFiles.SetColumnWidth(0,-2) 111 return
112
113 - def onEndLabelEdit(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
114 """Update the temperature in the datasets.""" 115 index = event.GetIndex() 116 text = event.GetText() 117 temperature = 300.0 118 try: 119 temperature = float(text) 120 except ValueError: 121 event.Veto() 122 return 123 if temperature <= 0: 124 event.Veto() 125 return 126 # update the internal information 127 self.datasets[index][0] = temperature 128 self.reverse = False 129 return
130
131 - def onOK(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
132 """Let's go!""" 133 paths = [tp[1] for tp in self.datasets] 134 temperatures = [tp[0] for tp in self.datasets] 135 org = makeTemperatureSeries(self.mainFrame.control, self.fit, 136 paths, temperatures) 137 self.treeCtrlMain.ExtendProjectTree(org, clear=False) 138 self.mainFrame.needsSave() 139 self.onCancel(event) 140 return 141
142 - def onCancel(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
143 """Let's go, but not actually do anything.""" 144 self.mainFrame.setMode("fitting") 145 self.treeCtrlMain.UnselectAll() 146 self.mainFrame.switchRightPanel("blank") 147 return 148
149 - def onUp(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
150 """Move an item in the list up.""" 151 index = self.listCtrlFiles.GetFirstSelected() 152 if index > 0: 153 temp = self.datasets[index] 154 self.datasets[index] = self.datasets[index-1] 155 self.datasets[index-1] = temp 156 self.fillList() 157 self.listCtrlFiles.Select(index-1) 158 return 159
160 - def onDown(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
161 """Move an item in the list down.""" 162 index = self.listCtrlFiles.GetFirstSelected() 163 if index > -1 and index != len(self.datasets)-1: 164 temp = self.datasets[index] 165 self.datasets[index] = self.datasets[index+1] 166 self.datasets[index+1] = temp 167 self.fillList() 168 self.listCtrlFiles.Select(index+1) 169 return 170
171 - def onAdd(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
172 """Append files to the list.""" 173 dir, filename = os.path.split(self.fullpath) 174 if not dir: 175 dir = self.mainFrame.workpath 176 177 matchstring = "PDF data files (*.gr)|*.gr|PDF fit files (*.fgr)|*.fgr|PDF fit files (*.fit)|*.fit|PDF calculation files (*.cgr)|*.cgr|PDF calculation files (*.calc)|*.calc|All Files|*" 178 d = wx.FileDialog(None, "Choose files", dir, "", matchstring, 179 wx.OPEN|wx.FILE_MUST_EXIST|wx.MULTIPLE) 180 paths = [] 181 if d.ShowModal() == wx.ID_OK: 182 paths = d.GetPaths() 183 d.Destroy() 184 185 # Assign the temperatures. Default to 300.0 186 newdatasets = [] 187 for path in paths: 188 self.fullpath = path 189 self.mainFrame.workpath = os.path.dirname(path) 190 191 # Look for the temperature in the filename 192 temperature = 300.0 193 rx = {'f' : r'(?:\d+(?:\.\d*)?|\d*\.\d+)' } 194 # Search for T123, t123, Temp123, temp123, 123k, 123K. 195 # Some filenames fool this, e.g. "test1.dat" will match '1' since it 196 # is preceeded by a 't'. 197 # Is there a better regexp? Probably... 198 regexp = r"(?:[Tt](?:emp(?:erature)?)?(%(f)s))|(?:(%(f)s)[Kk])" % rx 199 res = re.search(regexp, os.path.basename(path)) 200 if res: 201 groups = res.groups() 202 if groups[0] is not None: 203 temperature = float(res.groups()[0]) 204 else: 205 temperature = float(res.groups()[1]) 206 else: 207 # Look in the file 208 infile = file(path,'r') 209 datastring = infile.read() 210 infile.close() 211 # Look for it first in the file 212 res = re.search(r'^#+ start data\s*(?:#.*\s+)*', datastring, re.M) 213 # start_data is position where the first data line starts 214 if res: 215 start_data = res.end() 216 else: 217 res = re.search(r'^[^#]', datastring, re.M) 218 if res: 219 start_data = res.start() 220 else: 221 start_data = 0 222 header = datastring[:start_data] 223 # parse header to get temperature 224 regexp = r"\b(?:temp|temperature|T)\ *=\ *(%(f)s)\b" % rx 225 res = re.search(regexp, header) 226 if res: 227 temperature = float(res.groups()[0]) 228 # Add the new path 229 if temperature <= 0: temperature = 300.0 230 newdatasets.append([temperature, path]) 231 232 # DONT Sort the new paths according to temperature 233 #newdatasets.sort() 234 self.datasets.extend(newdatasets) 235 self.fillList() 236 return 237
238 - def onDelete(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
239 """Delete selected files from the list.""" 240 idxlist = [] 241 item = self.listCtrlFiles.GetFirstSelected() 242 while item != -1: 243 idxlist.append(item) 244 item = self.listCtrlFiles.GetNextSelected(item) 245 246 idxlist.reverse() 247 for item in idxlist: 248 del self.datasets[item] 249 self.fillList() 250 return 251
252 - def onColClick(self, event): # wxGlade: TemperatureSeriesPanel.<event_handler>
253 """Sort by temperature.""" 254 column = event.GetColumn() 255 # sort by temperature 256 if column == 0: 257 sortkey = lambda tf : float(tf[0]) 258 # sort by filename with numerical comparison of digits 259 elif column == 1: 260 filenames = [f for t, f in self.datasets] 261 numericStringSort(filenames) 262 order = dict(zip(filenames, range(len(filenames)))) 263 sortkey = lambda tf : order[tf[1]] 264 # ignore unhandled columns 265 else: 266 return 267 self.datasets.sort(key=sortkey, reverse=self.reverse) 268 self.reverse = not self.reverse 269 self.fillList() 270 return 271 272 ## Utility functions
273 - def fillList(self):
274 """Fill the list with the datasets.""" 275 self.listCtrlFiles.DeleteAllItems() 276 names = [pair[1] for pair in self.datasets] 277 cp = os.path.commonprefix(names) 278 # We want to break at the last path/separator in the common prefix 279 idx = cp.rfind(os.path.sep) 280 if idx == -1: idx = len(cp) 281 for temperature, filename in self.datasets: 282 shortname = "..." + filename[idx:] 283 index = self.listCtrlFiles.InsertStringItem(sys.maxint, str(temperature)) 284 self.listCtrlFiles.SetStringItem(index, 1, shortname) 285 return
286 287 ## Needed by mainframe
288 - def treeSelectionUpdate(self, node):
289 """Set the current fit when the tree selection changes.""" 290 nodetype = self.treeCtrlMain.GetNodeType(node) 291 if nodetype == 'fit': 292 self.fit = self.treeCtrlMain.GetControlData(node) 293 self.refresh() 294 return
295 296 ## Required by PDFPanel
297 - def refresh(self):
298 """Block out OK button if there is no fit. 299 300 This also blocks OK if the fit has no datasets or structures. 301 """ 302 # We can't rely on Veto to block unwanted tree selections on windows. 303 # So, we have to check for errors here. 304 node = None 305 nodetype = None 306 selections = self.treeCtrlMain.GetSelections() 307 if selections: 308 node = selections[0] 309 nodetype = self.treeCtrlMain.GetNodeType(node) 310 311 if node and nodetype == "fit" \ 312 and self.fit and self.fit.hasDataSets() \ 313 and self.fit.hasStructures(): 314 self.goButton.Enable() 315 else: 316 self.goButton.Enable(False) 317 return
318 319 # end of class TemperatureSeriesPanel 320 321 __id__ = "$Id: temperatureseriespanel.py 2980 2009-04-02 00:14:33Z juhas $" 322