Package gui :: Package spin_viewer :: Module frame
[hide private]
[frames] | no frames]

Source Code for Module gui.spin_viewer.frame

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2010-2012 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax is free software; you can redistribute it and/or modify               # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation; either version 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax is distributed in the hope that it will be useful,                    # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """The spin viewer frame.""" 
 25   
 26  # Python module imports. 
 27  import wx 
 28   
 29  # relax module imports. 
 30  from generic_fns.pipes import cdp_name, pipe_names 
 31  from graphics import WIZARD_IMAGE_PATH, fetch_icon 
 32  from status import Status; status = Status() 
 33  from relax_errors import RelaxNoPipeError 
 34   
 35  # relax GUI module imports. 
 36  from gui.icons import relax_icons 
 37  from gui.misc import gui_raise 
 38  from gui.spin_viewer.splitter import Tree_splitter 
 39  from gui.string_conv import gui_to_str, str_to_gui 
 40  from gui.wizard import Wiz_page, Wiz_window 
 41  from gui.uf_objects import build_uf_menus, Uf_storage; uf_store = Uf_storage() 
 42   
 43   
44 -class Spin_view_window(wx.Frame):
45 """A window element for the tree view.""" 46
47 - def __init__(self, *args, **kwds):
48 """Set up the relax prompt.""" 49 50 # Store the parent object. 51 self.gui = kwds.pop('parent') 52 53 # Create GUI elements 54 kwds["style"] = wx.DEFAULT_FRAME_STYLE 55 if not status.debug and status.wx_info["os"] != 'darwin': 56 kwds["style"] = kwds["style"] | wx.MAXIMIZE 57 wx.Frame.__init__(self, *args, **kwds) 58 59 # Force the main window to start maximised (needed for MS Windows). 60 if not status.debug and status.wx_info["os"] != 'darwin': 61 self.Maximize() 62 63 # Set up the window icon. 64 self.SetIcons(relax_icons) 65 66 # Some default values. 67 self.size_x = 1000 68 self.size_y = 750 69 70 # Set up the window. 71 sizer = self.setup_window() 72 73 # Create a menu. 74 self._create_menu() 75 76 # Build the toolbar. 77 self.toolbar() 78 79 # The splitter window. 80 splitter = Tree_splitter(self.gui, self, -1) 81 sizer.Add(splitter, 1, wx.EXPAND|wx.ALL, 0) 82 83 # Initialise observer name. 84 self.name = 'spin viewer'
85 86
87 - def _activate(self):
88 """Activate or deactivate certain elements in response to the execution lock.""" 89 90 # Flag for enabling or disabling the elements. 91 enable = False 92 if not status.exec_lock.locked(): 93 enable = True 94 95 # Loop over the menus. 96 for menu, label in self.menubar.GetMenus(): 97 # Loop over the menu items. 98 for item in menu.GetMenuItems(): 99 wx.CallAfter(item.Enable, enable) 100 101 # The spin loader. 102 wx.CallAfter(self.bar.EnableTool, self.spin_loader_id, enable) 103 104 # The pipe selector. 105 wx.CallAfter(self.pipe_name.Enable, enable)
106 107
108 - def _create_menu(self):
109 """Build a menu for the window.""" 110 111 # Create the menu bar GUI item and add it to the main frame. 112 self.menubar = wx.MenuBar() 113 if status.show_gui: 114 self.SetMenuBar(self.menubar) 115 116 # The user function menus. 117 self.menu_uf_ids = build_uf_menus(parent=self, menubar=self.menubar)
118 119
120 - def Show(self, show=True):
121 """Change the behaviour of showing the window to update the content. 122 123 @keyword show: A flag which is True shows the window. 124 @type show: bool 125 """ 126 127 # Register a few methods in the observer objects. 128 status.observers.gui_uf.register(self.name, self.refresh) 129 status.observers.pipe_alteration.register(self.name, self.refresh) 130 status.observers.exec_lock.register(self.name, self._activate) 131 132 # First update. 133 self.refresh() 134 135 # Activate or deactivate the frame. 136 self._activate() 137 138 # Then show the window using the base class method. 139 if status.show_gui: 140 super(Spin_view_window, self).Show(show)
141 142
143 - def refresh(self, event=None):
144 """Event handler for the refresh action (thread safe). 145 146 @keyword event: The wx event. 147 @type event: wx event 148 """ 149 150 # Thread safe. 151 wx.CallAfter(self.refresh_safe)
152 153
154 - def refresh_safe(self):
155 """Refresh the spin viewer window.""" 156 157 # Change the cursor to busy. 158 wx.BeginBusyCursor() 159 160 # Update the data pipe selector. 161 self.update_pipes() 162 163 # Update the tree. 164 self.tree_panel.update() 165 166 # Redisplay the container. 167 self.container.display(self.tree_panel.get_info()) 168 169 # Reset the cursor. 170 if wx.IsBusy(): 171 wx.EndBusyCursor()
172 173
174 - def handler_close(self, event=None):
175 """Event handler for the close window action. 176 177 @keyword event: The wx event. 178 @type event: wx event 179 """ 180 181 # Unregister the methods from the observers to avoid unnecessary updating. 182 status.observers.gui_uf.unregister(self.name) 183 status.observers.pipe_alteration.unregister(self.name) 184 status.observers.exec_lock.unregister(self.name) 185 186 # Close the window. 187 self.Hide()
188 189
190 - def load_spins_wizard(self, event=None):
191 """The spin loading wizard. 192 193 @keyword event: The wx event. 194 @type event: wx event 195 """ 196 197 # No current data pipe. 198 if not cdp_name(): 199 gui_raise(RelaxNoPipeError()) 200 return 201 202 # Change the cursor to busy. 203 wx.BeginBusyCursor() 204 205 # Initialise a wizard. 206 self.wizard = Wiz_window(parent=self, size_x=1000, size_y=800, title="Load spins") 207 self.page_indices = {} 208 209 # The loading method page. 210 self.page_method = Load_method_page(self.wizard) 211 self.page_indices['method'] = self.wizard.add_page(self.page_method, apply_button=True, skip_button=False) 212 self.wizard.set_seq_next_fn(self.page_indices['method'], self.wizard_page_after_load_method) 213 214 # The sequence.read page. 215 page = uf_store['sequence.read'].create_page(self.wizard) 216 self.page_indices['sequence.read'] = self.wizard.add_page(page, skip_button=True) 217 self.wizard.set_seq_next_fn(self.page_indices['sequence.read'], self.wizard_page_after_sequence_read) 218 219 # The structure.read_pdb page. 220 page = uf_store['structure.read_pdb'].create_page(self.wizard) 221 self.page_indices['structure.read_pdb'] = self.wizard.add_page(page, skip_button=True) 222 self.wizard.set_seq_next_fn(self.page_indices['structure.read_pdb'], self.wizard_page_after_structure_read) 223 224 # The structure.read_xyz page. 225 page = uf_store['structure.read_xyz'].create_page(self.wizard) 226 self.page_indices['structure.read_xyz'] = self.wizard.add_page(page, skip_button=True) 227 self.wizard.set_seq_next_fn(self.page_indices['structure.read_xyz'], self.wizard_page_after_structure_read) 228 229 # The structure.load_spins page. 230 page = uf_store['structure.load_spins'].create_page(self.wizard) 231 self.page_indices['structure.load_spins'] = self.wizard.add_page(page) 232 233 # The termination page. 234 page = Finish_page(self.wizard) 235 self.page_indices['fin'] = self.wizard.add_page(page, apply_button=False, skip_button=False) 236 237 # Reset the cursor. 238 if wx.IsBusy(): 239 wx.EndBusyCursor() 240 241 # Run the wizard. 242 self.wizard.run()
243 244
245 - def setup_window(self):
246 """Set up the window. 247 248 @return: The sizer object. 249 @rtype: wx.Sizer instance 250 """ 251 252 # Set the frame title. 253 self.SetTitle("The spin viewer") 254 255 # Use a box sizer for packing the shell. 256 sizer = wx.BoxSizer(wx.VERTICAL) 257 self.SetSizer(sizer) 258 259 # Close the window cleanly (hide so it can be reopened). 260 self.Bind(wx.EVT_CLOSE, self.handler_close) 261 262 # Set the default size of the controller. 263 self.SetSize((self.size_x, self.size_y)) 264 265 # Return the sizer. 266 return sizer
267 268
269 - def toolbar(self):
270 """Create the toolbar.""" 271 272 # Init. 273 self.bar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT|wx.TB_TEXT) 274 275 # The spin loading button. 276 self.spin_loader_id = wx.NewId() 277 tooltip = "Load spins from either a sequence file or from a 3D structure file." 278 self.bar.AddLabelTool(self.spin_loader_id, "Load spins", wx.Bitmap(fetch_icon('relax.spin', '32x32'), wx.BITMAP_TYPE_ANY), bmpDisabled=wx.Bitmap(fetch_icon('relax.spin_grey', '32x32'), wx.BITMAP_TYPE_ANY), shortHelp=tooltip, longHelp=tooltip) 279 self.Bind(wx.EVT_TOOL, self.load_spins_wizard, id=self.spin_loader_id) 280 281 # A separator. 282 self.bar.AddSeparator() 283 284 # The refresh button. 285 id = wx.NewId() 286 tooltip = "Refresh the spin view." 287 self.bar.AddLabelTool(id, "Refresh", wx.Bitmap(fetch_icon('oxygen.actions.view-refresh', '32x32'), wx.BITMAP_TYPE_ANY), shortHelp=tooltip, longHelp=tooltip) 288 self.Bind(wx.EVT_TOOL, self.refresh, id=id) 289 290 # A separator. 291 self.bar.AddSeparator() 292 293 # The pipe text. 294 text = wx.StaticText(self.bar, -1, ' Current data pipe: ', style=wx.ALIGN_LEFT) 295 self.bar.AddControl(text) 296 297 # The pipe selection. 298 self.pipe_name = wx.ComboBox(self.bar, -1, "", style=wx.CB_DROPDOWN|wx.CB_READONLY, choices=[]) 299 self.bar.AddControl(self.pipe_name) 300 self.Bind(wx.EVT_COMBOBOX, self.update_pipes, self.pipe_name) 301 302 # Build the toolbar. 303 self.bar.Realize()
304 305
306 - def update_pipes(self, event=None):
307 """Update the spin view data pipe selector. 308 309 @keyword event: The wx event. 310 @type event: wx event 311 """ 312 313 # Change the cursor to busy. 314 wx.BeginBusyCursor() 315 316 # Init. 317 pipe_switch = False 318 319 # The selected pipe. 320 if event: 321 # The name of the selected pipe. 322 pipe = gui_to_str(self.pipe_name.GetString(event.GetSelection())) 323 324 # A pipe change. 325 if pipe != cdp_name(): 326 pipe_switch = True 327 else: 328 pipe = cdp_name() 329 if not pipe: 330 pipe = '' 331 332 # Clear the previous data. 333 self.pipe_name.Clear() 334 335 # The list of pipe names. 336 for name in pipe_names(): 337 self.pipe_name.Append(str_to_gui(name)) 338 339 # Switch. 340 if pipe_switch: 341 # Switch data pipes. 342 self.gui.interpreter.apply('pipe.switch', pipe) 343 344 # Update the tree view. 345 self.tree_panel.update() 346 347 # Set the pipe name to the cdp. 348 self.pipe_name.SetValue(str_to_gui(pipe)) 349 350 # Reset the cursor. 351 if wx.IsBusy(): 352 wx.EndBusyCursor()
353 354
356 """Set the page after the load method choice. 357 358 @return: The index of the next page. 359 @rtype: int 360 """ 361 362 # Go to the sequence.read page. 363 if self.page_method.selection == 'sequence': 364 return self.page_indices['sequence.read'] 365 366 # Go to the structure.read_pdb page. 367 elif self.page_method.selection == 'new pdb': 368 return self.page_indices['structure.read_pdb'] 369 370 # Go to the structure.read_xyz page. 371 elif self.page_method.selection == 'new xyz': 372 return self.page_indices['structure.read_xyz'] 373 374 # Skip to the structure.load_spins page. 375 elif self.page_method.selection == 'preload': 376 return self.page_indices['structure.load_spins']
377 378
380 """Set the page after the sequence.read user function page. 381 382 @return: The index of the last page. 383 @rtype: int 384 """ 385 386 # Return the index of the terminal page. 387 return self.page_indices['fin']
388 389
391 """Set the page after the structure.read_* user function pages. 392 393 @return: The index of the structure.load_spins page. 394 @rtype: int 395 """ 396 397 # Return the index of the terminal page. 398 return self.page_indices['structure.load_spins']
399 400 401
402 -class Finish_page(Wiz_page):
403 """The terminating wizard page.""" 404 405 # Class variables. 406 image_path = WIZARD_IMAGE_PATH + 'spin.png' 407 main_text = 'The spin systems should now have been loaded into the relax data store.' 408 title = 'Spin loading complete' 409
410 - def add_contents(self, sizer):
411 """This blank method is needed so that the page shows and does nothing. 412 413 @param sizer: A sizer object. 414 @type sizer: wx.Sizer instance 415 """
416 417 418
419 -class Load_method_page(Wiz_page):
420 """The wizard page for specifying how to load spins.""" 421 422 # Class variables. 423 image_path = WIZARD_IMAGE_PATH + 'spin.png' 424 main_text = 'Select the method for loading spins into relax. Two options are possible: the first is to read sequence information out of a text file via the sequence.read user function; the second is to read in a 3D structure file via the structure.read_pdb user function and then to load the spins from this structure using the structure.load_spins user function.' 425 title = 'Spin loading' 426 427
428 - def add_contents(self, sizer):
429 """Add the specific GUI elements. 430 431 @param sizer: A sizer object. 432 @type sizer: wx.Sizer instance 433 """ 434 435 # Intro text. 436 msg = "Please specify by which method spins should be loaded into the relax data store:" 437 text = wx.StaticText(self, -1, msg) 438 text.Wrap(self._main_size) 439 sizer.Add(text, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 440 441 # Spacing. 442 sizer.AddStretchSpacer() 443 444 # A box sizer for placing the box sizer in. 445 sizer2 = wx.BoxSizer(wx.HORIZONTAL) 446 sizer.Add(sizer2, 1, wx.ALL|wx.EXPAND, 0) 447 448 # Bottom spacing. 449 sizer.AddStretchSpacer() 450 451 # A bit of indentation. 452 sizer2.AddStretchSpacer() 453 454 # A vertical sizer for the radio buttons. 455 sizer_radio = wx.BoxSizer(wx.VERTICAL) 456 sizer2.Add(sizer_radio, 1, wx.ALL|wx.EXPAND, 0) 457 458 # Pre-loaded structure exists. 459 self.preload_flag = False 460 if hasattr(cdp, 'structure') and not cdp.structure.empty(): 461 self.preload_flag = True 462 463 # The pre-load radio button. 464 if self.preload_flag: 465 # The button. 466 self.radio_preload = wx.RadioButton(self, -1, "From a pre-loaded structure.", style=wx.RB_GROUP) 467 sizer_radio.Add(self.radio_preload, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 468 469 # Spacing. 470 sizer_radio.AddSpacer(20) 471 472 # The sequence radio button. 473 if self.preload_flag: 474 style = 0 475 else: 476 style = wx.RB_GROUP 477 self.radio_seq = wx.RadioButton(self, -1, "From a file containing sequence data.", style=style) 478 sizer_radio.Add(self.radio_seq, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 479 480 # Spacing. 481 sizer_radio.AddSpacer(20) 482 483 # The PDB radio button. 484 self.radio_new_pdb = wx.RadioButton(self, -1, "From a new PDB structure file.") 485 sizer_radio.Add(self.radio_new_pdb, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 486 487 # Spacing. 488 sizer_radio.AddSpacer(20) 489 490 # The XYZ radio button. 491 self.radio_new_xyz = wx.RadioButton(self, -1, "From a new XYZ structure file.") 492 sizer_radio.Add(self.radio_new_xyz, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 493 494 # Bind the buttons. 495 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_seq) 496 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_new_pdb) 497 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_new_xyz) 498 if self.preload_flag: 499 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_preload) 500 501 # Right side spacing. 502 sizer2.AddStretchSpacer(3) 503 504 # Bottom spacing. 505 sizer.AddStretchSpacer() 506 507 # Set the default selection. 508 if self.preload_flag: 509 self.selection = 'preload' 510 else: 511 self.selection = 'sequence'
512 513
514 - def _on_select(self, event=None):
515 """Handle the radio button switching. 516 517 @keyword event: The wx event. 518 @type event: wx event 519 """ 520 521 # The button. 522 button = event.GetEventObject() 523 524 # RMSD. 525 if button == self.radio_seq: 526 self.selection = 'sequence' 527 elif button == self.radio_new_pdb: 528 self.selection = 'new pdb' 529 elif button == self.radio_new_xyz: 530 self.selection = 'new xyz' 531 elif self.preload_flag and button == self.radio_preload: 532 self.selection = 'preload'
533