Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.gui

File AppJmol.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
35% of files have more coverage

Code metrics

72
225
25
2
704
540
80
0.36
9
12.5
3.2

Classes

Class Line # Actions
AppJmol 55 202 70 123
0.572916757.3%
AppJmol.RenderPanel 629 23 10 27
0.2058823620.6%
 

Contributing tests

This file is covered by 15 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.gui;
22   
23    import jalview.bin.Cache;
24    import jalview.datamodel.AlignmentI;
25    import jalview.datamodel.PDBEntry;
26    import jalview.datamodel.SequenceI;
27    import jalview.gui.ImageExporter.ImageWriterI;
28    import jalview.gui.StructureViewer.ViewerType;
29    import jalview.structures.models.AAStructureBindingModel;
30    import jalview.util.BrowserLauncher;
31    import jalview.util.ImageMaker;
32    import jalview.util.MessageManager;
33    import jalview.util.Platform;
34    import jalview.ws.dbsources.Pdb;
35   
36    import java.awt.BorderLayout;
37    import java.awt.Color;
38    import java.awt.Dimension;
39    import java.awt.Font;
40    import java.awt.Graphics;
41    import java.awt.Rectangle;
42    import java.awt.event.ActionEvent;
43    import java.io.File;
44    import java.util.ArrayList;
45    import java.util.List;
46    import java.util.Vector;
47   
48    import javax.swing.JCheckBoxMenuItem;
49    import javax.swing.JPanel;
50    import javax.swing.JSplitPane;
51    import javax.swing.SwingUtilities;
52    import javax.swing.event.InternalFrameAdapter;
53    import javax.swing.event.InternalFrameEvent;
54   
 
55    public class AppJmol extends StructureViewerBase
56    {
57    // ms to wait for Jmol to load files
58    private static final int JMOL_LOAD_TIMEOUT = 20000;
59   
60    private static final String SPACE = " ";
61   
62    private static final String QUOTE = "\"";
63   
64    AppJmolBinding jmb;
65   
66    JPanel scriptWindow;
67   
68    JSplitPane splitPane;
69   
70    RenderPanel renderPanel;
71   
72    /**
73    *
74    * @param files
75    * @param ids
76    * @param seqs
77    * @param ap
78    * @param usetoColour
79    * - add the alignment panel to the list used for colouring these
80    * structures
81    * @param useToAlign
82    * - add the alignment panel to the list used for aligning these
83    * structures
84    * @param leaveColouringToJmol
85    * - do not update the colours from any other source. Jmol is
86    * handling them
87    * @param loadStatus
88    * @param bounds
89    * @param viewid
90    */
 
91  8 toggle public AppJmol(String[] files, String[] ids, SequenceI[][] seqs,
92    AlignmentPanel ap, boolean usetoColour, boolean useToAlign,
93    boolean leaveColouringToJmol, String loadStatus, Rectangle bounds,
94    String viewid)
95    {
96  8 PDBEntry[] pdbentrys = new PDBEntry[files.length];
97  16 for (int i = 0; i < pdbentrys.length; i++)
98    {
99    // PDBEntry pdbentry = new PDBEntry(files[i], ids[i]);
100  8 PDBEntry pdbentry = new PDBEntry(ids[i], null, PDBEntry.Type.PDB,
101    files[i]);
102  8 pdbentrys[i] = pdbentry;
103    }
104    // / TODO: check if protocol is needed to be set, and if chains are
105    // autodiscovered.
106  8 jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
107    pdbentrys, seqs, null);
108   
109  8 jmb.setLoadingFromArchive(true);
110  8 addAlignmentPanel(ap);
111  8 if (useToAlign)
112    {
113  0 useAlignmentPanelForSuperposition(ap);
114    }
115  8 initMenus();
116  8 if (leaveColouringToJmol || !usetoColour)
117    {
118  8 jmb.setColourBySequence(false);
119  8 seqColour.setSelected(false);
120  8 viewerColour.setSelected(true);
121    }
122  0 else if (usetoColour)
123    {
124  0 useAlignmentPanelForColourbyseq(ap);
125  0 jmb.setColourBySequence(true);
126  0 seqColour.setSelected(true);
127  0 viewerColour.setSelected(false);
128    }
129  8 this.setBounds(bounds);
130  8 setViewId(viewid);
131    // jalview.gui.Desktop.addInternalFrame(this, "Loading File",
132    // bounds.width,bounds.height);
133   
134  8 this.addInternalFrameListener(new InternalFrameAdapter()
135    {
 
136  8 toggle @Override
137    public void internalFrameClosing(
138    InternalFrameEvent internalFrameEvent)
139    {
140  8 closeViewer(false);
141    }
142    });
143  8 initJmol(loadStatus); // pdbentry, seq, JBPCHECK!
144    }
145   
 
146  10 toggle @Override
147    protected void initMenus()
148    {
149  10 super.initMenus();
150   
151  10 viewerActionMenu.setText(MessageManager.getString("label.jmol"));
152   
153  10 viewerColour
154    .setText(MessageManager.getString("label.colour_with_jmol"));
155  10 viewerColour.setToolTipText(MessageManager
156    .getString("label.let_jmol_manage_structure_colours"));
157    }
158   
159    IProgressIndicator progressBar = null;
160   
 
161  0 toggle @Override
162    protected IProgressIndicator getIProgressIndicator()
163    {
164  0 return progressBar;
165    }
166   
167    /**
168    * display a single PDB structure in a new Jmol view
169    *
170    * @param pdbentry
171    * @param seq
172    * @param chains
173    * @param ap
174    */
 
175  2 toggle public AppJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
176    final AlignmentPanel ap)
177    {
178  2 progressBar = ap.alignFrame;
179   
180  2 openNewJmol(ap, alignAddedStructures, new PDBEntry[] { pdbentry },
181    new SequenceI[][]
182    { seq });
183    }
184   
 
185  2 toggle private void openNewJmol(AlignmentPanel ap, boolean alignAdded,
186    PDBEntry[] pdbentrys,
187    SequenceI[][] seqs)
188    {
189  2 progressBar = ap.alignFrame;
190  2 jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
191    pdbentrys, seqs, null);
192  2 addAlignmentPanel(ap);
193  2 useAlignmentPanelForColourbyseq(ap);
194   
195  2 alignAddedStructures = alignAdded;
196  2 useAlignmentPanelForSuperposition(ap);
197   
198  2 jmb.setColourBySequence(true);
199  2 setSize(400, 400); // probably should be a configurable/dynamic default here
200  2 initMenus();
201  2 addingStructures = false;
202  2 worker = new Thread(this);
203  2 worker.start();
204   
205  2 this.addInternalFrameListener(new InternalFrameAdapter()
206    {
 
207  2 toggle @Override
208    public void internalFrameClosing(
209    InternalFrameEvent internalFrameEvent)
210    {
211  2 closeViewer(false);
212    }
213    });
214   
215    }
216   
217    /**
218    * create a new Jmol containing several structures optionally superimposed
219    * using the given alignPanel.
220    *
221    * @param ap
222    * @param alignAdded
223    * - true to superimpose
224    * @param pe
225    * @param seqs
226    */
 
227  0 toggle public AppJmol(AlignmentPanel ap, boolean alignAdded, PDBEntry[] pe,
228    SequenceI[][] seqs)
229    {
230  0 openNewJmol(ap, alignAdded, pe, seqs);
231    }
232   
233   
 
234  10 toggle void initJmol(String command)
235    {
236  10 jmb.setFinishedInit(false);
237  10 renderPanel = new RenderPanel();
238    // TODO: consider waiting until the structure/view is fully loaded before
239    // displaying
240  10 this.getContentPane().add(renderPanel, java.awt.BorderLayout.CENTER);
241  10 jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle(),
242    getBounds().width, getBounds().height);
243  10 if (scriptWindow == null)
244    {
245  10 BorderLayout bl = new BorderLayout();
246  10 bl.setHgap(0);
247  10 bl.setVgap(0);
248  10 scriptWindow = new JPanel(bl);
249  10 scriptWindow.setVisible(false);
250    }
251   
252  10 jmb.allocateViewer(renderPanel, true, "", null, null, "", scriptWindow,
253    null);
254    // jmb.newJmolPopup("Jmol");
255  10 if (command == null)
256    {
257  0 command = "";
258    }
259  10 jmb.evalStateCommand(command);
260  10 jmb.evalStateCommand("set hoverDelay=0.1");
261  10 jmb.setFinishedInit(true);
262    }
263   
 
264  0 toggle @Override
265    void showSelectedChains()
266    {
267  0 Vector<String> toshow = new Vector<>();
268  0 for (int i = 0; i < chainMenu.getItemCount(); i++)
269    {
270  0 if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
271    {
272  0 JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i);
273  0 if (item.isSelected())
274    {
275  0 toshow.addElement(item.getText());
276    }
277    }
278    }
279  0 jmb.centerViewer(toshow);
280    }
281   
 
282  11 toggle @Override
283    public void closeViewer(boolean closeExternalViewer)
284    {
285    // Jmol does not use an external viewer
286  11 if (jmb != null)
287    {
288  10 jmb.closeViewer();
289    }
290  11 setAlignmentPanel(null);
291  11 _aps.clear();
292  11 _alignwith.clear();
293  11 _colourwith.clear();
294    // TODO: check for memory leaks where instance isn't finalised because jmb
295    // holds a reference to the window
296  11 jmb = null;
297    }
298   
 
299  3 toggle @Override
300    public void run()
301    {
302  3 _started = true;
303  3 try
304    {
305  3 List<String> files = fetchPdbFiles();
306  3 if (files.size() > 0)
307    {
308  3 showFilesInViewer(files);
309    }
310    } finally
311    {
312  3 _started = false;
313  3 worker = null;
314    }
315    }
316   
317    /**
318    * Either adds the given files to a structure viewer or opens a new viewer to
319    * show them
320    *
321    * @param files
322    * list of absolute paths to structure files
323    */
 
324  3 toggle void showFilesInViewer(List<String> files)
325    {
326  3 long lastnotify = jmb.getLoadNotifiesHandled();
327  3 StringBuilder fileList = new StringBuilder();
328  3 for (String s : files)
329    {
330  3 fileList.append(SPACE).append(QUOTE)
331    .append(Platform.escapeString(s)).append(QUOTE);
332    }
333  3 String filesString = fileList.toString();
334   
335  3 if (!addingStructures)
336    {
337  2 try
338    {
339  2 initJmol("load FILES " + filesString);
340    } catch (OutOfMemoryError oomerror)
341    {
342  0 new OOMWarning("When trying to open the Jmol viewer!", oomerror);
343  0 Cache.log.debug("File locations are " + filesString);
344    } catch (Exception ex)
345    {
346  0 Cache.log.error("Couldn't open Jmol viewer!", ex);
347  0 ex.printStackTrace();
348  0 return;
349    }
350    }
351    else
352    {
353  1 StringBuilder cmd = new StringBuilder();
354  1 cmd.append("loadingJalviewdata=true\nload APPEND ");
355  1 cmd.append(filesString);
356  1 cmd.append("\nloadingJalviewdata=null");
357  1 final String command = cmd.toString();
358  1 lastnotify = jmb.getLoadNotifiesHandled();
359   
360  1 try
361    {
362  1 jmb.evalStateCommand(command);
363    } catch (OutOfMemoryError oomerror)
364    {
365  0 new OOMWarning("When trying to add structures to the Jmol viewer!",
366    oomerror);
367  0 Cache.log.debug("File locations are " + filesString);
368  0 return;
369    } catch (Exception ex)
370    {
371  0 Cache.log.error("Couldn't add files to Jmol viewer!", ex);
372  0 ex.printStackTrace();
373  0 return;
374    }
375    }
376   
377    // need to wait around until script has finished
378  3 int waitMax = JMOL_LOAD_TIMEOUT;
379  3 int waitFor = 35;
380  3 int waitTotal = 0;
381  3 while (addingStructures ? lastnotify >= jmb.getLoadNotifiesHandled()
382    : !(jmb.isFinishedInit() && jmb.getStructureFiles() != null
383    && jmb.getStructureFiles().length == files.size()))
384    {
385  0 try
386    {
387  0 Cache.log.debug("Waiting around for jmb notify.");
388  0 Thread.sleep(waitFor);
389  0 waitTotal += waitFor;
390    } catch (Exception e)
391    {
392    }
393  0 if (waitTotal > waitMax)
394    {
395  0 System.err.println("Timed out waiting for Jmol to load files after "
396    + waitTotal + "ms");
397    // System.err.println("finished: " + jmb.isFinishedInit()
398    // + "; loaded: " + Arrays.toString(jmb.getPdbFile())
399    // + "; files: " + files.toString());
400  0 jmb.getStructureFiles();
401  0 break;
402    }
403    }
404   
405    // refresh the sequence colours for the new structure(s)
406  3 for (AlignmentPanel ap : _colourwith)
407    {
408  3 jmb.updateColours(ap);
409    }
410    // do superposition if asked to
411  3 if (alignAddedStructures)
412    {
413  1 alignAddedStructures();
414    }
415  3 addingStructures = false;
416    }
417   
418    /**
419    * Queues a thread to align structures with Jalview alignments
420    */
 
421  1 toggle void alignAddedStructures()
422    {
423  1 javax.swing.SwingUtilities.invokeLater(new Runnable()
424    {
 
425  1 toggle @Override
426    public void run()
427    {
428  1 if (jmb.viewer.isScriptExecuting())
429    {
430  0 SwingUtilities.invokeLater(this);
431  0 try
432    {
433  0 Thread.sleep(5);
434    } catch (InterruptedException q)
435    {
436    }
437  0 return;
438    }
439    else
440    {
441  1 alignStructs_withAllAlignPanels();
442    }
443    }
444    });
445   
446    }
447   
448    /**
449    * Retrieves and saves as file any modelled PDB entries for which we do not
450    * already have a file saved. Returns a list of absolute paths to structure
451    * files which were either retrieved, or already stored but not modelled in
452    * the structure viewer (i.e. files to add to the viewer display).
453    *
454    * @return
455    */
 
456  3 toggle List<String> fetchPdbFiles()
457    {
458    // todo - record which pdbids were successfully imported.
459  3 StringBuilder errormsgs = new StringBuilder();
460   
461  3 List<String> files = new ArrayList<>();
462  3 String pdbid = "";
463  3 try
464    {
465  3 String[] filesInViewer = jmb.getStructureFiles();
466    // TODO: replace with reference fetching/transfer code (validate PDBentry
467    // as a DBRef?)
468  3 Pdb pdbclient = new Pdb();
469  7 for (int pi = 0; pi < jmb.getPdbCount(); pi++)
470    {
471  4 String file = jmb.getPdbEntry(pi).getFile();
472  4 if (file == null)
473    {
474    // todo: extract block as method and pull up (also ChimeraViewFrame)
475    // retrieve the pdb and store it locally
476  0 AlignmentI pdbseq = null;
477  0 pdbid = jmb.getPdbEntry(pi).getId();
478  0 long hdl = pdbid.hashCode() - System.currentTimeMillis();
479  0 if (progressBar != null)
480    {
481  0 progressBar.setProgressBar(MessageManager
482    .formatMessage("status.fetching_pdb", new String[]
483    { pdbid }), hdl);
484    }
485  0 try
486    {
487  0 pdbseq = pdbclient.getSequenceRecords(pdbid);
488    } catch (OutOfMemoryError oomerror)
489    {
490  0 new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
491    } catch (Exception ex)
492    {
493  0 ex.printStackTrace();
494  0 errormsgs.append("'").append(pdbid).append("'");
495    } finally
496    {
497  0 if (progressBar != null)
498    {
499  0 progressBar.setProgressBar(
500    MessageManager.getString("label.state_completed"),
501    hdl);
502    }
503    }
504  0 if (pdbseq != null)
505    {
506    // just transfer the file name from the first sequence's first
507    // PDBEntry
508  0 file = new File(pdbseq.getSequenceAt(0).getAllPDBEntries()
509    .elementAt(0).getFile()).getAbsolutePath();
510  0 jmb.getPdbEntry(pi).setFile(file);
511  0 files.add(file);
512    }
513    else
514    {
515  0 errormsgs.append("'").append(pdbid).append("' ");
516    }
517    }
518    else
519    {
520  4 if (filesInViewer != null && filesInViewer.length > 0)
521    {
522  2 addingStructures = true; // already files loaded.
523  3 for (int c = 0; c < filesInViewer.length; c++)
524    {
525  2 if (filesInViewer[c].equals(file))
526    {
527  1 file = null;
528  1 break;
529    }
530    }
531    }
532  4 if (file != null)
533    {
534  3 files.add(file);
535    }
536    }
537    }
538    } catch (OutOfMemoryError oomerror)
539    {
540  0 new OOMWarning("Retrieving PDB files: " + pdbid, oomerror);
541    } catch (Exception ex)
542    {
543  0 ex.printStackTrace();
544  0 errormsgs.append("When retrieving pdbfiles : current was: '")
545    .append(pdbid).append("'");
546    }
547  3 if (errormsgs.length() > 0)
548    {
549  0 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
550    MessageManager.formatMessage(
551    "label.pdb_entries_couldnt_be_retrieved", new String[]
552    { errormsgs.toString() }),
553    MessageManager.getString("label.couldnt_load_file"),
554    JvOptionPane.ERROR_MESSAGE);
555    }
556  3 return files;
557    }
558   
559    /**
560    * Outputs the Jmol viewer image as an image file, after prompting the user to
561    * choose a file and (for EPS) choice of Text or Lineart character rendering
562    * (unless a preference for this is set)
563    *
564    * @param type
565    */
 
566  0 toggle public void makePDBImage(ImageMaker.TYPE type)
567    {
568  0 int width = getWidth();
569  0 int height = getHeight();
570  0 ImageWriterI writer = new ImageWriterI()
571    {
 
572  0 toggle @Override
573    public void exportImage(Graphics g) throws Exception
574    {
575  0 jmb.viewer.renderScreenImage(g, width, height);
576    }
577    };
578  0 String view = MessageManager.getString("action.view").toLowerCase();
579  0 ImageExporter exporter = new ImageExporter(writer,
580    jmb.getIProgressIndicator(), type, getTitle());
581  0 exporter.doExport(null, this, width, height, view);
582    }
583   
 
584  0 toggle @Override
585    public void showHelp_actionPerformed(ActionEvent actionEvent)
586    {
587  0 try
588    {
589  0 BrowserLauncher
590    .openURL("http://jmol.sourceforge.net/docs/JmolUserGuide/");
591    } catch (Exception ex)
592    {
593    }
594    }
595   
 
596  0 toggle public void showConsole(boolean showConsole)
597    {
598   
599  0 if (showConsole)
600    {
601  0 if (splitPane == null)
602    {
603  0 splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
604  0 splitPane.setTopComponent(renderPanel);
605  0 splitPane.setBottomComponent(scriptWindow);
606  0 this.getContentPane().add(splitPane, BorderLayout.CENTER);
607  0 splitPane.setDividerLocation(getHeight() - 200);
608  0 scriptWindow.setVisible(true);
609  0 scriptWindow.validate();
610  0 splitPane.validate();
611    }
612   
613    }
614    else
615    {
616  0 if (splitPane != null)
617    {
618  0 splitPane.setVisible(false);
619    }
620   
621  0 splitPane = null;
622   
623  0 this.getContentPane().add(renderPanel, BorderLayout.CENTER);
624    }
625   
626  0 validate();
627    }
628   
 
629    class RenderPanel extends JPanel
630    {
631    final Dimension currentSize = new Dimension();
632   
 
633  172 toggle @Override
634    public void paintComponent(Graphics g)
635    {
636  172 getSize(currentSize);
637   
638  172 if (jmb != null && jmb.hasFileLoadingError())
639    {
640  0 g.setColor(Color.black);
641  0 g.fillRect(0, 0, currentSize.width, currentSize.height);
642  0 g.setColor(Color.white);
643  0 g.setFont(new Font("Verdana", Font.BOLD, 14));
644  0 g.drawString(MessageManager.getString("label.error_loading_file")
645    + "...", 20, currentSize.height / 2);
646  0 StringBuffer sb = new StringBuffer();
647  0 int lines = 0;
648  0 for (int e = 0; e < jmb.getPdbCount(); e++)
649    {
650  0 sb.append(jmb.getPdbEntry(e).getId());
651  0 if (e < jmb.getPdbCount() - 1)
652    {
653  0 sb.append(",");
654    }
655   
656  0 if (e == jmb.getPdbCount() - 1 || sb.length() > 20)
657    {
658  0 lines++;
659  0 g.drawString(sb.toString(), 20, currentSize.height / 2
660    - lines * g.getFontMetrics().getHeight());
661    }
662    }
663    }
664  172 else if (jmb == null || jmb.viewer == null || !jmb.isFinishedInit())
665    {
666  0 g.setColor(Color.black);
667  0 g.fillRect(0, 0, currentSize.width, currentSize.height);
668  0 g.setColor(Color.white);
669  0 g.setFont(new Font("Verdana", Font.BOLD, 14));
670  0 g.drawString(MessageManager.getString("label.retrieving_pdb_data"),
671    20, currentSize.height / 2);
672    }
673    else
674    {
675  172 jmb.viewer.renderScreenImage(g, currentSize.width,
676    currentSize.height);
677    }
678    }
679    }
680   
 
681  368 toggle @Override
682    public AAStructureBindingModel getBinding()
683    {
684  368 return this.jmb;
685    }
686   
 
687  2 toggle @Override
688    public String getStateInfo()
689    {
690  2 return jmb == null ? null : jmb.viewer.getStateInfo();
691    }
692   
 
693  20 toggle @Override
694    public ViewerType getViewerType()
695    {
696  20 return ViewerType.JMOL;
697    }
698   
 
699  11 toggle @Override
700    protected String getViewerName()
701    {
702  11 return "Jmol";
703    }
704    }