https://github.com/teerjk/VarSifter
Tip revision: 7e57e5857b08f5253f28e96477fc211f67a0ffea authored by Jamie K. Teer on 27 April 2020, 14:42:41 UTC
-Documentation updates to point to github.
-Documentation updates to point to github.
Tip revision: 7e57e58
CustomQueryView.java
import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.awt.event.*;
import java.util.regex.*;
import java.util.Collection;
import org.apache.commons.collections15.Transformer;
import org.apache.commons.collections15.functors.ChainedTransformer;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DelegateForest;
import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.algorithms.layout.TreeLayout;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.decorators.EdgeShape;
import edu.uci.ics.jung.visualization.renderers.Renderer.VertexLabel.Position;
import edu.uci.ics.jung.visualization.renderers.VertexLabelAsShapeRenderer;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.PluggableGraphMouse;
import edu.uci.ics.jung.visualization.control.PickingGraphMousePlugin;
/**
* Creates a window to handle GUI for custom query string generation
* This class will generate an if-statement for sifting data
* @author Jamie K. Teer
*/
public class CustomQueryView extends JPanel implements ActionListener, ListSelectionListener {
String[] sampleNames;
String[] annotNames;
AbstractMapper[] annotMap;
AbstractMapper currentMap;
private VarData vdat;
private VarSifter gui;
Map<String, Integer> dataTypeAt;
Map<String, Integer> sampleIndexOf; // The index in the main sample array (vdat.sampleNames) of the given sample name
int annoSize;
DelegateForest<CustomVertex, Integer> graph;
private int lastQueryIndex = 0;
private Integer edgeCount = 0;
final static int SAMPLE = 0;
final static int FIXED_SAMPLE = 1;
final static int ACTION = 2;
final static int ANNOT_ACTION = 3;
final static int ANNOT_COMP = 4;
final static int LOGICAL = 5;
final static int ANNOT_LIST = 6;
final static int ANNOT_VAL = 7;
private final static Pattern compPat = Pattern.compile("[<>=&]|get|isH");
private boolean isAnnotQuery = false;
String[] fixedSamples = { "Homozygous Reference",
"Homozygous Variant",
"Homozygous",
"Heterozygous",
"Hemizygous Reference",
"Hemizygous Variant",
"NA"
};
private JList sampleList;
private JList fixedSampleList = new JList(fixedSamples);
private JList annotList;
private JList stringAnnotList = new JList();
private JLabel sSampleLabel = new JLabel("Samples:");
private JLabel sGenLabel = new JLabel("Genotypes:");
private JLabel sActionLabel = new JLabel("Sample Actions:");
private JLabel aAnnoLabel = new JLabel("Annotations:");
private JLabel aValueLabel = new JLabel("Annotation Values:");
private JLabel aActionLabel = new JLabel("Annotation Actions:");
private JLabel aNumActionLabel = new JLabel("Annot. Numeric Actions:");
private JLabel logicLabel = new JLabel("Logical connectors:");
private JButton exactMatch = new JButton("Exactly Matches");
private JButton noMatch = new JButton("Does Not Match");
private JButton[] actionButtons = {exactMatch, noMatch};
private JButton annotExactMatch = new JButton("Exactly Matches");
private JButton annotNoMatch = new JButton("Does Not Match");
private JButton[] annotActionButtons = {annotExactMatch, annotNoMatch};
private JButton eqButton = new JButton("Equals");
private JButton gtButton = new JButton("Greater Than");
private JButton ltButton = new JButton("Less Than");
private JButton[] annotCompButtons = {eqButton, gtButton, ltButton};
private JButton applyAnnotComp = new JButton("Apply Number");
private JButton applyStringPattern = new JButton("Apply Search Text");
private JButton andButton = new JButton("AND");
private JButton orButton = new JButton("OR");
private JButton xorButton = new JButton("XOR");
private JButton[] logicButtons = {andButton, orButton, xorButton};
private JButton finalizeQuery = new JButton("Finalize Query");
private JButton reset = new JButton("Reset Current Query");
private JButton delete = new JButton("Delete Selected");
private JButton qSave = new JButton("Save Query");
private JButton qLoad = new JButton("Load Query");
private JButton clear = new JButton("Clear All");
private JComboBox modeBox;
private JTextField outText = new JTextField();
private JTextArea outMessage = new JTextArea("Select a Sample or Annotation");
private JTextField inAnnotNumber = new JTextField();
private JTextField inStringPattern = new JTextField();
private StringBuilder query;
private StringBuilder vertexLabel;
private int vertexLabelCount = 1; //Use this to know where we are in the query assembly process
private String outGroup;
private List<BitSet> bitSetList = new ArrayList<BitSet>();
private TreeLayout<CustomVertex,Integer> layout;
private VisualizationViewer<CustomVertex,Integer> vv;
/**
* Initializer
*
* @param inVdat VarData Object
*/
public CustomQueryView(VarData inVdat, VarSifter inGui) {
vdat = inVdat;
gui = inGui;
String[] origSampleNames = vdat.returnSampleNames(); // The original names - DON'T CHANGE THIS!!
sampleNames = new String[origSampleNames.length];
annotNames = vdat.returnDataNames();
dataTypeAt = vdat.returnDataTypeAt();
sampleIndexOf = new HashMap<String,Integer>(origSampleNames.length);
annoSize = dataTypeAt.size();
annotMap = vdat.returnAnnotMap();
for (int i=0; i<origSampleNames.length; i++) {
String n = origSampleNames[i];
sampleIndexOf.put(n, i);
sampleNames[i] = n;
}
graph = new DelegateForest<CustomVertex,Integer>();
layout = new TreeLayout<CustomVertex,Integer>(graph);
vv = new VisualizationViewer<CustomVertex,Integer>(layout);
VertexLabelAsShapeRenderer<CustomVertex,Integer> vlasr = new
VertexLabelAsShapeRenderer<CustomVertex,Integer>(vv.getRenderContext());
vv.getRenderContext().setVertexLabelTransformer(
new ChainedTransformer<CustomVertex,String>(new Transformer[]{
new ToStringLabeller<String>(),
new Transformer<String,String>() {
public String transform(String input) {
return "<html><center>"+input;
}
}
}));
vv.getRenderContext().setVertexShapeTransformer(vlasr);
vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
vv.getRenderer().setVertexLabelRenderer(vlasr);
final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
modeBox = graphMouse.getModeComboBox();
modeBox.setMaximumSize(modeBox.getPreferredSize());
modeBox.addItemListener(graphMouse.getModeListener());
graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
vv.setGraphMouse(graphMouse);
String out = "";
sampleList = new JList(sampleNames);
annotList = new JList(annotNames);
initQuery();
initTable();
}
/**
* Initialize GUI
*/
private void initTable() {
this.setLayout(new BorderLayout());
ToolTipManager.sharedInstance().setInitialDelay(1250);
ToolTipManager.sharedInstance().setReshowDelay(0);
ToolTipManager.sharedInstance().setDismissDelay(10000);
/* *******
* Sample query setup
* *******
*/
JPanel fixedPane = new JPanel();
fixedPane.setLayout(new BoxLayout(fixedPane, BoxLayout.Y_AXIS));
fixedPane.setAlignmentX(Component.LEFT_ALIGNMENT);
fixedSampleList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane fSS = new JScrollPane(fixedSampleList);
fSS.setMaximumSize(new Dimension(fSS.getMaximumSize().width, 60));
fixedPane.add(fSS);
fixedPane.setPreferredSize(new Dimension(fSS.getPreferredSize().width, 60));
JPanel samplePane = new JPanel();
samplePane.setLayout(new BoxLayout(samplePane, BoxLayout.Y_AXIS));
samplePane.setAlignmentX(Component.LEFT_ALIGNMENT);
sampleList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
samplePane.add(new JScrollPane(sampleList));
JPanel actionPane = new JPanel();
actionPane.setLayout(new BoxLayout(actionPane, BoxLayout.Y_AXIS));
actionPane.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.black),
BorderFactory.createEmptyBorder(7,7,7,7)
));
actionPane.add(exactMatch);
actionPane.add(Box.createRigidArea(new Dimension(0,5)));
actionPane.add(noMatch);
/* *******
* Annotation panel setup
* *******
*/
JPanel annotPane = new JPanel();
annotPane.setLayout(new BoxLayout(annotPane, BoxLayout.Y_AXIS));
annotPane.setAlignmentX(Component.LEFT_ALIGNMENT);
annotPane.setPreferredSize(new Dimension(200, annotPane.getPreferredSize().height));
annotList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane annotPaneScroller = new JScrollPane();
annotPane.add(new JScrollPane(annotList));
JPanel stringAnnotPane = new JPanel();
stringAnnotPane.setLayout(new BoxLayout(stringAnnotPane, BoxLayout.Y_AXIS));
stringAnnotPane.setPreferredSize(new Dimension(200, stringAnnotPane.getPreferredSize().height));
stringAnnotPane.setAlignmentX(Component.LEFT_ALIGNMENT);
stringAnnotList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
stringAnnotPane.add(new JScrollPane(stringAnnotList));
JPanel annotActionPane = new JPanel();
annotActionPane.setLayout(new BoxLayout(annotActionPane, BoxLayout.Y_AXIS));
annotActionPane.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.black),
BorderFactory.createEmptyBorder(7,7,7,7)
));
inStringPattern.setMaximumSize(new Dimension( inStringPattern.getMaximumSize().width,
inStringPattern.getMinimumSize().height));
annotActionPane.add(annotExactMatch);
annotActionPane.add(Box.createRigidArea(new Dimension(0,5)));
annotActionPane.add(annotNoMatch);
annotActionPane.add(Box.createRigidArea(new Dimension(0,5)));
annotActionPane.add(inStringPattern);
annotActionPane.add(Box.createRigidArea(new Dimension(0,5)));
annotActionPane.add(applyStringPattern);
JPanel annotCompPane = new JPanel();
annotCompPane.setLayout(new BoxLayout(annotCompPane, BoxLayout.Y_AXIS));
annotCompPane.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.black),
BorderFactory.createEmptyBorder(7,7,7,7)
));
annotCompPane.setAlignmentX(Component.LEFT_ALIGNMENT);
inAnnotNumber.setMaximumSize(new Dimension( inAnnotNumber.getMaximumSize().width,
inAnnotNumber.getMinimumSize().height));
inAnnotNumber.setAlignmentX(Component.LEFT_ALIGNMENT);
annotCompPane.add(eqButton);
annotCompPane.add(Box.createRigidArea(new Dimension(0,5)));
annotCompPane.add(gtButton);
annotCompPane.add(Box.createRigidArea(new Dimension(0,5)));
annotCompPane.add(ltButton);
annotCompPane.add(Box.createRigidArea(new Dimension(0,5)));
annotCompPane.add(inAnnotNumber);
annotCompPane.add(Box.createRigidArea(new Dimension(0,5)));
annotCompPane.add(applyAnnotComp);
/* ********
* Main Controls
* ********
*/
JPanel connectPane = new JPanel();
connectPane.setLayout(new BoxLayout(connectPane, BoxLayout.X_AXIS));
connectPane.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.black),
BorderFactory.createEmptyBorder(7,7,7,7)
));
connectPane.setAlignmentX(Component.LEFT_ALIGNMENT);
connectPane.add(andButton);
connectPane.add(Box.createRigidArea(new Dimension(5,0)));
connectPane.add(orButton);
connectPane.add(Box.createRigidArea(new Dimension(5,0)));
connectPane.add(xorButton);
JPanel runPane = new JPanel();
runPane.setLayout(new BoxLayout(runPane, BoxLayout.X_AXIS));
runPane.setBorder(BorderFactory.createEmptyBorder(7,7,7,7));
runPane.add(finalizeQuery);
runPane.add(Box.createRigidArea(new Dimension(5,0)));
runPane.add(reset);
runPane.add(Box.createRigidArea(new Dimension(5,0)));
runPane.add(qSave);
runPane.add(Box.createRigidArea(new Dimension(5,0)));
runPane.add(qLoad);
runPane.add(Box.createRigidArea(new Dimension(5,0)));
runPane.add(delete);
runPane.add(Box.createRigidArea(new Dimension(5,0)));
runPane.add(clear);
runPane.add(Box.createRigidArea(new Dimension(5,0)));
JPanel extraPane = new JPanel();
extraPane.setLayout(new BoxLayout(extraPane, BoxLayout.X_AXIS));
extraPane.setBorder(BorderFactory.createEmptyBorder(7,7,7,7));
extraPane.add(modeBox);
extraPane.add(Box.createRigidArea(new Dimension(5,0)));
outText.setMaximumSize(new Dimension( outText.getMaximumSize().width,
outText.getMinimumSize().height));
if (VarSifter.isDebug) {
extraPane.add(outText); //Debugging
}
extraPane.add(outMessage);
outMessage.setEditable(false);
extraPane.add(Box.createVerticalGlue());
//Icons
finalizeQuery.setIcon(createImageIcon("images/boxes.png", "filter tree"));
//Listeners
exactMatch.addActionListener(this);
noMatch.addActionListener(this);
annotExactMatch.addActionListener(this);
annotNoMatch.addActionListener(this);
eqButton.addActionListener(this);
gtButton.addActionListener(this);
ltButton.addActionListener(this);
applyAnnotComp.addActionListener(this);
applyStringPattern.addActionListener(this);
finalizeQuery.addActionListener(this);
reset.addActionListener(this);
qSave.addActionListener(this);
qLoad.addActionListener(this);
delete.addActionListener(this);
clear.addActionListener(this);
andButton.addActionListener(this);
orButton.addActionListener(this);
xorButton.addActionListener(this);
sampleList.addListSelectionListener(this);
fixedSampleList.addListSelectionListener(this);
annotList.addListSelectionListener(this);
stringAnnotList.addListSelectionListener(this);
// Sort the samples. Just click on the "Sample:" label above the sample list to have the sample list sorted.
// Click again to sort in reverse order
// (Thanks to Timothy Gall)
sSampleLabel.addMouseListener(new MouseAdapter() {
boolean isForward = false;
public void mousePressed(MouseEvent e) {
if (e.getClickCount() > 0) {
if (isForward) {
java.util.Arrays.sort(sampleNames, java.util.Collections.reverseOrder());
isForward = false;
}
else {
java.util.Arrays.sort(sampleNames);
isForward = true;
}
sampleList.repaint();
}
}
});
// Mask buttons
enableButtons(new int[] {ACTION,ANNOT_ACTION,ANNOT_COMP,LOGICAL,ANNOT_VAL,FIXED_SAMPLE}, false);
applyAnnotComp.setEnabled(false);
applyStringPattern.setEnabled(false);
//stringAnnotList.setEnabled(false);
inAnnotNumber.setEnabled(false);
//ToolTips
finalizeQuery.setToolTipText("<html>Prepares the query logic for filtering.<p>"
+ "Must be clicked before filtering will work!");
reset.setToolTipText("<html>Returns the current query to the intial state, without affecting query "
+ "boxes in the main window.<p>All selections used for the current query willl be lost.");
qSave.setToolTipText("<html>Saves the current query for later use.<p>"
+ "Will only work for THIS data file!");
qLoad.setToolTipText("<html>Loads a previously saved query.<p>"
+ "Can only load a query that was saved using THIS data file!");
clear.setToolTipText("Deletes are queries and logical connections.");
delete.setToolTipText("Deletes the selected query boxes.");
modeBox.setToolTipText("<html>Defines box selection behavior:<p>"
+ "PICKING: Allows selection of boxes. Shift-click to select multiple boxes,"
+ "or click-drag to draw a selection box.<p>"
+ "TRANSFORMING: Click-drag the screen to move it around.");
/* ********
* Layout the major sections
* ********
*/
JPanel sampleControlPane = new JPanel();
sampleControlPane.setLayout(new BoxLayout(sampleControlPane, BoxLayout.Y_AXIS));
JScrollPane sampleControlScroller = new JScrollPane(sampleControlPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sampleControlScroller.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),
BorderFactory.createEmptyBorder(2,5,2,2)
));
sampleControlPane.add(sSampleLabel);
sampleControlPane.add(samplePane);
sampleControlPane.add(Box.createRigidArea(new Dimension(0,5)));
sampleControlPane.add(sGenLabel);
sampleControlPane.add(fixedPane);
sampleControlPane.add(Box.createRigidArea(new Dimension(0,5)));
sampleControlPane.add(sActionLabel);
sampleControlPane.add(actionPane);
sampleControlPane.add(Box.createRigidArea(new Dimension(0,5)));
sampleControlPane.add(logicLabel);
sampleControlPane.add(connectPane);
JPanel annotControlPane = new JPanel();
annotControlPane.setLayout(new BoxLayout(annotControlPane, BoxLayout.Y_AXIS));
JScrollPane annotControlScroller = new JScrollPane(annotControlPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
annotControlScroller.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),
BorderFactory.createEmptyBorder(2,2,2,5)
));
annotControlPane.add(aAnnoLabel);
annotControlPane.add(annotPane);
annotControlPane.add(Box.createRigidArea(new Dimension(0,5)));
annotControlPane.add(aValueLabel);
annotControlPane.add(stringAnnotPane);
annotControlPane.add(Box.createRigidArea(new Dimension(0,5)));
annotControlPane.add(aActionLabel);
annotControlPane.add(annotActionPane);
annotControlPane.add(Box.createRigidArea(new Dimension(0,5)));
annotControlPane.add(aNumActionLabel);
annotControlPane.add(annotCompPane);
JPanel mainControlPane = new JPanel();
mainControlPane.setLayout(new BoxLayout(mainControlPane, BoxLayout.X_AXIS));
JScrollPane mainControlScroller = new JScrollPane(mainControlPane, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
mainControlScroller.setBorder(null);
mainControlPane.add(runPane);
mainControlPane.add(extraPane);
add(sampleControlScroller, BorderLayout.LINE_START);
add(annotControlScroller, BorderLayout.LINE_END);
add(mainControlScroller, BorderLayout.PAGE_END);
final GraphZoomScrollPane zoomPane = new GraphZoomScrollPane(vv);
zoomPane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
add(zoomPane, BorderLayout.CENTER);
}
/**
* Handle Actions
*
* @param e resulting from clicking a button
*/
public void actionPerformed(ActionEvent e) {
Object es = e.getSource();
if (es == finalizeQuery) {
finalizeQuery();
}
else if (es == reset) {
resetQuery();
}
else if (es == qSave) {
writeGraph();
}
else if (es == qLoad) {
readGraph();
}
else if (es == delete) {
deletePicked();
}
else if (es == clear) {
bitSetList = new ArrayList<BitSet>();
initQuery();
graph = new DelegateForest<CustomVertex,Integer>();
}
else if (es == exactMatch) {
buildQueryVertex("equals","==");
}
else if (es == noMatch) {
buildQueryVertex("does not equal","!=");
}
else if (es == annotExactMatch) {
buildQueryVertex("equals","==");
}
else if (es == annotNoMatch) {
buildQueryVertex("does not equal","!=");
}
else if (es == eqButton) {
buildQueryVertex("equals","==");
}
else if (es == gtButton) {
buildQueryVertex(">", ">");
}
else if (es == ltButton) {
buildQueryVertex("<", "<");
}
else if (es == applyAnnotComp) {
String in = inAnnotNumber.getText();
try {
int i = Integer.parseInt(in);
buildQueryVertex(in, in);
}
catch (NumberFormatException nfe) {
try {
float f = Float.parseFloat(in);
buildQueryVertex(Float.toString(f), Float.toString(f) + "f");
}
catch (NumberFormatException n) {
System.out.println("Entry not a number! Please enter a number and try again!");
VarSifter.showError("Entry not a number! Please enter a number and try again!");
}
}
}
else if (es == applyStringPattern) {
String in = inStringPattern.getText();
if (buildQueryFromRegex(in)) {
buildQueryVertex(in, "");
}
}
else if (es == andButton) {
linkVertices("AND", " && ");
}
else if (es == orButton) {
linkVertices("OR", " || ");
}
else if (es == xorButton) {
linkVertices("XOR", " ^ ");
}
redrawGraph();
}
/**
* Handle List Selections
*
* @param e Event from a list selection
*/
public void valueChanged(ListSelectionEvent e) {
Object es = e.getSource();
if (e.getValueIsAdjusting() == false) {
if (es == sampleList && sampleList.getSelectedIndex() >= 0) {
if (vertexLabelCount == 1) {
isAnnotQuery = false;
}
int selIndex = sampleList.getSelectedIndex();
String labelTemp = sampleNames[selIndex];
String queryTemp = ("sampData[i][" + sampleIndexOf.get(labelTemp) + "][0]");
labelTemp = labelTemp.replaceFirst("\\.NA$", "");
buildQueryVertex(labelTemp, queryTemp);
sampleList.clearSelection();
}
else if (es == fixedSampleList && fixedSampleList.getSelectedIndex() >= 0) {
int selIndex = fixedSampleList.getSelectedIndex();
switch (selIndex) {
case 0: //HomRef
buildQueryVertex(fixedSamples[0], "homRefGen");
break;
case 1: //HomVariant (HomNonref)
buildQueryVertex(fixedSamples[1], "homNonRefGen");
break;
case 2: //Homozygous
buildQueryFromBitSet("isHom");
buildQueryVertex(fixedSamples[2], "");
break;
case 3: //Heterzygous
buildQueryFromBitSet("isHet");
buildQueryVertex(fixedSamples[3], "");
break;
case 4: //Hemizygous reference
buildQueryVertex(fixedSamples[4], "hemiRefGen");
break;
case 5: //Hemizygous variant
buildQueryVertex(fixedSamples[5], "hemiVarGen");
break;
case 6: //NA
buildQueryVertex(fixedSamples[6], "NA_Allele");
break;
}
fixedSampleList.clearSelection();
}
else if (es == annotList && annotList.getSelectedIndex() >= 0) {
int selIndex = annotList.getSelectedIndex();
if (vertexLabelCount == 1) {
isAnnotQuery = true;
}
String labelTemp = annotNames[selIndex];
String queryTemp = ("allData[i][" + selIndex + "]");
buildQueryVertex(labelTemp, queryTemp);
}
else if (es == stringAnnotList && stringAnnotList.getSelectedIndex() >= 0) {
String selValue = (String)stringAnnotList.getSelectedValue();
buildQueryVertex(selValue, Integer.toString(currentMap.getIndexOf(selValue)));
}
}
}
/**
* Enable buttons to allow proper query building
*/
private void enableButtons(int[] buttonGroup, boolean toEnabled) {
for (int bG: buttonGroup) {
JButton[] group = null;
switch (bG) {
case SAMPLE:
sampleList.setEnabled(toEnabled);
sSampleLabel.setEnabled(toEnabled);
break;
case FIXED_SAMPLE:
fixedSampleList.setEnabled(toEnabled);
sGenLabel.setEnabled(toEnabled);
break;
case ACTION:
group = actionButtons;
sActionLabel.setEnabled(toEnabled);
break;
case ANNOT_ACTION:
group = annotActionButtons;
aActionLabel.setEnabled(toEnabled);
break;
case ANNOT_COMP:
group = annotCompButtons;
aNumActionLabel.setEnabled(toEnabled);
break;
case LOGICAL:
group = logicButtons;
logicLabel.setEnabled(toEnabled);
break;
case ANNOT_LIST:
annotList.setEnabled(toEnabled);
aAnnoLabel.setEnabled(toEnabled);
break;
case ANNOT_VAL:
stringAnnotList.setEnabled(toEnabled);
aValueLabel.setEnabled(toEnabled);
break;
}
if (group != null) {
for (JButton b: group) {
b.setEnabled(toEnabled);
}
}
}
}
/**
* Build the query based on what stage of button clicking one is at
*/
private void buildQueryVertex(String labelString, String queryString) {
switch (vertexLabelCount) {
case 1:
initQuery();
vertexLabel.append("<html>" + labelString + "<p>");
query.append(queryString);
vertexLabelCount++;
outText.setText(vertexLabel.toString());
if (isAnnotQuery) {
int selIndex = annotList.getSelectedIndex();
currentMap = annotMap[selIndex];
outMessage.setText("Next, please select an Annotation Action");
switch (currentMap.getDataType()) {
case VarData.MULTISTRING:
case VarData.STRING:
stringAnnotList.setListData(currentMap.getSortedEntries());
enableButtons(new int[] {ANNOT_ACTION}, true);
break;
case VarData.FLOAT:
query.insert(0, "annotMapper[" + selIndex + "].getFloat(");
query.append(")");
case VarData.INTEGER:
enableButtons(new int[] {ANNOT_COMP}, true);
break;
}
}
else {
outMessage.setText("Next, please select a Sample Action");
enableButtons(new int[] {ACTION}, true);
}
enableButtons(new int[] {SAMPLE, ANNOT_LIST, LOGICAL}, false);
//annotList.setEnabled(false);
break;
case 2:
vertexLabel.append(labelString + "<p>");
vertexLabelCount++;
outText.setText(vertexLabel.toString());
if (isAnnotQuery) {
enableButtons(new int[] {ANNOT_ACTION, ANNOT_COMP}, false);
switch (currentMap.getDataType()) {
case VarData.MULTISTRING:
if (queryString.equals("==")) {
queryString = " & ";
}
else if (queryString.equals("!=")) {
queryString = " & ";
query.insert(0,"~");
}
queryString += "(int)Math.pow(2,";
query.insert(0, "(");
case VarData.STRING:
applyStringPattern.setEnabled(true);
enableButtons(new int[] {ANNOT_VAL}, true);
outMessage.setText("Finally, select an Annotation Value, or enter Search Text" +
VarSifter.newLine + "and click \"Apply Search Text\"");
//stringAnnotList.setEnabled(true);
break;
case VarData.FLOAT:
case VarData.INTEGER:
inAnnotNumber.setEnabled(true);
applyAnnotComp.setEnabled(true);
outMessage.setText("Finally, enter a Number and click \"Apply Number\"");
break;
}
}
else {
outMessage.setText("Finally, select another Sample or a Genotype");
enableButtons(new int[] {ACTION}, false);
enableButtons(new int[] {FIXED_SAMPLE, SAMPLE}, true);
}
query.append(queryString);
break;
case 3:
vertexLabel.append(labelString);
query.append(queryString);
if (isAnnotQuery) {
switch (currentMap.getDataType()) {
case VarData.MULTISTRING:
if (!query.toString().contains("~")) {
query.append(")) > 0");
}
else {
int aI = query.lastIndexOf("&");
String maskNum = query.substring(aI+2);
query.append("))==" + maskNum);
if (query.toString().contains("Math.pow")) {
query.append(")");
}
}
case VarData.STRING:
stringAnnotList.setListData(new String[]{""});
break;
case VarData.FLOAT:
case VarData.INTEGER:
break;
}
currentMap = null;
}
query.append(")");
query.insert(0, "(");
graph.addVertex(new CustomVertex(vertexLabel.toString(), query.toString()));
redrawGraph();
resetQuery();
break;
}
}
/**
* Reset the query state to 1 (ready for a new query)
*/
private void resetQuery() {
enableButtons(new int[] {LOGICAL, SAMPLE, ANNOT_LIST}, true);
enableButtons(new int[] {ACTION, ANNOT_ACTION, ANNOT_COMP, ANNOT_VAL, FIXED_SAMPLE}, false);
annotList.clearSelection();
stringAnnotList.clearSelection();
stringAnnotList.setListData(new String[]{""});
isAnnotQuery = false;
outMessage.setText("Select a Sample or Annotation");
//annotList.setEnabled(true);
//stringAnnotList.setEnabled(false);
applyAnnotComp.setEnabled(false);
applyStringPattern.setEnabled(false);
vertexLabelCount = 1;
initQuery();
}
/**
* Use regex to get indices of matching entries, append to a list.
* Then, recreate query to interrogate BitSet in list.
* @param regex The regex to search with
* @return True on success.
*/
private boolean buildQueryFromRegex(String regex) {
int index = bitSetList.size();
Pattern pat;
StringBuilder tempQuery = new StringBuilder();
try {
pat = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
}
catch (PatternSyntaxException pse) {
VarSifter.showError("Error parsing search term. Not Applying! Please try again.");
System.out.println(pse.toString());
return false;
}
switch (currentMap.getDataType()) {
case VarData.MULTISTRING:
int lastIndex = -1;
int msBSMask = 0;
int thisIndex;
BitSet msBS = currentMap.filterWithPattern(pat);
while ( (thisIndex = msBS.nextSetBit(lastIndex+1)) >= 0 ) {
msBSMask += (int)Math.pow(2,thisIndex);
lastIndex = thisIndex;
}
tempQuery.append("(");
tempQuery.append(query.toString());
tempQuery.delete(tempQuery.length() - 16, tempQuery.length()); //remove "(int)Math.pow(2,"
tempQuery.append(msBSMask);
break;
case VarData.STRING:
bitSetList.add(currentMap.filterWithPattern(pat));
if (query.substring( query.length()-2 ).equals("!=")) {
tempQuery.append("!");
}
tempQuery.append("bitSets[" + index + "].get(");
tempQuery.append(query.toString());
tempQuery.delete(tempQuery.length()-2, tempQuery.length());
tempQuery.append(")");
break;
}
//System.out.println(tempQuery.toString()); //TESTING
//System.out.println(bitSetList.get(index).cardinality()); //TESTING
query = tempQuery;
index++;
return true;
}
/**
* Construct the query statement against a bitset compiled into the QueryModule class
* built by the CompileCustomQuery class. Only works for Step 3 (vertexLabelCount == 3)!!
* @param bs The name of the BitSet in QueryModule to interrogate. Compile error if this variable not present.
*/
private void buildQueryFromBitSet(String bs) {
StringBuilder tempQuery = new StringBuilder();
//For now, this is designed for Genotypes, so only String types are handled
switch (VarData.STRING) {
case VarData.STRING:
if (query.substring( query.length()-2 ).equals("!=")) {
tempQuery.append("!");
}
tempQuery.append(bs + "(");
tempQuery.append(query.toString());
tempQuery.delete(tempQuery.length()-2, tempQuery.length());
tempQuery.append(")");
break;
case VarData.MULTISTRING:
case VarData.FLOAT:
case VarData.INTEGER:
//Unhandled for now - kill query
VarSifter.showError("<html>Internal Error - Can only use buildQueryFromBitSet(String) with STRING data!"
+ "<p>Current Query will be reset. Please Contact developer.");
resetQuery();
break;
}
query = tempQuery;
}
/**
* Link vertices with "and/or/xor"
*/
private void linkVertices(String labelString, String queryString) {
Set<CustomVertex> picked = vv.getPickedVertexState().getPicked();
if (picked.size() > 2 && labelString.equals("XOR") ) {
VarSifter.showError("<html>Linking multiple elements with XOR will probably NOT work correctly!<p>"
+ "For example, \"true XOR true XOR true\" will be true, not false!<p>");
}
else if (picked.size() >= 2) {
CustomVertex tempCV = new CustomVertex(labelString, queryString);
graph.addVertex(tempCV);
for (CustomVertex cv: picked) {
graph.addEdge(edgeCount++, tempCV, cv);
}
}
else {
VarSifter.showError("Must pick two or more elements to connect!");
}
}
/**
* Delete selected boxes
*/
private void deletePicked() {
Set<CustomVertex> picked = vv.getPickedVertexState().getPicked();
if (picked.size() > 0) {
for (CustomVertex cv: picked) {
Collection<Integer> childEdges = graph.getChildEdges(cv);
Integer[] ceArray = childEdges.toArray(new Integer[childEdges.size()]);
for (Integer ce: ceArray) {
graph.removeEdge(ce, false);
}
graph.removeVertex(cv);
}
}
else {
VarSifter.showError("Must choose a box to delete!");
}
}
/**
* Return the built query (the if-statement)
*
* @return String containing the if statement constructed by the GUI
*/
public String getQuery() {
return outGroup;
}
/**
* Walk the tree, assembling the query parameters at each node
*/
private void findLeavesAndWrite(CustomVertex rootVertex, Collection<String> parentStringGroup) {
if (graph.getChildCount(rootVertex) > 0) {
List<String> stringGroup = new ArrayList<String>();
String outGroup = "(";
for (CustomVertex cv : graph.getChildren(rootVertex)) {
findLeavesAndWrite(cv, stringGroup);
}
for (Iterator<String> sgi = stringGroup.iterator(); sgi.hasNext();) {
outGroup += sgi.next();
if (sgi.hasNext()) {
outGroup += rootVertex.getQuery();
}
}
outGroup += ")";
parentStringGroup.add(outGroup);
}
else {
parentStringGroup.add(rootVertex.getQuery());
if (! compPat.matcher(rootVertex.getQuery()).find()) {
VarSifter.showError("It looks like one of the bottom elements is not a comparison: this will probably not work!");
}
}
}
private void initQuery() {
query = new StringBuilder(64);
vertexLabel = new StringBuilder(64);
outText.setText("");
}
private void finalizeQuery() {
Collection<CustomVertex> roots = graph.getRoots();
if (roots.size() == 1) {
List<String> stringGroup = new ArrayList<String>();
outGroup = "";
findLeavesAndWrite(roots.iterator().next(), stringGroup);
for (Iterator<String> sgi = stringGroup.iterator(); sgi.hasNext(); ) {
outGroup += sgi.next();
if (sgi.hasNext()) {
outGroup += roots.iterator().next();
}
}
outText.setText(outGroup);
vdat.setCustomQuery(outGroup);
vdat.setCustomBitSet(bitSetList.toArray(new BitSet[bitSetList.size()]));
if (gui != null) {
gui.setCBoxChecked(gui.CUSTOM, true);
gui.toFront();
}
}
else {
VarSifter.showError("The query is disconnected! Please make sure all the parts are connected as one unit!");
}
}
private void redrawGraph() {
Collection<CustomVertex> cv = graph.getVertices();
int maxWidth = 0;
for (CustomVertex s: cv) {
int width = vv.getRenderContext().getVertexShapeTransformer().transform(s).getBounds().width;
if (width >= maxWidth) {
maxWidth = width;
}
}
vv.setGraphLayout(new TreeLayout<CustomVertex,Integer>(graph, (maxWidth + 5), 80));
vv.repaint();
}
/**
* Use serialization to read graph object file
*/
private void readGraph() {
try {
File df = new File(vdat.dataFile);
File queryFile;
JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
fc.setDialogTitle("Open Query");
int fcReturnVal = fc.showOpenDialog(this);
if (fcReturnVal == JFileChooser.APPROVE_OPTION) {
queryFile = fc.getSelectedFile();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(queryFile));
String queryOfFile = (String)ois.readObject();
System.out.println("Read query for data " + queryOfFile);
if ( queryOfFile.equals(df.getName()) ) {
JOptionPane.showMessageDialog(this, "<html>The loaded query appears to match this data file by name."
+ "<p>However, if the query didn't really come from this EXACT data file, you will get incorrect results!!!");
graph = (DelegateForest<CustomVertex,Integer>)ois.readObject();
try {
bitSetList = (ArrayList<BitSet>)ois.readObject();
}
catch (IOException ioe) {
System.err.println(ioe);
VarSifter.showError("<html>You have loaded a query object created from a VarSifter version<p>" +
"earlier than 1.5. If there was a text search in your query, it will likely fail.<p>" +
"It is highly recommended to remake the query to avoid errors!!</html>");
}
redrawGraph();
}
else {
VarSifter.showError("<html>It looks like the query you loaded was saved from a different data file: " +
queryOfFile + " <p>Refusing to load, as the query results will be incorrect.");
}
ois.close();
}
else {
System.out.println("No file selected");
}
}
catch (IOException ioe) {
System.out.println(ioe.toString());
}
catch (ClassNotFoundException e) {
System.out.println(e.toString());
}
}
/**
* Use serialization to save graph
*/
private void writeGraph() {
try {
File df = new File(vdat.dataFile);
File queryFile;
int ovwResult = JOptionPane.YES_OPTION;
JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
fc.setDialogTitle("Save Query As");
int fcReturnVal = fc.showSaveDialog(this);
if (fcReturnVal == JFileChooser.APPROVE_OPTION) {
queryFile = fc.getSelectedFile();
if (queryFile.exists()) {
ovwResult = JOptionPane.showConfirmDialog(null, queryFile.getAbsolutePath() + "already exists. " +
"Do you want to overwrite it?", "Overwrite Warning",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
}
if (ovwResult == JOptionPane.YES_OPTION) {
ObjectOutputStream ow = new ObjectOutputStream(new FileOutputStream(queryFile));
ow.writeObject(df.getName());
ow.writeObject(graph);
ow.writeObject(bitSetList);
ow.close();
System.out.println("Saved query for data " + df.getName());
}
else {
System.out.println("Query file not written.");
}
}
else {
System.out.println("Query file not written.");
}
}
catch (IOException ioe) {
System.out.println(ioe.toString());
}
}
/**
* Create an ImageIcon from a path relative to this class.
* @param path Relative path of image file.
* @param desc Assistive tech description
* @return ImageIcon or null if path invalid.
*/
private ImageIcon createImageIcon(String path, String desc) {
java.net.URL url = getClass().getResource(path);
if (url != null) {
return new ImageIcon(url, desc);
}
else {
VarSifter.showError("Couldn't find icon path: " + path);
return null;
}
}
}