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