1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.gui

File ChimeraViewFrame.java

 

Coverage histogram

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

Code metrics

46
163
22
1
571
413
52
0.32
7.41
22
2.36

Classes

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