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

Source Code for Module gui.spin_viewer.tree

   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 molecule, residue, and spin tree view GUI elements.""" 
  25   
  26   
  27  # Python module imports. 
  28  import wx 
  29   
  30  # relax module imports. 
  31  from generic_fns.selection import is_mol_selected, is_res_selected, is_spin_selected 
  32  from generic_fns.mol_res_spin import get_molecule_ids, molecule_loop, residue_loop, return_molecule, return_residue, return_spin, spin_loop 
  33  from generic_fns.pipes import cdp_name, get_pipe 
  34  from graphics import fetch_icon 
  35  from status import Status; status = Status() 
  36   
  37  # relax GUI module imports. 
  38  from gui import paths 
  39  from gui.components.menu import build_menu_item 
  40  from gui.message import Question 
  41  from gui.string_conv import gui_to_str 
  42  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
  43   
  44   
45 -class Mol_res_spin_tree(wx.Window):
46 """The tree view class.""" 47 48 # Some IDs for the menu entries. 49 MENU_MOLECULE_MOLECULE_COPY = wx.NewId() 50 MENU_MOLECULE_MOLECULE_DELETE = wx.NewId() 51 MENU_MOLECULE_MOLECULE_DESELECT = wx.NewId() 52 MENU_MOLECULE_MOLECULE_NAME = wx.NewId() 53 MENU_MOLECULE_MOLECULE_SELECT = wx.NewId() 54 MENU_MOLECULE_MOLECULE_TYPE = wx.NewId() 55 MENU_MOLECULE_RESIDUE_CREATE = wx.NewId() 56 MENU_RESIDUE_RESIDUE_COPY = wx.NewId() 57 MENU_RESIDUE_RESIDUE_DELETE = wx.NewId() 58 MENU_RESIDUE_RESIDUE_DESELECT = wx.NewId() 59 MENU_RESIDUE_RESIDUE_NAME = wx.NewId() 60 MENU_RESIDUE_RESIDUE_NUMBER = wx.NewId() 61 MENU_RESIDUE_RESIDUE_SELECT = wx.NewId() 62 MENU_RESIDUE_SPIN_ADD = wx.NewId() 63 MENU_RESIDUE_SPIN_CREATE_PSEUDO = wx.NewId() 64 MENU_ROOT_MOLECULE_CREATE = wx.NewId() 65 MENU_ROOT_LOAD_SPINS = wx.NewId() 66 MENU_SPIN_SPIN_COPY = wx.NewId() 67 MENU_SPIN_SPIN_DELETE = wx.NewId() 68 MENU_SPIN_SPIN_DESELECT = wx.NewId() 69 MENU_SPIN_SPIN_ELEMENT = wx.NewId() 70 MENU_SPIN_SPIN_NAME = wx.NewId() 71 MENU_SPIN_SPIN_NUMBER = wx.NewId() 72 MENU_SPIN_SPIN_SELECT = wx.NewId() 73
74 - def __init__(self, gui, parent=None, id=None):
75 """Set up the tree GUI element. 76 77 @param gui: The gui object. 78 @type gui: wx object 79 @keyword parent: The parent GUI element that this is to be attached to. 80 @type parent: wx object 81 @keyword id: The ID number. 82 @type id: int 83 """ 84 85 # Store the args. 86 self.gui = gui 87 self.parent = parent 88 89 # Execute the base class method. 90 wx.Window.__init__(self, parent, id, style=wx.WANTS_CHARS) 91 92 # Some default values. 93 self.icon_size = 22 94 95 # The tree. 96 self.tree = wx.TreeCtrl(parent=self, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE) 97 98 # A tracking structure for the tree IDs. 99 self.tree_ids = {} 100 101 # Resize the tree element. 102 self.Bind(wx.EVT_SIZE, self._resize) 103 104 # The tree roots. 105 self.root = self.tree.AddRoot("Spin system information") 106 self.tree.SetPyData(self.root, "root") 107 108 # Build the icon list. 109 icon_list = wx.ImageList(self.icon_size, self.icon_size) 110 111 # The normal icons. 112 self.icon_mol_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule, wx.BITMAP_TYPE_ANY)) 113 self.icon_mol_unfold_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule_unfolded, wx.BITMAP_TYPE_ANY)) 114 self.icon_res_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.residue, wx.BITMAP_TYPE_ANY)) 115 self.icon_spin_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.spin, wx.BITMAP_TYPE_ANY)) 116 117 # The deselected icons. 118 self.icon_mol_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule_grey, wx.BITMAP_TYPE_ANY)) 119 self.icon_mol_unfold_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule_unfolded_grey, wx.BITMAP_TYPE_ANY)) 120 self.icon_res_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.residue_grey, wx.BITMAP_TYPE_ANY)) 121 self.icon_spin_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.spin_grey, wx.BITMAP_TYPE_ANY)) 122 123 # Set the icon list. 124 self.tree.SetImageList(icon_list) 125 126 # Some weird black magic (this is essential)!! 127 self.icon_list = icon_list 128 129 # Populate the tree. 130 self.update() 131 132 # Catch mouse events. 133 self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self._selection) 134 self.tree.Bind(wx.EVT_RIGHT_DOWN, self._right_click)
135 136
137 - def _resize(self, event):
138 """Resize the tree element. 139 140 @param event: The wx event. 141 @type event: wx event 142 """ 143 144 # The panel dimensions. 145 width, height = self.GetClientSizeTuple() 146 147 # Set the tree dimensions. 148 self.tree.SetDimensions(0, 0, width, height)
149 150
151 - def _right_click(self, event):
152 """Handle right clicks in the tree. 153 154 @param event: The wx event. 155 @type event: wx event 156 """ 157 158 # Obtain the position. 159 pos = event.GetPosition() 160 161 # Find the item clicked on. 162 item, flags = self.tree.HitTest(pos) 163 164 # The python data (with catch for wxPython 2.9 behaviour). 165 if not item.IsOk(): 166 self.info = None 167 else: 168 self.info = self.tree.GetItemPyData(item) 169 170 # Bring up the default menu. 171 if self.info == None: 172 self.menu_default() 173 174 # Bring up the root menu. 175 elif self.info == 'root': 176 self.menu_root() 177 178 # Bring up the molecule menu. 179 elif self.info['type'] == 'mol': 180 self.menu_molecule() 181 182 # Bring up the residue menu. 183 elif self.info['type'] == 'res': 184 self.menu_residue() 185 186 # Bring up the spin menu. 187 elif self.info['type'] == 'spin': 188 self.menu_spin()
189 190
191 - def _selection(self, event):
192 """Handle changes in selection in the tree. 193 194 @param event: The wx event. 195 @type event: wx event 196 """ 197 198 # Find the item clicked on. 199 item = event.GetItem() 200 201 # The python data. 202 info = self.tree.GetItemPyData(item) 203 204 # Display the container. 205 self.gui.spin_viewer.container.display(info)
206 207
208 - def action_molecule_molecule_copy(self, event):
209 """Wrapper method. 210 211 @param event: The wx event. 212 @type event: wx event 213 """ 214 215 # Launch the user function wizard. 216 uf_store['molecule.copy'](wx_parent=self.gui.spin_viewer, pipe_from=cdp_name(), mol_from=self.info['id'], pipe_to=cdp_name())
217 218
219 - def action_molecule_molecule_delete(self, event):
220 """Wrapper method. 221 222 @param event: The wx event. 223 @type event: wx event 224 """ 225 226 # Ask if this should be done. 227 msg = "Are you sure you would like to delete this molecule? This only affects the spin data, all structural data will remain. This operation cannot be undone." 228 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False, size=(400, 170)).ShowModal() == wx.ID_NO: 229 return 230 231 # Delete the molecule. 232 self.gui.interpreter.queue('molecule.delete', gui_to_str(self.info['id']))
233 234
235 - def action_molecule_molecule_deselect(self, event):
236 """Wrapper method. 237 238 @param event: The wx event. 239 @type event: wx event 240 """ 241 242 # Ask if this should be done. 243 msg = "Are you sure you would like to deselect all spins of this molecule?" 244 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO: 245 return 246 247 # Deselect the molecule. 248 self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
249 250
251 - def action_molecule_molecule_name(self, event):
252 """Wrapper method. 253 254 @param event: The wx event. 255 @type event: wx event 256 """ 257 258 # Launch the user function wizard. 259 uf_store['molecule.name'](wx_parent=self.gui.spin_viewer, mol_id=self.info['id'])
260 261
262 - def action_molecule_molecule_type(self, event):
263 """Wrapper method. 264 265 @param event: The wx event. 266 @type event: wx event 267 """ 268 269 # Get the current molecule type 270 mol = return_molecule(self.info['id']) 271 type = None 272 if hasattr(mol, 'type'): 273 type = mol.type 274 275 # Launch the user function wizard. 276 if type == None: 277 uf_store['molecule.type'](wx_parent=self.gui.spin_viewer, mol_id=self.info['id']) 278 else: 279 uf_store['molecule.type'](wx_parent=self.gui.spin_viewer, mol_id=self.info['id'], type=type)
280 281
282 - def action_molecule_molecule_select(self, event):
283 """Wrapper method. 284 285 @param event: The wx event. 286 @type event: wx event 287 """ 288 289 # Ask if this should be done. 290 msg = "Are you sure you would like to select all spins of this molecule?" 291 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO: 292 return 293 294 # Select the molecule. 295 self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
296 297
298 - def action_molecule_residue_create(self, event):
299 """Wrapper method. 300 301 @param event: The wx event. 302 @type event: wx event 303 """ 304 305 # Launch the user function wizard. 306 uf_store['residue.create'](wx_parent=self.gui.spin_viewer, mol_name=self.info['mol_name'])
307 308
309 - def action_residue_residue_copy(self, event):
310 """Wrapper method. 311 312 @param event: The wx event. 313 @type event: wx event 314 """ 315 316 # Launch the user function wizard. 317 uf_store['residue.copy'](wx_parent=self.gui.spin_viewer, pipe_from=cdp_name(), res_from=self.info['id'], pipe_to=cdp_name())
318 319
320 - def action_residue_residue_delete(self, event):
321 """Wrapper method. 322 323 @param event: The wx event. 324 @type event: wx event 325 """ 326 327 # Ask if this should be done. 328 msg = "Are you sure you would like to delete this residue? This only affects the spin data, all structural data will remain. This operation cannot be undone." 329 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False, size=(400, 170)).ShowModal() == wx.ID_NO: 330 return 331 332 # Delete the residue. 333 self.gui.interpreter.queue('residue.delete', gui_to_str(self.info['id']))
334 335
336 - def action_residue_residue_deselect(self, event):
337 """Wrapper method. 338 339 @param event: The wx event. 340 @type event: wx event 341 """ 342 343 # Ask if this should be done. 344 msg = "Are you sure you would like to deselect all spins of this residue?" 345 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO: 346 return 347 348 # Deselect the residue. 349 self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
350 351
352 - def action_residue_residue_name(self, event):
353 """Wrapper method. 354 355 @param event: The wx event. 356 @type event: wx event 357 """ 358 359 # Launch the user function wizard. 360 uf_store['residue.name'](wx_parent=self.gui.spin_viewer, res_id=self.info['id'])
361 362
363 - def action_residue_residue_number(self, event):
364 """Wrapper method. 365 366 @param event: The wx event. 367 @type event: wx event 368 """ 369 370 # Launch the user function wizard. 371 uf_store['residue.number'](wx_parent=self.gui.spin_viewer, res_id=self.info['id'])
372 373
374 - def action_residue_residue_select(self, event):
375 """Wrapper method. 376 377 @param event: The wx event. 378 @type event: wx event 379 """ 380 381 # Ask if this should be done. 382 msg = "Are you sure you would like to select all spins of this residue?" 383 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO: 384 return 385 386 # Select the residue. 387 self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
388 389
390 - def action_residue_spin_add(self, event):
391 """Wrapper method. 392 393 @param event: The wx event. 394 @type event: wx event 395 """ 396 397 # Launch the user function wizard. 398 uf_store['spin.create'](wx_parent=self.gui.spin_viewer, mol_name=self.info['mol_name'], res_num=self.info['res_num'], res_name=self.info['res_name'])
399 400
401 - def action_residue_spin_create_pseudo(self, event):
402 """Wrapper method. 403 404 @param event: The wx event. 405 @type event: wx event 406 """ 407 408 # Launch the user function wizard. 409 uf_store['spin.create_pseudo'](wx_parent=self.gui.spin_viewer, res_id=self.info['id'])
410 411
412 - def action_root_molecule_create(self, event):
413 """Wrapper method. 414 415 @param event: The wx event. 416 @type event: wx event 417 """ 418 419 # Launch the user function wizard. 420 uf_store['molecule.create'](wx_parent=self.gui.spin_viewer)
421 422
423 - def action_spin_spin_copy(self, event):
424 """Wrapper method. 425 426 @param event: The wx event. 427 @type event: wx event 428 """ 429 430 # Launch the user function wizard. 431 uf_store['spin.copy'](wx_parent=self.gui.spin_viewer, pipe_from=cdp_name(), spin_from=self.info['id'], pipe_to=cdp_name())
432 433
434 - def action_spin_spin_delete(self, event):
435 """Wrapper method. 436 437 @param event: The wx event. 438 @type event: wx event 439 """ 440 441 # Ask if this should be done. 442 msg = "Are you sure you would like to delete this spin? This only affects the spin data, all structural data will remain. This operation cannot be undone." 443 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False, size=(400, 170)).ShowModal() == wx.ID_NO: 444 return 445 446 # Delete the spin. 447 self.gui.interpreter.queue('spin.delete', gui_to_str(self.info['id']))
448 449
450 - def action_spin_spin_deselect(self, event):
451 """Wrapper method. 452 453 @param event: The wx event. 454 @type event: wx event 455 """ 456 457 # Deselect the spin. 458 self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
459 460
461 - def action_spin_spin_element(self, event):
462 """Wrapper method. 463 464 @param event: The wx event. 465 @type event: wx event 466 """ 467 468 # Get the current spin element. 469 spin = return_spin(self.info['id']) 470 element = None 471 if hasattr(spin, 'element'): 472 element = spin.element 473 474 # Launch the user function wizard. 475 uf_store['spin.element'](wx_parent=self.gui.spin_viewer, spin_id=self.info['id'], element=element)
476 477
478 - def action_spin_spin_name(self, event):
479 """Wrapper method. 480 481 @param event: The wx event. 482 @type event: wx event 483 """ 484 485 # Launch the user function wizard. 486 uf_store['spin.name'](wx_parent=self.gui.spin_viewer, spin_id=self.info['id'])
487 488
489 - def action_spin_spin_number(self, event):
490 """Wrapper method. 491 492 @param event: The wx event. 493 @type event: wx event 494 """ 495 496 # Launch the user function wizard. 497 uf_store['spin.number'](wx_parent=self.gui.spin_viewer, spin_id=self.info['id'])
498 499
500 - def action_spin_spin_select(self, event):
501 """Wrapper method. 502 503 @param event: The wx event. 504 @type event: wx event 505 """ 506 507 # Select the spin. 508 self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
509 510
511 - def get_info(self):
512 """Get the python data structure associated with the current item. 513 514 @return: The dictionary of data. 515 @rtype: dict 516 """ 517 518 # The current item. 519 item = self.tree.GetSelection() 520 521 # No data. 522 if not item.IsOk(): 523 return 524 525 # Return the associated python data. 526 return self.tree.GetItemPyData(item)
527 528
529 - def menu_default(self):
530 """The right click root menu.""" 531 532 # The menu. 533 menu = wx.Menu() 534 535 # The load spins entry. 536 item = build_menu_item(menu, id=self.MENU_ROOT_LOAD_SPINS, text="Load spins", icon=paths.icon_16x16.spin) 537 menu.AppendItem(item) 538 if status.exec_lock.locked(): 539 item.Enable(False) 540 541 # The menu actions. 542 self.Bind(wx.EVT_MENU, self.gui.spin_viewer.load_spins_wizard, id=self.MENU_ROOT_LOAD_SPINS) 543 544 # Show the menu. 545 if status.show_gui: 546 self.PopupMenu(menu) 547 menu.Destroy()
548 549
550 - def menu_molecule(self):
551 """The right click molecule menu.""" 552 553 # Init the item list. 554 items = [] 555 556 # The menu. 557 menu = wx.Menu() 558 559 # Add some menu items for the spin user functions. 560 items.append(build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_COPY, text="&Copy the molecule", icon=fetch_icon("oxygen.actions.list-add"))) 561 items.append(build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_DELETE, text="De&lete the molecule", icon=fetch_icon("oxygen.actions.list-remove"))) 562 items.append(build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_NAME, text="&Name the molecule", icon=fetch_icon("oxygen.actions.edit-rename"))) 563 items.append(build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_TYPE, text="Set the molecule &type", icon=fetch_icon("oxygen.actions.edit-rename"))) 564 items.append(build_menu_item(menu, id=self.MENU_MOLECULE_RESIDUE_CREATE, text="Add a &residue", icon=fetch_icon("oxygen.actions.list-add-relax-blue"))) 565 566 # Add the items and activate them. 567 for item in items: 568 menu.AppendItem(item) 569 if status.exec_lock.locked(): 570 item.Enable(False) 571 572 # Add a separator. 573 menu.AppendSeparator() 574 575 # Selection or deselection. 576 if self.info['select']: 577 item = build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_DESELECT, text="&Deselect", icon=fetch_icon("relax.molecule_grey")) 578 else: 579 item = build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_SELECT, text="&Select", icon=fetch_icon("relax.molecule")) 580 menu.AppendItem(item) 581 if status.exec_lock.locked(): 582 item.Enable(False) 583 584 # The menu actions. 585 self.Bind(wx.EVT_MENU, self.action_molecule_molecule_copy, id=self.MENU_MOLECULE_MOLECULE_COPY) 586 self.Bind(wx.EVT_MENU, self.action_molecule_molecule_delete, id=self.MENU_MOLECULE_MOLECULE_DELETE) 587 self.Bind(wx.EVT_MENU, self.action_molecule_molecule_name, id=self.MENU_MOLECULE_MOLECULE_NAME) 588 self.Bind(wx.EVT_MENU, self.action_molecule_molecule_type, id=self.MENU_MOLECULE_MOLECULE_TYPE) 589 self.Bind(wx.EVT_MENU, self.action_molecule_residue_create, id=self.MENU_MOLECULE_RESIDUE_CREATE) 590 if self.info['select']: 591 self.Bind(wx.EVT_MENU, self.action_molecule_molecule_deselect, id=self.MENU_MOLECULE_MOLECULE_DESELECT) 592 else: 593 self.Bind(wx.EVT_MENU, self.action_molecule_molecule_select, id=self.MENU_MOLECULE_MOLECULE_SELECT) 594 595 # Show the menu. 596 if status.show_gui: 597 self.PopupMenu(menu) 598 menu.Destroy()
599 600
601 - def menu_residue(self):
602 """The right click molecule menu.""" 603 604 # Init the item list. 605 items = [] 606 607 # The menu. 608 menu = wx.Menu() 609 610 # Add some menu items for the spin user functions. 611 items.append(build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_COPY, text="&Copy the residue", icon=fetch_icon("oxygen.actions.list-add"))) 612 items.append(build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_DELETE, text="De&lete the residue", icon=fetch_icon("oxygen.actions.list-remove"))) 613 items.append(build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_NAME, text="&Name the residue", icon=fetch_icon("oxygen.actions.edit-rename"))) 614 items.append(build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_NUMBER, text="N&umber the residue", icon=fetch_icon("oxygen.actions.edit-rename"))) 615 items.append(build_menu_item(menu, id=self.MENU_RESIDUE_SPIN_ADD, text="&Add a spin", icon=fetch_icon("oxygen.actions.list-add-relax-blue"))) 616 items.append(build_menu_item(menu, id=self.MENU_RESIDUE_SPIN_CREATE_PSEUDO, text="Create a &pseudo-atom", icon=fetch_icon("oxygen.actions.list-add-relax-blue"))) 617 618 # Add the items and activate them. 619 for item in items: 620 menu.AppendItem(item) 621 if status.exec_lock.locked(): 622 item.Enable(False) 623 624 # Add a separator. 625 menu.AppendSeparator() 626 627 # Selection or deselection. 628 if self.info['select']: 629 item = build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_DESELECT, text="&Deselect", icon=fetch_icon("relax.residue_grey")) 630 else: 631 item = build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_SELECT, text="&Select", icon=fetch_icon("relax.residue")) 632 menu.AppendItem(item) 633 if status.exec_lock.locked(): 634 item.Enable(False) 635 636 # The menu actions. 637 self.Bind(wx.EVT_MENU, self.action_residue_residue_copy, id=self.MENU_RESIDUE_RESIDUE_COPY) 638 self.Bind(wx.EVT_MENU, self.action_residue_residue_delete, id=self.MENU_RESIDUE_RESIDUE_DELETE) 639 self.Bind(wx.EVT_MENU, self.action_residue_residue_name, id=self.MENU_RESIDUE_RESIDUE_NAME) 640 self.Bind(wx.EVT_MENU, self.action_residue_residue_number, id=self.MENU_RESIDUE_RESIDUE_NUMBER) 641 self.Bind(wx.EVT_MENU, self.action_residue_spin_add, id=self.MENU_RESIDUE_SPIN_ADD) 642 self.Bind(wx.EVT_MENU, self.action_residue_spin_create_pseudo, id=self.MENU_RESIDUE_SPIN_CREATE_PSEUDO) 643 if self.info['select']: 644 self.Bind(wx.EVT_MENU, self.action_residue_residue_deselect, id=self.MENU_RESIDUE_RESIDUE_DESELECT) 645 else: 646 self.Bind(wx.EVT_MENU, self.action_residue_residue_select, id=self.MENU_RESIDUE_RESIDUE_SELECT) 647 648 # Show the menu. 649 if status.show_gui: 650 self.PopupMenu(menu) 651 menu.Destroy()
652 653
654 - def menu_root(self):
655 """The right click root menu.""" 656 657 # Init the item list. 658 items = [] 659 660 # The menu. 661 menu = wx.Menu() 662 663 # Add some menu items for the spin user functions. 664 items.append(build_menu_item(menu, id=self.MENU_ROOT_MOLECULE_CREATE, text="&Add a molecule", icon=fetch_icon("oxygen.actions.list-add-relax-blue"))) 665 items.append(build_menu_item(menu, id=self.MENU_ROOT_LOAD_SPINS, text="&Load spins", icon=paths.icon_16x16.spin)) 666 667 # Add the items and activate them. 668 for item in items: 669 menu.AppendItem(item) 670 if status.exec_lock.locked(): 671 item.Enable(False) 672 673 # The menu actions. 674 self.Bind(wx.EVT_MENU, self.action_root_molecule_create, id=self.MENU_ROOT_MOLECULE_CREATE) 675 self.Bind(wx.EVT_MENU, self.gui.spin_viewer.load_spins_wizard, id=self.MENU_ROOT_LOAD_SPINS) 676 677 # Show the menu. 678 if status.show_gui: 679 self.PopupMenu(menu) 680 menu.Destroy()
681 682
683 - def menu_spin(self):
684 """The right click spin menu.""" 685 686 # Init the item list. 687 items = [] 688 689 # The menu. 690 menu = wx.Menu() 691 692 # Add some menu items for the spin user functions. 693 items.append(build_menu_item(menu, id=self.MENU_SPIN_SPIN_COPY, text="&Copy the spin", icon=fetch_icon("oxygen.actions.list-add"))) 694 items.append(build_menu_item(menu, id=self.MENU_SPIN_SPIN_DELETE, text="De&lete the spin", icon=fetch_icon("oxygen.actions.list-remove"))) 695 items.append(build_menu_item(menu, id=self.MENU_SPIN_SPIN_ELEMENT, text="Set the element &type of the spin", icon=fetch_icon("oxygen.actions.edit-rename"))) 696 items.append(build_menu_item(menu, id=self.MENU_SPIN_SPIN_NAME, text="&Name the spin", icon=fetch_icon("oxygen.actions.edit-rename"))) 697 items.append(build_menu_item(menu, id=self.MENU_SPIN_SPIN_NUMBER, text="N&umber the spin", icon=fetch_icon("oxygen.actions.edit-rename"))) 698 699 # Add the items and activate them. 700 for item in items: 701 menu.AppendItem(item) 702 if status.exec_lock.locked(): 703 item.Enable(False) 704 705 # Add a separator. 706 menu.AppendSeparator() 707 708 # Selection or deselection. 709 if self.info['select']: 710 item = build_menu_item(menu, id=self.MENU_SPIN_SPIN_DESELECT, text="&Deselect", icon=fetch_icon("relax.spin_grey")) 711 else: 712 item = build_menu_item(menu, id=self.MENU_SPIN_SPIN_SELECT, text="&Select", icon=fetch_icon("relax.spin")) 713 menu.AppendItem(item) 714 if status.exec_lock.locked(): 715 item.Enable(False) 716 717 # The menu actions. 718 self.Bind(wx.EVT_MENU, self.action_spin_spin_copy, id=self.MENU_SPIN_SPIN_COPY) 719 self.Bind(wx.EVT_MENU, self.action_spin_spin_delete, id=self.MENU_SPIN_SPIN_DELETE) 720 self.Bind(wx.EVT_MENU, self.action_spin_spin_element, id=self.MENU_SPIN_SPIN_ELEMENT) 721 self.Bind(wx.EVT_MENU, self.action_spin_spin_name, id=self.MENU_SPIN_SPIN_NAME) 722 self.Bind(wx.EVT_MENU, self.action_spin_spin_number, id=self.MENU_SPIN_SPIN_NUMBER) 723 if self.info['select']: 724 self.Bind(wx.EVT_MENU, self.action_spin_spin_deselect, id=self.MENU_SPIN_SPIN_DESELECT) 725 else: 726 self.Bind(wx.EVT_MENU, self.action_spin_spin_select, id=self.MENU_SPIN_SPIN_SELECT) 727 728 # Show the menu. 729 if status.show_gui: 730 self.PopupMenu(menu) 731 menu.Destroy()
732 733
734 - def prune_mol(self):
735 """Remove any molecules which have been deleted.""" 736 737 # Get a list of molecule IDs from the relax data store. 738 mol_ids = get_molecule_ids() 739 740 # Find if the molecule has been removed. 741 prune_list = [] 742 for key in self.tree_ids.keys(): 743 # Get the python data. 744 info = self.tree.GetItemPyData(key) 745 746 # Prune if it has been removed. 747 if info['id'] not in mol_ids: 748 self.tree.Delete(key) 749 self.tree_ids.pop(key)
750 751
752 - def prune_res(self, mol_branch_id, mol_id):
753 """Remove any molecules which have been deleted. 754 755 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object. 756 @type mol_branch_id: TreeItemId 757 @param mol_id: The molecule identification string. 758 @type mol_id: str 759 """ 760 761 # Find if the molecule has been removed. 762 prune_list = [] 763 for key in self.tree_ids[mol_branch_id].keys(): 764 # Get the python data. 765 info = self.tree.GetItemPyData(key) 766 767 # Get the residue. 768 res = return_residue(info['id']) 769 770 # Prune if it has been removed or renamed/renumbered. 771 if res == None or res.name != info['res_name'] or res.num != info['res_num']: 772 self.tree.Delete(key) 773 self.tree_ids[mol_branch_id].pop(key)
774 775
776 - def prune_spin(self, mol_branch_id, res_branch_id, res_id):
777 """Remove any spins which have been deleted. 778 779 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object. 780 @type mol_branch_id: TreeItemId 781 @param res_branch_id: The residue branch ID of the wx.TreeCtrl object. 782 @type res_branch_id: TreeItemId 783 @param res_id: The residue identification string. 784 @type res_id: str 785 """ 786 787 # Find if the molecule has been removed. 788 prune_list = [] 789 for key in self.tree_ids[mol_branch_id][res_branch_id].keys(): 790 # Get the python data. 791 info = self.tree.GetItemPyData(key) 792 793 # Get the spin. 794 spin = return_spin(info['id']) 795 796 # Prune if it has been removed or renamed/renumbered. 797 if spin == None or spin.name != info['spin_name'] or spin.num != info['spin_num']: 798 self.tree.Delete(key) 799 self.tree_ids[mol_branch_id][res_branch_id].pop(key)
800 801
802 - def set_bitmap_mol(self, mol_branch_id, select=True):
803 """Set the molecule bitmaps. 804 805 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object. 806 @type mol_branch_id: TreeItemId 807 @keyword select: The selection flag. 808 @type select: bool 809 """ 810 811 # The bitmaps for the selected state. 812 if select: 813 bmp = self.icon_mol_index 814 bmp_unfold = self.icon_mol_unfold_index 815 816 # The bitmaps for the deselected state. 817 else: 818 bmp = self.icon_mol_index_desel 819 bmp_unfold = self.icon_mol_unfold_index_desel 820 821 # Set the image. 822 self.tree.SetItemImage(mol_branch_id, bmp, wx.TreeItemIcon_Normal) 823 self.tree.SetItemImage(mol_branch_id, bmp_unfold, wx.TreeItemIcon_Expanded)
824 825
826 - def set_bitmap_res(self, res_branch_id, select=True):
827 """Set the residue bitmaps. 828 829 @param res_branch_id: The residue branch ID of the wx.TreeCtrl object. 830 @type res_branch_id: TreeItemId 831 @keyword select: The selection flag. 832 @type select: bool 833 """ 834 835 # The bitmaps for the selected state. 836 if select: 837 bmp = self.icon_res_index 838 839 # The bitmaps for the deselected state. 840 else: 841 bmp = self.icon_res_index_desel 842 843 # Set the image. 844 self.tree.SetItemImage(res_branch_id, bmp, wx.TreeItemIcon_Normal & wx.TreeItemIcon_Expanded)
845 846
847 - def set_bitmap_spin(self, spin_branch_id, select=True):
848 """Set the spin bitmaps. 849 850 @param spin_branch_id: The spin branch ID of the wx.TreeCtrl object. 851 @type spin_branch_id: TreeItemId 852 @keyword select: The selection flag. 853 @type select: bool 854 """ 855 856 # The bitmaps for the selected state. 857 if select: 858 bmp = self.icon_spin_index 859 860 # The bitmaps for the deselected state. 861 else: 862 bmp = self.icon_spin_index_desel 863 864 # Set the image. 865 self.tree.SetItemImage(spin_branch_id, bmp, wx.TreeItemIcon_Normal & wx.TreeItemIcon_Expanded)
866 867
868 - def update(self, pipe_name=None):
869 """Update the tree view using the given data pipe.""" 870 871 # Acquire the pipe and spin locks. 872 status.pipe_lock.acquire('spin viewer window') 873 status.spin_lock.acquire('spin viewer window') 874 try: 875 # The data pipe. 876 if not pipe_name: 877 pipe = cdp 878 else: 879 pipe = get_pipe(pipe_name) 880 881 # No data pipe, so delete everything and return. 882 if not pipe: 883 self.tree.DeleteChildren(self.root) 884 return 885 886 # Update the molecules. 887 for mol, mol_id in molecule_loop(return_id=True): 888 self.update_mol(mol, mol_id) 889 890 # Remove any deleted molecules. 891 self.prune_mol() 892 893 # Release the locks. 894 finally: 895 status.pipe_lock.release('spin viewer window') 896 status.spin_lock.release('spin viewer window')
897 898
899 - def update_mol(self, mol, mol_id):
900 """Update the given molecule in the tree. 901 902 @param mol: The molecule container. 903 @type mol: MoleculeContainer instance 904 @param mol_id: The molecule identification string. 905 @type mol_id: str 906 """ 907 908 # Find the molecule, if it already exists. 909 new_mol = True 910 for key in self.tree_ids.keys(): 911 # Get the python data. 912 data = self.tree.GetItemPyData(key) 913 914 # Check the mol_id for a match and, if so, terminate to speed things up. 915 if mol_id == data['id']: 916 new_mol = False 917 mol_branch_id = key 918 break 919 920 # A new molecule. 921 if new_mol: 922 # Append a molecule with name to the tree. 923 mol_branch_id = self.tree.AppendItem(self.root, "Molecule: %s" % mol.name) 924 925 # The data to store. 926 data = { 927 'type': 'mol', 928 'mol_name': mol.name, 929 'id': mol_id, 930 'select': is_mol_selected(mol_id) 931 } 932 self.tree.SetPyData(mol_branch_id, data) 933 934 # Add the id to the tracking structure. 935 self.tree_ids[mol_branch_id] = {} 936 937 # Set the bitmap. 938 self.set_bitmap_mol(mol_branch_id, select=data['select']) 939 940 # An old molecule. 941 else: 942 # Check the selection state. 943 select = is_mol_selected(data['id']) 944 945 # Change of state. 946 if select != data['select']: 947 # Store the new state. 948 data['select'] = select 949 950 # Set the bitmap. 951 self.set_bitmap_mol(mol_branch_id, select=data['select']) 952 953 # Update the residues of this molecule. 954 for res, res_id in residue_loop(mol_id, return_id=True): 955 self.update_res(mol_branch_id, mol, res, res_id) 956 957 # Start new molecules expanded. 958 if new_mol and data['select']: 959 self.tree.Expand(mol_branch_id) 960 961 # Remove any deleted residues. 962 self.prune_res(mol_branch_id, mol_id) 963 964 # Expand the root. 965 self.tree.Expand(self.root)
966 967
968 - def update_res(self, mol_branch_id, mol, res, res_id):
969 """Update the given residue in the tree. 970 971 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object. 972 @type mol_branch_id: TreeItemId 973 @param mol: The molecule container. 974 @type mol: MoleculeContainer instance 975 @param res: The residue container. 976 @type res: ResidueContainer instance 977 @param res_id: The residue identification string. 978 @type res_id: str 979 """ 980 981 # Find the residue, if it already exists. 982 new_res = True 983 for key in self.tree_ids[mol_branch_id].keys(): 984 # Get the python data. 985 data = self.tree.GetItemPyData(key) 986 987 # Check the res_id, res name, and res number for a match and, if so, terminate to speed things up. 988 if res_id == data['id'] and res.name == data['res_name'] and res.num == data['res_num']: 989 new_res = False 990 res_branch_id = key 991 break 992 993 # A new residue. 994 if new_res: 995 # Append a residue with name and number to the tree. 996 res_branch_id = self.tree.AppendItem(mol_branch_id, "Residue: %s %s" % (res.num, res.name)) 997 998 # The data to store. 999 data = { 1000 'type': 'res', 1001 'mol_name': mol.name, 1002 'res_name': res.name, 1003 'res_num': res.num, 1004 'id': res_id, 1005 'select': is_res_selected(res_id) 1006 } 1007 self.tree.SetPyData(res_branch_id, data) 1008 1009 # Add the id to the tracking structure. 1010 self.tree_ids[mol_branch_id][res_branch_id] = {} 1011 1012 # Set the bitmap. 1013 self.set_bitmap_res(res_branch_id, select=data['select']) 1014 1015 # An old residue. 1016 else: 1017 # Check the selection state. 1018 select = is_res_selected(data['id']) 1019 1020 # Change of state. 1021 if select != data['select']: 1022 # Store the new state. 1023 data['select'] = select 1024 1025 # Set the bitmap. 1026 self.set_bitmap_res(res_branch_id, select=data['select']) 1027 1028 # Update the spins of this residue. 1029 for spin, spin_id in spin_loop(res_id, return_id=True): 1030 self.update_spin(mol_branch_id, res_branch_id, mol, res, spin, spin_id) 1031 1032 # Start new residues expanded. 1033 if new_res and data['select']: 1034 self.tree.Expand(res_branch_id) 1035 1036 # Remove any deleted spins. 1037 self.prune_spin(mol_branch_id, res_branch_id, res_id)
1038 1039
1040 - def update_spin(self, mol_branch_id, res_branch_id, mol, res, spin, spin_id):
1041 """Update the given spin in the tree. 1042 1043 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object. 1044 @type mol_branch_id: TreeItemId 1045 @param res_branch_id: The residue branch ID of the wx.TreeCtrl object. 1046 @type res_branch_id: TreeItemId 1047 @param mol: The molecule container. 1048 @type mol: MoleculeContainer instance 1049 @param res: The residue container. 1050 @type res: ResidueContainer instance 1051 @param spin: The spin container. 1052 @type spin: SpinContainer instance 1053 @param spin_id: The spin identification string. 1054 @type spin_id: str 1055 """ 1056 1057 # Find the spin, if it already exists. 1058 new_spin = True 1059 for key in self.tree_ids[mol_branch_id][res_branch_id].keys(): 1060 # Get the python data. 1061 data = self.tree.GetItemPyData(key) 1062 1063 # Check the spin_id, spin name and spin number for a match and, if so, terminate to speed things up. 1064 if spin_id == data['id'] and spin.name == data['spin_name'] and spin.num == data['spin_num']: 1065 new_spin = False 1066 spin_branch_id = key 1067 break 1068 1069 # A new spin. 1070 if new_spin: 1071 # Append a spin with name and number to the tree. 1072 spin_branch_id = self.tree.AppendItem(res_branch_id, "Spin: %s %s" % (spin.num, spin.name)) 1073 1074 # The data to store. 1075 data = { 1076 'type': 'spin', 1077 'mol_name': mol.name, 1078 'res_name': res.name, 1079 'res_num': res.num, 1080 'spin_name': spin.name, 1081 'spin_num': spin.num, 1082 'id': spin_id, 1083 'select': is_spin_selected(spin_id) 1084 } 1085 self.tree.SetPyData(spin_branch_id, data) 1086 1087 # Add the id to the tracking structure. 1088 self.tree_ids[mol_branch_id][res_branch_id][spin_branch_id] = True 1089 1090 # Set the bitmap. 1091 self.set_bitmap_spin(spin_branch_id, select=data['select']) 1092 1093 # An old spin. 1094 else: 1095 # Check the selection state. 1096 select = is_spin_selected(data['id']) 1097 1098 # Change of state. 1099 if select != data['select']: 1100 # Store the new state. 1101 data['select'] = select 1102 1103 # Set the bitmap. 1104 self.set_bitmap_spin(spin_branch_id, select=data['select']) 1105 1106 # Start new spins expanded. 1107 if new_spin and data['select']: 1108 self.tree.Expand(spin_branch_id)
1109