Clover icon

Coverage Report

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