1 /* $RCSfile$
2  * $Author: hansonr $
3  * $Date: 2010-05-11 15:47:18 -0500 (Tue, 11 May 2010) $
4  * $Revision: 13064 $
5  *
6  * Copyright (C) 2000-2005  The Jmol Development Team
7  *
8  * Contact: jmol-developers@lists.sf.net
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2.1 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 package org.jmol.popup;
25 
26 import java.util.Arrays;
27 import java.util.Hashtable;
28 import java.util.Map;
29 
30 import org.jmol.api.SC;
31 import org.jmol.i18n.GT;
32 import org.jmol.i18n.Language;
33 import org.jmol.modelset.Group;
34 import org.jmol.script.T;
35 import org.jmol.util.Elements;
36 import org.jmol.viewer.JC;
37 
38 import javajs.util.BS;
39 import javajs.util.Lst;
40 import javajs.util.PT;
41 
42 /**
43  * An abstract popup class that is
44  * instantiated for a given platform and
45  * context as one of:
46  *
47  * <pre>
48  *   -- abstract JmolPopup
49  *      -- AwtJmolPopup
50  *      -- JSJmolPopup
51  * </pre>
52  *
53  */
54 abstract public class JmolPopup extends JmolGenericPopup {
55 
56   //list is saved in http://www.stolaf.edu/academics/chemapps/jmol/docs/misc
57 
58   protected final static int UPDATE_NEVER = -1;
59   protected final static int UPDATE_ALL = 0;
60   protected final static int UPDATE_CONFIG = 1;
61   protected final static int UPDATE_SHOW = 2;
62 
63   //public void finalize() {
64   //  Sygstem.out.println("JmolPopup " + this + " finalize");
65   //}
66 
67   protected int updateMode = UPDATE_ALL;
68 
69   private static final int itemMax = 25;
70   private int titleWidthMax = 20;
71   private String nullModelSetName, modelSetName;
72   private String modelSetFileName, modelSetRoot;
73   private String currentFrankId = null;
74   private String configurationSelected = "";
75   private String altlocs;
76 
77   private Object[][] frankList = new Object[10][]; //enough to cover menu drilling
78 
79   private Map<String, Object> modelSetInfo;
80   protected Map<String, Object> modelInfo;
81 
82   private Lst<SC> NotPDB = new Lst<SC>();
83   private Lst<SC> PDBOnly = new Lst<SC>();
84   private Lst<SC> FileUnitOnly = new Lst<SC>();
85   private Lst<SC> FileMolOnly = new Lst<SC>();
86   private Lst<SC> UnitcellOnly = new Lst<SC>();
87   private Lst<SC> SingleModelOnly = new Lst<SC>();
88   private Lst<SC> FramesOnly = new Lst<SC>();
89   private Lst<SC> VibrationOnly = new Lst<SC>();
90   protected Lst<SC> Special = new Lst<SC>();
91   private Lst<SC> SymmetryOnly = new Lst<SC>();
92   private Lst<SC> ChargesOnly = new Lst<SC>();
93   private Lst<SC> TemperatureOnly = new Lst<SC>();
94 
95   private boolean fileHasUnitCell;
96   private boolean haveBFactors;
97   private boolean haveCharges;
98   private boolean isLastFrame;
99   private boolean isMultiConfiguration;
100   private boolean isMultiFrame;
101   private boolean isPDB;
102   private boolean hasSymmetry;
103   private boolean isUnitCell;
104   private boolean isVibration;
105   private boolean isZapped;
106 
107   protected int modelIndex;
108   private int modelCount;
109   private int ac;
110 
111   private String group3List;
112   private int[] group3Counts;
113   private Lst<String> cnmrPeaks;
114   private Lst<String> hnmrPeaks;
115 
116   ////// JmolPopupInterface methods //////
117 
118   private final static int MENUITEM_HEIGHT = 20;
119 
120   @Override
jpiDispose()121   public void jpiDispose() {
122     super.jpiDispose();
123     helper.menuClearListeners(frankPopup);
124     frankPopup = null;
125   }
126 
127   @Override
getBundle(String menu)128   protected PopupResource getBundle(String menu) {
129     return new MainPopupResourceBundle(strMenuStructure = menu,
130         menuText);
131   }
132 
133 
134   @Override
showFrankMenu()135   protected boolean showFrankMenu() {
136       // frank has been clicked
137       getViewerData();
138       setFrankMenu(currentMenuItemId);
139       thisx = -thisx - 50;
140       if (nFrankList > 1) {
141         thisy -= nFrankList * MENUITEM_HEIGHT;
142         menuShowPopup(frankPopup, thisx, thisy);
143         return false;
144       }
145       return true;
146   }
147 
148   @Override
jpiUpdateComputedMenus()149   public void jpiUpdateComputedMenus() {
150     if (updateMode == UPDATE_NEVER)
151       return;
152     isTainted = true;
153     getViewerData();
154     updateMode = UPDATE_ALL;
155     updateMenus();
156   }
157 
158   ///////// protected methods //////////
159 
160   @SuppressWarnings("unchecked")
updateMenus()161   protected void updateMenus() {
162     updateSelectMenu();
163     updateModelSetComputedMenu();
164     updateAboutSubmenu();
165     if (updateMode == UPDATE_ALL) {
166       updateFileMenu();
167       updateElementsComputedMenu(vwr.getElementsPresentBitSet(modelIndex));
168       updateHeteroComputedMenu(vwr.ms.getHeteroList(modelIndex));
169       updateSurfMoComputedMenu((Map<String, Object>) modelInfo.get("moData"));
170       updateFileTypeDependentMenus();
171       updatePDBResidueComputedMenus();
172       updateMode = UPDATE_CONFIG;
173       updateConfigurationComputedMenu();
174       updateSYMMETRYComputedMenus();
175       updateFRAMESbyModelComputedMenu();
176       updateLanguageSubmenu();
177     } else {
178       updateSpectraMenu();
179       updateFRAMESbyModelComputedMenu();
180       updateSceneComputedMenu();
181       for (int i = Special.size(); --i >= 0;)
182         updateSpecialMenuItem(Special.get(i));
183     }
184   }
185 
186   @Override
appCheckItem(String item, SC newMenu)187   protected void appCheckItem(String item, SC newMenu) {
188     if (item.indexOf("!PDB") >= 0) {
189       NotPDB.addLast(newMenu);
190     } else if (item.indexOf("PDB") >= 0) {
191       PDBOnly.addLast(newMenu);
192     }
193     if (item.indexOf("CHARGE") >= 0) {
194       ChargesOnly.addLast(newMenu);
195     } else if (item.indexOf("BFACTORS") >= 0) {
196       TemperatureOnly.addLast(newMenu);
197     } else if (item.indexOf("UNITCELL") >= 0) {
198       UnitcellOnly.addLast(newMenu);
199     } else if (item.indexOf("FILEUNIT") >= 0) {
200       FileUnitOnly.addLast(newMenu);
201     } else if (item.indexOf("FILEMOL") >= 0) {
202       FileMolOnly.addLast(newMenu);
203     }
204     if (item.indexOf("!FRAMES") >= 0) {
205       SingleModelOnly.addLast(newMenu);
206     } else if (item.indexOf("FRAMES") >= 0) {
207       FramesOnly.addLast(newMenu);
208     }
209     if (item.indexOf("VIBRATION") >= 0) {
210       VibrationOnly.addLast(newMenu);
211     } else if (item.indexOf("SYMMETRY") >= 0) {
212       SymmetryOnly.addLast(newMenu);
213     }
214     if (item.indexOf("SPECIAL") >= 0)
215       Special.addLast(newMenu);
216   }
217 
218   @Override
appGetMenuAsString(String title)219   protected String appGetMenuAsString(String title) {
220     return (new MainPopupResourceBundle(strMenuStructure, null))
221         .getMenuAsText(title);
222   }
223 
224   @Override
getScriptForCallback(SC source, String id, String script)225   protected String getScriptForCallback(SC source, String id, String script) {
226     int pt;
227     if (script == "" || id.endsWith("Checkbox"))
228       return script;
229 
230     if (script.indexOf("SELECT") == 0) {
231       return "select thisModel and (" + script.substring(6) + ")";
232     }
233 
234     if ((pt = id.lastIndexOf("[")) >= 0) {
235       // setSpin
236       id = id.substring(pt + 1);
237       if ((pt = id.indexOf("]")) >= 0)
238         id = id.substring(0, pt);
239       id = id.replace('_', ' ');
240       if (script.indexOf("[]") < 0)
241         script = "[] " + script;
242       script = script.replace('_', ' ');
243       return PT.rep(script, "[]", id);
244     } else if (script.indexOf("?FILEROOT?") >= 0) {
245       script = PT.rep(script, "FILEROOT?", modelSetRoot);
246     } else if (script.indexOf("?FILE?") >= 0) {
247       script = PT.rep(script, "FILE?", modelSetFileName);
248     } else if (script.indexOf("?PdbId?") >= 0) {
249       script = PT.rep(script, "PdbId?", "=xxxx");
250     }
251     return script;
252   }
253 
254   @Override
appRestorePopupMenu()255   protected void appRestorePopupMenu() {
256     thisPopup = popupMenu;
257     // JavaScript does not have to re-insert the menu
258     // because it never gets removed in the first place.
259     // first entry is just the main item
260     if (vwr.isJSNoAWT || nFrankList < 2) // TODO BOBJOB
261       return;
262     for (int i = nFrankList; --i > 0;) {
263       Object[] f = frankList[i];
264       helper.menuInsertSubMenu((SC) f[0], (SC) f[1],
265           ((Integer) f[2]).intValue());
266     }
267     nFrankList = 1;
268   }
269 
270   /**
271    * (1) setOption --> set setOption true or set setOption false
272    *
273    * @param item
274    *
275    * @param what
276    *        option to set
277    * @param TF
278    *        true or false
279    */
280   @Override
appUpdateSpecialCheckBoxValue(SC item, String what, boolean TF)281   protected void appUpdateSpecialCheckBoxValue(SC item, String what, boolean TF) {
282     if (!updatingForShow && what.indexOf("#CONFIG") >= 0) {
283       configurationSelected = what;
284       updateConfigurationComputedMenu();
285       updateModelSetComputedMenu();
286     }
287   }
288 
289   ///////// private methods /////////
290 
setFrankMenu(String id)291   private void setFrankMenu(String id) {
292     if (currentFrankId != null && currentFrankId == id && nFrankList > 0)
293       return;
294     if (frankPopup == null)
295       frankPopup = helper.menuCreatePopup("Frank", vwr.html5Applet);
296     // thisPopup is needed by the JavaScript side of the operation
297     thisPopup = frankPopup;
298     menuRemoveAll(frankPopup, 0);
299     menuCreateItem(frankPopup, getMenuText("mainMenuText"), "MAIN", "");
300     currentFrankId = id;
301     nFrankList = 0;
302     frankList[nFrankList++] = new Object[] { null, null, null };
303     if (id != null)
304       for (int i = id.indexOf(".", 2) + 1;;) {
305         int iNew = id.indexOf(".", i);
306         if (iNew < 0)
307           break;
308         SC menu = htMenus.get(id.substring(i, iNew));
309         frankList[nFrankList++] = new Object[] { menu.getParent(), menu,
310             Integer.valueOf(vwr.isJSNoAWT ? 0 : menuGetListPosition(menu)) };
311         menuAddSubMenu(frankPopup, menu);
312         i = iNew + 1;
313       }
314     thisPopup = popupMenu;
315   }
316 
checkBoolean(String key)317   private boolean checkBoolean(String key) {
318     return (modelSetInfo != null && modelSetInfo.get(key) == Boolean.TRUE); // not "Boolean.TRUE.equals(...)" (not working in Java2Script yet)
319   }
320 
321   @SuppressWarnings("unchecked")
getViewerData()322   private void getViewerData() {
323     modelSetName = vwr.ms.modelSetName;
324     modelSetFileName = vwr.getModelSetFileName();
325     int i = modelSetFileName.lastIndexOf(".");
326     isZapped = (JC.ZAP_TITLE.equals(modelSetName));
327     if (isZapped || "string".equals(modelSetFileName)
328         || "String[]".equals(modelSetFileName))
329       modelSetFileName = "";
330     modelSetRoot = modelSetFileName.substring(0,
331         i < 0 ? modelSetFileName.length() : i);
332     if (modelSetRoot.length() == 0)
333       modelSetRoot = "Jmol";
334     modelIndex = vwr.am.cmi;
335     modelCount = vwr.ms.mc;
336     ac = vwr.ms.getAtomCountInModel(modelIndex);
337     modelSetInfo = vwr.getModelSetAuxiliaryInfo();
338     modelInfo = vwr.ms.getModelAuxiliaryInfo(modelIndex);
339     if (modelInfo == null)
340       modelInfo = new Hashtable<String, Object>();
341     isPDB = checkBoolean("isPDB");
342     isMultiFrame = (modelCount > 1);
343     hasSymmetry = modelInfo.containsKey("hasSymmetry");
344     isUnitCell = modelInfo.containsKey("unitCellParams");
345     fileHasUnitCell = (isPDB && isUnitCell || checkBoolean("fileHasUnitCell"));
346     isLastFrame = (modelIndex == modelCount - 1);
347     altlocs = vwr.ms.getAltLocListInModel(modelIndex);
348     isMultiConfiguration = (altlocs.length() > 0);
349     isVibration = (vwr.modelHasVibrationVectors(modelIndex));
350     haveCharges = (vwr.ms.getPartialCharges() != null);
351     haveBFactors = (vwr.getBooleanProperty("haveBFactors"));
352     cnmrPeaks = (Lst<String>) modelInfo.get("jdxAtomSelect_13CNMR");
353     hnmrPeaks = (Lst<String>) modelInfo.get("jdxAtomSelect_1HNMR");
354   }
355 
356   @Override
appCheckSpecialMenu(String item, SC subMenu, String word)357   public void appCheckSpecialMenu(String item, SC subMenu, String word) {
358     // these will need tweaking:
359     if ("modelSetMenu".equals(item)) {
360       nullModelSetName = word;
361       menuEnable(subMenu, false);
362     }
363   }
364 
365   @Override
appUpdateForShow()366   protected void appUpdateForShow() {
367     if (updateMode == UPDATE_NEVER)
368       return;
369     isTainted = true;
370     getViewerData();
371     updateMode = UPDATE_SHOW;
372     updateMenus();
373   }
374 
updateFileMenu()375   protected void updateFileMenu() {
376     SC menu = htMenus.get("fileMenu");
377     if (menu == null)
378       return;
379     String text = getMenuText("writeFileTextVARIABLE");
380     menu = htMenus.get("writeFileTextVARIABLE");
381     if (menu == null)
382       return;
383     boolean ignore = (modelSetFileName.equals(JC.ZAP_TITLE) || modelSetFileName
384         .equals(""));
385     if (ignore) {
386       menuSetLabel(menu, "");
387       menuEnable(menu, false);
388     } else {
389       menuSetLabel(menu, GT.o(GT.$(text), modelSetFileName));
390       menuEnable(menu, true);
391     }
392   }
393 
getMenuText(String key)394   private String getMenuText(String key) {
395     String str = menuText.getProperty(key);
396     return (str == null ? key : str);
397   }
398 
updateSelectMenu()399   protected void updateSelectMenu() {
400     SC menu = htMenus.get("selectMenuText");
401     if (menu == null)
402       return;
403     menuEnable(menu, ac != 0);
404     menuSetLabel(menu, gti("selectMenuText", vwr.slm.getSelectionCount()));
405   }
406 
updateElementsComputedMenu(BS elementsPresentBitSet)407   protected void updateElementsComputedMenu(BS elementsPresentBitSet) {
408     SC menu = htMenus.get("elementsComputedMenu");
409     if (menu == null)
410       return;
411     menuRemoveAll(menu, 0);
412     menuEnable(menu, false);
413     if (elementsPresentBitSet == null)
414       return;
415     for (int i = elementsPresentBitSet.nextSetBit(0); i >= 0; i = elementsPresentBitSet
416         .nextSetBit(i + 1)) {
417       String elementName = Elements.elementNameFromNumber(i);
418       String elementSymbol = Elements.elementSymbolFromNumber(i);
419       String entryName = elementSymbol + " - " + elementName;
420       menuCreateItem(menu, entryName, "SELECT " + elementName, null);
421     }
422     for (int i = Elements.firstIsotope; i < Elements.altElementMax; ++i) {
423       int n = Elements.elementNumberMax + i;
424       if (elementsPresentBitSet.get(n)) {
425         n = Elements.altElementNumberFromIndex(i);
426         String elementName = Elements.elementNameFromNumber(n);
427         String elementSymbol = Elements.elementSymbolFromNumber(n);
428         String entryName = elementSymbol + " - " + elementName;
429         menuCreateItem(menu, entryName, "SELECT " + elementName, null);
430       }
431     }
432     menuEnable(menu, true);
433   }
434 
updateSpectraMenu()435   protected void updateSpectraMenu() {
436     SC menu = htMenus.get("spectraMenu");
437     if (menu == null)
438       return;
439     SC menuh = htMenus.get("hnmrMenu");
440     if (menuh != null)
441       menuRemoveAll(menuh, 0);
442     SC menuc = htMenus.get("cnmrMenu");
443     if (menuc != null)
444       menuRemoveAll(menuc, 0);
445     menuRemoveAll(menu, 0);
446     // yes binary | not logical || here -- need to try to set both
447     boolean isOK = setSpectraMenu(menuh, hnmrPeaks)
448         | setSpectraMenu(menuc, cnmrPeaks);
449     if (isOK) {
450       if (menuh != null)
451         menuAddSubMenu(menu, menuh);
452       if (menuc != null)
453         menuAddSubMenu(menu, menuc);
454     }
455     menuEnable(menu, isOK);
456   }
457 
setSpectraMenu(SC menu, Lst<String> peaks)458   private boolean setSpectraMenu(SC menu, Lst<String> peaks) {
459     int n = (peaks == null ? 0 : peaks.size());
460     if (n == 0)
461       return false;
462     if (menu == null)
463       return false;
464     menuEnable(menu, false);
465     for (int i = 0; i < n; i++) {
466       String peak = peaks.get(i);
467       String title = PT.getQuotedAttribute(peak, "title");
468       String atoms = PT.getQuotedAttribute(peak, "atoms");
469       if (atoms != null)
470         menuCreateItem(menu, title,
471             "select visible & (@" + PT.rep(atoms, ",", " or @") + ")", "Focus"
472                 + i);
473     }
474     menuEnable(menu, true);
475     return true;
476   }
477 
updateHeteroComputedMenu(Map<String, String> htHetero)478   protected void updateHeteroComputedMenu(Map<String, String> htHetero) {
479     SC menu = htMenus.get("PDBheteroComputedMenu");
480     if (menu == null)
481       return;
482     menuRemoveAll(menu, 0);
483     menuEnable(menu, false);
484     if (htHetero == null)
485       return;
486     int n = 0;
487     for (Map.Entry<String, String> hetero : htHetero.entrySet()) {
488       String heteroCode = hetero.getKey();
489       String heteroName = hetero.getValue();
490       if (heteroName.length() > 20)
491         heteroName = heteroName.substring(0, 20) + "...";
492       String entryName = heteroCode + " - " + heteroName;
493       menuCreateItem(menu, entryName, "SELECT [" + heteroCode + "]", null);
494       n++;
495     }
496     menuEnable(menu, (n > 0));
497   }
498 
499   @SuppressWarnings("unchecked")
updateSurfMoComputedMenu(Map<String, Object> moData)500   protected void updateSurfMoComputedMenu(Map<String, Object> moData) {
501     SC menu = htMenus.get("surfMoComputedMenuText");
502     if (menu == null)
503       return;
504     menuRemoveAll(menu, 0);
505     Lst<Map<String, Object>> mos = (moData == null ? null
506         : (Lst<Map<String, Object>>) (moData.get("mos")));
507     int nOrb = (mos == null ? 0 : mos.size());
508     String text = getMenuText("surfMoComputedMenuText");
509     if (nOrb == 0) {
510       menuSetLabel(menu, GT.o(GT.$(text), ""));
511       menuEnable(menu, false);
512       return;
513     }
514     menuSetLabel(menu, GT.i(GT.$(text), nOrb));
515     menuEnable(menu, true);
516     SC subMenu = menu;
517     int nmod = (nOrb % itemMax);
518     if (nmod == 0)
519       nmod = itemMax;
520     int pt = (nOrb > itemMax ? 0 : Integer.MIN_VALUE);
521     for (int i = nOrb; --i >= 0;) {
522       if (pt >= 0 && (pt++ % nmod) == 0) {
523         if (pt == nmod + 1)
524           nmod = itemMax;
525         String id = "mo" + pt + "Menu";
526         subMenu = menuNewSubMenu(Math.max(i + 2 - nmod, 1) + "..." + (i + 1),
527             menuGetId(menu) + "." + id);
528         menuAddSubMenu(menu, subMenu);
529         htMenus.put(id, subMenu);
530         pt = 1;
531       }
532       Map<String, Object> mo = mos.get(i);
533       String entryName = "#"
534           + (i + 1)
535           + " "
536           + (mo.containsKey("type") ? mo.get("type") + " " : "")
537           + (mo.containsKey("symmetry") ? mo.get("symmetry") + " "
538               : "")
539           + (mo.containsKey("occupancy") ? "(" + mo.get("occupancy") + ") " : "")
540 
541               + (mo.containsKey("energy") ? mo.get("energy") : "");
542       String script = "mo " + (i + 1);
543       menuCreateItem(subMenu, entryName, script, null);
544     }
545   }
546 
updateFileTypeDependentMenus()547   protected void updateFileTypeDependentMenus() {
548     for (int i = NotPDB.size(); --i >= 0;)
549       menuEnable(NotPDB.get(i), !isPDB);
550     for (int i = PDBOnly.size(); --i >= 0;)
551       menuEnable(PDBOnly.get(i), isPDB);
552     for (int i = UnitcellOnly.size(); --i >= 0;)
553       menuEnable(UnitcellOnly.get(i), isUnitCell);
554     for (int i = FileUnitOnly.size(); --i >= 0;)
555       menuEnable(FileUnitOnly.get(i), isUnitCell || fileHasUnitCell);
556     for (int i = FileMolOnly.size(); --i >= 0;)
557       menuEnable(FileMolOnly.get(i), isUnitCell || fileHasUnitCell);
558     for (int i = SingleModelOnly.size(); --i >= 0;)
559       menuEnable(SingleModelOnly.get(i), isLastFrame);
560     for (int i = FramesOnly.size(); --i >= 0;)
561       menuEnable(FramesOnly.get(i), isMultiFrame);
562     for (int i = VibrationOnly.size(); --i >= 0;)
563       menuEnable(VibrationOnly.get(i), isVibration);
564     for (int i = SymmetryOnly.size(); --i >= 0;)
565       menuEnable(SymmetryOnly.get(i), hasSymmetry && isUnitCell);
566     for (int i = ChargesOnly.size(); --i >= 0;)
567       menuEnable(ChargesOnly.get(i), haveCharges);
568     for (int i = TemperatureOnly.size(); --i >= 0;)
569       menuEnable(TemperatureOnly.get(i), haveBFactors);
570     updateSignedAppletItems();
571   }
572 
updateSceneComputedMenu()573   protected void updateSceneComputedMenu() {
574     SC menu = htMenus.get("sceneComputedMenu");
575     if (menu == null)
576       return;
577     menuRemoveAll(menu, 0);
578     menuEnable(menu, false);
579     String[] scenes = (String[]) vwr.ms.getInfoM("scenes");
580     if (scenes == null)
581       return;
582     for (int i = 0; i < scenes.length; i++)
583       menuCreateItem(menu, scenes[i], "restore scene " + PT.esc(scenes[i])
584           + " 1.0", null);
585     menuEnable(menu, true);
586   }
587 
updatePDBResidueComputedMenus()588   protected void updatePDBResidueComputedMenus() {
589     boolean haveMenu = false;
590     SC menu3 = htMenus.get("PDBaaResiduesComputedMenu");
591     if (menu3 != null) {
592       menuRemoveAll(menu3, 0);
593       menuEnable(menu3, false);
594       haveMenu = true;
595     }
596     SC menu1 = htMenus.get("PDBnucleicResiduesComputedMenu");
597     if (menu1 != null) {
598       menuRemoveAll(menu1, 0);
599       menuEnable(menu1, false);
600       haveMenu = true;
601     }
602 
603     SC menu2 = htMenus.get("PDBcarboResiduesComputedMenu");
604     if (menu2 != null) {
605       menuRemoveAll(menu2, 0);
606       menuEnable(menu2, false);
607       haveMenu = true;
608     }
609     if (modelSetInfo == null || !haveMenu)
610       return;
611     int n = (modelIndex < 0 ? 0 : modelIndex + 1);
612     String[] lists = ((String[]) modelSetInfo.get("group3Lists"));
613     group3List = (lists == null ? null : lists[n]);
614     group3Counts = (lists == null ? null
615         : ((int[][]) modelSetInfo.get("group3Counts"))[n]);
616 
617     if (group3List == null)
618       return;
619     //next is correct as "<=" because it includes "UNK"
620     int nItems = 0;
621     String groupList = Group.standardGroupList;
622     if (menu3 != null) {
623       for (int i = 1; i < JC.GROUPID_AMINO_MAX; ++i)
624         nItems += updateGroup3List(menu3,
625             groupList.substring(i * 6 - 4, i * 6 - 1).trim());
626       nItems += augmentGroup3List(menu3, "p>", true);
627       menuEnable(menu3, (nItems > 0));
628       menuEnable(htMenus.get("PDBproteinMenu"), (nItems > 0));
629     }
630     if (menu1 != null) {
631       nItems = augmentGroup3List(menu1, "n>", false);
632       menuEnable(menu1, nItems > 0);
633       menuEnable(htMenus.get("PDBnucleicMenu"), (nItems > 0));
634       @SuppressWarnings("unchecked")
635       Map<String, Object> dssr = (nItems > 0 && modelIndex >= 0
636           ? (Map<String, Object>) vwr.ms.getInfo(modelIndex, "dssr")
637           : null);
638       if (dssr != null)
639         setSecStrucMenu(htMenus.get("aaStructureMenu"), dssr);
640     }
641     if (menu2 != null) {
642       nItems = augmentGroup3List(menu2, "c>", false);
643       menuEnable(menu2, nItems > 0);
644       menuEnable(htMenus.get("PDBcarboMenu"), (nItems > 0));
645     }
646   }
647 
648   @SuppressWarnings("unchecked")
setSecStrucMenu(SC menu, Map<String, Object> dssr)649   private boolean setSecStrucMenu(SC menu, Map<String, Object> dssr) {
650      Map<String, Object> counts = (Map<String, Object>) dssr.get("counts");
651     if (counts == null)
652       return false;
653     String[] keys = new String[counts.size()];
654     counts.keySet().toArray(keys);
655     Arrays.sort(keys);
656     if (keys.length == 0)
657       return false;
658     menu.removeAll();
659     for (int i = 0; i < keys.length; i++)
660       menuCreateItem(menu, keys[i] + " (" +counts.get(keys[i]) +")", "select modelIndex=" + modelIndex + " && within('dssr', '"+keys[i]+"');", null);
661     return true;
662   }
663 
updateGroup3List(SC menu, String name)664   private int updateGroup3List(SC menu, String name) {
665     int nItems = 0;
666     int n = group3Counts[group3List.indexOf(name) / 6];
667     name = name.trim();
668     String script = null;
669     if (n > 0) {
670       script = "SELECT " + name;
671       name += "  (" + n + ")";
672       nItems++;
673     }
674     SC item = menuCreateItem(menu, name, script, menuGetId(menu) + "." + name);
675     if (n == 0)
676       menuEnable(item, false);
677     return nItems;
678   }
679 
augmentGroup3List(SC menu, String type, boolean addSeparator)680   private int augmentGroup3List(SC menu, String type, boolean addSeparator) {
681     int pt = JC.GROUPID_AMINO_MAX * 6 - 6;
682     // ...... p>AFN]o>ODH]n>+T ]
683     int nItems = 0;
684     while (true) {
685       pt = group3List.indexOf(type, pt);
686       if (pt < 0)
687         break;
688       if (nItems++ == 0 && addSeparator)
689         menuAddSeparator(menu);
690       int n = group3Counts[pt / 6];
691       String heteroCode = group3List.substring(pt + 2, pt + 5);
692       String name = heteroCode + "  (" + n + ")";
693       menuCreateItem(menu, name, "SELECT [" + heteroCode + "]", menuGetId(menu)
694           + "." + name);
695       pt++;
696     }
697     return nItems;
698   }
699 
updateSYMMETRYComputedMenus()700   protected void updateSYMMETRYComputedMenus() {
701     updateSYMMETRYSelectComputedMenu();
702     updateSYMMETRYShowComputedMenu();
703   }
704 
705   @SuppressWarnings("unchecked")
updateSYMMETRYShowComputedMenu()706   protected void updateSYMMETRYShowComputedMenu() {
707     SC menu = htMenus.get("SYMMETRYShowComputedMenu");
708     if (menu == null)
709       return;
710     menuRemoveAll(menu, 0);
711     menuEnable(menu, false);
712     if (!hasSymmetry || modelIndex < 0)
713       return;
714     Map<String, Object> info = (Map<String, Object>) vwr.getProperty(
715         "DATA_API", "spaceGroupInfo", null);
716     if (info == null)
717       return;
718     Object[][] infolist = (Object[][]) info.get("operations");
719     if (infolist == null)
720       return;
721     String name = (String) info.get("spaceGroupName");
722     menuSetLabel(menu, name == null ? GT.$("Space Group") : name);
723     SC subMenu = menu;
724     int pt = (infolist.length > itemMax ? 0 : Integer.MIN_VALUE);
725     for (int i = 0; i < infolist.length; i++) {
726       if (pt >= 0 && (pt++ % itemMax) == 0) {
727         String id = "drawsymop" + pt + "Menu";
728         subMenu = menuNewSubMenu(
729             (i + 1) + "..." + Math.min(i + itemMax, infolist.length),
730             menuGetId(menu) + "." + id);
731         menuAddSubMenu(menu, subMenu);
732         htMenus.put(id, subMenu);
733         pt = 1;
734       }
735       if (i == 0)
736         menuEnable(
737             menuCreateItem(subMenu, GT.$("none"), "draw sym_* delete", null),
738             true);
739       String sym = (String) infolist[i][1]; // XYZoriginal
740       if (sym.indexOf("x1") < 0)
741         sym = (String) infolist[i][0]; // normalized XYZ
742       String entryName = (i + 1) + " " + infolist[i][2] + " (" + sym + ")";
743       menuEnable(
744           menuCreateItem(subMenu, entryName, "draw SYMOP " + (i + 1), null),
745           true);
746     }
747     menuEnable(menu, true);
748   }
749 
updateSYMMETRYSelectComputedMenu()750   protected void updateSYMMETRYSelectComputedMenu() {
751     SC menu = htMenus.get("SYMMETRYSelectComputedMenu");
752     if (menu == null)
753       return;
754     menuRemoveAll(menu, 0);
755     menuEnable(menu, false);
756     if (!hasSymmetry || modelIndex < 0)
757       return;
758     String[] list = (String[]) modelInfo.get("symmetryOperations");
759     if (list == null)
760       return;
761     int[] cellRange = (int[]) modelInfo.get("unitCellRange");
762     boolean haveUnitCellRange = (cellRange != null);
763     SC subMenu = menu;
764     int nmod = itemMax;
765     int pt = (list.length > itemMax ? 0 : Integer.MIN_VALUE);
766     for (int i = 0; i < list.length; i++) {
767       if (pt >= 0 && (pt++ % nmod) == 0) {
768         String id = "symop" + pt + "Menu";
769         subMenu = menuNewSubMenu(
770             (i + 1) + "..." + Math.min(i + itemMax, list.length),
771             menuGetId(menu) + "." + id);
772         menuAddSubMenu(menu, subMenu);
773         htMenus.put(id, subMenu);
774         pt = 1;
775       }
776       String entryName = "symop=" + (i + 1) + " # " + list[i];
777       menuEnable(
778           menuCreateItem(subMenu, entryName, "SELECT symop=" + (i + 1), null),
779           haveUnitCellRange);
780     }
781     menuEnable(menu, true);
782   }
783 
updateFRAMESbyModelComputedMenu()784   protected void updateFRAMESbyModelComputedMenu() {
785     //allowing this in case we move it later
786     SC menu = htMenus.get("FRAMESbyModelComputedMenu");
787     if (menu == null)
788       return;
789     menuEnable(menu, (modelCount > 0));
790     menuSetLabel(menu, (modelIndex < 0 ? gti("allModelsText", modelCount)
791         : gto("modelMenuText", (modelIndex + 1) + "/" + modelCount)));
792     menuRemoveAll(menu, 0);
793     if (modelCount < 1)
794       return;
795     if (modelCount > 1)
796       menuCreateCheckboxItem(menu, GT.$("All"), "frame 0 ##", null,
797           (modelIndex < 0), false);
798 
799     SC subMenu = menu;
800     int pt = (modelCount > itemMax ? 0 : Integer.MIN_VALUE);
801     for (int i = 0; i < modelCount; i++) {
802       if (pt >= 0 && (pt++ % itemMax) == 0) {
803         String id = "model" + pt + "Menu";
804         subMenu = menuNewSubMenu(
805             (i + 1) + "..." + Math.min(i + itemMax, modelCount),
806             menuGetId(menu) + "." + id);
807         menuAddSubMenu(menu, subMenu);
808         htMenus.put(id, subMenu);
809         pt = 1;
810       }
811       String script = "" + vwr.getModelNumberDotted(i);
812       String entryName = vwr.getModelName(i);
813       String spectrumTypes = (String) vwr.ms.getInfo(i,
814           "spectrumTypes");
815       if (spectrumTypes != null && entryName.startsWith(spectrumTypes))
816         spectrumTypes = null;
817       if (!entryName.equals(script)) {
818         int ipt = entryName.indexOf(";PATH");
819         if (ipt >= 0)
820           entryName = entryName.substring(0, ipt);
821         if (entryName.indexOf("Model[") == 0
822             && (ipt = entryName.indexOf("]:")) >= 0)
823           entryName = entryName.substring(ipt + 2);
824         entryName = script + ": " + entryName;
825       }
826       if (entryName.length() > 60)
827         entryName = entryName.substring(0, 55) + "...";
828       if (spectrumTypes != null)
829         entryName += " (" + spectrumTypes + ")";
830       menuCreateCheckboxItem(subMenu, entryName, "model " + script + " ##",
831           null, (modelIndex == i), false);
832     }
833   }
834 
updateConfigurationComputedMenu()835   protected void updateConfigurationComputedMenu() {
836     SC menu = htMenus.get("configurationComputedMenu");
837     if (menu == null)
838       return;
839     menuEnable(menu, isMultiConfiguration);
840     if (!isMultiConfiguration)
841       return;
842     int nAltLocs = altlocs.length();
843     menuSetLabel(menu, gti("configurationMenuText", nAltLocs));
844     menuRemoveAll(menu, 0);
845     String script = "hide none ##CONFIG";
846     menuCreateCheckboxItem(menu, GT.$("All"), script, null,
847         (updateMode == UPDATE_CONFIG && configurationSelected.equals(script)),
848         false);
849     for (int i = 0; i < nAltLocs; i++) {
850       script = "configuration " + (i + 1)
851           + "; hide thisModel and not selected ##CONFIG";
852       String entryName = "" + (i + 1) + " -- \"" + altlocs.charAt(i) + "\"";
853       menuCreateCheckboxItem(
854           menu,
855           entryName,
856           script,
857           null,
858           (updateMode == UPDATE_CONFIG && configurationSelected.equals(script)),
859           false);
860     }
861   }
862 
863   private final String[] noZapped = { "surfaceMenu", "measureMenu",
864       "pickingMenu", "computationMenu",
865       "SIGNEDJAVAcaptureMenuSPECIAL" };
866 
867   @SuppressWarnings("unchecked")
updateModelSetComputedMenu()868   protected void updateModelSetComputedMenu() {
869     SC menu = htMenus.get("modelSetMenu");
870     if (menu == null)
871       return;
872     menuRemoveAll(menu, 0);
873     menuSetLabel(menu, nullModelSetName);
874     menuEnable(menu, false);
875     for (int i = noZapped.length; --i >= 0;)
876       menuEnable(htMenus.get(noZapped[i]), !isZapped);
877     if (modelSetName == null || isZapped)
878       return;
879     if (isMultiFrame) {
880       modelSetName = gti("modelSetCollectionText", modelCount);
881       if (modelSetName.length() > titleWidthMax)
882         modelSetName = modelSetName.substring(0, titleWidthMax) + "...";
883     } else if (vwr.getBooleanProperty("hideNameInPopup")) {
884       modelSetName = getMenuText("hiddenModelSetText");
885     } else if (modelSetName.length() > titleWidthMax) {
886       modelSetName = modelSetName.substring(0, titleWidthMax) + "...";
887     }
888     menuSetLabel(menu, modelSetName);
889     menuEnable(menu, true);
890 
891     // 100 here is totally arbitrary. You can do a minimization on any number of atoms
892     menuEnable(htMenus.get("computationMenu"), ac <= 100);
893     addMenuItem(menu, gti("atomsText", ac));
894     addMenuItem(menu, gti("bondsText", vwr.ms.getBondCountInModel(modelIndex)));
895     if (isPDB) {
896       menuAddSeparator(menu);
897       addMenuItem(menu,
898           gti("groupsText", vwr.ms.getGroupCountInModel(modelIndex)));
899       addMenuItem(menu,
900           gti("chainsText", vwr.ms.getChainCountInModelWater(modelIndex, false)));
901       addMenuItem(menu,
902           gti("polymersText", vwr.ms.getBioPolymerCountInModel(modelIndex)));
903       SC submenu = htMenus.get("BiomoleculesMenu");
904       if (submenu == null) {
905         submenu = menuNewSubMenu(GT.$(getMenuText("biomoleculesMenuText")),
906             menuGetId(menu) + ".biomolecules");
907         menuAddSubMenu(menu, submenu);
908       }
909       menuRemoveAll(submenu, 0);
910       menuEnable(submenu, false);
911       Lst<Map<String, Object>> biomolecules;
912       if (modelIndex >= 0
913           && (biomolecules = (Lst<Map<String, Object>>) vwr
914               .ms.getInfo(modelIndex, "biomolecules")) != null) {
915         menuEnable(submenu, true);
916         int nBiomolecules = biomolecules.size();
917         for (int i = 0; i < nBiomolecules; i++) {
918           String script = (isMultiFrame ? ""
919               : "save orientation;load \"\" FILTER \"biomolecule " + (i + 1)
920                   + "\";restore orientation;");
921           int nAtoms = ((Integer) biomolecules.get(i).get("atomCount"))
922               .intValue();
923           String entryName = gto(isMultiFrame ? "biomoleculeText"
924               : "loadBiomoleculeText", new Object[] { Integer.valueOf(i + 1),
925               Integer.valueOf(nAtoms) });
926           menuCreateItem(submenu, entryName, script, null);
927         }
928       }
929     }
930     if (isApplet && !vwr.getBooleanProperty("hideNameInPopup")) {
931       menuAddSeparator(menu);
932       menuCreateItem(menu, gto("viewMenuText", modelSetFileName), "show url",
933           null);
934     }
935   }
936 
gti(String s, int n)937   private String gti(String s, int n) {
938     return GT.i(GT.$(getMenuText(s)), n);
939   }
940 
gto(String s, Object o)941   private String gto(String s, Object o) {
942     return GT.o(GT.$(getMenuText(s)), o);
943   }
944 
updateAboutSubmenu()945   protected void updateAboutSubmenu() {
946     if (isApplet)
947       setText("APPLETid", vwr.appletName);
948 
949     /**
950      * @j2sNative
951      *
952      */
953     {
954       Runtime runtime = Runtime.getRuntime();
955       int n = runtime.availableProcessors();
956       if (n > 0)
957         setText("JAVAprocessors", GT.i(GT.$("{0} processors"), n));
958       setText("JAVAmemTotal",
959           GT.i(GT.$("{0} MB total"), convertToMegabytes(runtime.totalMemory())));
960       //     memFree.setText(GT.i(GT.$("{0} MB free"), convertToMegabytes(runtime.freeMemory())));
961       setText("JAVAmemMax",
962           GT.i(GT.$("{0} MB maximum"), convertToMegabytes(runtime.maxMemory())));
963     }
964 
965   }
966 
updateLanguageSubmenu()967   protected void updateLanguageSubmenu() {
968     SC menu = htMenus.get("languageComputedMenu");
969     if (menu == null)
970       return;
971     menuRemoveAll(menu, 0);
972     String language = GT.getLanguage();
973     String id = menuGetId(menu);
974     Language[] languages = GT.getLanguageList(null);
975     for (int i = 0, p = 0; i < languages.length; i++) {
976       if (language.equals(languages[i].code))
977         languages[i].display = true;
978       if (languages[i].display) {
979         String code = languages[i].code;
980         String name = languages[i].language;
981         String nativeName = languages[i].nativeLanguage;
982         String menuLabel = code + " - " + GT.$(name);
983         if ((nativeName != null) && (!nativeName.equals(GT.$(name)))) {
984           menuLabel += " - " + nativeName;
985         }
986         if (p++ > 0 && (p % 4 == 1))
987           menuAddSeparator(menu);
988         menuCreateCheckboxItem(menu, menuLabel, "language = \"" + code
989             + "\" ##" + name, id + "." + code, language.equals(code), false);
990       }
991     }
992   }
993 
updateSpecialMenuItem(SC m)994   protected void updateSpecialMenuItem(SC m) {
995     m.setText(getSpecialLabel(m.getName(), m.getText()));
996   }
997 
998   /**
999    * menus or menu items with SPECIAL in their name are sent here for on-the-fly
1000    * labeling
1001    *
1002    * @param name
1003    * @param text
1004    * @return revised text
1005    */
getSpecialLabel(String name, String text)1006   protected String getSpecialLabel(String name, String text) {
1007     int pt = text.indexOf(" (");
1008     if (pt < 0)
1009       pt = text.length();
1010     String info = null;
1011     if (name.indexOf("captureLooping") >= 0)
1012       info = (vwr.am.animationReplayMode == T.once ? "ONCE" : "LOOP");
1013     else if (name.indexOf("captureFps") >= 0)
1014       info = "" + vwr.getInt(T.animationfps);
1015     else if (name.indexOf("captureMenu") >= 0)
1016       info = (vwr.captureParams == null ? GT.$("not capturing") : vwr.fm
1017           .getFilePath((String) vwr.captureParams.get("captureFileName"),
1018               false, true)
1019           + " " + vwr.captureParams.get("captureCount"));
1020     return (info == null ? text : text.substring(0, pt) + " (" + info + ")");
1021   }
1022 
1023 }
1024