+ * Loads any saved PCA viewers
+ *
+ * @param jms
+ * @param ap
+ */
+ protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap)
+ {
+ try
+ {
+ List<PcaViewer> pcaviewers = model.getPcaViewer();
+ for (PcaViewer viewer : pcaviewers)
+ {
+ String modelName = viewer.getScoreModelName();
+ SimilarityParamsI params = new SimilarityParams(
+ viewer.isIncludeGappedColumns(), viewer.isMatchGaps(),
+ viewer.isIncludeGaps(),
+ viewer.isDenominateByShortestLength());
+
+ /*
+ * create the panel (without computing the PCA)
+ */
+ PCAPanel panel = new PCAPanel(ap, modelName, params);
+
+ panel.setTitle(viewer.getTitle());
+ panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
+ viewer.getWidth(), viewer.getHeight()));
+
+ boolean showLabels = viewer.isShowLabels();
+ panel.setShowLabels(showLabels);
+ panel.getRotatableCanvas().setShowLabels(showLabels);
+ panel.getRotatableCanvas()
+ .setBgColour(new Color(viewer.getBgColour()));
+ panel.getRotatableCanvas()
+ .setApplyToAllViews(viewer.isLinkToAllViews());
+
+ /*
+ * load PCA output data
+ */
+ ScoreModelI scoreModel = ScoreModels.getInstance()
+ .getScoreModel(modelName, ap);
+ PCA pca = new PCA(null, scoreModel, params);
+ PcaDataType pcaData = viewer.getPcaData();
+
+ MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
+ pca.setPairwiseScores(pairwise);
+
+ MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
+ pca.setTridiagonal(triDiag);
+
+ MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
+ pca.setEigenmatrix(result);
+
+ panel.getPcaModel().setPCA(pca);
+
+ /*
+ * we haven't saved the input data! (JAL-2647 to do)
+ */
+ panel.setInputData(null);
+
+ /*
+ * add the sequence points for the PCA display
+ */
+ List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
+ for (SequencePoint sp : viewer.getSequencePoint())
+ {
+ String seqId = sp.getSequenceRef();
+ SequenceI seq = seqRefIds.get(seqId);
+ if (seq == null)
+ {
+ throw new IllegalStateException(
+ "Unmatched seqref for PCA: " + seqId);
+ }
+ Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
+ jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
+ seq, pt);
+ seqPoints.add(seqPoint);
+ }
+ panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
+
+ /*
+ * set min-max ranges and scale after setPoints (which recomputes them)
+ */
+ panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
+ SeqPointMin spMin = viewer.getSeqPointMin();
+ float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
+ spMin.getZPos() };
+ SeqPointMax spMax = viewer.getSeqPointMax();
+ float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
+ spMax.getZPos() };
+ panel.getRotatableCanvas().setSeqMinMax(min, max);
+
+ // todo: hold points list in PCAModel only
+ panel.getPcaModel().setSequencePoints(seqPoints);
+
+ panel.setSelectedDimensionIndex(viewer.getXDim(), X);
+ panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
+ panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
+
+ // is this duplication needed?
+ panel.setTop(seqPoints.size() - 1);
+ panel.getPcaModel().setTop(seqPoints.size() - 1);
+
+ /*
+ * add the axes' end points for the display
+ */
+ for (int i = 0; i < 3; i++)
+ {
+ Axis axis = viewer.getAxis().get(i);
+ panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(
+ axis.getXPos(), axis.getYPos(), axis.getZPos());
+ }
+
+ Desktop.addInternalFrame(panel, MessageManager.formatMessage(
+ "label.calc_title", "PCA", modelName), 475, 450);
+ }
+ } catch (Exception ex)
+ {
+ Console.error("Error loading PCA: " + ex.toString());
+ }
+ }
+
+ /**
+ * Creates a new structure viewer window
+ *
+ * @param viewerType
+ * @param viewerData
+ * @param af
+ * @param jprovider
+ */
+ protected void createStructureViewer(ViewerType viewerType,
+ final Entry<String, StructureViewerModel> viewerData,
+ AlignFrame af, jarInputStreamProvider jprovider)
+ {
+ final StructureViewerModel viewerModel = viewerData.getValue();
+ String sessionFilePath = null;
+
+ if (viewerType == ViewerType.JMOL)
+ {
+ sessionFilePath = rewriteJmolSession(viewerModel, jprovider);
+ }
+ else
+ {
+ String viewerJarEntryName = getViewerJarEntryName(
+ viewerModel.getViewId());
+ sessionFilePath = copyJarEntry(jprovider, viewerJarEntryName,
+ "viewerSession", ".tmp");
+ }
+ final String sessionPath = sessionFilePath;
+ final String sviewid = viewerData.getKey();
+ try
+ {
+ SwingUtilities.invokeAndWait(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ JalviewStructureDisplayI sview = null;
+ try
+ {
+ sview = StructureViewer.createView(viewerType, af.alignPanel,
+ viewerModel, sessionPath, sviewid);
+ addNewStructureViewer(sview);
+ } catch (OutOfMemoryError ex)
+ {
+ new OOMWarning("Restoring structure view for " + viewerType,
+ (OutOfMemoryError) ex.getCause());
+ if (sview != null && sview.isVisible())
+ {
+ sview.closeViewer(false);
+ sview.setVisible(false);
+ sview.dispose();
+ }
+ }
+ }
+ });
+ } catch (InvocationTargetException | InterruptedException ex)
+ {
+ Console.warn("Unexpected error when opening " + viewerType
+ + " structure viewer", ex);
+ }
+ }
+
+ /**
+ * Rewrites a Jmol session script, saves it to a temporary file, and returns
+ * the path of the file. "load file" commands are rewritten to change the
+ * original PDB file names to those created as the Jalview project is loaded.
+ *
+ * @param svattrib
+ * @param jprovider
+ * @return
+ */
+ private String rewriteJmolSession(StructureViewerModel svattrib,
+ jarInputStreamProvider jprovider)
+ {
+ String state = svattrib.getStateData(); // Jalview < 2.9
+ if (state == null || state.isEmpty()) // Jalview >= 2.9
+ {
+ String jarEntryName = getViewerJarEntryName(svattrib.getViewId());
+ state = readJarEntry(jprovider, jarEntryName);
+ }
+ // TODO or simpler? for each key in oldFiles,
+ // replace key.getPath() in state with oldFiles.get(key).getFilePath()
+ // (allowing for different path escapings)
+ StringBuilder rewritten = new StringBuilder(state.length());
+ 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
+ rewritten.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));
+ if (filedat == null)
+ {
+ String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
+ filedat = oldFiles.get(new File(reformatedOldFilename));
+ }
+ rewritten.append(Platform.escapeBackslashes(filedat.getFilePath()));
+ rewritten.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
+ rewritten.append(state.substring(cp));
+ }
+ else
+ {
+ System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
+ rewritten = new StringBuilder(state);
+ rewritten.append("; load append ");
+ for (File id : oldFiles.keySet())
+ {
+ // add pdb files that should be present in the viewer
+ StructureData filedat = oldFiles.get(id);
+ rewritten.append(" \"").append(filedat.getFilePath()).append("\"");
+ }
+ rewritten.append(";");
+ }
+
+ if (rewritten.length() == 0)
+ {
+ return null;
+ }
+ final String history = "history = ";
+ int historyIndex = rewritten.indexOf(history);
+ if (historyIndex > -1)
+ {
+ /*
+ * change "history = [true|false];" to "history = [1|0];"
+ */
+ historyIndex += history.length();
+ String val = rewritten.substring(historyIndex, historyIndex + 5);
+ if (val.startsWith("true"))
+ {
+ rewritten.replace(historyIndex, historyIndex + 4, "1");
+ }
+ else if (val.startsWith("false"))
+ {
+ rewritten.replace(historyIndex, historyIndex + 5, "0");
+ }
+ }
+
+ try
+ {
+ File tmp = File.createTempFile("viewerSession", ".tmp");
+ try (OutputStream os = new FileOutputStream(tmp))
+ {
+ InputStream is = new ByteArrayInputStream(
+ rewritten.toString().getBytes());
+ copyAll(is, os);
+ return tmp.getAbsolutePath();
+ }
+ } catch (IOException e)
+ {
+ Console.error("Error restoring Jmol session: " + e.toString());
+ }
+ return null;
+ }
+
+ /**