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