+ /**
+ * Add a model (e.g. loaded from project file)
+ *
+ * @param rna
+ * @param modelName
+ */
+ public RNA addModel(RnaModel model, String modelName)
+ {
+ if (!model.ann.isValidStruc())
+ {
+ throw new IllegalArgumentException(
+ "Invalid RNA structure annotation");
+ }
+
+ /*
+ * opened on request in Jalview session
+ */
+ RNA rna = new RNA(modelName);
+ String struc = model.ann.getRNAStruc();
+ struc = replaceOddGaps(struc);
+
+ String strucseq = model.seq.getSequenceAsString();
+ try
+ {
+ rna.setRNA(strucseq, struc);
+ } catch (ExceptionUnmatchedClosingParentheses e2)
+ {
+ e2.printStackTrace();
+ } catch (ExceptionFileFormatOrSyntax e3)
+ {
+ e3.printStackTrace();
+ }
+
+ if (!model.gapped)
+ {
+ rna = trimRNA(rna, modelName);
+ }
+ models.put(rna, new RnaModel(modelName, model.ann, model.seq, rna,
+ model.gapped));
+ vab.addStructure(rna);
+ return rna;
+ }
+
+ /**
+ * Constructs a shift list that describes the gaps in the sequence
+ *
+ * @param seq
+ * @return
+ */
+ protected ShiftList buildOffset(SequenceI seq)
+ {
+ // TODO refactor to avoid duplication with trimRNA()
+ // TODO JAL-1789 bugs in use of ShiftList here
+ ShiftList offset = new ShiftList();
+ int ofstart = -1;
+ int sleng = seq.getLength();
+
+ for (int i = 0; i < sleng; i++)
+ {
+ if (Comparison.isGap(seq.getCharAt(i)))
+ {
+ if (ofstart == -1)
+ {
+ ofstart = i;
+ }
+ }
+ else
+ {
+ if (ofstart > -1)
+ {
+ offset.addShift(offset.shift(ofstart), ofstart - i);
+ ofstart = -1;
+ }
+ }
+ }
+ // final gap
+ if (ofstart > -1)
+ {
+ offset.addShift(offset.shift(ofstart), ofstart - sleng);
+ ofstart = -1;
+ }
+ return offset;
+ }
+
+ /**
+ * Set the selected index in the model selection list
+ *
+ * @param selectedIndex
+ */
+ public void setInitialSelection(final int selectedIndex)
+ {
+ /*
+ * empirically it needs a second for Varna/AWT to finish loading/drawing
+ * models for this to work; SwingUtilities.invokeLater _not_ a solution;
+ * explanation and/or better solution welcome!
+ */
+ synchronized (this)
+ {
+ try
+ {
+ wait(1000);
+ } catch (InterruptedException e)
+ {
+ // meh
+ }
+ }
+ vab.setSelectedIndex(selectedIndex);
+ }
+
+ /**
+ * Add a model with associated Varna session file
+ *
+ * @param rna
+ * @param modelName
+ */
+ public RNA addModelSession(RnaModel model, String modelName,
+ String sessionFile)
+ {
+ if (!model.ann.isValidStruc())
+ {
+ throw new IllegalArgumentException(
+ "Invalid RNA structure annotation");
+ }
+
+ try
+ {
+ FullBackup fromSession = vab.vp.loadSession(sessionFile);
+ vab.addStructure(fromSession.rna, fromSession.config);
+ RNA rna = fromSession.rna;
+ // copy the model, but now including the RNA object
+ RnaModel newModel = new RnaModel(model.title, model.ann, model.seq,
+ rna, model.gapped);
+ if (!model.gapped)
+ {
+ registerOffset(rna, buildOffset(model.seq));
+ }
+ models.put(rna, newModel);
+ // capture rna selection state when saved
+ selectionHighlighter = new VarnaHighlighter(rna);
+ return fromSession.rna;
+ } catch (ExceptionLoadingFailed e)
+ {
+ System.err
+ .println("Error restoring Varna session: " + e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * Replace everything except RNA secondary structure characters with a period
+ *
+ * @param s
+ * @return
+ */
+ public static String replaceOddGaps(String s)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+
+ // this is measured to be 10 times faster than a regex replace
+ boolean changed = false;
+ byte[] bytes = s.getBytes();
+ for (int i = 0; i < bytes.length; i++)
+ {
+ boolean ok = false;
+ // todo check for ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')) if
+ // wanted also
+ for (int j = 0; !ok && (j < PAIRS.length); j++)
+ {
+ if (bytes[i] == PAIRS[j])
+ {
+ ok = true;
+ }
+ }
+ if (!ok)
+ {
+ bytes[i] = '.';
+ changed = true;
+ }
+ }
+ return changed ? new String(bytes) : s;
+ }