Clover icon

Coverage Report

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

File StructureViewer.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
44% of files have more coverage

Code metrics

52
116
15
2
406
275
50
0.43
7.73
7.5
3.33

Classes

Class Line # Actions
StructureViewer 45 116 50
0.3879781438.8%
StructureViewer.ViewerType 56 0 0
-1.0 -
 

Contributing tests

This file is covered by 6 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.util.ArrayList;
24    import java.util.HashMap;
25    import java.util.LinkedHashMap;
26    import java.util.List;
27    import java.util.Map;
28    import java.util.Map.Entry;
29   
30    import jalview.api.structures.JalviewStructureDisplayI;
31    import jalview.bin.Cache;
32    import jalview.datamodel.PDBEntry;
33    import jalview.datamodel.SequenceI;
34    import jalview.datamodel.StructureViewerModel;
35    import jalview.structure.StructureSelectionManager;
36   
37    /**
38    * A proxy for handling structure viewers, that orchestrates adding selected
39    * structures, associated with sequences in Jalview, to an existing viewer, or
40    * opening a new one. Currently supports either Jmol or Chimera as the structure
41    * viewer.
42    *
43    * @author jprocter
44    */
 
45    public class StructureViewer
46    {
47    private static final String UNKNOWN_VIEWER_TYPE = "Unknown structure viewer type ";
48   
49    StructureSelectionManager ssm;
50   
51    /**
52    * decide if new structures are aligned to existing ones
53    */
54    private boolean superposeAdded = true;
55   
 
56    public enum ViewerType
57    {
58    JMOL, CHIMERA, CHIMERAX, PYMOL
59    };
60   
61    /**
62    * Constructor
63    *
64    * @param structureSelectionManager
65    */
 
66  3 toggle public StructureViewer(StructureSelectionManager structureSelectionManager)
67    {
68  3 ssm = structureSelectionManager;
69    }
70   
71    /**
72    * Factory to create a proxy for modifying existing structure viewer
73    *
74    */
 
75  0 toggle public static StructureViewer reconfigure(
76    JalviewStructureDisplayI display)
77    {
78  0 StructureViewer sv = new StructureViewer(display.getBinding().getSsm());
79  0 sv.sview = display;
80  0 return sv;
81    }
82   
 
83  0 toggle @Override
84    public String toString()
85    {
86  0 if (sview != null)
87    {
88  0 return sview.toString();
89    }
90  0 return "New View";
91    }
 
92  2 toggle public ViewerType getViewerType()
93    {
94  2 String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
95    ViewerType.JMOL.name());
96  2 return ViewerType.valueOf(viewType);
97    }
98   
 
99  2 toggle public void setViewerType(ViewerType type)
100    {
101  2 Cache.setProperty(Preferences.STRUCTURE_DISPLAY, type.name());
102    }
103   
104    /**
105    * View multiple PDB entries, each with associated sequences
106    *
107    * @param pdbs
108    * @param seqs
109    * @param ap
110    * @return
111    */
 
112  0 toggle public JalviewStructureDisplayI viewStructures(PDBEntry[] pdbs,
113    SequenceI[] seqs, AlignmentPanel ap)
114    {
115  0 JalviewStructureDisplayI viewer = onlyOnePdb(pdbs, seqs, ap);
116  0 if (viewer != null)
117    {
118    /*
119    * user added structure to an existing viewer - all done
120    */
121  0 return viewer;
122    }
123   
124  0 ViewerType viewerType = getViewerType();
125   
126  0 Map<PDBEntry, SequenceI[]> seqsForPdbs = getSequencesForPdbs(pdbs,
127    seqs);
128  0 PDBEntry[] pdbsForFile = seqsForPdbs.keySet().toArray(
129    new PDBEntry[seqsForPdbs.size()]);
130  0 SequenceI[][] theSeqs = seqsForPdbs.values().toArray(
131    new SequenceI[seqsForPdbs.size()][]);
132  0 if (sview != null)
133    {
134  0 sview.setAlignAddedStructures(superposeAdded);
135  0 new Thread(new Runnable()
136    {
 
137  0 toggle @Override
138    public void run()
139    {
140   
141  0 for (int pdbep = 0; pdbep < pdbsForFile.length; pdbep++)
142    {
143  0 PDBEntry pdb = pdbsForFile[pdbep];
144  0 if (!sview.addAlreadyLoadedFile(theSeqs[pdbep], null, ap,
145    pdb.getId()))
146    {
147  0 sview.addToExistingViewer(pdb, theSeqs[pdbep], null, ap,
148    pdb.getId());
149    }
150    }
151   
152  0 sview.updateTitleAndMenus();
153    }
154    }).start();
155  0 return sview;
156    }
157   
158  0 if (viewerType.equals(ViewerType.JMOL))
159    {
160  0 sview = new AppJmol(ap, superposeAdded, pdbsForFile, theSeqs);
161    }
162  0 else if (viewerType.equals(ViewerType.CHIMERA))
163    {
164  0 sview = new ChimeraViewFrame(pdbsForFile, superposeAdded, theSeqs,
165    ap);
166    }
167  0 else if (viewerType.equals(ViewerType.CHIMERAX))
168    {
169  0 sview = new ChimeraXViewFrame(pdbsForFile, superposeAdded, theSeqs,
170    ap);
171    }
172  0 else if (viewerType.equals(ViewerType.PYMOL))
173    {
174  0 sview = new PymolViewer(pdbsForFile, superposeAdded, theSeqs, ap);
175    }
176    else
177    {
178  0 Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
179    }
180  0 return sview;
181    }
182   
183    /**
184    * Converts the list of selected PDB entries (possibly including duplicates
185    * for multiple chains), and corresponding sequences, into a map of sequences
186    * for each distinct PDB file. Returns null if either argument is null, or
187    * their lengths do not match.
188    *
189    * @param pdbs
190    * @param seqs
191    * @return
192    */
 
193  2 toggle Map<PDBEntry, SequenceI[]> getSequencesForPdbs(PDBEntry[] pdbs,
194    SequenceI[] seqs)
195    {
196  2 if (pdbs == null || seqs == null || pdbs.length != seqs.length)
197    {
198  1 return null;
199    }
200   
201    /*
202    * we want only one 'representative' PDBEntry per distinct file name
203    * (there may be entries for distinct chains)
204    */
205  1 Map<String, PDBEntry> pdbsSeen = new HashMap<>();
206   
207    /*
208    * LinkedHashMap preserves order of PDB entries (significant if they
209    * will get superimposed to the first structure)
210    */
211  1 Map<PDBEntry, List<SequenceI>> pdbSeqs = new LinkedHashMap<>();
212  8 for (int i = 0; i < pdbs.length; i++)
213    {
214  7 PDBEntry pdb = pdbs[i];
215  7 SequenceI seq = seqs[i];
216  7 String pdbFile = pdb.getFile();
217  7 if (pdbFile == null || pdbFile.length() == 0)
218    {
219  3 pdbFile = pdb.getId();
220    }
221  7 if (!pdbsSeen.containsKey(pdbFile))
222    {
223  4 pdbsSeen.put(pdbFile, pdb);
224  4 pdbSeqs.put(pdb, new ArrayList<SequenceI>());
225    }
226    else
227    {
228  3 pdb = pdbsSeen.get(pdbFile);
229    }
230  7 List<SequenceI> seqsForPdb = pdbSeqs.get(pdb);
231  7 if (!seqsForPdb.contains(seq))
232    {
233  7 seqsForPdb.add(seq);
234    }
235    }
236   
237    /*
238    * convert to Map<PDBEntry, SequenceI[]>
239    */
240  1 Map<PDBEntry, SequenceI[]> result = new LinkedHashMap<>();
241  1 for (Entry<PDBEntry, List<SequenceI>> entry : pdbSeqs.entrySet())
242    {
243  4 List<SequenceI> theSeqs = entry.getValue();
244  4 result.put(entry.getKey(),
245    theSeqs.toArray(new SequenceI[theSeqs.size()]));
246    }
247   
248  1 return result;
249    }
250   
251    /**
252    * A strictly temporary method pending JAL-1761 refactoring. Determines if all
253    * the passed PDB entries are the same (this is the case if selected sequences
254    * to view structure for are chains of the same structure). If so, calls the
255    * single-pdb version of viewStructures and returns the viewer, else returns
256    * null.
257    *
258    * @param pdbs
259    * @param seqsForPdbs
260    * @param ap
261    * @return
262    */
 
263  0 toggle private JalviewStructureDisplayI onlyOnePdb(PDBEntry[] pdbs,
264    SequenceI[] seqsForPdbs, AlignmentPanel ap)
265    {
266  0 List<SequenceI> seqs = new ArrayList<>();
267  0 if (pdbs == null || pdbs.length == 0)
268    {
269  0 return null;
270    }
271  0 int i = 0;
272  0 String firstFile = pdbs[0].getFile();
273  0 for (PDBEntry pdb : pdbs)
274    {
275  0 String pdbFile = pdb.getFile();
276  0 if (pdbFile == null || !pdbFile.equals(firstFile))
277    {
278  0 return null;
279    }
280  0 SequenceI pdbseq = seqsForPdbs[i++];
281  0 if (pdbseq != null)
282    {
283  0 seqs.add(pdbseq);
284    }
285    }
286  0 return viewStructures(pdbs[0], seqs.toArray(new SequenceI[seqs.size()]),
287    ap);
288    }
289   
290    JalviewStructureDisplayI sview = null;
291   
 
292  3 toggle public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
293    SequenceI[] seqsForPdb, AlignmentPanel ap)
294    {
295  3 if (sview != null)
296    {
297  1 sview.setAlignAddedStructures(superposeAdded);
298  1 String pdbId = pdb.getId();
299  1 if (!sview.addAlreadyLoadedFile(seqsForPdb, null, ap, pdbId))
300    {
301  1 sview.addToExistingViewer(pdb, seqsForPdb, null, ap, pdbId);
302    }
303  1 sview.updateTitleAndMenus();
304  1 sview.raiseViewer();
305  1 return sview;
306    }
307  2 ViewerType viewerType = getViewerType();
308  2 if (viewerType.equals(ViewerType.JMOL))
309    {
310  2 sview = new AppJmol(pdb, seqsForPdb, null, ap);
311    }
312  0 else if (viewerType.equals(ViewerType.CHIMERA))
313    {
314  0 sview = new ChimeraViewFrame(pdb, seqsForPdb, null, ap);
315    }
316  0 else if (viewerType.equals(ViewerType.CHIMERAX))
317    {
318  0 sview = new ChimeraXViewFrame(pdb, seqsForPdb, null, ap);
319    }
320  0 else if (viewerType.equals(ViewerType.PYMOL))
321    {
322  0 sview = new PymolViewer(pdb, seqsForPdb, null, ap);
323    }
324    else
325    {
326  0 Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
327    }
328  2 return sview;
329    }
330   
331    /**
332    * Creates a new panel controlling a structure viewer
333    *
334    * @param type
335    * @param alignPanel
336    * @param viewerData
337    * @param sessionFile
338    * @param vid
339    * @return
340    */
 
341  5 toggle public static JalviewStructureDisplayI createView(ViewerType type,
342    AlignmentPanel alignPanel, StructureViewerModel viewerData,
343    String sessionFile, String vid)
344    {
345  5 JalviewStructureDisplayI viewer = null;
346  5 switch (type)
347    {
348  5 case JMOL:
349  5 viewer = new AppJmol(viewerData, alignPanel, sessionFile, vid);
350    // todo or construct and then openSession(sessionFile)?
351  5 break;
352  0 case CHIMERA:
353  0 viewer = new ChimeraViewFrame(viewerData, alignPanel, sessionFile,
354    vid);
355  0 break;
356  0 case CHIMERAX:
357  0 viewer = new ChimeraXViewFrame(viewerData, alignPanel, sessionFile,
358    vid);
359  0 break;
360  0 case PYMOL:
361  0 viewer = new PymolViewer(viewerData, alignPanel, sessionFile, vid);
362  0 break;
363  0 default:
364  0 Cache.log.error(UNKNOWN_VIEWER_TYPE + type.toString());
365    }
366  5 return viewer;
367    }
368   
 
369  3 toggle public boolean isBusy()
370    {
371  3 if (sview != null)
372    {
373  3 if (!sview.hasMapping())
374    {
375  2 return true;
376    }
377    }
378  1 return false;
379    }
380   
381    /**
382    *
383    * @param pDBid
384    * @return true if view is already showing PDBid
385    */
 
386  0 toggle public boolean hasPdbId(String pDBid)
387    {
388  0 if (sview == null)
389    {
390  0 return false;
391    }
392   
393  0 return sview.getBinding().hasPdbId(pDBid);
394    }
395   
 
396  0 toggle public boolean isVisible()
397    {
398  0 return sview != null && sview.isVisible();
399    }
400   
 
401  0 toggle public void setSuperpose(boolean alignAddedStructures)
402    {
403  0 superposeAdded = alignAddedStructures;
404    }
405   
406    }