Package gui :: Module results_viewer
[hide private]
[frames] | no frames]

Source Code for Module gui.results_viewer

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2010 Michael Bieri                                            # 
  4  # Copyright (C) 2011-2012 Edward d'Auvergne                                   # 
  5  #                                                                             # 
  6  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program is free software: you can redistribute it and/or modify        # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation, either version 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program is distributed in the hope that it will be useful,             # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """Module containing the base class for the results frame.""" 
 25   
 26  # Python module imports. 
 27  import wx 
 28  from wx.lib import buttons 
 29   
 30  # relax module imports. 
 31  from data import Relax_data_store; ds = Relax_data_store() 
 32  from generic_fns.pipes import cdp_name, pipe_names 
 33  from status import Status; status = Status() 
 34   
 35  # relax GUI module imports. 
 36  from gui.fonts import font 
 37  from gui.icons import relax_icons 
 38  from gui.interpreter import Interpreter; interpreter = Interpreter() 
 39  from gui.misc import add_border, open_file 
 40  from gui.paths import icon_22x22 
 41  from gui.string_conv import gui_to_str, str_to_gui 
 42  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 43   
 44   
45 -class Results_viewer(wx.Frame):
46 """The results viewer frame.""" 47 48 # Some class variables. 49 border = 10 50 size = (800, 400) 51
52 - def __init__(self, parent):
53 """Build the results frame. 54 55 @param parent: The parent wx object. 56 @type parent: wx object 57 """ 58 59 # Initialise the base frame. 60 wx.Frame.__init__(self, parent=parent, style=wx.DEFAULT_FRAME_STYLE) 61 62 # Set up the window icon. 63 self.SetIcons(relax_icons) 64 65 # Set the window title, size, etc. 66 self.SetTitle("Results viewer") 67 self.SetSize(self.size) 68 69 # Place all elements within a panel (to remove the dark grey in MS Windows). 70 self.main_panel = wx.Panel(self, -1) 71 72 # Pack a sizer into the panel. 73 box_main = wx.BoxSizer(wx.HORIZONTAL) 74 self.main_panel.SetSizer(box_main) 75 76 # Build the central sizer, with borders. 77 box_centre = add_border(box_main, border=self.border, packing=wx.VERTICAL) 78 79 # Build the data pipe selector. 80 self.build_pipe_sel(box_centre) 81 82 # Spacer. 83 box_centre.AddSpacer(self.border) 84 85 # Add the list of results files. 86 self.add_files(box_centre) 87 88 # Spacer. 89 box_centre.AddSpacer(self.border) 90 91 # Add the open button. 92 self.button_open = buttons.ThemedGenBitmapTextButton(self.main_panel, -1, None, " Open") 93 self.button_open.SetBitmapLabel(wx.Bitmap(icon_22x22.document_open, wx.BITMAP_TYPE_ANY)) 94 self.button_open.SetFont(font.normal) 95 self.button_open.SetMinSize((103, 33)) 96 self.Bind(wx.EVT_BUTTON, self.open_result_file, self.button_open) 97 box_centre.Add(self.button_open, 0, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 5) 98 99 # Relayout the main panel. 100 self.main_panel.Layout() 101 self.main_panel.Refresh() 102 103 # Bind some events. 104 self.Bind(wx.EVT_COMBOBOX, self.switch_pipes, self.pipe_name) 105 self.Bind(wx.EVT_CLOSE, self.handler_close) 106 107 # Initialise observer name. 108 self.name = 'results viewer'
109 110
111 - def Show(self, show=True):
112 """Change the behaviour of showing the window to update the content. 113 114 @keyword show: A flag which is True shows the window. 115 @type show: bool 116 """ 117 118 # Register a few methods in the observer objects. 119 status.observers.gui_uf.register(self.name, self.refresh, method_name='refresh') 120 status.observers.pipe_alteration.register(self.name, self.refresh, method_name='refresh') 121 status.observers.result_file.register(self.name, self.refresh, method_name='refresh') 122 status.observers.exec_lock.register(self.name, self.activate, method_name='activate') 123 124 # First update. 125 self.refresh() 126 127 # Activate or deactivate the frame. 128 self.activate() 129 130 # Show the window using the base class method. 131 if status.show_gui: 132 super(Results_viewer, self).Show(show)
133 134
135 - def activate(self):
136 """Activate or deactivate certain elements in response to the execution lock.""" 137 138 # Flag for enabling or disabling the elements. 139 enable = False 140 if not status.exec_lock.locked(): 141 enable = True 142 143 # The pipe selector. 144 wx.CallAfter(self.pipe_name.Enable, enable) 145 146 # The open button. 147 wx.CallAfter(self.button_open.Enable, enable)
148 149
150 - def add_files(self, box):
151 """Create the list of results files. 152 153 @param box: The box sizer to pack the box into. 154 @type box: wx.BoxSizer instance 155 @return: The list box element. 156 @rtype: wx.ListBox element 157 """ 158 159 # Initialise the list box. 160 self.file_list = wx.ListCtrl(self.main_panel, -1, style=wx.BORDER_SUNKEN|wx.LC_REPORT) 161 162 # Properties. 163 self.file_list.SetFont(font.normal) 164 165 # Store the base heights. 166 self.height_char = self.file_list.GetCharHeight() 167 168 # The headers. 169 self.file_list.InsertColumn(0, "File type") 170 self.file_list.InsertColumn(1, "File path") 171 172 # Add to the sizer. 173 box.Add(self.file_list, 1, wx.ALL|wx.EXPAND, 0) 174 175 # Bind events. 176 self.file_list.Bind(wx.EVT_SIZE, self.resize) 177 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.open_result_file, self.file_list)
178 179
180 - def build_pipe_sel(self, box):
181 """Create the data pipe selection element. 182 183 @param box: The horizontal box element to pack the elements into. 184 @type box: wx.BoxSizer instance 185 """ 186 187 # Use a horizontal packing of elements. 188 sizer = wx.BoxSizer(wx.HORIZONTAL) 189 190 # The text. 191 label = wx.StaticText(self.main_panel, -1, "Data pipe selection") 192 193 # The font and label properties. 194 label.SetFont(font.subtitle) 195 196 # Add the label to the box. 197 sizer.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) 198 199 # Add a spacer. 200 sizer.AddSpacer(self.border) 201 202 # A combo box. 203 self.pipe_name = wx.ComboBox(self.main_panel, -1, value='', style=wx.CB_DROPDOWN|wx.CB_READONLY, choices=[]) 204 self.pipe_name.SetMinSize((50, 27)) 205 sizer.Add(self.pipe_name, 1, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) 206 207 # Add the pipe sizer to the main sizer. 208 box.Add(sizer, 0, wx.ALL|wx.EXPAND, 0)
209 210
211 - def handler_close(self, event):
212 """Event handler for the close window action. 213 214 @param event: The wx event. 215 @type event: wx event 216 """ 217 218 # Unregister the methods from the observers to avoid unnecessary updating. 219 status.observers.gui_uf.unregister(self.name) 220 status.observers.pipe_alteration.unregister(self.name) 221 status.observers.result_file.unregister(self.name) 222 status.observers.exec_lock.unregister(self.name) 223 224 # Close the window. 225 self.Hide()
226 227
228 - def open_result_file(self, event):
229 """Open the results in the appropriate program. 230 231 @param event: The wx event. 232 @type event: wx event 233 """ 234 235 # Loop over all files. 236 for i in range(self.file_list.GetItemCount()): 237 # Not selected. 238 if not self.file_list.IsSelected(i): 239 continue 240 241 # Get the type and file. 242 type = self.file_data[i] 243 file = gui_to_str(self.file_list.GetItem(i, 1).GetText()) 244 245 # Grace files. 246 if type == 'grace': 247 uf_store['grace.view'](file=file, wx_parent=self) 248 249 # PyMOL macro files. 250 elif type == 'pymol': 251 uf_store['pymol.macro_run'](file=file, wx_parent=self) 252 253 # Molmol macro files. 254 elif type == 'molmol': 255 uf_store['molmol.macro_run'](file=file, wx_parent=self) 256 257 # Diffusion tensor PDB. 258 elif type == 'diff_tensor_pdb': 259 # Try and see if PyMOL is installed. 260 if not interpreter.apply('pymol.view'): 261 return 262 263 # Display the tensor. 264 interpreter.apply('pymol.cartoon') 265 interpreter.apply('pymol.tensor_pdb', file=file) 266 267 # A special table. 268 elif type == 'Table_of_Results': 269 # The data. 270 model_result = [ds.relax_gui.table_residue, ds.relax_gui.table_model, ds.relax_gui.table_s2, ds.relax_gui.table_rex, ds.relax_gui.table_te] 271 272 # Text files. 273 elif type == 'text': 274 open_file(file, force_text=True) 275 276 # Open all other files in which ever editor the platform decides on. 277 else: 278 open_file(file)
279 280
281 - def refresh(self):
282 """Update the list of result files.""" 283 284 # Thread safe. 285 wx.CallAfter(self.refresh_safe)
286 287
288 - def refresh_safe(self):
289 """Update the list of result files (thread safe).""" 290 291 # Acquire the pipe lock. 292 status.pipe_lock.acquire('results viewer window') 293 try: 294 # Update the data pipe selector. 295 self.update_pipes() 296 297 # Clear the list. 298 self.file_list.DeleteAllItems() 299 self.file_data = [] 300 301 # Nothing to do. 302 if not hasattr(cdp, 'result_files'): 303 return 304 305 # Update the list. 306 for i in range(len(cdp.result_files)): 307 self.file_list.Append((str_to_gui(cdp.result_files[i][1]), str_to_gui(cdp.result_files[i][2]))) 308 self.file_data.append(cdp.result_files[i][0]) 309 310 # Release the locks. 311 finally: 312 status.pipe_lock.release('results viewer window')
313 314
315 - def resize(self, event):
316 """Catch the resize to allow the element to be resized. 317 318 @param event: The wx event. 319 @type event: wx event 320 """ 321 322 # Set the column sizes. 323 self.size_cols() 324 325 # Continue with the normal resizing. 326 event.Skip()
327 328
329 - def switch_pipes(self, event):
330 """Switch data pipes. 331 332 @param event: The wx event. 333 @type event: wx event 334 """ 335 336 # The name of the selected pipe. 337 pipe = gui_to_str(self.pipe_name.GetString(event.GetSelection())) 338 339 # No pipe change. 340 if pipe == cdp_name(): 341 return 342 343 # Switch data pipes. 344 interpreter.queue('pipe.switch', pipe) 345 interpreter.flush() 346 347 # Update the window. 348 self.refresh() 349 350 # Bug fix for MS Windows (bring the window back). 351 wx.CallAfter(self.Raise)
352 353
354 - def update_pipes(self):
355 """Update the data pipe list.""" 356 357 # Clear the previous data pipe. 358 self.pipe_name.Clear() 359 360 # The list of data pipes. 361 for pipe in pipe_names(): 362 self.pipe_name.Append(str_to_gui(pipe)) 363 364 # Set the name to the current data pipe. 365 self.pipe_name.SetValue(str_to_gui(cdp_name()))
366 367
368 - def size_cols(self):
369 """Set the column sizes.""" 370 371 # The list size. 372 x, y = self.file_list.GetSize() 373 374 # Remove a little to prevent the horizontal scroll bar from appearing. 375 x = x - 10 376 377 # Set the column sizes. 378 self.file_list.SetColumnWidth(0, int(x/3)) 379 self.file_list.SetColumnWidth(1, int(2*x/3))
380