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   
  42      """The tree view class.""" 
  43   
  44       
  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           
  82          self.gui = gui 
  83          self.parent = parent 
  84   
  85           
  86          wx.Window.__init__(self, parent, id, style=wx.WANTS_CHARS) 
  87   
  88           
  89          self.icon_size = 22 
  90   
  91           
  92          self.tree = wx.TreeCtrl(parent=self, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE) 
  93   
  94           
  95          self.tree_ids = {} 
  96   
  97           
  98          self.Bind(wx.EVT_SIZE, self._resize) 
  99   
 100           
 101          self.root = self.tree.AddRoot("Spin system information") 
 102          self.tree.SetPyData(self.root, "root") 
 103   
 104           
 105          icon_list = wx.ImageList(self.icon_size, self.icon_size) 
 106   
 107           
 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           
 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           
 120          self.tree.SetImageList(icon_list) 
 121   
 122           
 123          self.icon_list = icon_list 
 124   
 125           
 126          self.update() 
 127   
 128           
 129          self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self._selection) 
 130          self.tree.Bind(wx.EVT_RIGHT_DOWN, self._right_click) 
  131   
 132   
 134          """Resize the tree element. 
 135   
 136          @param event:   The wx event. 
 137          @type event:    wx event 
 138          """ 
 139   
 140           
 141          width, height = self.GetClientSizeTuple() 
 142   
 143           
 144          self.tree.SetDimensions(0, 0, width, height) 
  145   
 146   
 148          """Handle right clicks in the tree. 
 149   
 150          @param event:   The wx event. 
 151          @type event:    wx event 
 152          """ 
 153   
 154           
 155          pos = event.GetPosition() 
 156   
 157           
 158          item, flags = self.tree.HitTest(pos) 
 159   
 160           
 161          if not item.IsOk(): 
 162              self.info = None 
 163          else: 
 164              self.info = self.tree.GetItemPyData(item) 
 165   
 166           
 167          if self.info == None: 
 168              self.menu_default() 
 169   
 170           
 171          elif self.info == 'root': 
 172              self.menu_root() 
 173   
 174           
 175          elif self.info['type'] == 'mol': 
 176              self.menu_molecule() 
 177   
 178           
 179          elif self.info['type'] == 'res': 
 180              self.menu_residue() 
 181   
 182           
 183          elif self.info['type'] == 'spin': 
 184              self.menu_spin() 
  185   
 186   
 188          """Handle changes in selection in the tree. 
 189   
 190          @param event:   The wx event. 
 191          @type event:    wx event 
 192          """ 
 193   
 194           
 195          item = event.GetItem() 
 196   
 197           
 198          info = self.tree.GetItemPyData(item) 
 199   
 200           
 201          self.gui.spin_viewer.container.display(info) 
  202   
 203   
 205          """Wrapper method. 
 206   
 207          @param event:   The wx event. 
 208          @type event:    wx event 
 209          """ 
 210   
 211           
 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   
 216          """Wrapper method. 
 217   
 218          @param event:   The wx event. 
 219          @type event:    wx event 
 220          """ 
 221   
 222           
 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           
 228          self.gui.interpreter.queue('molecule.delete', gui_to_str(self.info['id'])) 
  229   
 230   
 232          """Wrapper method. 
 233   
 234          @param event:   The wx event. 
 235          @type event:    wx event 
 236          """ 
 237   
 238           
 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           
 244          self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False) 
  245   
 246   
 248          """Wrapper method. 
 249   
 250          @param event:   The wx event. 
 251          @type event:    wx event 
 252          """ 
 253   
 254           
 255          uf_store['molecule.name'](wx_parent=self.gui.spin_viewer, mol_id=self.info['id']) 
  256   
 257   
 276   
 277   
 279          """Wrapper method. 
 280   
 281          @param event:   The wx event. 
 282          @type event:    wx event 
 283          """ 
 284   
 285           
 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           
 291          self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False) 
  292   
 293   
 295          """Wrapper method. 
 296   
 297          @param event:   The wx event. 
 298          @type event:    wx event 
 299          """ 
 300   
 301           
 302          uf_store['residue.create'](wx_parent=self.gui.spin_viewer, mol_name=self.info['mol_name']) 
  303   
 304   
 306          """Wrapper method. 
 307   
 308          @param event:   The wx event. 
 309          @type event:    wx event 
 310          """ 
 311   
 312           
 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   
 317          """Wrapper method. 
 318   
 319          @param event:   The wx event. 
 320          @type event:    wx event 
 321          """ 
 322   
 323           
 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           
 329          self.gui.interpreter.queue('residue.delete', gui_to_str(self.info['id'])) 
  330   
 331   
 333          """Wrapper method. 
 334   
 335          @param event:   The wx event. 
 336          @type event:    wx event 
 337          """ 
 338   
 339           
 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           
 345          self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False) 
  346   
 347   
 349          """Wrapper method. 
 350   
 351          @param event:   The wx event. 
 352          @type event:    wx event 
 353          """ 
 354   
 355           
 356          uf_store['residue.name'](wx_parent=self.gui.spin_viewer, res_id=self.info['id']) 
  357   
 358   
 360          """Wrapper method. 
 361   
 362          @param event:   The wx event. 
 363          @type event:    wx event 
 364          """ 
 365   
 366           
 367          uf_store['residue.number'](wx_parent=self.gui.spin_viewer, res_id=self.info['id']) 
  368   
 369   
 371          """Wrapper method. 
 372   
 373          @param event:   The wx event. 
 374          @type event:    wx event 
 375          """ 
 376   
 377           
 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           
 383          self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False) 
  384   
 385   
 387          """Wrapper method. 
 388   
 389          @param event:   The wx event. 
 390          @type event:    wx event 
 391          """ 
 392   
 393           
 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   
 398          """Wrapper method. 
 399   
 400          @param event:   The wx event. 
 401          @type event:    wx event 
 402          """ 
 403   
 404           
 405          uf_store['spin.create_pseudo'](wx_parent=self.gui.spin_viewer, res_id=self.info['id']) 
  406   
 407   
 409          """Wrapper method. 
 410   
 411          @param event:   The wx event. 
 412          @type event:    wx event 
 413          """ 
 414   
 415           
 416          uf_store['molecule.create'](wx_parent=self.gui.spin_viewer) 
  417   
 418   
 420          """Wrapper method. 
 421   
 422          @param event:   The wx event. 
 423          @type event:    wx event 
 424          """ 
 425   
 426           
 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   
 431          """Wrapper method. 
 432   
 433          @param event:   The wx event. 
 434          @type event:    wx event 
 435          """ 
 436   
 437           
 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           
 443          self.gui.interpreter.queue('spin.delete', gui_to_str(self.info['id'])) 
  444   
 445   
 447          """Wrapper method. 
 448   
 449          @param event:   The wx event. 
 450          @type event:    wx event 
 451          """ 
 452   
 453           
 454          self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False) 
  455   
 456   
 458          """Wrapper method. 
 459   
 460          @param event:   The wx event. 
 461          @type event:    wx event 
 462          """ 
 463   
 464           
 465          spin = return_spin(self.info['id']) 
 466          element = None 
 467          if hasattr(spin, 'element'): 
 468              element = spin.element 
 469   
 470           
 471          uf_store['spin.element'](wx_parent=self.gui.spin_viewer, spin_id=self.info['id'], element=element) 
  472   
 473   
 475          """Wrapper method. 
 476   
 477          @param event:   The wx event. 
 478          @type event:    wx event 
 479          """ 
 480   
 481           
 482          uf_store['spin.name'](wx_parent=self.gui.spin_viewer, spin_id=self.info['id']) 
  483   
 484   
 486          """Wrapper method. 
 487   
 488          @param event:   The wx event. 
 489          @type event:    wx event 
 490          """ 
 491   
 492           
 493          uf_store['spin.number'](wx_parent=self.gui.spin_viewer, spin_id=self.info['id']) 
  494   
 495   
 497          """Wrapper method. 
 498   
 499          @param event:   The wx event. 
 500          @type event:    wx event 
 501          """ 
 502   
 503           
 504          self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False) 
  505   
 506   
 508          """Get the python data structure associated with the current item. 
 509   
 510          @return:    The dictionary of data. 
 511          @rtype:     dict 
 512          """ 
 513   
 514           
 515          item = self.tree.GetSelection() 
 516   
 517           
 518          if not item.IsOk(): 
 519              return 
 520   
 521           
 522          return self.tree.GetItemPyData(item) 
  523   
 524   
 544   
 545   
 547          """The right click molecule menu.""" 
 548   
 549           
 550          items = [] 
 551   
 552           
 553          menu = wx.Menu() 
 554   
 555           
 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           
 563          for item in items: 
 564              menu.AppendItem(item) 
 565              if status.exec_lock.locked(): 
 566                  item.Enable(False) 
 567   
 568           
 569          menu.AppendSeparator() 
 570   
 571           
 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           
 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           
 592          if status.show_gui: 
 593              self.PopupMenu(menu) 
 594              menu.Destroy() 
  595   
 596   
 598          """The right click molecule menu.""" 
 599   
 600           
 601          items = [] 
 602   
 603           
 604          menu = wx.Menu() 
 605   
 606           
 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           
 615          for item in items: 
 616              menu.AppendItem(item) 
 617              if status.exec_lock.locked(): 
 618                  item.Enable(False) 
 619   
 620           
 621          menu.AppendSeparator() 
 622   
 623           
 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           
 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           
 645          if status.show_gui: 
 646              self.PopupMenu(menu) 
 647              menu.Destroy() 
  648   
 649   
 651          """The right click root menu.""" 
 652   
 653           
 654          items = [] 
 655   
 656           
 657          menu = wx.Menu() 
 658   
 659           
 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           
 664          for item in items: 
 665              menu.AppendItem(item) 
 666              if status.exec_lock.locked(): 
 667                  item.Enable(False) 
 668   
 669           
 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           
 674          if status.show_gui: 
 675              self.PopupMenu(menu) 
 676              menu.Destroy() 
  677   
 678   
 680          """The right click spin menu.""" 
 681   
 682           
 683          items = [] 
 684   
 685           
 686          menu = wx.Menu() 
 687   
 688           
 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           
 696          for item in items: 
 697              menu.AppendItem(item) 
 698              if status.exec_lock.locked(): 
 699                  item.Enable(False) 
 700   
 701           
 702          menu.AppendSeparator() 
 703   
 704           
 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           
 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           
 725          if status.show_gui: 
 726              self.PopupMenu(menu) 
 727              menu.Destroy() 
  728   
 729   
 731          """Remove any molecules which have been deleted.""" 
 732   
 733           
 734          mol_ids = get_molecule_ids() 
 735   
 736           
 737          prune_list = [] 
 738          for key in self.tree_ids.keys(): 
 739               
 740              info = self.tree.GetItemPyData(key) 
 741   
 742               
 743              if info['id'] not in mol_ids: 
 744                  self.tree.Delete(key) 
 745                  self.tree_ids.pop(key) 
  746   
 747   
 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           
 758          prune_list = [] 
 759          for key in self.tree_ids[mol_branch_id].keys(): 
 760               
 761              info = self.tree.GetItemPyData(key) 
 762   
 763               
 764              res = return_residue(info['id']) 
 765   
 766               
 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           
 784          prune_list = [] 
 785          for key in self.tree_ids[mol_branch_id][res_branch_id].keys(): 
 786               
 787              info = self.tree.GetItemPyData(key) 
 788   
 789               
 790              spin = return_spin(info['id']) 
 791   
 792               
 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   
 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           
 808          if select: 
 809              bmp = self.icon_mol_index 
 810              bmp_unfold = self.icon_mol_unfold_index 
 811   
 812           
 813          else: 
 814              bmp = self.icon_mol_index_desel 
 815              bmp_unfold = self.icon_mol_unfold_index_desel 
 816   
 817           
 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   
 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           
 832          if select: 
 833              bmp = self.icon_res_index 
 834   
 835           
 836          else: 
 837              bmp = self.icon_res_index_desel 
 838   
 839           
 840          self.tree.SetItemImage(res_branch_id, bmp, wx.TreeItemIcon_Normal & wx.TreeItemIcon_Expanded) 
  841   
 842   
 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           
 853          if select: 
 854              bmp = self.icon_spin_index 
 855   
 856           
 857          else: 
 858              bmp = self.icon_spin_index_desel 
 859   
 860           
 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           
 868          status.pipe_lock.acquire('spin viewer window') 
 869          status.spin_lock.acquire('spin viewer window') 
 870          try: 
 871               
 872              if not pipe_name: 
 873                  pipe = cdp 
 874              else: 
 875                  pipe = get_pipe(pipe_name) 
 876   
 877               
 878              if not pipe: 
 879                  self.tree.DeleteChildren(self.root) 
 880                  return 
 881   
 882               
 883              for mol, mol_id in molecule_loop(return_id=True): 
 884                  self.update_mol(mol, mol_id) 
 885   
 886               
 887              self.prune_mol() 
 888   
 889           
 890          finally: 
 891              status.pipe_lock.release('spin viewer window') 
 892              status.spin_lock.release('spin viewer window') 
  893   
 894   
 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           
 905          new_mol = True 
 906          for key in self.tree_ids.keys(): 
 907               
 908              data = self.tree.GetItemPyData(key) 
 909   
 910               
 911              if mol_id == data['id']: 
 912                  new_mol = False 
 913                  mol_branch_id = key 
 914                  break 
 915   
 916           
 917          if new_mol: 
 918               
 919              mol_branch_id = self.tree.AppendItem(self.root, "Molecule: %s" % mol.name) 
 920   
 921               
 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               
 931              self.tree_ids[mol_branch_id] = {} 
 932   
 933               
 934              self.set_bitmap_mol(mol_branch_id, select=data['select']) 
 935   
 936           
 937          else: 
 938               
 939              select = is_mol_selected(data['id']) 
 940   
 941               
 942              if select != data['select']: 
 943                   
 944                  data['select'] = select 
 945   
 946                   
 947                  self.set_bitmap_mol(mol_branch_id, select=data['select']) 
 948   
 949           
 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           
 954          if new_mol and data['select']: 
 955              self.tree.Expand(mol_branch_id) 
 956   
 957           
 958          self.prune_res(mol_branch_id, mol_id) 
 959   
 960           
 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           
 978          new_res = True 
 979          for key in self.tree_ids[mol_branch_id].keys(): 
 980               
 981              data = self.tree.GetItemPyData(key) 
 982   
 983               
 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           
 990          if new_res: 
 991               
 992              res_branch_id = self.tree.AppendItem(mol_branch_id, "Residue: %s %s" % (res.num, res.name)) 
 993   
 994               
 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               
1006              self.tree_ids[mol_branch_id][res_branch_id] = {} 
1007   
1008               
1009              self.set_bitmap_res(res_branch_id, select=data['select']) 
1010   
1011           
1012          else: 
1013               
1014              select = is_res_selected(data['id']) 
1015   
1016               
1017              if select != data['select']: 
1018                   
1019                  data['select'] = select 
1020   
1021                   
1022                  self.set_bitmap_res(res_branch_id, select=data['select']) 
1023   
1024           
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           
1029          if new_res and data['select']: 
1030              self.tree.Expand(res_branch_id) 
1031   
1032           
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           
1054          new_spin = True 
1055          for key in self.tree_ids[mol_branch_id][res_branch_id].keys(): 
1056               
1057              data = self.tree.GetItemPyData(key) 
1058   
1059               
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           
1066          if new_spin: 
1067               
1068              spin_branch_id = self.tree.AppendItem(res_branch_id, "Spin: %s %s" % (spin.num, spin.name)) 
1069   
1070               
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               
1084              self.tree_ids[mol_branch_id][res_branch_id][spin_branch_id] = True 
1085   
1086               
1087              self.set_bitmap_spin(spin_branch_id, select=data['select']) 
1088   
1089           
1090          else: 
1091               
1092              select = is_spin_selected(data['id']) 
1093   
1094               
1095              if select != data['select']: 
1096                   
1097                  data['select'] = select 
1098   
1099                   
1100                  self.set_bitmap_spin(spin_branch_id, select=data['select']) 
1101   
1102           
1103          if new_spin and data['select']: 
1104              self.tree.Expand(spin_branch_id) 
  1105