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