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