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