2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import jalview.api.structures.JalviewStructureDisplayI;
24 import jalview.bin.Cache;
25 import jalview.datamodel.PDBEntry;
26 import jalview.datamodel.SequenceI;
27 import jalview.datamodel.StructureViewerModel;
28 import jalview.structure.StructureSelectionManager;
30 import java.awt.Rectangle;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.LinkedHashMap;
34 import java.util.List;
36 import java.util.Map.Entry;
39 * A proxy for handling structure viewers, that orchestrates adding selected
40 * structures, associated with sequences in Jalview, to an existing viewer, or
41 * opening a new one. Currently supports either Jmol or Chimera as the structure
46 public class StructureViewer
48 private static final String UNKNOWN_VIEWER_TYPE = "Unknown structure viewer type ";
50 StructureSelectionManager ssm;
52 public enum ViewerType
60 * @param structureSelectionManager
62 public StructureViewer(StructureSelectionManager structureSelectionManager)
64 ssm = structureSelectionManager;
68 * Factory to create a proxy for modifying existing structure viewer
71 public static StructureViewer reconfigure(
72 JalviewStructureDisplayI display)
74 StructureViewer sv = new StructureViewer(display.getBinding().getSsm());
80 public String toString()
84 return sview.toString();
88 public ViewerType getViewerType()
90 String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
91 ViewerType.JMOL.name());
92 return ViewerType.valueOf(viewType);
95 public void setViewerType(ViewerType type)
97 Cache.setProperty(Preferences.STRUCTURE_DISPLAY, type.name());
101 * View multiple PDB entries, each with associated sequences
108 public JalviewStructureDisplayI viewStructures(PDBEntry[] pdbs,
109 SequenceI[] seqs, AlignmentPanel ap)
111 JalviewStructureDisplayI viewer = onlyOnePdb(pdbs, seqs, ap);
115 * user added structure to an existing viewer - all done
120 ViewerType viewerType = getViewerType();
122 Map<PDBEntry, SequenceI[]> seqsForPdbs = getSequencesForPdbs(pdbs,
124 PDBEntry[] pdbsForFile = seqsForPdbs.keySet().toArray(
125 new PDBEntry[seqsForPdbs.size()]);
126 SequenceI[][] theSeqs = seqsForPdbs.values().toArray(
127 new SequenceI[seqsForPdbs.size()][]);
130 new Thread(new Runnable()
136 for (int pdbep = 0; pdbep < pdbsForFile.length; pdbep++)
138 PDBEntry pdb = pdbsForFile[pdbep];
139 if (!sview.addAlreadyLoadedFile(theSeqs[pdbep], null, ap,
142 sview.addToExistingViewer(pdb, theSeqs[pdbep], null, ap,
147 sview.updateTitleAndMenus();
153 if (viewerType.equals(ViewerType.JMOL))
155 sview = new AppJmol(ap, pdbsForFile, theSeqs);
157 else if (viewerType.equals(ViewerType.CHIMERA))
159 sview = new ChimeraViewFrame(pdbsForFile, theSeqs, ap);
163 Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
169 * Converts the list of selected PDB entries (possibly including duplicates
170 * for multiple chains), and corresponding sequences, into a map of sequences
171 * for each distinct PDB file. Returns null if either argument is null, or
172 * their lengths do not match.
178 Map<PDBEntry, SequenceI[]> getSequencesForPdbs(PDBEntry[] pdbs,
181 if (pdbs == null || seqs == null || pdbs.length != seqs.length)
187 * we want only one 'representative' PDBEntry per distinct file name
188 * (there may be entries for distinct chains)
190 Map<String, PDBEntry> pdbsSeen = new HashMap<>();
193 * LinkedHashMap preserves order of PDB entries (significant if they
194 * will get superimposed to the first structure)
196 Map<PDBEntry, List<SequenceI>> pdbSeqs = new LinkedHashMap<>();
197 for (int i = 0; i < pdbs.length; i++)
199 PDBEntry pdb = pdbs[i];
200 SequenceI seq = seqs[i];
201 String pdbFile = pdb.getFile();
202 if (pdbFile == null || pdbFile.length() == 0)
204 pdbFile = pdb.getId();
206 if (!pdbsSeen.containsKey(pdbFile))
208 pdbsSeen.put(pdbFile, pdb);
209 pdbSeqs.put(pdb, new ArrayList<SequenceI>());
213 pdb = pdbsSeen.get(pdbFile);
215 List<SequenceI> seqsForPdb = pdbSeqs.get(pdb);
216 if (!seqsForPdb.contains(seq))
223 * convert to Map<PDBEntry, SequenceI[]>
225 Map<PDBEntry, SequenceI[]> result = new LinkedHashMap<>();
226 for (Entry<PDBEntry, List<SequenceI>> entry : pdbSeqs.entrySet())
228 List<SequenceI> theSeqs = entry.getValue();
229 result.put(entry.getKey(),
230 theSeqs.toArray(new SequenceI[theSeqs.size()]));
237 * A strictly temporary method pending JAL-1761 refactoring. Determines if all
238 * the passed PDB entries are the same (this is the case if selected sequences
239 * to view structure for are chains of the same structure). If so, calls the
240 * single-pdb version of viewStructures and returns the viewer, else returns
248 private JalviewStructureDisplayI onlyOnePdb(PDBEntry[] pdbs,
249 SequenceI[] seqsForPdbs, AlignmentPanel ap)
251 List<SequenceI> seqs = new ArrayList<>();
252 if (pdbs == null || pdbs.length == 0)
257 String firstFile = pdbs[0].getFile();
258 for (PDBEntry pdb : pdbs)
260 String pdbFile = pdb.getFile();
261 if (pdbFile == null || !pdbFile.equals(firstFile))
265 SequenceI pdbseq = seqsForPdbs[i++];
271 return viewStructures(pdbs[0], seqs.toArray(new SequenceI[seqs.size()]),
275 JalviewStructureDisplayI sview = null;
277 public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
278 SequenceI[] seqsForPdb, AlignmentPanel ap)
282 if (!sview.addAlreadyLoadedFile(seqsForPdb, null, ap, pdb.getId()))
284 sview.addToExistingViewer(pdb, seqsForPdb, null, ap, pdb.getId());
286 sview.updateTitleAndMenus();
289 ViewerType viewerType = getViewerType();
290 if (viewerType.equals(ViewerType.JMOL))
292 sview = new AppJmol(pdb, seqsForPdb, null, ap);
294 else if (viewerType.equals(ViewerType.CHIMERA))
296 sview = new ChimeraViewFrame(pdb, seqsForPdb, null, ap);
300 Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
306 * Create a new panel controlling a structure viewer.
319 public JalviewStructureDisplayI createView(ViewerType type, String[] pdbf,
320 String[] id, SequenceI[][] sq, AlignmentPanel alignPanel,
321 StructureViewerModel viewerData, String fileloc, Rectangle rect,
324 final boolean useinViewerSuperpos = viewerData.isAlignWithPanel();
325 final boolean usetoColourbyseq = viewerData.isColourWithAlignPanel();
326 final boolean viewerColouring = viewerData.isColourByViewer();
331 sview = new AppJmol(pdbf, id, sq, alignPanel, usetoColourbyseq,
332 useinViewerSuperpos, viewerColouring, fileloc, rect, vid);
336 "Unsupported structure viewer type " + type.toString());
339 Cache.log.error(UNKNOWN_VIEWER_TYPE + type.toString());
344 public boolean isBusy()
348 if (!sview.hasMapping())
359 * @return true if view is already showing PDBid
361 public boolean hasPdbId(String pDBid)
368 return sview.getBinding().hasPdbId(pDBid);
371 public boolean isVisible()
373 return sview != null && sview.isVisible();