diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/cytoUtil/GraphAnalyzer.java b/src/main/java/de/hhu/ba/yoshikoWrapper/cytoUtil/GraphAnalyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..dfc6d39ea6efbcff99994b46f3b760d66d3610ca --- /dev/null +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/cytoUtil/GraphAnalyzer.java @@ -0,0 +1,50 @@ +package de.hhu.ba.yoshikoWrapper.cytoUtil; + +import java.util.List; + +import org.cytoscape.model.CyEdge; +import org.cytoscape.model.CyNetwork; + +public class GraphAnalyzer { + public static boolean isMultiGraph(CyNetwork net) { + //TODO: Better algorithm? + + + int n = net.getNodeCount(); + List<CyEdge> edges = net.getEdgeList(); + + //Easiest check: Check if the graph contains more edges than a complete graph + if (edges.size() > (n*(n-1))/2) { + return true; + } + + for (int i = 0; i < edges.size()-1; i++) { + for (int j=i+1; j<edges.size();j++) { + if (connectSameNodes(edges.get(i),edges.get(j))){ + return true; + } + } + } + + return false; + } + + private static boolean connectSameNodes(CyEdge e1, CyEdge e2) { + if (//Treating all edges as undirected here + (e1.getSource() == e2.getTarget() && e1.getTarget() == e2.getSource()) || + (e1.getSource() == e2.getSource() && e1.getTarget() == e2.getTarget()) + ) { + return true; + } + return false; + } + + public static boolean isDirected(CyNetwork net) { + for (CyEdge e: net.getEdgeList()) { + if (e.isDirected()) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/MainPanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/MainPanel.java index 54063d36c3689abec64f5158236e10d21667b806..77553e9f0d963c906dce5c976e648584f9408a81 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/MainPanel.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/MainPanel.java @@ -49,6 +49,7 @@ import javax.swing.ScrollPaneConstants; import org.cytoscape.application.swing.CytoPanelComponent; import org.cytoscape.application.swing.CytoPanelName; +import org.cytoscape.model.CyNetwork; import org.cytoscape.util.swing.BasicCollapsiblePanel; import org.cytoscape.work.AbstractTask; import org.cytoscape.work.TaskIterator; @@ -57,6 +58,7 @@ import de.hhu.ba.yoshikoWrapper.core.CyCore; import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; import de.hhu.ba.yoshikoWrapper.core.ParameterSet; import de.hhu.ba.yoshikoWrapper.core.YoshikoLoader; +import de.hhu.ba.yoshikoWrapper.cytoUtil.GraphAnalyzer; import de.hhu.ba.yoshikoWrapper.swing.AboutDialogFactory; import de.hhu.ba.yoshikoWrapper.swing.GraphicsLoader; import de.hhu.ba.yoshikoWrapper.swing.LanguageSwitcherPanelFactory; @@ -263,6 +265,32 @@ public class MainPanel extends JPanel implements CytoPanelComponent { @Override public void actionPerformed(ActionEvent e) { + CyNetwork networkToBeProcessed = CyCore.cy.getCurrentNetwork(); + + //WARNINGS FOR FEATURES THAT ARE NOT RESEARCHED + //TODO: (Obviously) research! + if (GraphAnalyzer.isMultiGraph(networkToBeProcessed)) { + JOptionPane.showMessageDialog( + null, + LocalizationManager.get("multiGraphWarning"), + LocalizationManager.get("optionpane_title"), + JOptionPane.WARNING_MESSAGE + ); + } + + //Annotation: Currently Cytoscape is really weird concerning directed/undirected edges + //There is an API function isDirected() for edges but all edges are directed + //I'll leave this commented out until CS makes sense + +// if (GraphAnalyzer.isDirected(networkToBeProcessed)) { +// JOptionPane.showMessageDialog( +// null, +// LocalizationManager.get("directedGraphWarning"), +// LocalizationManager.get("optionpane_title"), +// JOptionPane.WARNING_MESSAGE +// ); +// } + //SWING BLACK MAGIC Window noWindow = null; JDialog statusWindow = new JDialog(noWindow); @@ -277,7 +305,7 @@ public class MainPanel extends JPanel implements CytoPanelComponent { if (YoshikoLoader.isLibraryLoaded()){ AbstractTask yoshiko = new AlgorithmTask( popupLevel, - CyCore.cy.getCurrentNetwork(), + networkToBeProcessed, fetchParameter() ); /** diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/ResultPanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/ResultPanel.java index 09d41554c356d1f2b3ef86008dc66b80dfa9bc6a..907ea0179d4916e793d840901da5f3136abb5294 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/ResultPanel.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/swing/components/ResultPanel.java @@ -32,13 +32,16 @@ import java.util.Properties; import javax.swing.BoxLayout; import javax.swing.GroupLayout; -import javax.swing.GroupLayout.Group; +import javax.swing.GroupLayout.ParallelGroup; +import javax.swing.GroupLayout.SequentialGroup; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTabbedPane; +import javax.swing.LayoutStyle; +import javax.swing.SwingConstants; import org.cytoscape.application.swing.CytoPanelComponent; import org.cytoscape.application.swing.CytoPanelName; @@ -93,6 +96,11 @@ NetworkAboutToBeDestroyedListener private boolean isValid; + //SWING LAYOUT + + private ParallelGroup horizontalGroup; + private SequentialGroup verticalGroup; + public ResultPanel(YoshikoResult result) throws Exception { this.result = result; @@ -101,6 +109,7 @@ NetworkAboutToBeDestroyedListener //Init subcomponents invalidLabel = new JLabel(); + invalidLabel.setHorizontalAlignment(SwingConstants.CENTER); tabbedPane = new JTabbedPane(); solutionTabs = new ArrayList<SolutionTab>(); @@ -157,8 +166,8 @@ NetworkAboutToBeDestroyedListener //Layout GroupLayout layout = new GroupLayout(this); - Group horizontalGroup = layout.createParallelGroup(Alignment.LEADING,true); - Group verticalGroup = layout.createSequentialGroup(); + horizontalGroup = layout.createParallelGroup(Alignment.CENTER,true); + verticalGroup = layout.createSequentialGroup(); layout.setHorizontalGroup(horizontalGroup); layout.setVerticalGroup(verticalGroup); @@ -169,12 +178,13 @@ NetworkAboutToBeDestroyedListener } horizontalGroup - .addComponent(invalidLabel,HACKFIX_FIXED_WIDTH, PREFERRED_SIZE,Short.MAX_VALUE) + .addComponent(invalidLabel,DEFAULT_SIZE, PREFERRED_SIZE,Short.MAX_VALUE) .addComponent(tabbedPane,HACKFIX_FIXED_WIDTH, PREFERRED_SIZE,Short.MAX_VALUE) .addComponent(destroyButton,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE); verticalGroup - .addComponent(invalidLabel,DEFAULT_SIZE, PREFERRED_SIZE,Short.MAX_VALUE) + .addComponent(invalidLabel,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE) .addComponent(tabbedPane,DEFAULT_SIZE, DEFAULT_SIZE,PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(destroyButton,DEFAULT_SIZE, DEFAULT_SIZE,PREFERRED_SIZE); layout.setAutoCreateGaps(true); diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateClusterViews.java b/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateClusterViews.java index a681836cfa8bd4108aa63e6f35d49a69943a4042..28bc3faea2f10eb11808512439dc56ebfdb2088a 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateClusterViews.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateClusterViews.java @@ -15,19 +15,45 @@ import de.hhu.ba.yoshikoWrapper.graphModel.YoshikoCluster; public class CreateClusterViews implements Task { + //TODO: Merge redundant code with CreateMetaGraphTask + private ArrayList<YoshikoCluster> clusters; + private boolean isTerminated; + + /** + * Used to fall back upon cancellation + */ + private CyNetworkView previousView; + + /** + * This internal list is used to track which networks have already been initialized. + * This is used to remove those views upon cancellation. + */ + private ArrayList<CySubNetwork> initializedSubNetworks; + public CreateClusterViews(ArrayList<YoshikoCluster> clusters) { this.clusters = clusters; + + this.previousView = CyCore.cy.getCurrentNetworkView(); + this.isTerminated = false; + this.initializedSubNetworks = new ArrayList<CySubNetwork>(); } @Override public void run(TaskMonitor taskMonitor) throws Exception { + + taskMonitor.setTitle(LocalizationManager.get("task_ccv")); + CyLayoutAlgorithm layout = CyCore.layoutAlgorithmManager.getDefaultLayout(); for (YoshikoCluster c : clusters) { + if (this.isTerminated) { + throw new Exception("Terminated by user!"); //TODO: Localize + } CySubNetwork subnet = c.getSubNetwork(); + initializedSubNetworks.add(subnet); taskMonitor.setStatusMessage(LocalizationManager.get("status_createCV")+" "+(c.getID()+1)); - CyCore.networkManager.addNetwork(subnet); + CyCore.networkManager.addNetwork(subnet,false); //Create network view and register it CyNetworkView subnetView = CyCore.networkViewFactory.createNetworkView(subnet); //layout cluster @@ -47,6 +73,13 @@ public class CreateClusterViews implements Task { } @Override - public void cancel() {} + public void cancel() { + this.isTerminated = true; + //Remove generated ClusterViews + for (CySubNetwork v: initializedSubNetworks) { + CyCore.networkManager.destroyNetwork(v); + } + CyCore.cy.setCurrentNetworkView(previousView); + } } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateMetaGraphTask.java b/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateMetaGraphTask.java index b5fd244dac47e3ddd763bd5913998d8131332f7c..caa8663bee3816c97e8d836b2585bf9e2145e443 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateMetaGraphTask.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/tasks/CreateMetaGraphTask.java @@ -1,5 +1,6 @@ package de.hhu.ba.yoshikoWrapper.tasks; +import java.util.ArrayList; import java.util.HashMap; import org.cytoscape.model.CyEdge; @@ -24,12 +25,26 @@ public class CreateMetaGraphTask extends AbstractTask { private final YoshikoSolution solution; + private boolean isTerminated; + + /** + * This internal list is used to track which networks have already been initialized. + * This is used to remove those views upon cancellation. + */ + private ArrayList<CySubNetwork> initializedSubNetworks; + public CreateMetaGraphTask(YoshikoSolution s) { this.solution = s; + + this.isTerminated = false; + this.initializedSubNetworks = new ArrayList<CySubNetwork>(); } @Override public void run(TaskMonitor taskMonitor) throws Exception { + + taskMonitor.setTitle(LocalizationManager.get("task_cmg")); + CyNetwork metaGraph = CyCore.networkFactory.createNetwork(); metaGraph.getRow(metaGraph).set(CyNetwork.NAME, LocalizationManager.get("metaGraph")); @@ -44,14 +59,21 @@ public class CreateMetaGraphTask extends AbstractTask { HashMap<YoshikoCluster,CyNode> map = new HashMap<YoshikoCluster,CyNode>(); + //Add nodes for (YoshikoCluster c: solution.getClusters()) { + if(isTerminated) { + throw new Exception("Terminated by user!"); + } + CyNode clusterNode = metaGraph.addNode(); CySubNetwork subnet = c.getSubNetwork(); + //Store reference + this.initializedSubNetworks.add(subnet); taskMonitor.setStatusMessage(LocalizationManager.get("status_createCV")+" "+(c.getID()+1)); - CyCore.networkManager.addNetwork(subnet); + CyCore.networkManager.addNetwork(subnet,false); //Create network view and register it CyNetworkView subnetView = CyCore.networkViewFactory.createNetworkView(subnet); //layout cluster @@ -66,8 +88,9 @@ public class CreateMetaGraphTask extends AbstractTask { StyleManager.style(subnetView,CyCore.visualMappingManager.getCurrentVisualStyle()); - CyCore.networkViewManager.addNetworkView(subnetView); + CyCore.networkViewManager.addNetworkView(subnetView,false); + //Link cluster node in meta graph and subnet graph to use Cytoscape Nested Network feature clusterNode.setNetworkPointer(subnet); //Set node attributes metaGraph.getRow(clusterNode).set("name", LocalizationManager.get("cluster")+" "+c.getID()); @@ -78,6 +101,11 @@ public class CreateMetaGraphTask extends AbstractTask { //Add edges (O(|C|^2*|V|^2) can maybe be improved? //TODO for (YoshikoCluster c1:solution.getClusters()) { for (YoshikoCluster c2:solution.getClusters()) { + + if(isTerminated) { + throw new Exception("Terminated by user!"); + } + if ( metaGraph.containsEdge(map.get(c1),map.get(c2)) || c1 == c2 @@ -130,7 +158,7 @@ public class CreateMetaGraphTask extends AbstractTask { it ); - CyCore.networkManager.addNetwork(metaGraph); + CyCore.networkManager.addNetwork(metaGraph,false); CyCore.networkViewManager.addNetworkView( view ); @@ -140,4 +168,14 @@ public class CreateMetaGraphTask extends AbstractTask { CyCore.cy.setCurrentNetworkView(view); } + @Override + public void cancel() { + //Set killswitch + isTerminated = true; + //Remove generated ClusterViews + for (CySubNetwork v: initializedSubNetworks) { + CyCore.networkManager.destroyNetwork(v); + } + } + } diff --git a/src/main/resources/YoshikoStrings.properties b/src/main/resources/YoshikoStrings.properties index 75d34207e234662c01ba1b1a8cad786a651f99e1..a5051e928a1c17aa405e3c1af3b03317e4d76e94 100644 --- a/src/main/resources/YoshikoStrings.properties +++ b/src/main/resources/YoshikoStrings.properties @@ -19,6 +19,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. #------------------------------------------------------------------------------- + + +#TODO: Give more meaningful names to keys, sort + about = INSERT SOME AMAZING INFO ABOUT THIS APPLICATION,\n THE AUTHOR AND WHERE TO FIND MORE INFO HERE\n <a href=\"www.hhu.de\" >LINK</a> aboutButton = About Yoshiko aboutTitle = Yoshiko Plugin Info @@ -33,6 +37,7 @@ currentGap = [ILP] Current Instance Gap defaultDeletion = Default deletion cost: defaultInsertion = Default insertion cost: deleteSolution = Do you really want to delete this solution? +directedGraphWarning = This algorithm works on undirected graphs. Directed edges are \n treated as undirected edges. disableMultiThreading = Disable Multithreading discardSolution = Discard editingCostPanel = Editing Costs @@ -51,6 +56,7 @@ libraryPanel = Library metaGraph = Meta Graph metaGraph_edges = Fetching edges and calculating edge strengths multFactor = Multiplicative Factor for SNR: +multiGraphWarning = This graph is a multigraph. This algorithms behavior on multigraphs is not yet researched. noFeasible = No feasible solution found! noLibMessage = There is no Yoshiko Library currently loaded! You might have to specify its location. noLibTitle = Library not loaded! @@ -85,6 +91,10 @@ status_reductionSN = Applying "Similar-Neighborhood" reduction rule status_solvingILP = Solving ILP switchLanguage = Plugin language + +task_ccv = Yoshiko: Create Cluster Views +task_cmg = Yoshiko: Create Meta Graph + timeLimitILP = Use time limit for ILP (s): timedOutMessage = The ILP exceeded the time-limit! timedOutTitle = Timeout