import jalview.util.MessageManager;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Stack;
public class Rna
{
- static Hashtable<Integer, Integer> pairHash = new Hashtable<Integer, Integer>();
-
- private static final Character[] openingPars = { '(', '[', '{', '<', 'A',
- 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
-
- private static final Character[] closingPars = { ')', ']', '}', '>', 'a',
- 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
-
- private static HashSet<Character> openingParsSet = new HashSet<Character>(
- Arrays.asList(openingPars));
-
- private static HashSet<Character> closingParsSet = new HashSet<Character>(
- Arrays.asList(closingPars));
-
- private static Hashtable<Character, Character> closingToOpening = new Hashtable<Character, Character>()
- // Initializing final data structure
- {
- private static final long serialVersionUID = 1L;
- {
- for (int i = 0; i < openingPars.length; i++)
- {
- // System.out.println(closingPars[i] + "->" + openingPars[i]);
- put(closingPars[i], openingPars[i]);
- }
- }
- };
-
+ /**
+ * Answers true if the character is a valid open pair rna secondary structure
+ * symbol. Currently accepts A-Z, ([{<
+ *
+ * @param c
+ * @return
+ */
public static boolean isOpeningParenthesis(char c)
{
- return openingParsSet.contains(c);
+ return ('A' <= c && c <= 'Z' || c == '(' || c == '[' || c == '{' || c == '<');
}
+ /**
+ * Answers true if the character is a valid close pair rna secondary structure
+ * symbol. Currently accepts a-z, )]}>
+ *
+ * @param c
+ * @return
+ */
public static boolean isClosingParenthesis(char c)
{
- return closingParsSet.contains(c);
+ return ('a' <= c && c <= 'z' || c == ')' || c == ']' || c == '}' || c == '>');
}
- private static char matchingOpeningParenthesis(char closingParenthesis)
- throws WUSSParseException
+ /**
+ * Returns the matching open pair symbol for the given closing symbol.
+ * Currently returns A-Z for a-z, or ([{< for )]}>, or the input symbol if it
+ * is not a valid closing symbol.
+ *
+ * @param c
+ * @return
+ */
+ public static char getMatchingOpeningParenthesis(char c)
{
- if (!isClosingParenthesis(closingParenthesis))
+ if ('a' <= c && c <= 'z')
{
- throw new WUSSParseException(
- MessageManager.formatMessage(
- "exception.querying_matching_opening_parenthesis_for_non_closing_parenthesis",
- new String[] { String.valueOf(closingParenthesis) }),
- -1);
+ return (char) (c + 'A' - 'a');
+ }
+ switch (c)
+ {
+ case ')':
+ return '(';
+ case ']':
+ return '[';
+ case '}':
+ return '{';
+ case '>':
+ return '<';
+ default:
+ return c;
}
-
- return closingToOpening.get(closingParenthesis);
}
/**
else if (isClosingParenthesis(base))
{
- char opening = matchingOpeningParenthesis(base);
+ char opening = getMatchingOpeningParenthesis(base);
if (!stacks.containsKey(opening))
{
}
return false;
}
+
+ /**
+ * Returns the matching close pair symbol for the given opening symbol.
+ * Currently returns a-z for A-Z, or )]}> for ([{<, or the input symbol if it
+ * is not a valid opening symbol.
+ *
+ * @param c
+ * @return
+ */
+ public static char getMatchingClosingParenthesis(char c)
+ {
+ if ('A' <= c && c <= 'Z')
+ {
+ return (char) (c + 'a' - 'A');
+ }
+ switch (c)
+ {
+ case '(':
+ return ')';
+ case '[':
+ return ']';
+ case '{':
+ return '}';
+ case '<':
+ return '>';
+ default:
+ return c;
+ }
+ }
}
import jalview.renderer.AwtRenderPanelI;
import jalview.util.Comparison;
import jalview.util.MessageManager;
+import jalview.util.Platform;
import java.awt.Color;
import java.awt.Dimension;
public AnnotationPanel(AlignmentPanel ap)
{
- MAC = new jalview.util.Platform().isAMac();
+ new jalview.util.Platform();
+ MAC = Platform.isAMac();
this.ap = ap;
av = ap.av;
setLayout(null);
else if (evt.getActionCommand().equals(STEM))
{
type = 'S';
- symbol = "(";// "\u03C3"; sigma
+ int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
+ symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
}
- symbol = getCurrentAnnotationCharacter(anot, symbol);
-
if (!aa[activeRow].hasIcons)
{
aa[activeRow].hasIcons = true;
return null;
}
}
-
- /**
- * Returns the current annotation symbol (if any) within the visible selected
- * columns (first symbol found left to right in selection). If none is found,
- * the supplied default value is returned.
- *
- * @param annotations
- * @param defaultValue
- * @return
- */
- String getCurrentAnnotationCharacter(Annotation[] annotations,
- String defaultValue)
- {
- String result = defaultValue;
- for (int index : av.getColumnSelection().getSelected())
- {
- if (!av.getColumnSelection().isVisible(index))
- {
- continue;
- }
-
- Annotation annotation = annotations[index];
- if (annotation != null)
- {
- String displayed = annotation.displayCharacter;
- if (displayed != null && displayed.length() > 0)
- {
- result = displayed.substring(0, 1);
- break;
- }
- }
- }
- return result;
- }
}
if (annotations == null)
{
visible = false; // try to prevent renderer from displaying.
+ invalidrnastruc = -1;
return; // this is a non-annotation row annotation - ie a sequence score.
}
this.annotationId = ANNOTATION_ID_PREFIX + Long.toString(nextId());
}
+ /**
+ * Returns the match for the last unmatched opening RNA helix pair symbol
+ * preceding the given column, or '(' if nothing found to match.
+ *
+ * @param column
+ * @return
+ */
+ public String getDefaultRnaHelixSymbol(int column)
+ {
+ String result = "(";
+ if (annotations == null)
+ {
+ return result;
+ }
+
+ /*
+ * for each preceding column, if it contains an open bracket,
+ * count whether it is still unmatched at column, if so return its pair
+ * (likely faster than the fancy alternative using stacks)
+ */
+ for (int col = column - 1; col >= 0; col--)
+ {
+ Annotation annotation = annotations[col];
+ if (annotation == null)
+ {
+ continue;
+ }
+ String displayed = annotation.displayCharacter;
+ if (displayed == null || displayed.length() != 1)
+ {
+ continue;
+ }
+ char symbol = displayed.charAt(0);
+ if (!Rna.isOpeningParenthesis(symbol))
+ {
+ continue;
+ }
+
+ /*
+ * found an opening bracket symbol
+ * count (closing-opening) symbols of this type that follow it,
+ * up to and excluding the target column; if the count is less
+ * than 1, the opening bracket is unmatched, so return its match
+ */
+ String closer = String.valueOf(Rna
+ .getMatchingClosingParenthesis(symbol));
+ String opener = String.valueOf(symbol);
+ int count = 0;
+ for (int j = col + 1; j < column; j++)
+ {
+ if (annotations[j] != null)
+ {
+ String s = annotations[j].displayCharacter;
+ if (closer.equals(s))
+ {
+ count++;
+ }
+ else if (opener.equals(s))
+ {
+ count--;
+ }
+ }
+ }
+ if (count < 1)
+ {
+ return closer;
+ }
+ }
+ return result;
+ }
+
protected static synchronized long nextId()
{
return counter++;
aa[activeRow].annotations = anot;
}
- if (evt.getActionCommand().equals(REMOVE))
+ String action = evt.getActionCommand();
+ if (action.equals(REMOVE))
{
for (int sel : av.getColumnSelection().getSelected())
{
anot[sel] = null;
}
}
- else if (evt.getActionCommand().equals(LABEL))
+ else if (action.equals(LABEL))
{
String exMesg = collectAnnotVals(anot, LABEL);
String label = JOptionPane.showInputDialog(this,
if (anot[index] == null)
{
- anot[index] = new Annotation(label, "", ' ', 0); // TODO: verify that
- // null exceptions
- // aren't raised
- // elsewhere.
+ anot[index] = new Annotation(label, "", ' ', 0);
}
else
{
}
}
}
- else if (evt.getActionCommand().equals(COLOUR))
+ else if (action.equals(COLOUR))
{
Color col = JColorChooser.showDialog(this,
MessageManager.getString("label.select_foreground_colour"),
char type = 0;
String symbol = "\u03B1"; // alpha
- if (evt.getActionCommand().equals(HELIX))
+ if (action.equals(HELIX))
{
type = 'H';
}
- else if (evt.getActionCommand().equals(SHEET))
+ else if (action.equals(SHEET))
{
type = 'E';
symbol = "\u03B2"; // beta
}
// Added by LML to color stems
- else if (evt.getActionCommand().equals(STEM))
+ else if (action.equals(STEM))
{
type = 'S';
- symbol = "(";// "\u03C3"; // sigma
+ int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
+ symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
}
if (!aa[activeRow].hasIcons)
aa[activeRow].hasIcons = true;
}
- symbol = getCurrentAnnotationCharacter(anot, symbol);
-
String label = JOptionPane.showInputDialog(MessageManager
.getString("label.enter_label_for_the_structure"), symbol);
if ((label.length() > 0) && !aa[activeRow].hasText)
{
aa[activeRow].hasText = true;
- if (evt.getActionCommand().equals(STEM))
+ if (action.equals(STEM))
{
aa[activeRow].showAllColLabels = true;
}
return;
}
- /**
- * Returns the current annotation symbol (if any) within the visible selected
- * columns (first symbol found left to right in selection). If none is found,
- * the supplied default value is returned.
- *
- * @param annotations
- * @param defaultValue
- * @return
- */
- String getCurrentAnnotationCharacter(Annotation[] annotations,
- String defaultValue)
- {
- String result = defaultValue;
- for (int index : av.getColumnSelection().getSelected())
- {
- if (!av.getColumnSelection().isVisible(index))
- {
- continue;
- }
-
- Annotation annotation = annotations[index];
- if (annotation != null)
- {
- String displayed = annotation.displayCharacter;
- if (displayed != null && displayed.length() > 0)
- {
- result = displayed.substring(0, 1);
- break;
- }
- }
- }
- return result;
- }
-
private String collectAnnotVals(Annotation[] anot, String label2)
{
String collatedInput = "";
}
}
}
+
+ @Test(groups = { "Functional" })
+ public void testGetMatchingOpeningParenthesis() throws WUSSParseException
+ {
+ for (int i = 0; i <= 255; i++)
+ {
+ boolean isClosing = Rna.isClosingParenthesis((char) i);
+ if (isClosing)
+ {
+ char opening = Rna.getMatchingOpeningParenthesis((char) i);
+ if (i >= 'a' && i <= 'z')
+ {
+ assertEquals(i + 'A' - 'a', opening);
+ }
+ else if (i == ')' && opening == '(' || i == ']' && opening == '['
+ || i == '}' && opening == '{' || i == '>' && opening == '<')
+ {
+ // ok
+ }
+ else
+ {
+ fail("Got " + opening + " as opening bracket pair for "
+ + ((char) i));
+ }
+ }
+ }
+ }
}
assertEquals(1, ann.annotations[1].value, 0.001);
assertEquals(2, ann.annotations[2].value, 0.001);
}
-}
+
+ /**
+ * Test the method that defaults rna symbol to the one matching the preceding
+ * unmatched opening bracket (if any)
+ */
+ @Test(groups = { "Functional" })
+ public void testGetDefaultRnaHelixSymbol()
+ {
+ AlignmentAnnotation ann = new AlignmentAnnotation("SS",
+ "secondary structure", null);
+ assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+
+ Annotation[] anns = new Annotation[20];
+ ann.annotations = anns;
+ assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+
+ anns[1] = new Annotation("(", "S", '(', 0f);
+ assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
+ assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
+ assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
+ assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
+
+ /*
+ * .(.[.{.<.}.>.).].
+ */
+ anns[1] = new Annotation("(", "S", '(', 0f);
+ anns[3] = new Annotation("[", "S", '[', 0f);
+ anns[5] = new Annotation("{", "S", '{', 0f);
+ anns[7] = new Annotation("<", "S", '<', 0f);
+ anns[9] = new Annotation("}", "S", '}', 0f);
+ anns[11] = new Annotation(">", "S", '>', 0f);
+ anns[13] = new Annotation(")", "S", ')', 0f);
+ anns[15] = new Annotation("]", "S", ']', 0f);
+
+ String expected = "(())]]}}>>>>]]]](";
+ for (int i = 0; i < expected.length(); i++)
+ {
+ assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+ ann.getDefaultRnaHelixSymbol(i));
+ }
+
+ /*
+ * .(.[.(.).{.}.<.].D.
+ */
+ anns[1] = new Annotation("(", "S", '(', 0f);
+ anns[3] = new Annotation("[", "S", '[', 0f);
+ anns[5] = new Annotation("(", "S", '(', 0f);
+ anns[7] = new Annotation(")", "S", ')', 0f);
+ anns[9] = new Annotation("{", "S", '{', 0f);
+ anns[11] = new Annotation("}", "S", '}', 0f);
+ anns[13] = new Annotation("<", "S", '>', 0f);
+ anns[15] = new Annotation("]", "S", ']', 0f);
+ anns[17] = new Annotation("D", "S", 'D', 0f);
+
+ expected = "(())]]))]]}}]]>>>>dd";
+ for (int i = 0; i < expected.length(); i++)
+ {
+ assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+ ann.getDefaultRnaHelixSymbol(i));
+ }
+ }
+}
\ No newline at end of file