1 /* $RCSfile$
2  * $Author: hansonr $
3  * $Date: 2009-06-26 23:35:44 -0500 (Fri, 26 Jun 2009) $
4  * $Revision: 11131 $
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.openscience.jmol.app.janocchio;
25 
26 import java.awt.BorderLayout;
27 import java.awt.Color;
28 import java.awt.Component;
29 import java.awt.Container;
30 import java.awt.Dimension;
31 import java.awt.Image;
32 import java.awt.Point;
33 import java.awt.event.ActionEvent;
34 import java.beans.PropertyChangeEvent;
35 import java.beans.PropertyChangeListener;
36 import java.io.BufferedReader;
37 import java.io.File;
38 import java.io.FileReader;
39 import java.io.FileWriter;
40 import java.io.IOException;
41 import java.io.PrintWriter;
42 import java.util.ArrayList;
43 import java.util.HashSet;
44 import java.util.Hashtable;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48 import java.util.StringTokenizer;
49 
50 import javajs.util.BS;
51 import javajs.util.JSJSONParser;
52 
53 import javax.swing.AbstractAction;
54 import javax.swing.Action;
55 import javax.swing.Box;
56 import javax.swing.BoxLayout;
57 import javax.swing.ImageIcon;
58 import javax.swing.JCheckBoxMenuItem;
59 import javax.swing.JFileChooser;
60 import javax.swing.JFrame;
61 import javax.swing.JLabel;
62 import javax.swing.JMenuItem;
63 import javax.swing.JOptionPane;
64 import javax.swing.JPanel;
65 import javax.swing.JSplitPane;
66 import javax.swing.JToolBar;
67 import javax.swing.SwingConstants;
68 
69 import org.jmol.c.CBK;
70 import org.jmol.dialog.FileChooser;
71 import org.jmol.i18n.GT;
72 import org.jmol.modelset.Atom;
73 import org.jmol.quantum.NMRCalculation;
74 import org.openscience.jmol.app.Jmol;
75 import org.openscience.jmol.app.JmolApp;
76 import org.openscience.jmol.app.jmolpanel.DisplayPanel;
77 import org.openscience.jmol.app.jmolpanel.GuiMap;
78 import org.openscience.jmol.app.jmolpanel.JmolPanel;
79 import org.openscience.jmol.app.jmolpanel.JmolResourceHandler;
80 import org.openscience.jmol.app.jmolpanel.Splash;
81 import org.openscience.jmol.app.jmolpanel.StatusBar;
82 import org.openscience.jmol.app.jmolpanel.StatusListener;
83 
84 public class NMR_JmolPanel extends JmolPanel {
85 
86   final static int MIN_SIZE = 600;
87 
88   private NMR_DisplayPanel nmrDisplay;
89 
90   public JSplitPane mainSplitPane;
91   public NoeTable noeTable;
92   public CoupleTable coupleTable;
93   public FrameCounter frameCounter;
94   public LabelSetter labelSetter;
95   public PopulationDisplay populationDisplay;
96   public FrameDeltaDisplay frameDeltaDisplay;
97 
98   protected static File currentDir;
99 
100   FileChooser openChooser;
101   JFileChooser exportChooser;
102   JFileChooser saveNmrChooser;
103   JFileChooser readNmrChooser;
104   JFileChooser saveNamfisChooser;
105   JFileChooser readNamfisChooser;
106 
107   NmrApplet nmrApplet;
108   boolean isApplet;
109   // private CDKPluginManager pluginManager;
110 
111   private NmrGuiMap nmrguimap; // ha ha! Can't initialize this if superclass is also initializing!
112 
113   @Override
getMenuItem(String name)114   public JMenuItem getMenuItem(String name) {
115     return (JMenuItem) nmrguimap.get(name);
116   }
117 
118   static Point border;
119   static Boolean haveBorder = Boolean.FALSE;
120 
121   static Set<String> htGuiChanges;
122 
123   static {
124     htGuiChanges = new HashSet<String>();
125     String[] changes = tokenize(NmrResourceHandler.getStringX("changes"));
126     for (int i = changes.length; --i >= 0;)
127       htGuiChanges.add(changes[i]);
128   }
129 
NMR_JmolPanel(JmolApp jmolApp, Splash splash, JFrame frame, Jmol parent, int startupWidth, int startupHeight, Map<String, Object> vwrOptions, Point loc)130   public NMR_JmolPanel(JmolApp jmolApp, Splash splash, JFrame frame,
131       Jmol parent, int startupWidth, int startupHeight,
132       Map<String, Object> vwrOptions, Point loc) {
133     super(jmolApp, splash, frame, parent, startupWidth, startupHeight,
134         vwrOptions, loc);
135   }
136 
getDistanceJMolecule(BS mol, String[] labelArray, boolean forNOE)137   NmrMolecule getDistanceJMolecule(BS mol, String[] labelArray, boolean forNOE) {
138     return new NmrMolecule(this, (mol == null ? vwr.getFrameAtoms()
139         : mol), labelArray, forNOE);
140   }
141 
getAllMolecules()142   BS[] getAllMolecules() {
143     BS[] mols;
144     int mc = ((NMR_Viewer) vwr).getModelCount();
145     mols = new BS[mc];
146     for (int i = mc; --i >= 0;) {
147       mols[i] = vwr.getModelUndeletedAtomsBitSet(i);
148     }
149     return mols;
150   }
151 
152   @Override
getWindowName()153   protected String getWindowName() {
154     return "Janocchio";
155   }
156 
157   /**
158    * @return A list of Actions that is understood by the upper level application
159    */
160   @Override
getFrameActions()161   protected List<Action> getFrameActions() {
162     List<Action> actions = super.getFrameActions();
163     Action[] a = {
164         //new PdfAction(),
165         new ReadNmrAction(), new SaveNmrAction(), new DetachAppletAction(),
166         new ReattachAppletAction(), new WriteNamfisAction(),
167         new ReadNamfisAction(), new LabelNmrAction(),
168         new JumpBestFrameAction(), new ViewNoeTableAction(),
169         new ViewCoupleTableAction() };
170     for (int i = a.length; --i >= 0;)
171       actions.add(a[i]);
172     return actions;
173   }
174 
175   @Override
getStringX(String cmd)176   protected String getStringX(String cmd) {
177     return (cmd.indexOf("NMR.") == 0 ? NmrResourceHandler.getStringX(cmd)
178         : JmolResourceHandler.getStringX(cmd));
179   }
180 
181   @Override
getIconX(String img)182   protected ImageIcon getIconX(String img) {
183     return (img.indexOf("NMR.") == 0 ? NmrResourceHandler.getIconX(img)
184         : JmolResourceHandler.getIconX(img));
185   }
186 
187   @Override
createGuiMap()188   protected GuiMap createGuiMap() {
189     return nmrguimap = new NmrGuiMap();
190   }
191 
192   @Override
createStatusBar()193   protected StatusBar createStatusBar() {
194     return super.createStatusBar();
195   }
196 
197   @Override
createToolBar()198   protected JToolBar createToolBar() {
199     JToolBar toolbar = newToolbar(tokenize(NmrResourceHandler
200         .getStringX("toolbar")));
201     //DAE add extra label
202     frameCounter = new FrameCounter((NMR_Viewer) vwr);
203     toolbar.add(frameCounter, BorderLayout.EAST);
204     say(GT.$("Initializing Noes..."));
205     noeTable = new NoeTable(this, frame);
206     say(GT.$("Initializing Couples..."));
207     coupleTable = new CoupleTable(this, frame);
208     labelSetter = new LabelSetter((NMR_Viewer) vwr, noeTable, coupleTable);
209     toolbar.add(labelSetter, BorderLayout.EAST);
210     //Action handler implementation would go here.
211     toolbar.add(Box.createHorizontalGlue());
212     return toolbar;
213   }
214 
215   @Override
createDisplayAndAddStatusListener()216   protected void createDisplayAndAddStatusListener() {
217     isPlugin = ((Nmr) jmolApp).isPlugin();
218     say(GT.$("Initializing 3D display..."));
219     display = nmrDisplay = new NMR_DisplayPanel(this);
220     vwrOptions.put("display", display);
221     myStatusListener = new MyStatusListener(this, display);
222     vwrOptions.put("statusListener", myStatusListener);
223   }
224 
225   @Override
setupModelAdapterAndViewer()226   protected void setupModelAdapterAndViewer() {
227     if (JmolResourceHandler.codePath != null)
228       vwrOptions.put("codePath", JmolResourceHandler.codePath);
229     if (modelAdapter != null)
230       vwrOptions.put("modelAdapter", modelAdapter);
231     say(GT.$("Initializing 3D display...4"));
232     vwr = new NMR_Viewer(vwrOptions);
233     say(GT.$("Initializing 3D display...5"));
234     nmrDisplay.setViewer(vwr);
235     myStatusListener.setViewer(vwr);
236 
237   }
238 
239   @Override
getDialogs()240   protected void getDialogs() {
241     super.getDialogs();
242   }
243 
244   @Override
getMeasurementTable()245   protected void getMeasurementTable() {
246     super.getMeasurementTable();
247   }
248 
249   @Override
setupDisplay()250   protected void setupDisplay() {
251     super.setupDisplay();
252   }
253 
254   @Override
setFrameLocation(Point loc, JmolPanel parent)255   protected void setFrameLocation(Point loc, JmolPanel parent) {
256     super.setFrameLocation(loc, parent);
257   }
258 
259   @Override
setIntoFrame()260   protected void setIntoFrame() {
261 
262     frame.setTitle("Janocchio");
263     frame.setBackground(Color.lightGray);
264     frame.setLayout(new BorderLayout());
265     frame.setBounds(0, 0, startupWidth, startupHeight);
266     Container contentPane = frame.getContentPane();
267     //    contentPane.setPreferredSize(new Dimension(500, 500));
268     //    display.setPreferredSize(new Dimension(500, 500));
269 
270     mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, null, null);
271     mainSplitPane.setOneTouchExpandable(true);
272     mainSplitPane.setContinuousLayout(true);
273     mainSplitPane.setLeftComponent(this);
274     //    setMinimumSize(new Dimension(MIN_SIZE, MIN_SIZE));
275     frame.setMinimumSize(new Dimension(startupWidth + 400, 100));
276 
277     JSplitPane splitPaneRight = new JSplitPane(JSplitPane.VERTICAL_SPLIT, null,
278         null);
279     splitPaneRight.setOneTouchExpandable(true);
280     //splitPaneRight.setDividerLocation(0.5); Doesn't do anything here
281     //splitPaneRight.setContinuousLayout(true);
282     JPanel noePanel = new JPanel();
283     noePanel.setLayout(new BoxLayout(noePanel, BoxLayout.PAGE_AXIS));
284 
285     JLabel label = new JLabel("NOE Table", null, SwingConstants.CENTER);
286     label.setAlignmentX(Component.CENTER_ALIGNMENT);
287 
288     noePanel.add(label);
289     noePanel.add(noeTable);
290 
291     JPanel couplePanel = new JPanel();
292     couplePanel.setLayout(new BoxLayout(couplePanel, BoxLayout.PAGE_AXIS));
293 
294     JLabel label1 = new JLabel("Couple Table", null, SwingConstants.CENTER);
295     label1.setAlignmentX(Component.CENTER_ALIGNMENT);
296 
297     populationDisplay = new PopulationDisplay(((NMR_Viewer) vwr));
298     frameDeltaDisplay = new FrameDeltaDisplay(((NMR_Viewer) vwr));
299 
300     nmrDisplay.setPopulationDisplay(populationDisplay);
301     nmrDisplay.setFrameDeltaDisplay(frameDeltaDisplay);
302 
303     noeTable.setFrameDeltaDisplay(frameDeltaDisplay);
304     coupleTable.setFrameDeltaDisplay(frameDeltaDisplay);
305 
306     couplePanel.add(label1, BorderLayout.PAGE_START);
307     couplePanel.add(coupleTable, BorderLayout.CENTER);
308 
309     couplePanel.add(populationDisplay, BorderLayout.PAGE_END);
310     couplePanel.add(frameDeltaDisplay, BorderLayout.PAGE_END);
311 
312     splitPaneRight.setTopComponent(couplePanel);
313     splitPaneRight.setBottomComponent(noePanel);
314 
315     mainSplitPane.setRightComponent(splitPaneRight);
316     splitPaneRight.setMinimumSize(new Dimension(300, 500));
317 
318     //noeTable.setMinimumSize(new Dimension(0,0));
319     contentPane.add(mainSplitPane, BorderLayout.CENTER);
320 
321     contentPane.setPreferredSize(new Dimension(startupWidth, startupHeight));
322     //dumpContainer(frame, "");
323     frame.pack();
324     //dumpContainer(frame, "");
325     //    dumpContainer(frame, "");
326 
327     ImageIcon jmolIcon = JmolResourceHandler.getIconX("icon");
328     Image iconImage = jmolIcon.getImage();
329     frame.setIconImage(iconImage);
330     if (!((Nmr) jmolApp).isPlugin())
331       frame.addWindowListener(new AppCloser());
332 
333   }
334 
335   @Override
setupConsole()336   protected void setupConsole() {
337     super.setupConsole();
338   }
339 
340   @Override
setupDnD()341   protected void setupDnD() {
342     super.setupDnD();
343   }
344 
345   @Override
setAtomChooser()346   protected void setAtomChooser() {
347     super.setAtomChooser();
348   }
349 
350   @Override
launchMainFrame()351   protected void launchMainFrame() {
352     say(GT.$("Launching main frame..."));
353   }
354 
355   @Override
saveWindowSizes()356   protected void saveWindowSizes() {
357     super.saveWindowSizes();
358   }
359 
360   @Override
getJavaConsole()361   public void getJavaConsole() {
362     super.getJavaConsole();
363   }
364 
365   @Override
setMenuKeys(String key, String tokens)366   protected String setMenuKeys(String key, String tokens) {
367     if (htGuiChanges.contains(key)) {
368       String s = NmrResourceHandler.getStringX(key);
369       if (s == null) {
370         System.err.println("Replacement for " + key + " not found; using "
371             + tokens);
372       } else {
373         // insert at end or prior to last -
374         if (s.startsWith("+")) {
375           s = s.substring(1);
376           int pt = tokens.lastIndexOf(" - ");
377           if (pt < 0) {
378             // menubar, toolbar will not hvae - s
379             tokens += (key.endsWith("bar") ? " " : " - ") + s;
380           } else {
381             tokens = tokens.substring(0, pt + 3) + s + tokens.substring(pt);
382           }
383         } else {
384           tokens = s;
385         }
386         System.out.println("Replacement for " + key + " = " + tokens);
387       }
388     }
389     return tokens;
390   }
391 
392   @Override
doClose(boolean saveSize)393   protected boolean doClose(boolean saveSize) {
394     if (isPlugin) {
395       frame.setVisible(false);
396       ((Nmr) jmolApp).plugin.setVisible(false);
397     } else {
398       super.doClose(saveSize);
399     }
400     return true;
401 
402   }
403 
setCurrentDirectoryAll(File cDir)404   void setCurrentDirectoryAll(File cDir) {
405     openChooser.setCurrentDirectory(cDir);
406     saveNmrChooser.setCurrentDirectory(cDir);
407     saveNamfisChooser.setCurrentDirectory(cDir);
408 
409     readNmrChooser.setCurrentDirectory(cDir);
410     readNamfisChooser.setCurrentDirectory(cDir);
411   }
412 
getMinindex()413   public int getMinindex() {
414     return labelSetter.getMinindex();
415   }
416 
getCurrentStructureFile()417   public String getCurrentStructureFile() {
418     return vwr.getModelSetPathName();
419   }
420 
421   /**
422    * Returns a new File referenced by the property 'user.dir', or null if the
423    * property is not defined.
424    *
425    * @return a File to the user directory
426    */
getUserDirectory()427   public static File getUserDirectory() {
428     if (System.getProperty("user.dir") == null) {
429       return null;
430     }
431     return new File(System.getProperty("user.dir"));
432   }
433 
dumpContainer(Container c, String s)434   protected static void dumpContainer(Container c, String s) {
435     if (c == null)
436       return;
437     for (int i = c.getComponentCount(); --i >= 0;) {
438       Container c1 = (Container) c.getComponent(i);
439       System.out.println(s + c1);
440       dumpContainer(c1, s + " ");
441     }
442   }
443 
444   /**
445    * Take the given string and chop it up into a series of strings on whitespace
446    * boundries. This is useful for trying to get an array of strings out of the
447    * resource file.
448    *
449    * @param input
450    *        String to chop
451    * @return Strings chopped on whitespace boundries
452    */
tokenize(String input)453   protected static String[] tokenize(String input) {
454 
455     List<String> v = new ArrayList<String>();
456     StringTokenizer t = new StringTokenizer(input);
457     String cmd[];
458 
459     while (t.hasMoreTokens()) {
460       v.add(t.nextToken());
461     }
462     cmd = new String[v.size()];
463     for (int i = 0; i < cmd.length; i++) {
464       cmd[i] = v.get(i);
465     }
466     return cmd;
467   }
468 
469   // these correlate with items in NMR_GuiMap.java
470 
471   //  private static final String pdfActionProperty = "NMR.pdf";
472   private static final String saveNmrAction = "NMR.saveNmr";
473   private static final String readNmrAction = "NMR.readNmr";
474   private static final String detachAppletAction = "NMR.detachApplet";
475   private static final String reattachAppletAction = "NMR.reattachApplet";
476   private static final String writeNamfisAction = "NMR.writeNamfis";
477   private static final String readNamfisAction = "NMR.readNamfis";
478   private static final String jumpBestFrameAction = "NMR.jumpBestFrame";
479   private static final String labelNmrAction = "NMR.labelNmr";
480 
481   // --- action implementations -----------------------------------
482 
483   //  private PdfAction pdfAction;
484   //  private ViewNoeTableAction viewNoeTableAction;
485   //  private ViewCoupleTableAction viewCoupleTableAction;
486 
487   class SaveNmrAction extends AbstractAction {
488 
SaveNmrAction()489     public SaveNmrAction() {
490       super(saveNmrAction);
491     }
492 
493     @Override
actionPerformed(ActionEvent e)494     public void actionPerformed(ActionEvent e) {
495       NmrSaver nmrSaver = new NmrSaver(saveNmrChooser);
496 
497       saveNmrChooser.setAccessory(nmrSaver);
498 
499       int retval = saveNmrChooser.showSaveDialog(NMR_JmolPanel.this);
500       File cDir = saveNmrChooser.getCurrentDirectory();
501       setCurrentDirectoryAll(cDir);
502       if (retval == 0) {
503         File file = saveNmrChooser.getSelectedFile();
504         MyFileFilter filter = new MyFileFilter("jsn", "NMR Data files");
505 
506         if (file != null) {
507           if (!filter.checkExtension(file)) {
508             String name = file.getAbsolutePath();
509             // name = name + ".jnc";
510             // file = new File(name);
511             name = name + ".jsn";
512             file = new File(name);
513           }
514 
515           try {
516             new LoadMeasureThreadJSON(NMR_JmolPanel.this, null)
517                 .writeNmrDataJSON(file);
518           } catch (Exception exc) {
519             // Help
520           }
521         }
522         //
523       }
524 
525     }
526 
527   }
528 
writeNmrData(File file)529   public void writeNmrData(File file) throws IOException {
530     PrintWriter out = new PrintWriter(new FileWriter(file));
531 
532     String structurefile = vwr.getModelSetPathName();
533     out.println(structurefile);
534 
535     String[] labelArray = labelSetter.getLabelArray();
536     for (int i = 0; i < labelArray.length; i++) {
537       if (labelArray[i] != null) {
538         out.println(String.valueOf(i + 1) + " " + labelArray[i]);
539       }
540     }
541     out.println("");
542     int noeCount = noeTable.getRowCount();
543     for (int i = 0; i < noeCount; i++) {
544       int[] atomIndices = noeTable.getMeasurementCountPlusIndices(i);
545       out.println(String.valueOf(atomIndices[1] + 1) + " "
546           + String.valueOf(atomIndices[2] + 1) + " "
547           + noeTable.getExpNoe(atomIndices[1], atomIndices[2]));
548     }
549     out.println("");
550 
551     int coupleCount = coupleTable.getRowCount();
552     for (int i = 0; i < coupleCount; i++) {
553       int[] atomIndices = coupleTable.getMeasurementCountPlusIndices(i);
554       out.println(String.valueOf(atomIndices[1] + 1) + " "
555           + String.valueOf(atomIndices[2] + 1) + " "
556           + String.valueOf(atomIndices[3] + 1) + " "
557           + String.valueOf(atomIndices[4] + 1) + " "
558           + coupleTable.getExpCouple(atomIndices[1], atomIndices[4]));
559     }
560 
561     out.flush();
562     out.close();
563   }
564 
565   public class ReadNmrAction extends AbstractAction {
566 
ReadNmrAction()567     public ReadNmrAction() {
568       super(readNmrAction);
569     }
570 
571     @Override
actionPerformed(ActionEvent e)572     public void actionPerformed(ActionEvent e) {
573       NmrReader nmrReader = new NmrReader(readNmrChooser);
574 
575       readNmrChooser.setAccessory(nmrReader);
576 
577       int retval = readNmrChooser.showOpenDialog(NMR_JmolPanel.this);
578       File cDir = readNmrChooser.getCurrentDirectory();
579       setCurrentDirectoryAll(cDir);
580       if (retval == 0) {
581         File file = readNmrChooser.getSelectedFile();
582         if (file != null) {
583           try {
584             MyFileFilter filter = new MyFileFilter("jnc", "NMR Data files");
585             if (filter.checkExtension(file)) {
586               readNmrData(file);
587             } else {
588               readNmrDataJSON(file);
589             }
590 
591           } catch (Exception exc) {
592             // Help
593           }
594         }
595         //
596       }
597 
598     }
599 
600   }
601 
readNmrData(File file)602   public void readNmrData(File file) throws Exception {
603     // Structure File
604     String fileData = vwr.getFileAsString(file.getAbsolutePath());
605     String structureFile = firstLineOf(fileData);
606     fileData = fileData.substring(structureFile.length()).trim();
607     checkLoadAndRun(structureFile, fileData, "jnc");
608   }
609 
readNmrDataJSON(File file)610   public void readNmrDataJSON(File file) throws Exception {
611     String json = vwr.getFileAsString(file.getAbsolutePath());
612     Map<String, Object> jsonData = new JSJSONParser().parseMap(json, true);
613     String structureFile = (String) jsonData.get("StructureFile");
614     checkLoadAndRun(structureFile, jsonData, "json");
615   }
616 
checkLoadAndRun(String structureFile, Object fileData, String fileType)617   private void checkLoadAndRun(String structureFile, Object fileData, String fileType) {
618     String currentStructureFile = getCurrentStructureFile();
619     if (currentStructureFile == null) {
620       int opt = JOptionPane.showConfirmDialog(this,
621           "No Structure File currently loaded.\nLoad Structure File " + structureFile
622               + "\ndefined in this NMR Data File?", "No Structure Warning",
623           JOptionPane.YES_NO_OPTION);
624       if (opt != JOptionPane.YES_OPTION)
625         return;
626     } else if (!currentStructureFile.equals(structureFile)) {
627       int opt = JOptionPane
628           .showConfirmDialog(
629               NMR_JmolPanel.this,
630               "This NMR Data file was saved from a different structure file from that currently loaded.\nContinue Reading Data?",
631               "Read NMR Data Warning", JOptionPane.YES_NO_OPTION);
632       if (opt != JOptionPane.YES_OPTION) {
633         return;
634       }
635       structureFile = null;
636     }
637     @SuppressWarnings("unchecked")
638     LoadMeasureThread thread = ("jnc".equals(fileType) ? new LoadMeasureThread(this, (String) fileData) :
639       new LoadMeasureThreadJSON(this, (Map<String, Object>)fileData));
640     if (structureFile == null) {
641       thread.start();
642     } else {
643       thread.loadAndRun(structureFile);
644     }
645   }
646 
firstLineOf(String s)647   private static String firstLineOf(String s) {
648     int pt;
649     if ((pt = s.indexOf("\n")) < 0 && (pt = s.indexOf("\r")) < 0)
650       pt = s.length();
651     return s.substring(0, pt).trim();
652   }
653 
654   public class LabelNmrAction extends AbstractAction {
LabelNmrAction()655     public LabelNmrAction() {
656       super(labelNmrAction);
657     }
658 
659     @Override
actionPerformed(ActionEvent e)660     public void actionPerformed(ActionEvent e) {
661       String[] labelArray = labelSetter.getLabelArray();
662       String command = new String();
663       //    int minindex = labelSetter.getMinindex();
664       for (int i = 0; i < labelArray.length; i++) {
665         // if (labelArray[i] != null) {
666         command = command + labelSetter.setLabelString(i, labelArray[i]);
667         // }
668       }
669       vwr.script(command);
670     }
671   }
672 
673   public class DetachAppletAction extends AbstractAction {
674 
DetachAppletAction()675     public DetachAppletAction() {
676       super(detachAppletAction);
677     }
678 
679     @Override
actionPerformed(ActionEvent e)680     public void actionPerformed(ActionEvent e) {
681       // ??
682       //      nmrApplet.detach();
683     }
684 
685   }
686 
687   public class ReattachAppletAction extends AbstractAction {
688 
ReattachAppletAction()689     public ReattachAppletAction() {
690       super(reattachAppletAction);
691     }
692 
693     @Override
actionPerformed(ActionEvent e)694     public void actionPerformed(ActionEvent e) {
695       //      nmrApplet.reattach();
696     }
697 
698   }
699 
700   public class ReadNamfisAction extends AbstractAction {
701 
ReadNamfisAction()702     public ReadNamfisAction() {
703       super(readNamfisAction);
704     }
705 
706     @Override
actionPerformed(ActionEvent e)707     public void actionPerformed(ActionEvent e) {
708 
709       NamfisReader namfisReader = new NamfisReader(readNamfisChooser);
710 
711       readNamfisChooser.setAccessory(namfisReader);
712 
713       int retval = readNamfisChooser.showOpenDialog(NMR_JmolPanel.this);
714       File cDir = readNamfisChooser.getCurrentDirectory();
715       setCurrentDirectoryAll(cDir);
716       if (retval == 0) {
717         File file = readNamfisChooser.getSelectedFile();
718         // MyFileFilter filter = new MyFileFilter("in1");
719 
720         if (file != null) {
721 
722           try {
723             readNamfisOutput(file);
724           } catch (Exception exc) {
725             // Help
726           }
727         }
728         //
729       }
730 
731     }
732 
readNamfisOutput(File file)733     private boolean readNamfisOutput(File file) throws IOException {
734       BufferedReader inp = new BufferedReader(new FileReader(file));
735       String line;
736 
737       // NAMFIS often fails to fit the data
738       // Indicated by first line
739 
740       line = inp.readLine();
741       if (line.matches("No feasible solution")) {
742         inp.close();
743         return false;
744       }
745       inp.readLine();
746       inp.readLine();
747       inp.readLine();
748       int nmodel = ((NMR_Viewer) vwr).getModelCount();
749       double[] population = new double[nmodel + 1];
750       for (int i = 0; i <= nmodel; i++) {
751         population[i] = 0.0;
752       }
753 
754       while ((line = inp.readLine()).trim().length() != 0) {
755         String[] l = line.split("[()=\\s]+");
756 
757         int i = (new Integer(l[1])).intValue();
758         double p = (new Double(l[2])).doubleValue();
759 
760         population[i] = p;
761       }
762       populationDisplay.addPopulation(population);
763       frameDeltaDisplay.setVisible(false);
764       JCheckBoxMenuItem mi = (JCheckBoxMenuItem) getMenuItem("NMR.populationDisplayCheck");
765       mi.setSelected(true);
766 
767       inp.close();
768       return true;
769     }
770   }
771 
772   public class WriteNamfisAction extends AbstractAction {
773 
WriteNamfisAction()774     public WriteNamfisAction() {
775       super(writeNamfisAction);
776     }
777 
778     @Override
actionPerformed(ActionEvent e)779     public void actionPerformed(ActionEvent e) {
780       // nmrApplet.reattach();
781       NamfisSaver namfisSaver = new NamfisSaver(saveNamfisChooser);
782 
783       saveNamfisChooser.setAccessory(namfisSaver);
784 
785       int retval = saveNamfisChooser.showSaveDialog(NMR_JmolPanel.this);
786       File cDir = saveNamfisChooser.getCurrentDirectory();
787       setCurrentDirectoryAll(cDir);
788       if (retval == 0) {
789         File file = saveNamfisChooser.getSelectedFile();
790         // MyFileFilter filter = new MyFileFilter("in1");
791 
792         if (file != null) {
793           String name = file.getAbsolutePath();
794           String[] exts = { "in1", "in2", "in3" };
795           MyFileFilter filter = new MyFileFilter(exts, "");
796           if (filter.checkExtension(file)) {
797             // Pattern p = Pattern.compile(".in[0-9]$");
798             name = name.replaceFirst(".in[0-9]$", "");
799 
800           }
801 
802           try {
803             new LoadMeasureThreadJSON(NMR_JmolPanel.this, null)
804                 .writeNamfisFiles(name);
805           } catch (Exception exc) {
806             // Help
807           }
808         }
809         //
810       }
811 
812     }
813 
814   }
815 
816   public class JumpBestFrameAction extends AbstractAction {
817 
JumpBestFrameAction()818     public JumpBestFrameAction() {
819       super(jumpBestFrameAction);
820     }
821 
822     @Override
actionPerformed(ActionEvent e)823     public void actionPerformed(ActionEvent e) {
824       int frame = new LoadMeasureThreadJSON(NMR_JmolPanel.this, null)
825           .jumpBestFrame();
826       if (frame >= 0)
827         frameCounter.setFrameNumberChangeViewer(frame);
828 
829     }
830 
831   }
832 
833   class AtomSetChooserAction extends AbstractAction {
AtomSetChooserAction()834     public AtomSetChooserAction() {
835       super(atomsetchooserAction);
836     }
837 
838     @Override
actionPerformed(ActionEvent e)839     public void actionPerformed(ActionEvent e) {
840       atomSetChooser.setVisible(true);
841     }
842   }
843 
844   //  public class PdfAction extends MoleculeDependentAction {
845   //
846   //    public PdfAction() {
847   //      super(pdfActionProperty);
848   //    }
849   //
850   //    @Override
851   //    public void actionPerformed(ActionEvent e) {
852   //
853   //      exportChooser.setAccessory(null);
854   //
855   //      int retval = exportChooser.showSaveDialog(NMR_JmolPanel.this);
856   //      File cDir = exportChooser.getCurrentDirectory();
857   //      setCurrentDirectoryAll(cDir);
858   //      if (retval == JFileChooser.APPROVE_OPTION) {
859   //        File file = exportChooser.getSelectedFile();
860   //
861   //        if (file != null) {
862   //          Document document = new Document();
863   //
864   //          try {
865   //            PdfWriter writer = PdfWriter.getInstance(document,
866   //                new FileOutputStream(file));
867   //
868   //            document.open();
869   //
870   //            int w = display.getWidth();
871   //            int h = display.getHeight();
872   //            PdfContentByte cb = writer.getDirectContent();
873   //            PdfTemplate tp = cb.createTemplate(w, h);
874   //            Graphics2D g2 = tp.createGraphics(w, h);
875   //            g2.setStroke(new BasicStroke(0.1f));
876   //            tp.setWidth(w);
877   //            tp.setHeight(h);
878   //
879   //            display.print(g2);
880   //            g2.dispose();
881   //            cb.addTemplate(tp, 72, 720 - h);
882   //          } catch (DocumentException de) {
883   //            System.err.println(de.getMessage());
884   //          } catch (IOException ioe) {
885   //            System.err.println(ioe.getMessage());
886   //          }
887   //
888   //          document.close();
889   //        }
890   //      }
891   //    }
892   //
893   //  }
894 
895   public class ViewNoeTableAction extends MoleculeDependentAction {
896 
ViewNoeTableAction()897     public ViewNoeTableAction() {
898       super("viewNoeTable");
899     }
900 
901     @Override
actionPerformed(ActionEvent e)902     public void actionPerformed(ActionEvent e) {
903       noeTable.activate();
904     }
905   }
906 
907   public class ViewCoupleTableAction extends MoleculeDependentAction {
908 
ViewCoupleTableAction()909     public ViewCoupleTableAction() {
910       super("viewCoupleTable");
911     }
912 
913     @Override
actionPerformed(ActionEvent e)914     public void actionPerformed(ActionEvent e) {
915       coupleTable.activate();
916     }
917   }
918 
919   public static final String chemFileProperty = "chemFile";
920 
921   private abstract class MoleculeDependentAction extends AbstractAction
922       implements PropertyChangeListener {
923 
MoleculeDependentAction(String name)924     public MoleculeDependentAction(String name) {
925       super(name);
926       setEnabled(false);
927     }
928 
929     @Override
propertyChange(PropertyChangeEvent event)930     public void propertyChange(PropertyChangeEvent event) {
931 
932       if (event.getPropertyName().equals(chemFileProperty)) {
933         if (event.getNewValue() != null) {
934           setEnabled(true);
935         } else {
936           setEnabled(false);
937         }
938       }
939     }
940   }
941 
942   protected Map<String, Thread> htMessageCallbacks = new Hashtable<String, Thread>();
943 
runScriptWithCallback(Thread t, String command)944   void runScriptWithCallback(Thread t, String command) {
945     String key = "NMR:" + t.getClass().getName();
946     htMessageCallbacks.put(key, t);
947     vwr.script(command);
948     vwr.script("#>NMR>" + key + "<NMR<");
949   }
950 
notifyScriptCallback(String script)951   void notifyScriptCallback(String script) {
952     int pt = (script.startsWith("#>NMR>") ? script.indexOf("<NMR<") : -1);
953     if (pt < 0)
954       return;
955     String key = script.substring(6, pt);
956     Thread t = htMessageCallbacks.remove(key);
957     if (t != null)
958       t.start();
959   }
960 
961   class MyStatusListener extends StatusListener {
962 
963     private String defaultFormat = "set measurementUnits noe_hz";
964 
MyStatusListener(JmolPanel jmol, DisplayPanel display)965     MyStatusListener(JmolPanel jmol, DisplayPanel display) {
966       super(jmol, display);
967     }
968 
969     /**
970      * @param fullPathName
971      * @param fileName
972      * @param modelName
973      * @param errorMsg
974      * @param isAsync
975      */
notifyFileLoaded(String fullPathName, String fileName, String modelName, String errorMsg, Boolean isAsync)976     private void notifyFileLoaded(String fullPathName, String fileName,
977                                   String modelName, String errorMsg,
978                                   Boolean isAsync) {
979       if (errorMsg != null) {
980         return;
981       }
982       if (jmolApp.haveDisplay)
983         pcs.firePropertyChange(chemFileProperty, null, fullPathName);
984 
985       int nmodel = ((NMR_Viewer) vwr).getModelCount();
986 
987       frameCounter.setFrameCount(nmodel);
988 
989       populationDisplay.setVisible(false);
990       frameDeltaDisplay.setVisible(true);
991       JCheckBoxMenuItem mi = (JCheckBoxMenuItem) getMenuItem("NMR.frameDeltaDisplayCheck");
992       mi.setSelected(true);
993       if (defaultFormat != null)
994         vwr.script(defaultFormat);
995     }
996 
notifyFrameChanged(int modelIndex)997     public void notifyFrameChanged(int modelIndex) {
998       if (vwr == null || modelIndex < 0)
999         return;
1000       if (modelIndex == Integer.MIN_VALUE)
1001         modelIndex = ((NMR_Viewer) vwr).getCurrentModelIndex();
1002       int modelAtomCount = getFrameAtomCount();
1003       if (labelSetter.getLabelArray() == null || modelAtomCount != labelSetter.getLabelArray().length) {
1004         labelSetter.allocateLabelArray(modelAtomCount);
1005 
1006         noeTable.allocateLabelArray(modelAtomCount);
1007         noeTable.allocateExpNoes(modelAtomCount);
1008         coupleTable.allocateLabelArray(modelAtomCount);
1009         coupleTable.allocateExpCouples(modelAtomCount);
1010       }
1011 
1012       frameCounter.setFrameNumberFromViewer(modelIndex + 1);
1013       populationDisplay.setFrameNumberFromViewer(modelIndex + 1);
1014 
1015       coupleTable.setmolCDKuptodate(false);
1016       noeTable.setmolCDKuptodate(false);
1017       noeTable.addMol();
1018 
1019       coupleTable.updateTables();
1020       noeTable.updateTables();
1021     }
1022 
1023     /**
1024      * @param atomIndex
1025      * @param strInfo
1026      */
notifyAtomPicked(int atomIndex, String strInfo)1027     public void notifyAtomPicked(int atomIndex, String strInfo) {
1028       if (atomIndex < 0) {
1029         // bond picked;
1030         return;
1031       }
1032       int atomNo = ((NMR_Viewer) vwr).getAtomNumber(atomIndex);
1033       labelSetter.setSelectedAtomIndex(atomNo - 1);
1034       String command = "set display SELECTED; select (atomindex="
1035           + atomIndex + ")";
1036       vwr.script(command);
1037     }
1038 
1039     @Override
notifyCallback(CBK type, Object[] data)1040     public void notifyCallback(CBK type, Object[] data) {
1041       String strInfo = (data == null || data[1] == null ? null : data[1]
1042           .toString());
1043 
1044 //      System.out.println("NMR_JmolPanel notifyCallback "+type + " " + strInfo + " " + data[2]);
1045       super.notifyCallback(type, data);
1046       switch (type) {
1047       case LOADSTRUCT:
1048         notifyFileLoaded(strInfo, (String) data[2], (String) data[3],
1049             (String) data[4], (Boolean) data[8]);
1050         break;
1051       case ANIMFRAME:
1052         int[] iData = (int[]) data[1];
1053         int modelIndex = iData[0];
1054         notifyFrameChanged(modelIndex);
1055         break;
1056       case PICK:
1057         int atomIndex = ((Integer) data[2]).intValue();
1058         notifyAtomPicked(atomIndex, strInfo);
1059         break;
1060       case MEASURE:
1061         String mystatus = (String) data[3];
1062         if (defaultFormat != null) {
1063           vwr.script(defaultFormat);
1064           defaultFormat = null;
1065         }
1066         if (mystatus.equals("measurePending")
1067             || mystatus.equals("measureDeleted"))
1068           return;
1069         if (mystatus.indexOf("Sequence") < 0) {
1070           if (mystatus.indexOf("Picked") >= 0) {
1071             // picking mode
1072             Integer picked = (Integer) vwr.getPOrNull("_picked");
1073             if (picked != null)
1074               notifyAtomPicked(picked.intValue(), strInfo);
1075           }
1076         }
1077         int n = vwr.getMeasurementCount() - 1;
1078         System.out.println("checking for measurement " + n);
1079         if (getViewerMeasurement(n, NMRCalculation.MODE_CALC_J) == null
1080             && getViewerMeasurement(n, NMRCalculation.MODE_CALC_NOE) == null) {
1081           vwr.deleteMeasurement(n);
1082           return;
1083         }
1084         System.out.println("updating for measurement " + n);
1085         noeTable.updateTables();
1086         coupleTable.updateTables();
1087         break;
1088       case MESSAGE:
1089         // this one is totally not helpful. Why doesn't MESSAGE fire this??
1090         break;
1091       case APPLETREADY:
1092         break;
1093       case ATOMMOVED:
1094         break;
1095       case AUDIO:
1096         break;
1097       case CLICK:
1098         break;
1099       case DRAGDROP:
1100         break;
1101       case ECHO:
1102         break;
1103       case ERROR:
1104         break;
1105       case EVAL:
1106         break;
1107       case HOVER:
1108         break;
1109       case IMAGE:
1110         break;
1111       case MINIMIZATION:
1112         break;
1113       case RESIZE:
1114         break;
1115       case SCRIPT:
1116         // looking for the script started, which has the script as data[2]
1117         // We make sure the script we send is a separate script that is just
1118         // the message.
1119         Integer status = (Integer) data[3];
1120         if (status.intValue() < -1)
1121           notifyScriptCallback(data[2].toString());
1122         break;
1123       case SERVICE:
1124         break;
1125       case STRUCTUREMODIFIED:
1126         notifyStructureModified();
1127         break;
1128       case SYNC:
1129         break;
1130       default:
1131         break;
1132       }
1133 
1134     }
1135 
notifyStructureModified()1136     public void notifyStructureModified() {
1137       vwr.deleteMeasurement(vwr.getMeasurementCount() - 1);
1138       notifyFrameChanged(Integer.MIN_VALUE);
1139     }
1140 
1141 
1142   }
1143 
getFrameAtomCount()1144   public int getFrameAtomCount() {
1145     return vwr.getFrameAtoms().cardinality();
1146   }
1147 
getViewerMeasurement(int vRow, int type)1148   Atom[] getViewerMeasurement(int vRow, int type) {
1149     int[] m = vwr.getMeasurementCountPlusIndices(vRow);
1150     if (m[0] != 2)
1151       return null;
1152     Atom[] atoms = new Atom[] { ((NMR_Viewer)vwr).getAtomAt(m[1]), null, null,
1153         ((NMR_Viewer)vwr).getAtomAt(m[2]) };
1154     return (NMRCalculation.getCalcType(atoms, null, type) == NMRCalculation.MODE_CALC_INVALID ? null
1155         : atoms);
1156   }
1157 
getViewerRow(int row, int type)1158   int getViewerRow(int row, int type) {
1159     for (int j = -1, i = 0; i < vwr.getMeasurementCount(); i++) {
1160       if (getViewerMeasurement(i, type) == null)
1161         continue;
1162      if (++j == row) {
1163         return i;
1164       }
1165     }
1166     return -1;
1167   }
1168 
clearViewerSelection()1169   void clearViewerSelection() {
1170     vwr.script("select none");
1171   }
1172 
1173 
1174 
1175 }
1176