Clover icon

Coverage Report

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

File ChimeraViewFrame.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
56% of files have more coverage

Code metrics

44
157
21
1
549
399
50
0.32
7.48
21
2.38

Classes

Class Line # Actions
ChimeraViewFrame 61 157 50
0.00%
 

Contributing tests

No tests hitting this source file were found.

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.event.ActionEvent;
24    import java.awt.event.ActionListener;
25    import java.awt.event.MouseAdapter;
26    import java.awt.event.MouseEvent;
27    import java.io.File;
28    import java.util.ArrayList;
29    import java.util.Collections;
30    import java.util.List;
31    import java.util.Map;
32   
33    import javax.swing.JInternalFrame;
34    import javax.swing.JMenu;
35    import javax.swing.JMenuItem;
36    import javax.swing.event.InternalFrameAdapter;
37    import javax.swing.event.InternalFrameEvent;
38   
39    import jalview.api.AlignmentViewPanel;
40    import jalview.api.FeatureRenderer;
41    import jalview.bin.Cache;
42    import jalview.datamodel.PDBEntry;
43    import jalview.datamodel.SequenceI;
44    import jalview.datamodel.StructureViewerModel;
45    import jalview.datamodel.StructureViewerModel.StructureData;
46    import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
47    import jalview.gui.StructureViewer.ViewerType;
48    import jalview.io.DataSourceType;
49    import jalview.io.StructureFile;
50    import jalview.structures.models.AAStructureBindingModel;
51    import jalview.util.ImageMaker.TYPE;
52    import jalview.util.MessageManager;
53    import jalview.util.Platform;
54   
55    /**
56    * GUI elements for handling an external chimera display
57    *
58    * @author jprocter
59    *
60    */
 
61    public class ChimeraViewFrame extends StructureViewerBase
62    {
63    private JalviewChimeraBinding jmb;
64   
65    /*
66    * Path to Chimera session file. This is set when an open Jalview/Chimera
67    * session is saved, or on restore from a Jalview project (if it holds the
68    * filename of any saved Chimera sessions).
69    */
70    private String chimeraSessionFile = null;
71   
72    private int myWidth = 500;
73   
74    private int myHeight = 150;
75   
76    /**
77    * Initialise menu options.
78    */
 
79  0 toggle @Override
80    protected void initMenus()
81    {
82  0 super.initMenus();
83   
84  0 savemenu.setVisible(false); // not yet implemented
85  0 viewMenu.add(fitToWindow);
86   
87  0 JMenuItem writeFeatures = new JMenuItem(
88    MessageManager.getString("label.create_viewer_attributes"));
89  0 writeFeatures.setToolTipText(MessageManager
90    .getString("label.create_viewer_attributes_tip"));
91  0 writeFeatures.addActionListener(new ActionListener()
92    {
 
93  0 toggle @Override
94    public void actionPerformed(ActionEvent e)
95    {
96  0 sendFeaturesToChimera();
97    }
98    });
99  0 viewerActionMenu.add(writeFeatures);
100   
101  0 final JMenu fetchAttributes = new JMenu(
102    MessageManager.getString("label.fetch_chimera_attributes"));
103  0 fetchAttributes.setToolTipText(
104    MessageManager.getString("label.fetch_chimera_attributes_tip"));
105  0 fetchAttributes.addMouseListener(new MouseAdapter()
106    {
107   
 
108  0 toggle @Override
109    public void mouseEntered(MouseEvent e)
110    {
111  0 buildAttributesMenu(fetchAttributes);
112    }
113    });
114  0 viewerActionMenu.add(fetchAttributes);
115    }
116   
117    /**
118    * Query the structure viewer for its residue attribute names and add them as
119    * items off the attributes menu
120    *
121    * @param attributesMenu
122    */
 
123  0 toggle protected void buildAttributesMenu(JMenu attributesMenu)
124    {
125  0 List<String> atts = jmb.getChimeraAttributes();
126  0 attributesMenu.removeAll();
127  0 Collections.sort(atts);
128  0 for (String attName : atts)
129    {
130  0 JMenuItem menuItem = new JMenuItem(attName);
131  0 menuItem.addActionListener(new ActionListener()
132    {
 
133  0 toggle @Override
134    public void actionPerformed(ActionEvent e)
135    {
136  0 if (getBinding().copyStructureAttributesToFeatures(attName,
137    getAlignmentPanel()) > 0)
138    {
139  0 getAlignmentPanel().getFeatureRenderer().featuresAdded();
140    }
141    }
142    });
143  0 attributesMenu.add(menuItem);
144    }
145    }
146   
147    /**
148    * Sends command(s) to the structure viewer to create residue attributes for
149    * visible Jalview features
150    */
 
151  0 toggle protected void sendFeaturesToChimera()
152    {
153    // todo pull up?
154  0 int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
155  0 statusBar.setText(
156    MessageManager.formatMessage("label.attributes_set", count));
157    }
158   
159    /**
160    * open a single PDB structure in a new Chimera view
161    *
162    * @param pdbentry
163    * @param seq
164    * @param chains
165    * @param ap
166    */
 
167  0 toggle public ChimeraViewFrame(PDBEntry pdbentry, SequenceI[] seq,
168    String[] chains, final AlignmentPanel ap)
169    {
170  0 this();
171   
172  0 openNewChimera(ap, new PDBEntry[] { pdbentry },
173    new SequenceI[][]
174    { seq });
175    }
176   
177    /**
178    * Create a helper to manage progress bar display
179    */
 
180  0 toggle protected void createProgressBar()
181    {
182  0 if (getProgressIndicator() == null)
183    {
184  0 setProgressIndicator(new ProgressBar(statusPanel, statusBar));
185    }
186    }
187   
 
188  0 toggle private void openNewChimera(AlignmentPanel ap, PDBEntry[] pdbentrys,
189    SequenceI[][] seqs)
190    {
191  0 createProgressBar();
192  0 jmb = newBindingModel(ap, pdbentrys, seqs);
193  0 addAlignmentPanel(ap);
194  0 useAlignmentPanelForColourbyseq(ap);
195   
196  0 if (pdbentrys.length > 1)
197    {
198  0 useAlignmentPanelForSuperposition(ap);
199    }
200  0 jmb.setColourBySequence(true);
201  0 setSize(myWidth, myHeight);
202  0 initMenus();
203   
204  0 addingStructures = false;
205  0 worker = new Thread(this);
206  0 worker.start();
207   
208  0 this.addInternalFrameListener(new InternalFrameAdapter()
209    {
 
210  0 toggle @Override
211    public void internalFrameClosing(
212    InternalFrameEvent internalFrameEvent)
213    {
214  0 closeViewer(false);
215    }
216    });
217   
218    }
219   
 
220  0 toggle protected JalviewChimeraBindingModel newBindingModel(AlignmentPanel ap,
221    PDBEntry[] pdbentrys, SequenceI[][] seqs)
222    {
223  0 return new JalviewChimeraBindingModel(this,
224    ap.getStructureSelectionManager(), pdbentrys, seqs, null);
225    }
226   
227    /**
228    * Create a new viewer from saved session state data including Chimera session
229    * file
230    *
231    * @param chimeraSessionFile
232    * @param alignPanel
233    * @param pdbArray
234    * @param seqsArray
235    * @param colourByChimera
236    * @param colourBySequence
237    * @param newViewId
238    */
 
239  0 toggle public ChimeraViewFrame(StructureViewerModel viewerData,
240    AlignmentPanel alignPanel, String sessionFile, String vid)
241    {
242  0 this();
243  0 setViewId(vid);
244  0 this.chimeraSessionFile = sessionFile;
245  0 Map<File, StructureData> pdbData = viewerData.getFileData();
246  0 PDBEntry[] pdbArray = new PDBEntry[pdbData.size()];
247  0 SequenceI[][] seqsArray = new SequenceI[pdbData.size()][];
248  0 int i = 0;
249  0 for (StructureData data : pdbData.values())
250    {
251  0 PDBEntry pdbentry = new PDBEntry(data.getPdbId(), null,
252    PDBEntry.Type.PDB, data.getFilePath());
253  0 pdbArray[i] = pdbentry;
254  0 List<SequenceI> sequencesForPdb = data.getSeqList();
255  0 seqsArray[i] = sequencesForPdb
256    .toArray(new SequenceI[sequencesForPdb.size()]);
257  0 i++;
258    }
259  0 openNewChimera(alignPanel, pdbArray, seqsArray);
260  0 if (viewerData.isColourByViewer())
261    {
262  0 jmb.setColourBySequence(false);
263  0 seqColour.setSelected(false);
264  0 viewerColour.setSelected(true);
265    }
266  0 else if (viewerData.isColourWithAlignPanel())
267    {
268  0 jmb.setColourBySequence(true);
269  0 seqColour.setSelected(true);
270  0 viewerColour.setSelected(false);
271    }
272    }
273   
274    /**
275    * create a new viewer containing several structures, optionally superimposed
276    * using the given alignPanel.
277    *
278    * @param pe
279    * @param seqs
280    * @param ap
281    */
 
282  0 toggle public ChimeraViewFrame(PDBEntry[] pe, boolean alignAdded,
283    SequenceI[][] seqs,
284    AlignmentPanel ap)
285    {
286  0 this();
287  0 setAlignAddedStructures(alignAdded);
288  0 openNewChimera(ap, pe, seqs);
289    }
290   
291    /**
292    * Default constructor
293    */
 
294  0 toggle public ChimeraViewFrame()
295    {
296  0 super();
297   
298    /*
299    * closeViewer will decide whether or not to close this frame
300    * depending on whether user chooses to Cancel or not
301    */
302  0 setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
303    }
304   
305    /**
306    * Launch Chimera. If we have a chimera session file name, send Chimera the
307    * command to open its saved session file.
308    */
 
309  0 toggle void initChimera()
310    {
311  0 jmb.setFinishedInit(false);
312  0 Desktop.addInternalFrame(this,
313    jmb.getViewerTitle(getViewerName(), true), getBounds().width,
314    getBounds().height);
315   
316  0 if (!jmb.launchChimera())
317    {
318  0 JvOptionPane.showMessageDialog(Desktop.desktop,
319    MessageManager.formatMessage("label.open_viewer_failed",
320    getViewerName()),
321    MessageManager.getString("label.error_loading_file"),
322    JvOptionPane.ERROR_MESSAGE);
323  0 this.dispose();
324  0 return;
325    }
326   
327  0 if (this.chimeraSessionFile != null)
328    {
329  0 boolean opened = jmb.openSession(chimeraSessionFile);
330  0 if (!opened)
331    {
332  0 System.err.println("An error occurred opening Chimera session file "
333    + chimeraSessionFile);
334    }
335    }
336   
337  0 jmb.startChimeraListener();
338    }
339   
340    /**
341    * Open any newly added PDB structures in Chimera, having first fetched data
342    * from PDB (if not already saved).
343    */
 
344  0 toggle @Override
345    public void run()
346    {
347  0 _started = true;
348    // todo - record which pdbids were successfully imported.
349  0 StringBuilder errormsgs = new StringBuilder(128);
350  0 StringBuilder files = new StringBuilder(128);
351  0 List<PDBEntry> filePDB = new ArrayList<>();
352  0 List<Integer> filePDBpos = new ArrayList<>();
353  0 PDBEntry thePdbEntry = null;
354  0 StructureFile pdb = null;
355  0 try
356    {
357  0 String[] curfiles = jmb.getStructureFiles(); // files currently in viewer
358    // TODO: replace with reference fetching/transfer code (validate PDBentry
359    // as a DBRef?)
360  0 for (int pi = 0; pi < jmb.getPdbCount(); pi++)
361    {
362  0 String file = null;
363  0 thePdbEntry = jmb.getPdbEntry(pi);
364  0 if (thePdbEntry.getFile() == null)
365    {
366    /*
367    * Retrieve PDB data, save to file, attach to PDBEntry
368    */
369  0 file = fetchPdbFile(thePdbEntry);
370  0 if (file == null)
371    {
372  0 errormsgs.append("'" + thePdbEntry.getId() + "' ");
373    }
374    }
375    else
376    {
377    /*
378    * Got file already - ignore if already loaded in Chimera.
379    */
380  0 file = new File(thePdbEntry.getFile()).getAbsoluteFile()
381    .getPath();
382  0 if (curfiles != null && curfiles.length > 0)
383    {
384  0 addingStructures = true; // already files loaded.
385  0 for (int c = 0; c < curfiles.length; c++)
386    {
387  0 if (curfiles[c].equals(file))
388    {
389  0 file = null;
390  0 break;
391    }
392    }
393    }
394    }
395  0 if (file != null)
396    {
397  0 filePDB.add(thePdbEntry);
398  0 filePDBpos.add(Integer.valueOf(pi));
399  0 files.append(" \"" + Platform.escapeBackslashes(file) + "\"");
400    }
401    }
402    } catch (OutOfMemoryError oomerror)
403    {
404  0 new OOMWarning("Retrieving PDB files: " + thePdbEntry.getId(),
405    oomerror);
406    } catch (Exception ex)
407    {
408  0 ex.printStackTrace();
409  0 errormsgs.append(
410    "When retrieving pdbfiles for '" + thePdbEntry.getId() + "'");
411    }
412  0 if (errormsgs.length() > 0)
413    {
414   
415  0 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
416    MessageManager.formatMessage(
417    "label.pdb_entries_couldnt_be_retrieved", new Object[]
418    { errormsgs.toString() }),
419    MessageManager.getString("label.couldnt_load_file"),
420    JvOptionPane.ERROR_MESSAGE);
421    }
422   
423  0 if (files.length() > 0)
424    {
425  0 jmb.setFinishedInit(false);
426  0 if (!addingStructures)
427    {
428  0 try
429    {
430  0 initChimera();
431    } catch (Exception ex)
432    {
433  0 Cache.log.error("Couldn't open Chimera viewer!", ex);
434    }
435    }
436  0 int num = -1;
437  0 for (PDBEntry pe : filePDB)
438    {
439  0 num++;
440  0 if (pe.getFile() != null)
441    {
442  0 try
443    {
444  0 int pos = filePDBpos.get(num).intValue();
445  0 long startTime = startProgressBar(getViewerName() + " "
446    + MessageManager.getString("status.opening_file_for")
447    + " " + pe.getId());
448  0 jmb.openFile(pe);
449  0 jmb.addSequence(pos, jmb.getSequence()[pos]);
450  0 File fl = new File(pe.getFile());
451  0 DataSourceType protocol = DataSourceType.URL;
452  0 try
453    {
454  0 if (fl.exists())
455    {
456  0 protocol = DataSourceType.FILE;
457    }
458    } catch (Throwable e)
459    {
460    } finally
461    {
462  0 stopProgressBar("", startTime);
463    }
464    // Explicitly map to the filename used by Chimera ;
465   
466  0 pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
467    jmb.getChains()[pos], pe.getFile(), protocol,
468    getProgressIndicator());
469  0 jmb.stashFoundChains(pdb, pe.getFile());
470   
471    } catch (OutOfMemoryError oomerror)
472    {
473  0 new OOMWarning(
474    "When trying to open and map structures from Chimera!",
475    oomerror);
476    } catch (Exception ex)
477    {
478  0 Cache.log.error(
479    "Couldn't open " + pe.getFile() + " in Chimera viewer!",
480    ex);
481    } finally
482    {
483  0 Cache.log.debug("File locations are " + files);
484    }
485    }
486    }
487   
488  0 jmb.refreshGUI();
489  0 jmb.setFinishedInit(true);
490  0 jmb.setLoadingFromArchive(false);
491   
492    /*
493    * ensure that any newly discovered features (e.g. RESNUM)
494    * are added to any open feature settings dialog
495    */
496  0 FeatureRenderer fr = getBinding().getFeatureRenderer(null);
497  0 if (fr != null)
498    {
499  0 fr.featuresAdded();
500    }
501   
502    // refresh the sequence colours for the new structure(s)
503  0 for (AlignmentViewPanel ap : _colourwith)
504    {
505  0 jmb.updateColours(ap);
506    }
507    // do superposition if asked to
508  0 if (alignAddedStructures)
509    {
510  0 new Thread(new Runnable()
511    {
 
512  0 toggle @Override
513    public void run()
514    {
515  0 alignStructsWithAllAlignPanels();
516    }
517    }).start();
518    }
519  0 addingStructures = false;
520    }
521  0 _started = false;
522  0 worker = null;
523    }
524   
 
525  0 toggle @Override
526    public void makePDBImage(TYPE imageType)
527    {
528  0 throw new UnsupportedOperationException(
529    "Image export for Chimera is not implemented");
530    }
531   
 
532  0 toggle @Override
533    public AAStructureBindingModel getBinding()
534    {
535  0 return jmb;
536    }
537   
 
538  0 toggle @Override
539    public ViewerType getViewerType()
540    {
541  0 return ViewerType.CHIMERA;
542    }
543   
 
544  0 toggle @Override
545    protected String getViewerName()
546    {
547  0 return "Chimera";
548    }
549    }