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