+ /*
+ * Pending an XML element for ViewerType, just check if stateData contains
+ * "chimera" (part of the chimera session filename).
+ */
+ if (svattrib.getStateData().indexOf("chimera") > -1)
+ {
+ createChimeraViewer(viewerData, af);
+ }
+ else
+ {
+ createJmolViewer(viewerData, af);
+ }
+ }
+
+ /**
+ * Create a new Chimera viewer.
+ *
+ * @param viewerData
+ * @param af
+ */
+ protected void createChimeraViewer(Entry<String, StructureViewerModel> viewerData,
+ AlignFrame af)
+ {
+ final StructureViewerModel data = viewerData.getValue();
+ String chimeraSession = data.getStateData();
+
+ if (new File(chimeraSession).exists())
+ {
+ Set<Entry<File, StructureData>> fileData = data.getFileData()
+ .entrySet();
+ List<PDBEntry> pdbs = new ArrayList<PDBEntry>();
+ List<SequenceI[]> allseqs = new ArrayList<SequenceI[]>();
+ for (Entry<File, StructureData> pdb : fileData)
+ {
+ String filePath = pdb.getValue().getFilePath();
+ String pdbId = pdb.getValue().getPdbId();
+ pdbs.add(new PDBEntry(filePath, pdbId));
+ final List<SequenceI> seqList = pdb.getValue().getSeqList();
+ SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
+ allseqs.add(seqs);
+ }
+
+ boolean colourByChimera = data.isColourByViewer();
+ boolean colourBySequence = data.isColourWithAlignPanel();
+
+ // TODO can/should this be done via StructureViewer (like Jmol)?
+ final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs
+ .size()]);
+ final SequenceI[][] seqsArray = allseqs.toArray(new SequenceI[allseqs.size()][]);
+ new ChimeraViewFrame(chimeraSession, af.alignPanel, pdbArray,
+ seqsArray,
+ colourByChimera, colourBySequence);
+ }
+ else
+ {
+ Cache.log.error("Chimera session file " + chimeraSession
+ + " not found");
+ }
+ }
+
+ /**
+ * Create a new Jmol window. First parse the Jmol state to translate filenames
+ * loaded into the view, and record the order in which files are shown in the
+ * Jmol view, so we can add the sequence mappings in same order.
+ *
+ * @param viewerData
+ * @param af
+ */
+ protected void createJmolViewer(
+ final Entry<String, StructureViewerModel> viewerData, AlignFrame af)
+ {
+ final StructureViewerModel svattrib = viewerData.getValue();
+ String state = svattrib.getStateData();
+ List<String> pdbfilenames = new ArrayList<String>();
+ List<SequenceI[]> seqmaps = new ArrayList<SequenceI[]>();
+ List<String> pdbids = new ArrayList<String>();
+ StringBuilder newFileLoc = new StringBuilder(64);
+ int cp = 0, ncp, ecp;
+ Map<File, StructureData> oldFiles = svattrib.getFileData();
+ while ((ncp = state.indexOf("load ", cp)) > -1)
+ {
+ do
+ {
+ // look for next filename in load statement
+ newFileLoc.append(state.substring(cp,
+ ncp = (state.indexOf("\"", ncp + 1) + 1)));
+ String oldfilenam = state.substring(ncp,
+ ecp = state.indexOf("\"", ncp));
+ // recover the new mapping data for this old filename
+ // have to normalize filename - since Jmol and jalview do
+ // filename
+ // translation differently.
+ StructureData filedat = oldFiles.get(new File(oldfilenam));
+ newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
+ pdbfilenames.add(filedat.getFilePath());
+ pdbids.add(filedat.getPdbId());
+ seqmaps.add(filedat.getSeqList()
+ .toArray(new SequenceI[0]));
+ newFileLoc.append("\"");
+ cp = ecp + 1; // advance beyond last \" and set cursor so we can
+ // look for next file statement.
+ } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
+ }
+ if (cp > 0)
+ {
+ // just append rest of state
+ newFileLoc.append(state.substring(cp));
+ }
+ else
+ {
+ System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
+ newFileLoc = new StringBuilder(state);
+ newFileLoc.append("; load append ");
+ for (File id : oldFiles.keySet())
+ {
+ // add this and any other pdb files that should be present in
+ // the viewer
+ StructureData filedat = oldFiles.get(id);
+ newFileLoc.append(filedat.getFilePath());
+ pdbfilenames.add(filedat.getFilePath());
+ pdbids.add(filedat.getPdbId());
+ seqmaps.add(filedat.getSeqList()
+ .toArray(new SequenceI[0]));
+ newFileLoc.append(" \"");
+ newFileLoc.append(filedat.getFilePath());
+ newFileLoc.append("\"");
+
+ }
+ newFileLoc.append(";");
+ }
+
+ if (newFileLoc.length() > 0)
+ {
+ int histbug = newFileLoc.indexOf("history = ");
+ histbug += 10;
+ int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
+ String val = (diff == -1) ? null : newFileLoc
+ .substring(histbug, diff);
+ if (val != null && val.length() >= 4)
+ {
+ if (val.contains("e"))
+ {
+ if (val.trim().equals("true"))
+ {
+ val = "1";
+ }
+ else
+ {
+ val = "0";
+ }
+ newFileLoc.replace(histbug, diff, val);
+ }
+ }
+
+ final String[] pdbf = pdbfilenames.toArray(new String[pdbfilenames
+ .size()]);
+ final String[] id = pdbids.toArray(new String[pdbids.size()]);
+ final SequenceI[][] sq = seqmaps
+ .toArray(new SequenceI[seqmaps.size()][]);
+ final String fileloc = newFileLoc.toString();
+ final String sviewid = viewerData.getKey();
+ final AlignFrame alf = af;
+ final Rectangle rect = new Rectangle(svattrib.getX(),
+ svattrib.getY(), svattrib.getWidth(), svattrib.getHeight());
+ try
+ {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ JalviewStructureDisplayI sview = null;
+ try
+ {
+ // JAL-1333 note - we probably can't migrate Jmol views to UCSF
+ // Chimera!
+ sview = new StructureViewer(alf.alignPanel
+ .getStructureSelectionManager()).createView(
+ StructureViewer.ViewerType.JMOL, pdbf, id, sq,
+ alf.alignPanel, svattrib, fileloc, rect, sviewid);
+ addNewStructureViewer(sview);
+ } catch (OutOfMemoryError ex)
+ {
+ new OOMWarning("restoring structure view for PDB id " + id,
+ (OutOfMemoryError) ex.getCause());
+ if (sview != null && sview.isVisible())
+ {
+ sview.closeViewer();
+ sview.setVisible(false);
+ sview.dispose();
+ }
+ }
+ }
+ });
+ } catch (InvocationTargetException ex)
+ {
+ warn("Unexpected error when opening Jmol view.", ex);
+
+ } catch (InterruptedException e)
+ {
+ // e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Returns any open frame that matches given structure viewer data. The match
+ * is based on the unique viewId, or (for older project versions) the frame's
+ * geometry.
+ *
+ * @param viewerData
+ * @return
+ */
+ protected StructureViewerBase findMatchingViewer(
+ Entry<String, StructureViewerModel> viewerData)
+ {
+ final String sviewid = viewerData.getKey();
+ final StructureViewerModel svattrib = viewerData.getValue();
+ StructureViewerBase comp = null;
+ JInternalFrame[] frames = getAllFrames();
+ for (JInternalFrame frame : frames)
+ {
+ if (frame instanceof StructureViewerBase)
+ {
+ /*
+ * Post jalview 2.4 schema includes structure view id
+ */
+ if (sviewid != null
+ && ((StructureViewerBase) frame).getViewId().equals(
+ sviewid))
+ {
+ comp = (AppJmol) frame;
+ // todo: break?
+ }
+ /*
+ * Otherwise test for matching position and size of viewer frame
+ */
+ else if (frame.getX() == svattrib.getX()
+ && frame.getY() == svattrib.getY()
+ && frame.getHeight() == svattrib.getHeight()
+ && frame.getWidth() == svattrib.getWidth())
+ {
+ comp = (AppJmol) frame;
+ // todo: break?
+ }
+ }
+ }
+ return comp;
+ }
+
+ /**
+ * Link an AlignmentPanel to an existing structure viewer.
+ *
+ * @param ap
+ * @param viewer
+ * @param oldFiles
+ * @param useinViewerSuperpos
+ * @param usetoColourbyseq
+ * @param viewerColouring
+ */
+ protected void linkStructureViewer(AlignmentPanel ap,
+ StructureViewerBase viewer, StructureViewerModel svattrib)
+ {
+ // NOTE: if the jalview project is part of a shared session then
+ // view synchronization should/could be done here.
+
+ final boolean useinViewerSuperpos = svattrib.isAlignWithPanel();
+ final boolean usetoColourbyseq = svattrib.isColourWithAlignPanel();
+ final boolean viewerColouring = svattrib.isColourByViewer();
+ Map<File, StructureData> oldFiles = svattrib.getFileData();
+
+ /*
+ * Add mapping for sequences in this view to an already open viewer
+ */
+ final AAStructureBindingModel binding = viewer.getBinding();
+ for (File id : oldFiles.keySet())
+ {
+ // add this and any other pdb files that should be present in the
+ // viewer
+ StructureData filedat = oldFiles.get(id);
+ String pdbFile = filedat.getFilePath();
+ SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
+ binding.getSsm().setMapping(seq, null, pdbFile,
+ jalview.io.AppletFormatAdapter.FILE);
+ binding.addSequenceForStructFile(pdbFile, seq);
+ }
+ // and add the AlignmentPanel's reference to the view panel
+ viewer.addAlignmentPanel(ap);
+ if (useinViewerSuperpos)
+ {
+ viewer.useAlignmentPanelForSuperposition(ap);
+ }
+ else
+ {
+ viewer.excludeAlignmentPanelForSuperposition(ap);
+ }
+ if (usetoColourbyseq)
+ {
+ viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
+ }
+ else
+ {
+ viewer.excludeAlignmentPanelForColourbyseq(ap);
+ }
+ }
+
+ /**
+ * Get all frames within the Desktop.
+ *
+ * @return
+ */
+ protected JInternalFrame[] getAllFrames()
+ {
+ JInternalFrame[] frames = null;
+ // TODO is this necessary - is it safe - risk of hanging?
+ do
+ {
+ try
+ {
+ frames = Desktop.desktop.getAllFrames();
+ } catch (ArrayIndexOutOfBoundsException e)
+ {
+ // occasional No such child exceptions are thrown here...
+ try
+ {
+ Thread.sleep(10);
+ } catch (InterruptedException f)
+ {
+ }
+ }
+ } while (frames == null);
+ return frames;
+ }
+
+ /**
+ *
+ * @param supported
+ * - minimum version we are comparing against
+ * @param version
+ * - version of data being processsed.
+ * @return true if version is development/null or evaluates to the same or
+ * later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*)
+ */
+ private boolean isVersionStringLaterThan(String supported, String version)
+ {
+ if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD")
+ || version.equalsIgnoreCase("Test")
+ || version.equalsIgnoreCase("AUTOMATED BUILD"))
+ {
+ System.err.println("Assuming project file with "
+ + (version == null ? "null" : version)
+ + " is compatible with Jalview version " + supported);
+ return true;
+ }
+ else
+ {
+ StringTokenizer currentV = new StringTokenizer(supported, "."), fileV = new StringTokenizer(
+ version, ".");
+ while (currentV.hasMoreTokens() && fileV.hasMoreTokens())