diff --git a/src/main/java/datastructure/Condition.java b/src/main/java/datastructure/Condition.java new file mode 100644 index 0000000..1ab87f8 --- /dev/null +++ b/src/main/java/datastructure/Condition.java @@ -0,0 +1,45 @@ +package datastructure; + + +import javafx.scene.paint.Color; + +/** + * Created by 101010. + */ +public abstract class Condition { + /** + * The color to be painted when condition holds. + */ + private final Color color; + + /** + * Default constructor. + */ + public Condition() { + color = Color.BLACK; + } + + /** + * Constructor of the condition. + * @param color the color of this condition. + */ + public Condition(Color color) { + this.color = color; + } + /** + * Derives if condition holds. + * @param drawNode the node to derive condition on. + * @return true iff the condition holds. + */ + public abstract boolean addColor(DrawNode drawNode); + + /** + * Gets the color of the condition. + * @return the color of the condition. + */ + public Color getColor() { + return color; + } + + +} diff --git a/src/main/java/datastructure/DrawNode.java b/src/main/java/datastructure/DrawNode.java index 2d36297..905bcf4 100644 --- a/src/main/java/datastructure/DrawNode.java +++ b/src/main/java/datastructure/DrawNode.java @@ -1,6 +1,7 @@ package datastructure; import javafx.scene.shape.Rectangle; +import screens.GraphInfo; /** * Created by 101010. @@ -49,4 +50,25 @@ public int hashCode() { return id; } + /** + * Getter for the genome paths going through a DrawNode. + * @return all genomes that cross this DrawNode. + */ + public String[] getGenomes() { + int[][] allGenomes = GraphInfo.getInstance().getGenomes(); + int index = -1; + for (int i = 0; i < allGenomes.length; i++) { + if (allGenomes[i][0] == this.getIndex()) { + index = i; + break; + } + } + int[] genomes = GraphInfo.getInstance().getGenomes()[index]; + String[] strGenomes = new String[genomes.length - 1]; + for (int i = 1; i < genomes.length; i++) { + String name = GraphInfo.getInstance().getGenomeNames()[genomes[i]]; + strGenomes[i - 1] = name.substring(0, name.length() - 6); + } + return strGenomes; + } } diff --git a/src/main/java/datastructure/GenomeCountCondition.java b/src/main/java/datastructure/GenomeCountCondition.java new file mode 100644 index 0000000..7ac87c5 --- /dev/null +++ b/src/main/java/datastructure/GenomeCountCondition.java @@ -0,0 +1,58 @@ +package datastructure; + +import javafx.scene.paint.Color; + +/** + * Created by 101010. + */ +public class GenomeCountCondition extends Condition { + + /** + * The decision number of the condition. + */ + private int decisionNumber; + + /** + * True iff condition is greater than. + */ + private boolean greater; + + /** + * True iff condition in equal. + */ + private boolean equal; + + + /** + * Constructor of the condition. + * @param decisionNumber the number that decides the condition. + * @param greater true iff condition is greater than the decisionNumber. + * @param equal true iff condition is equal to the decisionNumber. + * @param color the color of the condition. + */ + public GenomeCountCondition(int decisionNumber, boolean greater, boolean equal, Color color) { + super(color); + this.decisionNumber = decisionNumber; + this.greater = greater; + this.equal = equal; + } + + @Override + public boolean addColor(DrawNode drawNode) { + int genomes = drawNode.getGenomes().length; + if (greater) { + if (equal) { + return decisionNumber <= genomes; + } else { + return decisionNumber < genomes; + } + } else { + if (equal) { + return decisionNumber >= genomes; + } else { + return decisionNumber > genomes; + } + } + + } +} diff --git a/src/main/java/datastructure/NodeGraph.java b/src/main/java/datastructure/NodeGraph.java index 193d8fe..86d616f 100644 --- a/src/main/java/datastructure/NodeGraph.java +++ b/src/main/java/datastructure/NodeGraph.java @@ -7,10 +7,15 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; +import javafx.scene.paint.CycleMethod; +import javafx.scene.paint.LinearGradient; +import javafx.scene.paint.Stop; + import java.util.Queue; import java.util.TreeSet; + /** * Created by 101010. */ @@ -197,7 +202,6 @@ public void generateDrawNodes(int center, int radius) { addEdges(current, q, visited); drawNode = new DrawNode(current); drawNode.setWidth(nodes.get(current).getLength()); - drawNode.setFill(Color.CRIMSON); drawNode.setHeight(10); drawNodes.addLast(drawNode); } @@ -622,7 +626,6 @@ public Pair, LinkedList> addAtRoot() { nodes.get(newNodes.get(i).getIndex()).computeLength(); newNodes.get(i).setWidth(nodes.get(newNodes.get(i).getIndex()).getLength()); newNodes.get(i).setHeight(10); - newNodes.get(i).setFill(Color.CRIMSON); newDrawNodes.add(newNodes.get(i)); } else { Node dummyIn = nodes.get(newNodes.get(i).getIndex()); @@ -688,7 +691,6 @@ public Pair, LinkedList> addAtLeaf() { nodes.get(newNodes.get(i).getIndex()).computeLength(); newNodes.get(i).setWidth(nodes.get(newNodes.get(i).getIndex()).getLength()); newNodes.get(i).setHeight(10); - newNodes.get(i).setFill(Color.CRIMSON); newDrawNodes.add(newNodes.get(i)); } else { Node dummyOut = nodes.get(newNodes.get(i).getIndex()); @@ -814,4 +816,25 @@ protected LinkedList getRootNodes() { protected LinkedList getLeafNodes() { return leafNodes; } + + /** + * Colors the node in even strokes. + * @param drawNode the node to be colored. + * @param colors the colors of the strokes. + */ + public void colorDrawNode(DrawNode drawNode, ArrayList colors) { + drawNode.setFill(Color.CRIMSON); + Stop[] stops = new Stop[colors.size() * 2]; + if (stops.length == 0) { + return; + } + double offset = 1 / (double) colors.size(); + + for (int i = 0; i < colors.size(); i++) { + stops[2 * i] = new Stop((i * offset), colors.get(i)); + stops[(2 * i) + 1] = new Stop(((i + 1) * offset), colors.get(i)); + } + LinearGradient lg1 = new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, stops); + drawNode.setFill(lg1); + } } diff --git a/src/main/java/datastructure/RegexCondition.java b/src/main/java/datastructure/RegexCondition.java new file mode 100644 index 0000000..ea3bd6c --- /dev/null +++ b/src/main/java/datastructure/RegexCondition.java @@ -0,0 +1,35 @@ +package datastructure; + +import javafx.scene.paint.Color; + +/** + * Created by 101010. + */ +public class RegexCondition extends Condition { + + /** + * the regex of the condition. + */ + private String regex; + + /** + * The constructor of the RegexCondition. + * @param regex the regex of the condition. + * @param color the color of the condition. + */ + public RegexCondition(String regex, Color color) { + super(color); + this.regex = regex; + } + + @Override + public boolean addColor(DrawNode drawNode) { + String[] genomes = drawNode.getGenomes(); + for (int i = 0; i < genomes.length; i++) { + if (genomes[i].contains(regex)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/parsing/Parser.java b/src/main/java/parsing/Parser.java index 3f12a5d..e81bd98 100644 --- a/src/main/java/parsing/Parser.java +++ b/src/main/java/parsing/Parser.java @@ -1,9 +1,12 @@ package parsing; +import datastructure.DrawNode; import datastructure.Node; import datastructure.NodeGraph; import datastructure.SegmentDB; +import java.util.LinkedList; import javafx.application.Platform; +import screens.GraphInfo; import screens.Window; import java.io.BufferedReader; @@ -33,6 +36,11 @@ public final class Parser { */ private static Thread parser; + /** + * The file path to the cache files. + */ + private String path; + /** * Constructor of the parser. */ @@ -57,8 +65,8 @@ public static Parser getInstance() { */ public NodeGraph parse(File file) { NodeGraph graph = new NodeGraph(); - String cacheName = file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - 4); + path = cacheName; graph.setSegmentDB(new SegmentDB(cacheName + "Segments.txt")); File cache = new File(cacheName + ".txt"); @@ -122,15 +130,18 @@ public NodeGraph parse(final File file, NodeGraph graph) { id = Integer.parseInt(line2.substring(0, line2.indexOf('\t'))) - 1; line2 = line2.substring(line2.indexOf('\t') + 1); segment = line2.substring(0, line2.indexOf('\t')); - graph.addNode(id, new Node(segment.length(), new int[0], new int[0])); + Node node = new Node(segment.length(), new int[0], new int[0]); + graph.addNode(id, node); out.write(segment + "\n"); out.flush(); line2 = line2.substring(line2.indexOf('\t') + 1); line2 = line2.substring(line2.indexOf('\t') + 1); + if (line2.contains("\t")) { line2 = line2.substring(0, line2.indexOf("\t")); } addGenomes(gw, line2, threadIntegerBased, allGenomes); + line2 = in.readLine(); lineCounter++; while (line2 != null && line2.startsWith("L")) { @@ -153,6 +164,7 @@ public NodeGraph parse(final File file, NodeGraph graph) { e.printStackTrace(); } } + //readGenomes(genomesName); in.close(); out.close(); gw.close(); @@ -178,7 +190,6 @@ public NodeGraph parse(final File file, NodeGraph graph) { System.out.println("Error while reading file"); e.printStackTrace(); } - return graph; } @@ -198,6 +209,7 @@ public NodeGraph parseCache(NodeGraph graph, File cache) { int lineCounter = 0; try { int nol = getNumberOfLine(cache); + String path = cache.getAbsolutePath(); for (int i = 0; i < graphSize; i++) { int length = Integer.parseInt(in.readLine()); int outLength = Integer.parseInt(in.readLine()); @@ -215,7 +227,6 @@ public NodeGraph parseCache(NodeGraph graph, File cache) { Node temp = new Node(length, outgoing, incoming); graph.addNodeCache(i, temp); lineCounter = lineCounter + 5; - updateProgressBar(lineCounter, nol); } in.close(); @@ -277,8 +288,9 @@ private void createCache(String filename, NodeGraph graph) { * @param hasInt true iff the genomes displayed as integers instead of names. * @param genomeList list of all genomes in the gfa file. * @throws IOException when the writer can't write to the file. + * @return the number of genome paths going through the node. */ - private void addGenomes(BufferedWriter gw, String str, boolean hasInt, String[] genomeList) throws IOException { + private int addGenomes(BufferedWriter gw, String str, boolean hasInt, String[] genomeList) throws IOException { str = str.substring(str.indexOf(':') + 1); str = str.substring(str.indexOf(':') + 1); String[] genomeTemp = str.split(";"); @@ -297,6 +309,7 @@ private void addGenomes(BufferedWriter gw, String str, boolean hasInt, String[] } gw.write("\n"); gw.flush(); + return genomeTemp.length; } /** @@ -333,8 +346,7 @@ public static Thread getThread() { return parser; } - /** - * Reads all genomes of the gfa file and caches them. + /** Reads all genomes of the gfa file and caches them. * @param gw the writer used to write to the cache. * @param line the line on which all genomes are listed. * @throws IOException when the writer can't write to the file. @@ -379,4 +391,41 @@ private boolean determineBasis(String line, String[] allGenomes) { } return result; } + + /** + * Reads the genomes going through each node from the cache and puts these in an accessible array. + * @param drawNodes the path of the genome cache file. + */ + public void readGenomes(LinkedList drawNodes) { + try { + BufferedReader br = new BufferedReader(new FileReader(path + "Genomes.txt")); + int nol = getNumberOfLine(new File(path + "Genomes.txt")); + String line = br.readLine(); + String[] nodeGenomes = line.split("\t"); + GraphInfo.getInstance().setGenomesNum(Integer.parseInt(nodeGenomes[0])); + String[] genomeNames = new String[Integer.parseInt(nodeGenomes[0])]; + for (int i = 1; i < nodeGenomes.length; i++) { + genomeNames[i - 1] = nodeGenomes[i]; + } + GraphInfo.getInstance().setGenomeNames(genomeNames); + int[][] genomes = new int[drawNodes.size()][]; + int index = 0; + for (int i = 0; i < nol - 2; i++) { + if (NodeGraph.getCurrentInstance().getDrawNode(i) != null) { + line = br.readLine(); + nodeGenomes = line.split("\t"); + int[] genPath = new int[Integer.parseInt(nodeGenomes[0]) + 1]; + genPath[0] = i; + for (int j = 1; j < genPath.length; j++) { + genPath[j] = Integer.parseInt(nodeGenomes[j]); + } + genomes[index] = genPath; + index++; + } + } + GraphInfo.getInstance().setGenomes(genomes); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/screens/FileSelector.java b/src/main/java/screens/FileSelector.java index f037353..ad3c37c 100644 --- a/src/main/java/screens/FileSelector.java +++ b/src/main/java/screens/FileSelector.java @@ -86,7 +86,7 @@ public File showOpenDialog(Window ownerWindow) { } if (chosenFile != null) { - saveDirectory(chosenFile.getParentFile().getAbsolutePath()); + saveDirectory(chosenFile.getParentFile().getAbsolutePath() + "\\"); } return chosenFile; } diff --git a/src/main/java/screens/GraphInfo.java b/src/main/java/screens/GraphInfo.java new file mode 100644 index 0000000..db8340d --- /dev/null +++ b/src/main/java/screens/GraphInfo.java @@ -0,0 +1,200 @@ +package screens; + +import datastructure.Condition; +import java.util.ArrayList; +import javafx.scene.paint.Color; + +/** + * Class that can store information about the current state on the drawn graph used for navigation. + */ +public class GraphInfo { + + /** + * The radius of the currently drawn graph. + */ + private int currentRadius; + + /** + * The center node id of the currently drawn graph. + */ + private int currentCenterNode; + + /** + * The number of genomes paths that are specified. + */ + private int genomeNum; + + /** + * All specified genome paths per node. + */ + private int[][] genomes; + + /** + * A singleton instance of GraphInfo. + */ + private static GraphInfo instance; + + /** + * List of colors that can still be assigned to new conditions. + */ + private ArrayList colors; + + /** + * List of all conditions that are currently checked for. + */ + private ArrayList conditions; + + /** + * List of all genome names specified in the file. + */ + private String[] genomeNames; + + /** + * Constructor for the information. + */ + public GraphInfo() { + this.currentCenterNode = 0; + this.currentRadius = 200; + colors = new ArrayList<>(); + colors.add(Color.GREEN); + colors.add(Color.BLUE); + colors.add(Color.YELLOW); + colors.add(Color.MAGENTA); + colors.add(Color.CYAN); + conditions = new ArrayList<>(); + } + + /** + * Getter for the instance of the GraphInfo. + * @return the currrent instance of the GraphInfo. + */ + public static GraphInfo getInstance() { + if (instance == null) { + instance = new GraphInfo(); + } + return instance; + } + + /** + * Setter for the instance of the GraphInfo. + * @param gi the new GraphInfo. + */ + public static void setInstance(GraphInfo gi) { + instance = gi; + } + + /** + * Getter for the current radius. + * @return the current radius. + */ + public int getCurrentRadius() { + return this.currentRadius; + } + + /** + * Getter for the current center node id. + * @return the id of the current center node. + */ + public int getCurrentCenterNode() { + return this.currentCenterNode; + } + + /** + * Setter for the current radius of the graph. + * @param radius the new radius of the graph. + */ + public void setCurrentRadius(int radius) { + this.currentRadius = radius; + } + + /** + * Setter for the center node id of the current graph. + * @param id the new id of the center node of the graph. + */ + public void setCurrentCenterNode(int id) { + this.currentCenterNode = id; + } + + /** + * Setter for the number of genome paths specified in the file. + * @param num the number of genome paths specified in the file. + */ + public void setGenomesNum(int num) { + this.genomeNum = num; + } + + /** + * Getter for the number of genome paths specified in the file. + * @return the number of genome paths specified in the file. + */ + public int getGenomesNum() { + return this.genomeNum; + } + + /** + * Setter for the genome paths of the file. + * @param newGenomes the genome paths to set. + */ + public void setGenomes(int[][] newGenomes) { + this.genomes = newGenomes; + } + + /** + * Getter for the genome paths of the file. + * @return the genome paths of the file per node. + */ + public int[][] getGenomes() { + return this.genomes; + } + + /** + * Determines the color of the next condition. + * @return the color the next condition should get. + */ + public Color determineColor() { + if (colors.size() != 0) { + return colors.remove(0); + } + return Color.GRAY; + } + + /** + * Add a color to the list of colors to assign to conditions. + * @param color the color that will get added to the list. + */ + public void addColor(Color color) { + colors.add(color); + } + + /** + * Add a new condition to the list of conditions. + * @param cond the condition that will get added. + */ + public void addCondition(Condition cond) { + this.conditions.add(cond); + } + + /** + * Getter for the list of condition that are checked for. + * @return a list of all current conditionals. + */ + public ArrayList getConditions() { + return this.conditions; + } + + /** + * Setter for the list of all genome names in the current file. + * @param names all names of the genomes in the file. + */ + public void setGenomeNames(String[] names) { + this.genomeNames = names; + } + + /** + * Getter for the genome names. + * @return the genome names. + */ + public String[] getGenomeNames() { + return this.genomeNames; + } +} diff --git a/src/main/java/screens/Window.java b/src/main/java/screens/Window.java index 89c51c6..51a5943 100644 --- a/src/main/java/screens/Window.java +++ b/src/main/java/screens/Window.java @@ -2,9 +2,11 @@ import datastructure.DrawNode; import datastructure.NodeGraph; + import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; + import javafx.scene.control.Label; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; @@ -220,7 +222,6 @@ private Menu addFileSelector(Stage stage) { if (file != null && file.exists()) { pB.setVisible(true); NodeGraph.setCurrentInstance(Parser.getInstance().parse(file)); - new Thread() { public void run() { try { @@ -234,7 +235,8 @@ public void run() { pB.setProgress(0.0); } }.start(); - + this.interactionScene.resetController(); + GraphInfo.setInstance(new GraphInfo()); Thread drawing = graphScene.drawGraph(0, 200); new Thread(() -> { diff --git a/src/main/java/screens/scenes/Controller.java b/src/main/java/screens/scenes/Controller.java index d1e1392..006825f 100644 --- a/src/main/java/screens/scenes/Controller.java +++ b/src/main/java/screens/scenes/Controller.java @@ -1,12 +1,22 @@ package screens.scenes; +import datastructure.Condition; +import datastructure.GenomeCountCondition; import datastructure.NodeGraph; +import datastructure.RegexCondition; +import java.util.ArrayList; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.Button; +import javafx.scene.control.ChoiceBox; import javafx.scene.control.Label; +import javafx.scene.control.ListView; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; +import javafx.scene.paint.Color; +import screens.GraphInfo; import screens.Window; import services.ServiceLocator; @@ -18,18 +28,48 @@ public class Controller extends GridPane { * Labels. */ @SuppressWarnings("FieldCanBeLocal") - private Label currentCenter, centerInput, radius; + private Label currentCenter, centerInput, radius, genomeNum, genomeRegex, legend; /** * Input fields. */ - private static TextField centerInputField, radiusInputField, currentCenterField; + private static TextField centerInputField, radiusInputField, currentCenterField, numGenomesField, regexGenomesField; /** * Submit button to initiate center queries. */ private Button submitButton; + /** + * Submit button to add conditional regarding number of genomes. + */ + private Button submitButtonNoGen; + + /** + * Submit button to add conditional regarding genome regex. + */ + private Button submitRegex; + + /** + * Button to initiate clearing a selected condition. + */ + private Button condClear; + + /** + * List of choices for operations on selecting nodes on numbers of genomes. + */ + private ChoiceBox choices; + + /** + * ListView where condition are shown. + */ + private ListView