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