summaryrefslogtreecommitdiff
path: root/cad/src/outtakes/MMKit.py
blob: 9d5607e4afb7dc4a23f79133732ede4c46def81c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
# Copyright 2004-2007 Nanorex, Inc.  See LICENSE file for details.
"""
MMKit.py

THIS FILE HAS BEEN DEPRECATED.

SEE NEW IMPLEMETATION IN --
Ui_BuildAtomsPropertyManager.py,
BuildAtomsPropertyManager.py,
Ui_PartLibPropertyManager.py,
PartLibPropertyManager.py,
Ui_PastePropertyManager.py
PastePropertyManager.py


$Id$

History:

Created by Huaicai.

Modified by several developers since then.

ninad 20070716: Code cleanup to make mmkit a propMgr object in deposit mode
instead of being inherited by that mode.


"""

import os, sys

from PyQt4 import QtGui
from PyQt4.Qt import Qt
from PyQt4.Qt import QDialog, SIGNAL, QIcon, QVBoxLayout, QStringList, QFileDialog
from PyQt4.Qt import QDir, QTreeView, QTreeWidgetItem, QAbstractItemDelegate, QWhatsThis

from MMKitDialog import Ui_MMKitDialog
from graphics.widgets.ThumbView import MMKitView, ChunkView
from model.elements import PeriodicTable
from utilities.constants import diTUBES
## from model.chem import Atom [not used i think - bruce 071113]
## from model.chunk import Chunk [not used i think - bruce 071113]
from foundation.Utility import imagename_to_icon, geticon
from model.assembly import Assembly
from files.mmp.files_mmp import readmmp
from model.part import Part
import foundation.env as env
from utilities import debug_flags
from utilities.debug import print_compact_traceback
from sponsors.Sponsors import SponsorableMixin
from PropertyManagerMixin import PropertyManagerMixin, pmSetPropMgrIcon, pmSetPropMgrTitle
from PM.PropMgr_Constants import pmMMKitPageMargin
from model.bond_constants import btype_from_v6

# PageId constants for mmkit_tab
AtomsPage = 0
ClipboardPage = 1
LibraryPage = 2

noblegases = ["He", "Ne", "Ar", "Kr"] # Mark 2007-05-31

# debugging flags -- do not commit with True
debug_mmkit_events = False

class MMKit(QDialog,
            Ui_MMKitDialog,
            PropertyManagerMixin,
            SponsorableMixin):
    """
    THIS CLASS HAS BEEN DEPRECATED.
    SEE NEW IMPLEMETATION IN--
    Ui_BuildAtomsPropertyManager.py,
    BuildAtomsPropertyManager.py,
    Ui_PartLibPropertyManager.py,
    PartLibPropertyManager.py,
    Ui_PastePropertyManager.py
    PastePropertyManager.py

    Provide the MMKit PM for Build Atoms mode.
    """
    # <title> - the title that appears in the property manager header.
    title = "Build Atoms"
    # <iconPath> - full path to PNG file that appears in the header.
    iconPath = "ui/actions/Tools/Build Structures/Build Atoms.png"

    bond_id2name =['sp3', 'sp2', 'sp', 'sp2(graphitic)']
    sponsor_keyword = 'Build'

    def __init__(self, parentMode, win):
        QDialog.__init__(self, win, Qt.Dialog)# Qt.WStyle_Customize | Qt.WStyle_Tool | Qt.WStyle_Title | Qt.WStyle_NoBorder)

        self.w = win
        self.o = self.w.glpane

        #@NOTE: As of 20070717, MMKit supports only depositMode as its parent
        #(and perhaps subclasses of depositMode ..but such a class that also
        #uses MMKit is NIY so it is unconfirmed)  -- ninad
        self.parentMode = parentMode

        self.setupUi(self)

        # setupUi() did not add the icon or title. We do that here.
        pmSetPropMgrIcon( self, self.iconPath )
        pmSetPropMgrTitle( self, self.title )

        #self.connect(self.hybrid_btngrp,SIGNAL("buttonClicked(int)"),self.set_hybrid_type)

        self.pw = None # pw = partwindow

        self.connect(self.mmkit_tab,
                     SIGNAL("currentChanged(int)"),
                     self.tabCurrentChanged)

        self.connect(self.chunkListBox,
                     SIGNAL("currentItemChanged(QListWidgetItem*,QListWidgetItem*)"),
                     self.chunkChanged)
        self.connect(self.browseButton,
                     SIGNAL("clicked(bool)"),
                     self.browseDirectories)
        self.connect(self.defaultPartLibButton,
                     SIGNAL("clicked(bool)"),
                     self.useDefaultPartLibDirectory)

        #self.connect(self.elementButtonGroup,SIGNAL("buttonClicked(int)"),self.setElementInfo)

        self.connect(self.thumbView_groupBoxButton, SIGNAL("clicked()"),
                     self.toggle_thumbView_groupBox)
        self.connect(self.bondTool_groupBoxButton , SIGNAL("clicked()"),
                     self.toggle_bondTool_groupBox)
        self.connect(self.MMKitGrpBox_TitleButton, SIGNAL("clicked()"),
                     self.toggle_MMKit_groupBox)
        self.connect(self.filterCB, SIGNAL("stateChanged(int)"),
                     self.toggle_selectionFilter_groupBox)
        self.connect(self.advancedOptions_groupBoxButton, SIGNAL("clicked()"),
                     self.toggle_advancedOptions_groupBox)

        # Make the elements act like a big exclusive radio button.
        self.theElements = QtGui.QButtonGroup()
        self.theElements.setExclusive(True)
        self.theElements.addButton(self.toolButton1, 1)
        self.theElements.addButton(self.toolButton2, 2)
        self.theElements.addButton(self.toolButton6, 6)
        self.theElements.addButton(self.toolButton7, 7)
        self.theElements.addButton(self.toolButton8, 8)
        self.theElements.addButton(self.toolButton10, 10)
        self.theElements.addButton(self.toolButton9, 9)
        self.theElements.addButton(self.toolButton13,13)
        self.theElements.addButton(self.toolButton17,17)
        self.theElements.addButton(self.toolButton5, 5)
        self.theElements.addButton(self.toolButton10_2, 18)
        self.theElements.addButton(self.toolButton15, 15)
        self.theElements.addButton(self.toolButton16, 16)
        self.theElements.addButton(self.toolButton14, 14)
        self.theElements.addButton(self.toolButton33, 33)
        self.theElements.addButton(self.toolButton34, 34)
        self.theElements.addButton(self.toolButton35, 35)
        self.theElements.addButton(self.toolButton32, 32)
        self.theElements.addButton(self.toolButton36, 36)
        self.connect(self.theElements, SIGNAL("buttonPressed(int)"), self.update_dialog)

        self.theHybridizations = QtGui.QButtonGroup()
        self.theHybridizations.setExclusive(True)
        self.theHybridizations.addButton(self.sp3_btn, 0)
        self.theHybridizations.addButton(self.sp2_btn, 1)
        self.theHybridizations.addButton(self.sp_btn, 2)
        self.theHybridizations.addButton(self.graphitic_btn, 3)
        self.connect(self.theHybridizations, SIGNAL("buttonClicked(int)"), self.update_hybrid_btngrp)

        self.connect(self.filterCB,
                        SIGNAL("toggled(bool)"),self.set_selection_filter)


        self.elemTable = PeriodicTable
        self.displayMode = diTUBES
        self.elm = None

        self.newModel = None  ## used to save the selected lib part

        self.flayout = None

        # It looks like we now have correct fixes for bugs 1659 and bug 1824. If so, it would be safe to simply
        # hardware self.icon_tabs to True and simplify code accordingly. But we're not 100% certain, so by leaving
        # it as a debug pref, we can help any users who see those bugs come up again.
        # wware 060420
        #
        # Update, bruce 070328: the False value of this debug_pref is known to fail in the Qt4 version (on Mac anyway),
        # due to AttributeError exceptions for setMargin and setTabLabel,
        # so I'm changing the prefs key for it in order to let Qt3 and Qt4 have independent debug_pref settings,
        # adding a warning in the menu text, and adding a try/except to help in debugging this if anyone ever wants to.
        # (If the bugs Will mentioned go away entirely, we can abandon support for the False value instead of fixing it,
        #  as Will suggested.)
        from utilities.debug_prefs import debug_pref, Choice_boolean_True
        self.icon_tabs = debug_pref("use icons in MMKit tabs? (only True works in Qt4)", Choice_boolean_True,
                                    prefs_key = "A7/mmkit tab icons/Qt4")
            #e Changes to this only take effect in the next session.
            # Ideally we'd add a history message about that, when this is changed.
            # (It's not yet easy to do that in a supported way in debug_pref.) [bruce 060313]

        if not self.icon_tabs:
            # This code is known to fail in Qt4 Mac version, as explained above. [bruce 061222 and 070328]
            try:
                self.mmkit_tab.setMargin ( 0 )
            except:
                print_compact_traceback("ignoring this Qt4-specific exception: ") #bruce 061222
                pass
            self.mmkit_tab.setTabLabel (self.atomsPage, 'Atoms')
            self.mmkit_tab.setTabLabel (self.clipboardPage, 'Clipbd')
            self.mmkit_tab.setTabLabel (self.libraryPage, 'Lib')
        else:
            # Add icons to MMKit's tabs. mark 060223.
            atoms_ic = imagename_to_icon("actions/Properties Manager/MMKit.png")
            self.mmkit_tab.setTabIcon(self.mmkit_tab.indexOf(self.atomsPage), QIcon(atoms_ic))

            self.update_clipboard_page_icon() # Loads proper icon for clibpoard tab. Mark 2007-06-01

            library_ic = imagename_to_icon("actions/Properties Manager/library.png")
            self.mmkit_tab.setTabIcon(self.mmkit_tab.indexOf(self.libraryPage), QIcon(library_ic))

        # Tab tooltips. mark 060326
        self.mmkit_tab.setTabToolTip(self.mmkit_tab.indexOf(self.atomsPage), 'Atoms')
        self.mmkit_tab.setTabToolTip(self.mmkit_tab.indexOf(self.clipboardPage), 'Clipboard')
        self.mmkit_tab.setTabToolTip(self.mmkit_tab.indexOf(self.libraryPage), 'Part Library')

        self._setNewView('MMKitView')

        # Set current element in element button group.


        self.theElements.button(self.w.Element).setChecked(True)

        #self.connect(self., SIGNAL("), )

        self.connect(self.w.hybridComboBox, SIGNAL("activated(int)"), self.hybridChangedOutside)

        self.connect(self.w.hybridComboBox, SIGNAL("activated(const QString&)"), self.change2AtomsPage)
        self.connect(self.w.elemChangeComboBox, SIGNAL("activated(const QString&)"), self.change2AtomsPage)
        self.connect(self.w.pasteComboBox, SIGNAL("activated(const QString&)"), self.change2ClipboardPage)

        #self.connect(self.w.depositAtomDashboard.pasteBtn, SIGNAL("pressed()"), self.change2ClipboardPage)
        self.connect(self.w.depositAtomDashboard.pasteBtn, SIGNAL("stateChanged(int)"), self.pasteBtnStateChanged)
        self.connect(self.w.depositAtomDashboard.depositBtn, SIGNAL("stateChanged(int)"), self.depositBtnStateChanged)

        self.connect(self.dirView, SIGNAL("selectionChanged(QItemSelection *, QItemSelection *)"), self.partChanged)

        self.add_whats_this_text()

        return # from __init__

    # ==

    #bruce 060412 added everything related to __needs_update_xxx, to fix bugs 1726, 1629 and mitigate bug 1677;
    # for more info see the comments where update_clipboard_items is called (in depositMode.py).

    __needs_update_clipboard_items = False
        # (there could be other flags like this for other kinds of updates we might need)


    def show_propMgr(self):
        """
        Show the Build Property Manager.
        """
        #@NOTE: The build property manager files are still refered as MMKit and
        #MMKitDialog. This will change in the near future. -- ninad 20070717

        self.update_dialog(self.parentMode.w.Element)
        self.parentMode.set_selection_filter(False) # disable selection filter
        self.openPropertyManager(self)

        #Following is an old comment, was originally in depositMode.init_gui:
        #Do these before connecting signals or we'll get history msgs.
        #Part of fix for bug 1620. mark 060322
        self.highlightingCB.setChecked(self.parentMode.hover_highlighting_enabled)
        self.waterCB.setChecked(self.parentMode.water_enabled)


    def update_dialog(self, elemNum):
        """Called when the current element has been changed.
           Update non user interactive controls display for current selected
           element: element label info and element graphics info """

        elm = self.elemTable.getElement(elemNum)

        currentIndex = self.mmkit_tab.currentIndex()
        atomPageIndex = self.mmkit_tab.indexOf(self.atomsPage)

        ##if elm == self.elm and self.currentPageOpen(AtomsPage): return
        if elm == self.elm and (currentIndex == atomPageIndex) : return

        ## The following statements are redundant in some situations.
        self.theElements.button(elemNum).setChecked(True)
        self.w.Element = elemNum

        self.color = self.elemTable.getElemColor(elemNum)
        self.elm = self.elemTable.getElement(elemNum)

        self.update_hybrid_btngrp()

        self.elemGLPane.resetView()
        self.elemGLPane.refreshDisplay(self.elm, self.displayMode)

        #update the selection filter
        self.update_selection_filter_list()

        # Fix for bug 353, to allow the dialog to be updated with the correct page.  For example,
        # when the user selects Paste from the Edit toolbar/menu, the MMKit should show
        # the Clipboard page and not the Atoms page. Mark 050808
        if self.w.depositState == 'Clipboard':
            self.change2ClipboardPage()
        else:
            self.change2AtomsPage()
        self.tabCurrentChanged()

        self.updateBuildAtomsMessage() # Mark 2007-06-01

    def updateBuildAtomsMessage(self):
        """Updates the message box with an informative message based on the current page
        and current selected atom type.
        """
        msg = ""

        if self.MMKit_groupBox.isVisible():
            pageIndex = self.mmkit_tab.currentIndex()
            page = None

            if pageIndex is 0: # atomsPage
                msg = "Double click in empty space to insert a single " + self.elm.name + " atom. "
                if not self.elm.symbol in noblegases:
                    msg += "Click on an atom's <i>red bondpoint</i> to attach a " + self.elm.name + " atom to it."

            elif pageIndex is 1: # clipboardPage
                pastableItems = self.w.assy.shelf.get_pastable_chunks()
                if pastableItems:
                    msg = "Double click in empty space to insert a copy of the selected clipboard item. \
                    Click on a <i>red bondpoint</i> to attach a copy of the selected clipboard item."
                else:
                    msg = "There are no items on the clipboard."

            elif pageIndex is 2: # libraryPage
                msg = "Double click in empty space to insert a copy of the selected part in the library."

        else: # Bonds Tool is selected (MMKit groupbox is hidden).
            if self.parentMode.cutBondsAction.isChecked():
                msg = "<b> Cut Bonds </b> tool is active. \
                Click on bonds in order to delete them."
                self.MessageGroupBox.insertHtmlMessage(msg)
                return

            if not hasattr(self, 'bondclick_v6'): # Mark 2007-06-01
                return
            if self.bondclick_v6:
                name = btype_from_v6(self.bondclick_v6)
                msg = "Click bonds or bondpoints to make them %s bonds." % name # name is 'single' etc

        # Post message.
        self.MessageGroupBox.insertHtmlMessage(msg)

    #== Atom Selection Filter helper methods

    def set_selection_filter(self, enabled):
        """Slot for Atom Selection Filter checkbox. Prints history message when selection filter is
        enabled/disabled and updates the cursor.
        """

        if enabled != self.w.selection_filter_enabled:
            if enabled:
                env.history.message("Atom Selection Filter enabled.")
            else:
                env.history.message("Atom Selection Filter disabled.")

        self.w.selection_filter_enabled = enabled

        #print "update_selection_filter_list(): self.w.filtered_elements=", self.w.filtered_elements

        ##self.update_selection_filter_list_widget()
        self.update_selection_filter_list()
        self.filterlistLE.setEnabled(enabled)
        self.filterCB.setChecked(enabled)
        self.o.graphicsMode.update_cursor()

    def update_selection_filter_list(self):
        """Adds/removes the element selected in the MMKit to/from Atom Selection Filter
        based on what modifier key is pressed (if any).
        """
        eltnum = self.w.Element

        if self.o.modkeys is None:
            self.w.filtered_elements = []
            self.w.filtered_elements.append(PeriodicTable.getElement(eltnum))
        if self.o.modkeys == 'Shift':
            if not PeriodicTable.getElement(eltnum) in self.w.filtered_elements[:]:
                self.w.filtered_elements.append(PeriodicTable.getElement(eltnum))
        elif self.o.modkeys == 'Control':
            if PeriodicTable.getElement(eltnum) in self.w.filtered_elements[:]:
                self.w.filtered_elements.remove(PeriodicTable.getElement(eltnum))

        self.update_selection_filter_list_widget()

    def update_selection_filter_list_widget(self):
        """Updates the list of elements displayed in the Atom Selection Filter List.
        """
        filtered_syms=''
        for e in self.w.filtered_elements[:]:
            if filtered_syms: filtered_syms += ", "
            filtered_syms += e.symbol
        #self.w.depositAtomDashboard.filterlistLE.setText(filtered_syms)
        self.filterlistLE.setText(filtered_syms)

    def toggle_bondTool_groupBox(self):
        self.toggle_groupbox(self.bondTool_groupBoxButton, self.bondToolWidget)

    def toggle_thumbView_groupBox(self):
        self.toggle_groupbox(self.thumbView_groupBoxButton, self.elementFrame)

    def toggle_MMKit_groupBox(self):
        self.toggle_groupbox(self.MMKitGrpBox_TitleButton, self.mmkit_tab, self.transmuteBtn, self.transmuteCB)

    def toggle_selectionFilter_groupBox(self, state):
        """ Toggles the groupbox item display depending on checked state of the selection filter checkbox """

        #Current state is 'off' or(Qt.Unchecked)

        if state is 0:
            styleSheet = self.getGroupBoxCheckBoxStyleSheet(bool_expand = False)
            self.filterCB.setStyleSheet(styleSheet)

            palette = self.getGroupBoxCheckBoxPalette()
            self.filterCB.setPalette(palette)

            #hide the following widgets when checkbox is unchecked --
            self.selectionFilter_label.hide()
            self.filterlistLE.hide()
        else:
            styleSheet = self.getGroupBoxCheckBoxStyleSheet(bool_expand = True)
            self.filterCB.setStyleSheet(styleSheet)

            palette = self.getGroupBoxCheckBoxPalette()
            self.filterCB.setPalette(palette)

            #hide the following widgets when checkbox is unchecked --
            self.selectionFilter_label.show()
            self.filterlistLE.show()


    def toggle_advancedOptions_groupBox(self):
        self.toggle_groupbox(self.advancedOptions_groupBoxButton, self.autobondCB, self.waterCB, self.highlightingCB)

    #bruce 070615 removed 'def toggle_groupbox', since our mixin superclass PropertyManagerMixin
    # provides an identical-enough version.

    def tabCurrentChanged(self):
        pageIndex = self.mmkit_tab.currentIndex()
        page = None
        if pageIndex is 0: page = self.atomsPage
        elif pageIndex is 1: page = self.clipboardPage
        elif pageIndex is 2: page = self.libraryPage
        self.setup_current_page(page)

    def update_clipboard_items(self):
        self.__needs_update_clipboard_items = True
        self.update() # this makes sure self.event will get called; it might be better to test the flag only in self.repaint, not sure
        return

    def event(self, event): #bruce 060412 debug code, but also checks all self.__needs_update_xxx flags (an essential bugfix)
        if debug_mmkit_events:
            print "debug: MMKit.event got %r, type %r" % (event, event.type())
                # Qt doc for QEvent lists 'enum type' codes; the subclass is also printed by %r

        if self.__needs_update_clipboard_items:
            self.__really_update_clipboard_items()
            self.__needs_update_clipboard_items = False

        res = QDialog.event(self, event)
        if debug_mmkit_events:
            if res is not None:
                print "debug: MMKit.event returns %r" % (res,) # usually True, sometimes False
        # if we return None we get TypeError: invalid result type from MMKit.event()
        return res

    # ==

    def pasteBtnStateChanged(self, state):
        """Slot method. Called when the state of the Paste button of deposit dashboard has been changed. """
        if state == QButton.On:
            self.change2ClipboardPage()


    def depositBtnStateChanged(self, state):
        """Slot method. Called when the state of the Deposit button of deposit dashboard has been changed. """
        if state == QButton.On:
           self.change2AtomsPage()


    def hybridChangedOutside(self, newId):
        """Slot method. Called when user changes element hybridization from the dashboard.
         This method achieves the same effect as user clicked one of the hybridization buttons."""
        self.theElements.button(newId).setChecked(True)
        self.set_hybrid_type(newId)
        self.w.Element = newId

        ## fix bug 868
        self.w.depositAtomDashboard.depositBtn.setChecked(True)


    def change2AtomsPage(self):
        """Slot method called when user changes element/hybrid combobox or
        presses Deposit button from Build mode dashboard.
        """
        if self.mmkit_tab.currentIndex() != AtomsPage:
            self.mmkit_tab.setCurrentIndex(AtomsPage) # Generates signal

    def change2ClipboardPage(self):
        """Slot method called when user changes pastable item combobox or
        presses the Paste button from the Build mode dashboard. """
        if self.mmkit_tab.currentIndex() != ClipboardPage:
            self.mmkit_tab.setCurrentIndex(ClipboardPage) # Generates signal??


    def setElementInfo(self,value):
        """Slot method called when an element button is pressed in the element ButtonGroup.
        """
        self.w.setElement(value)


    def update_hybrid_btngrp(self, buttonIndex = 0):
        """Update the buttons of the current element\'s hybridization types into hybrid_btngrp;
        select the specified one if provided"""
        elem = PeriodicTable.getElement(self.w.Element) # self.w.Element is atomic number

        atypes = elem.atomtypes

        if elem.name == 'Carbon':
            self.setup_C_hybrid_buttons()
        elif elem.name == 'Nitrogen':
            self.setup_N_hybrid_buttons()
        elif elem.name == 'Oxygen':
            self.setup_O_hybrid_buttons()
        elif elem.name == 'Sulfur':
            self.setup_S_hybrid_buttons()
        else:
            self.hide_hybrid_btngrp()
            self.elemGLPane.changeHybridType(None)
            return

        #if len(atypes) > 1:
        # Prequisite: w.hybridComboBox has been updated at this moment.
        b_name = self.bond_id2name[buttonIndex]
        self.elemGLPane.changeHybridType(b_name)
        self.elemGLPane.refreshDisplay(self.elm, self.displayMode)
        self.theHybridizations.button(buttonIndex).setChecked(True)
        self.set_hybrid_type(buttonIndex)
        # Added Atomic Hybrids label. Mark 2007-05-30
        self.atomic_hybrids_label.setText("Atomic Hybrids for " + elem.name + " :")
        self.show_hybrid_btngrp()

    def show_hybrid_btngrp(self): # Mark 2007-06-20
        """Show the hybrid button group and label above it.
        This is a companion method to hide_hybrid_btngrp().
        It includes workarounds for Qt layout issues that crop up
        when hiding/showing the hybrid button groupbox using Qt's
        hide() and show() methods. See bug 2407 for more information.
        """
        if 1:
            self.hybrid_btngrp.show()
        else:
            self.hybrid_btngrp.show()
            self.atomic_hybrids_label.show()

    def hide_hybrid_btngrp(self): # Mark 2007-06-20
        """Hide the hybrid button group and label above it.
        This is a companion method to show_hybrid_btngrp().
        It includes workarounds for Qt layout issues that crop up
        when hiding/showing the hybrid button groupbox using Qt's
        hide() and show() methods. See bug 2407 for more information.
        """
        if 1:
            # This way of hiding confuses the layout manager, so I had
            # do create special spacers and set sizepolicies just to make
            # this work.
            self.hybrid_btngrp.hide()
            # I had to do this instead of use hide() since hide()
            # confuses the layout manager in special situations, like
            # that described in bug 2407. Mark 2007-06-20
            self.atomic_hybrids_label.setText(" ")
        else:
            # Alternate way of hiding. Hide all contents and the QButtonGroupbox
            # border, but there is no way to hide the border.
            self.sp3_btn.hide()
            self.sp2_btn.hide()
            self.sp_btn.hide()
            self.graphitic_btn.hide()
            self.atomic_hybrids_label.hide()

    def setup_C_hybrid_buttons(self):
        """Displays the Carbon hybrid buttons.
        """
        self.theElements.button(self.w.Element).setChecked(True)
        self.sp3_btn.setIcon(imagename_to_icon('modeltree/C_sp3.png'))
        self.sp3_btn.show()
        self.sp2_btn.setIcon(imagename_to_icon('modeltree/C_sp2.png'))
        self.sp2_btn.show()
        self.sp_btn.setIcon(imagename_to_icon('modeltree/C_sp.png'))
        self.sp_btn.show()
        self.graphitic_btn.hide()

    def setup_N_hybrid_buttons(self):
        """Displays the Nitrogen hybrid buttons.
        """
        self.sp3_btn.setIcon(imagename_to_icon('modeltree/N_sp3.png'))
        self.sp3_btn.show()
        self.sp2_btn.setIcon(imagename_to_icon('modeltree/N_sp2.png'))
        self.sp2_btn.show()
        self.sp_btn.setIcon(imagename_to_icon('modeltree/N_sp.png'))
        self.sp_btn.show()
        self.graphitic_btn.setIcon(imagename_to_icon('modeltree/N_graphitic.png'))
        self.graphitic_btn.show()


    def setup_O_hybrid_buttons(self):
        """Displays the Oxygen hybrid buttons.
        """
        self.sp3_btn.setIcon(imagename_to_icon('modeltree/O_sp3.png'))
        self.sp3_btn.show()
        self.sp2_btn.setIcon(imagename_to_icon('modeltree/O_sp2.png'))
        self.sp2_btn.show()
        self.sp_btn.hide()
        self.graphitic_btn.hide()


    def setup_S_hybrid_buttons(self):
        """Displays the Sulfur hybrid buttons.
        """
        self.sp3_btn.setIcon(imagename_to_icon('modeltree/O_sp3.png')) # S and O are the same.
        self.sp3_btn.show()
        self.sp2_btn.setIcon(imagename_to_icon('modeltree/O_sp2.png'))
        self.sp2_btn.show()
        self.sp_btn.hide()
        self.graphitic_btn.hide()


    def set_hybrid_type(self, type_id):
        """Slot method. Called when any of the hybrid type buttons was clicked. """
        self.w.hybridComboBox.setCurrentIndex( type_id )

        b_name = self.bond_id2name[type_id]

        #This condition fixs bug 866, also saves time since no need to draw without MMKIt shown
        if self.isVisible():
            self.elemGLPane.changeHybridType(b_name)
            self.elemGLPane.refreshDisplay(self.elm, self.displayMode)


    def setup_current_page(self, page):
        """Slot method that is called whenever a user clicks on the
        'Atoms', 'Clipboard' or 'Library' tab to change to that page.
        """

        #print "setup_current_page: page=", page

        if page == self.atomsPage:  # Atoms page
            self.w.depositState = 'Atoms'
            self.w.update_depositState_buttons()
            self.elemGLPane.resetView()
            self.elemGLPane.refreshDisplay(self.elm, self.displayMode)
            self.browseButton.hide()
            self.defaultPartLibButton.hide()
            self.atomsPageSpacer.changeSize(0,5,
                QtGui.QSizePolicy.Expanding,
                QtGui.QSizePolicy.Minimum)

        elif page == self.clipboardPage: # Clipboard page
            self.w.depositState = 'Clipboard'
            self.w.update_depositState_buttons()
            self.elemGLPane.setDisplay(self.displayMode)
            self._clipboardPageView()
            self.browseButton.hide()
            self.defaultPartLibButton.hide()
            self.atomsPageSpacer.changeSize(0,5,
                QtGui.QSizePolicy.Expanding,
                QtGui.QSizePolicy.Minimum)

        elif page == self.libraryPage: # Library page
            if self.rootDir:
                self.elemGLPane.setDisplay(self.displayMode)
                self._libPageView()
            self.browseButton.show()
            self.defaultPartLibButton.show()
            self.atomsPageSpacer.changeSize(0,5,
                QtGui.QSizePolicy.Minimum,
                QtGui.QSizePolicy.Minimum)

            #Turn off both paste and deposit buttons, so when in library page and user choose 'set hotspot and copy'
            #it will change to paste page, also, when no chunk selected, a history message shows instead of depositing an atom.
            self.w.depositState = 'Library'
            self.w.update_depositState_buttons()
        else:
            print 'Error: MMKit page unknown: ', page

        self.elemGLPane.setFocus()
        self.updateBuildAtomsMessage()

    def chunkChanged(self, item, previous):
        """Slot method. Called when user changed the selected chunk. """

        itemId = self.chunkListBox.row(item)

        if itemId != -1:

            newChunk = self.pastableItems[itemId]

            #self.w.pasteComboBox.setCurrentIndex(itemId)
            #buildModeObj = self.w.commandSequencer._commandTable['DEPOSIT']
            #assert buildModeObj
            #buildModeObj.setPaste()

            ##Compared to the above way, I think this way is better. Modules are more uncoupled.
            self.w.pasteComboBox.setCurrentIndex(itemId) # Fixes bug 1754. mark 060325

            self.elemGLPane.updateModel(newChunk)


    def __really_update_clipboard_items(self): #bruce 060412 renamed this from update_clipboard_items to __really_update_clipboard_items
        """Updates the items in the clipboard\'s listview, if the clipboard is currently shown. """
        if self.currentPageOpen(ClipboardPage): #bruce 060313 added this condition to fix bugs 1631, 1669, and MMKit part of 1627
            self._clipboardPageView() # includes self.update_clipboard_page_icon()
        else:
            self.update_clipboard_page_icon() # do this part of it, even if page not shown
        return

    def partChanged(self, item):
        """Slot method, called when user changed the partlib brower tree"""
        if isinstance(item, self.FileItem):
           self._libPageView(True)
        else:
           self.newModel = None
           self.elemGLPane.updateModel(self.newModel)


    def getPastablePart(self):
        """Public method. Retrieve pastable part and hotspot if current tab page is in libary, otherwise, return None. """
        if self.currentPageOpen(LibraryPage):
            return self.newModel, self.elemGLPane.hotspotAtom
        return None, None

    def currentPageOpen(self, page_id):
        """Returns True if <page_id> is the current page open in the tab widget, where:
            0 = Atoms page
            1 = Clipboard page
            2 = Library page
        """
        pageIndex = self.mmkit_tab.currentIndex()

        if page_id == pageIndex:
            return True
        else:
            return False

    def _libPageView(self, isFile = False):
        item = self.dirView.selectedItem()
        if not isFile and not isinstance(item, self.FileItem):
            self.newModel = None
            self.elemGLPane.updateModel(self.newModel)
            return

        mmpfile = str(item.getFileObj())
        if os.path.isfile(mmpfile):
            #self.newModel = Assembly(self.w, "Assembly 1")
            self.newModel = Assembly(self.w, os.path.normpath(mmpfile)) #ninad060924 to fix bug 1164
            self.newModel.o = self.elemGLPane ## Make it looks "Assembly" used by glpane.
            readmmp(self.newModel, mmpfile)

# What we did in Qt 3:
##         #self.newModel = Assembly(self.w, "Assembly 1")
##         self.newModel = Assembly(self.w, os.path.normpath(mmpfile)) #ninad060924 to fix bug 1164

##         self.newModel.o = self.elemGLPane ## Make it looks "Assembly" used by glpane.
##         readmmp(self.newModel, mmpfile)

##         # The following is absolute nonsense, and is part of what's breaking the fix of bug 2028,
##         # so it needs to be revised, to give this assy a standard structure.
##         # We'll have to find some other way to draw the hotspot singlet
##         # (e.g. a reasonable, straightforward way). So we did -- MMKitView.always_draw_hotspot is True.
##         # [bruce 060627]

## ##        # Move all stuff under assembly.tree into assy.shelf. This is needed to draw hotspot singlet
## ##        def addChild(child):
## ##            self.newModel.shelf.addchild(child)
## ##
## ##        # Remove existing clipboard items from the libary part before adopting childern from 'tree'.
## ##        self.newModel.shelf.members = []
## ##        self.newModel.tree.apply2all(addChild)
## ##
## ##        self.newModel.shelf.prior_part = None
## ##        self.newModel.part = Part(self.newModel, self.newModel.shelf)

##         if 1: #bruce 060627

            self.newModel.update_parts() #k not sure if needed after readmmp)
            self.newModel.checkparts()
            if self.newModel.shelf.members:
                if debug_flags.atom_debug:
                    print "debug warning: library part %r contains clipboard items" % mmpfile
                    # we'll see if this is common
                    # happens for e.g. nanokids/nanoKid-C39H42O2.mmp
                for m in self.newModel.shelf.members[:]:
                    m.kill() #k guess about a correct way to handle them
                self.newModel.update_parts() #k probably not needed
                self.newModel.checkparts() #k probably not needed
        else:
            self.newModel = None

        self.elemGLPane.updateModel(self.newModel)


    def _clipboardPageView(self):
        """Updates the clipboard page. """
        if not self.currentPageOpen(ClipboardPage):
            # (old code permitted this to be false below in 'if len(list):',
            #  but failed to check for it in the 'else' clause,
            #  thus causing bug 1627 [I think], now fixed in our caller)
            print "bug: _clipboardPageView called when not self.currentPageOpen(ClipboardPage)" #bruce 060313
            return

        self.pastableItems = self.w.assy.shelf.get_pastable_chunks()
        self.chunkListBox.clear()
        for item in self.pastableItems:
            self.chunkListBox.addItem(item.name)

        newModel = None
        if len(self.pastableItems):
            i = self.w.pasteComboBox.currentIndex()
            if i < 0:
                i = self.w.pasteComboBox.count() - 1
            # Make sure the clipboard page is open before calling selSelected(), because
            # setSelected() causes the clipboard page to be displayed when we don't want it to
            # be displayed (i.e. pressing Control+C to copy something to the clipboard).
            self.chunkListBox.setCurrentItem(self.chunkListBox.item(i))
            # bruce 060313 question: why don't we now have to pass the selected chunk to
            # self.elemGLPane.updateModel? ###@@@
            newModel = self.pastableItems[i]
        self.elemGLPane.updateModel(newModel)
        self.update_clipboard_page_icon()


    def update_clipboard_page_icon(self):
        """Updates the Clipboard page (tab) icon with a full or empty clipboard icon
        based on whether there is anything on the clipboard (pasteables).
        """
        if not self.icon_tabs:
            # Work around for bug 1659. mark 060310 [revised by bruce 060313]
            return

        if self.w.assy.shelf.get_pastable_chunks():
            clipboard_ic = imagename_to_icon("actions/Properties Manager/clipboard-full.png")
        else:
            clipboard_ic = imagename_to_icon("actions/Properties Manager/clipboard-empty.png")

        self.mmkit_tab.setTabIcon(self.mmkit_tab.indexOf(self.clipboardPage), QIcon(clipboard_ic))

    class DirView(QTreeView):
        def __init__(self, mmkit, parent):
            QTreeView.__init__(self, parent)

            self.setEnabled(True)
            self.model = QtGui.QDirModel(['*.mmp', '*.MMP'], # name filters
                                         QDir.AllEntries|QDir.AllDirs|QDir.NoDotAndDotDot, # filters
                                         QDir.Name # sort order
                                         )
                # explanation of filters (from Qt 4.2 doc for QDirModel):
                # - QDir.AllEntries = list files, dirs, drives, symlinks.
                # - QDir.AllDirs = include dirs regardless of other filters [guess: needed to ignore the name filters for dirs]
                # - QDir.NoDotAndDotDot = don't include '.' and '..' dirs
                #
                # about dirnames of "CVS":
                # The docs don't mention any way to filter the dirnames using a callback,
                # or any choices besides "filter them same as filenames" or "don't filter them".
                # So there is no documented way to filter out the "CVS" subdirectories like we did in Qt3
                # (short of subclassing this and overriding some methods,
                #  but the docs don't make it obvious how to do that correctly).
                # Fortunately, autoBuild.py removes them from the partlib copy in built releases.
                #
                # Other QDirModel methods we might want to use:
                # QDirModel.refresh, to update its state from the filesystem (but see the docs --
                #  they imply we might have to pass the model's root pathname to that method,
                #  even if it hasn't changed, but they're not entirely clear on that).
                #
                # [bruce 070502 comments]

            self.path = None
            self.mmkit = mmkit
            self.setModel(self.model)
            self.setWindowTitle(self.tr("Dir View"))

            self.setItemsExpandable(True)
            self.setAlternatingRowColors(True)
            self.setColumnWidth(0, 200)
            for i in range(2,4):
                self.setColumnWidth(i, 4)

            self.show()

        #Ninad 070326 reimplementing mouseReleaseEvent and resizeEvent
        #for DirView Class (which is a subclass of QTreeView)
        #The old code reimplemented 'event' class which handles *all* events.
        #There was a bad bug which didn't send an event when the widget is resized
        # and then the seletcion is changed. In NE1Qt3 this wasn't a problem because
        #it only had one column. Now that we have multiple columns
        #(which are needed to show the horizontal scrollbar.
        # While using Library page only resize event or mouse release events
        #by the user should update the thumbview.
        #The Qt documentation also suggests reimplementing subevents instead of the main
        #event handler method (event())
        def mouseReleaseEvent(self, evt):
            """ Reimplementation of mouseReleaseEvent method of QTreeView"""
            if self.selectedItem() is not None:
                    self.mmkit._libPageView()
            return QTreeView.mouseReleaseEvent(self, evt)

        def resizeEvent(self, evt):
            """ Reimplementation of resizeEvent method of QTreeView"""
            if self.selectedItem() is not None:
                    self.mmkit._libPageView()
            return QTreeView.resizeEvent(self, evt)


        #Following method (event() ) is not reimplemented anymore. Instead, the subevent handlers are
        #reimplemented (see above)  -- ninad 070326
        """
        def event(self, evt):
            if evt.type() == evt.Timer:
                # This is the event we get when the library selection changes, so if there has
                # been a library selection, update the library page's GLPane. But this can also
                # happen without a selection; in that case don't erase the atom page's display.
                if self.selectedItem() is not None:
                    self.mmkit._libPageView()
            return QTreeView.event(self, evt)"""

        def setRootPath(self, path):
            self.path = path
            self.setRootIndex(self.model.index(path))

        def selectedItem(self):
            indexes = self.selectedIndexes()
            if not indexes:
                return None
            index = indexes[0]
            if not index.isValid():
                return None

            return self.FileItem(str(self.model.filePath(index)))

    class FileItem:
        def __init__(self, path):
            self.path = path
            dummy, self.filename = os.path.split(path)
        def name(self):
            return self.filename
        def getFileObj(self):
            return self.path
    DirView.FileItem = FileItem

    def _setNewView(self, viewClassName):
        # Put the GL widget inside the frame
        if not self.flayout:
            self.flayout = QVBoxLayout(self.elementFrame)
            self.flayout.setMargin(1)
            self.flayout.setSpacing(1)
        else:
            if self.elemGLPane:
                self.flayout.removeChild(self.elemGLPane)
                self.elemGLPane = None

        if viewClassName == 'ChunkView':
            # We never come here! How odd.
            self.elemGLPane = ChunkView(self.elementFrame, "chunk glPane", self.w.glpane)
        elif viewClassName == 'MMKitView':
            self.elemGLPane = MMKitView(self.elementFrame, "MMKitView glPane", self.w.glpane)

        self.flayout.addWidget(self.elemGLPane,1)


        #ninad 070326. Note that self.DirView inherits QTreeView.
        #It has got nothing to do with the experimental class DirView in file Dirview.py
        self.dirView = self.DirView(self, self.libraryPage)
        self.dirView.setSortingEnabled(False) #bruce 070521 changed True to False -- fixes "reverse order" bug on my Mac
        ##self.dirView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        libraryPageLayout = QVBoxLayout(self.libraryPage)
        libraryPageLayout.setMargin(pmMMKitPageMargin) # Was 4. Mark 2007-05-30
        libraryPageLayout.setSpacing(2)
        libraryPageLayout.addWidget(self.dirView)


        filePath = os.path.dirname(os.path.abspath(sys.argv[0]))
        libDir = os.path.normpath(filePath + '/../partlib')

        self.libPathKey = '/nanorex/nE-1/libraryPath'
        libDir = env.prefs.get(self.libPathKey, libDir)

        if os.path.isdir(libDir):
            self.rootDir = libDir
            self.dirView.setRootPath(libDir)
        else:
            self.rootDir = None
            from history.HistoryWidget import redmsg
            env.history.message(redmsg("The part library directory: %s doesn't exist." %libDir))

    def browseDirectories(self):
       """Slot method for the browse button of library page. """
       # Determine what directory to open.
       if self.w.assy.filename:
           odir = os.path.dirname(self.w.assy.filename)
       else:
           from utilities.prefs_constants import workingDirectory_prefs_key
           odir = env.prefs[workingDirectory_prefs_key]

       fdir = QFileDialog.getExistingDirectory(self, "Choose library directory", odir)
       libDir = str(fdir)
       if libDir and os.path.isdir(libDir):
           env.prefs[self.libPathKey] = libDir
           self.dirView.setRootPath(libDir)
           #Refresh GL-thumbView display
           self.newModel = None
           self.elemGLPane.updateModel(self.newModel)

    def useDefaultPartLibDirectory(self):
        """ Slot method that to reset the part lib directory path to default"""
        from history.HistoryWidget import redmsg

        #ninad070503 : A future enhancement would be a preference to have
        # a user defined 'default dir path' for the
        #part lib location.

        # set libDir to the standard partlib path
        filePath = os.path.dirname(os.path.abspath(sys.argv[0]))
        libDir = os.path.normpath(filePath + '/../partlib')

        if libDir and os.path.isdir(libDir):
            if self.dirView.path == libDir:
                msg1 = "Current directory path for the partlib is the default path."
                msg2 = " Current path not changed"
                env.history.message(redmsg(msg1 + msg2))
                return
            env.prefs[self.libPathKey] = libDir
            self.dirView.setRootPath(libDir)
            #Refresh GL-thumbView display
            self.newModel = None
            self.elemGLPane.updateModel(self.newModel)
        else:
            msg1 = "The default patlib directory %s doesn't exist."%libDir
            msg2 = "Current path not changed"
            env.history.message(redmsg(msg1 + msg2))


    def closeEvent(self, e):
        """This event handler receives all MMKit close events.  In other words,
        when this dialog's close() slot gets called, this gets called with event 'e'.
        """
        self.hide()

        # If the 'Library' page is open, change it to 'Atoms'.  Mark 051212.
        if self.currentPageOpen(LibraryPage):
            self.setup_current_page(self.atomsPage)


#bruce 070615 commented out the following since I think it's obsolete:
# (evidence: no other mentions of 'polish' or 'move_to_best_location' in our code,
#  and MMKit is no longer a movable dialog)
##    num_polish = 0
##
##    def polish(self):
##        """This slot is called after a widget has been fully created and before it is shown the very first time.
##        Polishing is useful for final initialization which depends on having an instantiated widget.
##        This is something a constructor cannot guarantee since the initialization of the subclasses might not be finished.
##        After this function, the widget has a proper font and palette and QApplication.polish() has been called.
##        Remember to call QDialog's implementation when reimplementing this function.
##        """
##        QDialog.polish(self) # call QDialog's polish() implementation
##        self.num_polish += 1
##        #&print "num_polish =", self.num_polish
##        if self.num_polish < 2:
##            # polish() is called twice; not sure why.
##            # Call move_to_best_location() only after the second polish signal since
##            # get_location() can only get self.frameGeometry() after that.
##            return
##        self.move_to_best_location(True)


    def show(self):
        """MMKit\'s show slot.
        """
        #QDialog.show(self)
        #&print "MMKit.move: setting mainwindow to active window"
        #Show it in Property Manager Tab ninad061207
        if not self.pw or self:
            self.pw = self.w.activePartWindow()       #@@@ ninad061206
            self.pw.updatePropertyManagerTab(self)
            self.setSponsor()

        else:
            if not self.pw:
                self.pw = self.w.activePartWindow()
            self.pw.updatePropertyManagerTab(self)


        self.w.activateWindow() # Fixes bug 1503.  mark 060216.
            # Required to give the keyboard input focus back to self (MainWindow).

    def add_whats_this_text(self):
        """What's This text for some of the widgets in the Build > Atoms Property Manager.
        Many are still missing.
        """

        self.elementFrame.setWhatsThis("""<b>Preview Window</b>
        <p>This displays the active object. It can be inserted by double
        clicking in the 3D graphics area.</p>
        <p>Left click on a red bondpoint to make it a green <i>hotspot</i>
        (clipboard and library parts only). The hotspot indicates which
        bondpoint should be used to bond the current object when selecting
        a bondpoint in the model.</p>
        <p><u>Mouse Commands Supported</u><br>
        Left - Select hotspot (clipboard and library parts only)<br>
        Middle - Rotate view<br> \
        Wheel - Zoom in/out \
        </p>""")

        self.MMKit_groupBox.setWhatsThis("""<b>Molecular Modeling Kit</b>
        <p>A tabular widget for selecting atom types or other structures to insert
        into the model.</p>
        <p><b>Atoms Tab</b> - A select group of atom types options from the periodic
        table of elements.</p>
        <p><b>Clipboard Tab</b> - the list of objects copied on the clipboard (using
        the Copy command).</p>
        <p><b>Library Tab</b> - Accesses the NE1 Part Library. There are hundreds of
        structures to choose from.</p>""")

        self.transmuteBtn.setWhatsThis("""<b>Transmute Atoms</b>
        <p>When clicked, transmutes selected atoms to the current type displayed
        in the Preview window.</p>""")

        self.transmuteCB.setWhatsThis("""<b>Force to keep bonds</b>
        <p>When checked, all bonds remain in place when atoms are transmuted,
        even if this will result in unrealistic (chemical) bonds.</p>""")

        self.selectionFilter_groupBox.setWhatsThis("""<b>Atoms Selection Filter</b>
        <p>When activated, only atoms listed can be selected.</p>""")

        self.advancedOptions_groupBox.setWhatsThis("""<b>Advanced Options</b>
        <p><b>Autobond</b> - when checked, the atom being inserted or attached to another
        atom will autobond to other bondpoints of other candidate atoms automatically.</p>
        <p><b>Highlighting</b> - Turns on/off hover highlighting.</p>
        <p><b>Water</b>- Adds a tranparent plane normal to the screen through 0,0,0. Anything
        behind the water plane can not be selected.</p>""")

        self.transmuteAtomsAction.setWhatsThis("""<b>Transmute Atoms</b>
        <p>When clicked, transmutes selected atoms to the current type displayed
        in the Preview window.</p>""")

    pass # end of class MMKit

# end