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