Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.gui

File AppJmol.java

 

Coverage histogram

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

Code metrics

58
218
21
2
664
509
69
0.32
10.38
10.5
3.29

Classes

Class Line # Actions
AppJmol 56 195 59
0.653992465.4%
AppJmol.RenderPanel 595 23 10
0.2058823620.6%
 

Contributing tests

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