From 7ea3d8d5c8b1a5159987434e35b7e9d78ecbacf9 Mon Sep 17 00:00:00 2001
From: Philipp Spohr <spohr.philipp@web.de>
Date: Thu, 7 Sep 2017 09:56:52 +0200
Subject: [PATCH] Added "About" panel and various small fixes Bumped up version
 number to 0.1

---
 pom.xml                                       |   2 +-
 .../de/hhu/ba/yoshikoWrapper/CyActivator.java |   4 ++
 .../ba/yoshikoWrapper/core/AlgorithmTask.java |  10 ++-
 .../yoshikoWrapper/core/GraphicsLoader.java   |  14 +++++
 .../core/{Util.java => YoshUtil.java}         |   5 +-
 .../ba/yoshikoWrapper/gui/AboutDialog.java    |  56 +++++++++++++++++
 .../hhu/ba/yoshikoWrapper/gui/MainPanel.java  |  58 +++++++++++++-----
 .../gui/ReductionRulesChooser.java            |   2 +-
 .../hhu/ba/yoshikoWrapper/gui/SwingUtil.java  |   7 ++-
 src/main/resources/YoshikoStrings.properties  |   6 +-
 src/main/resources/graphics/Info.png          | Bin 0 -> 4115 bytes
 11 files changed, 139 insertions(+), 25 deletions(-)
 rename src/main/java/de/hhu/ba/yoshikoWrapper/core/{Util.java => YoshUtil.java} (60%)
 create mode 100644 src/main/java/de/hhu/ba/yoshikoWrapper/gui/AboutDialog.java
 create mode 100644 src/main/resources/graphics/Info.png

diff --git a/pom.xml b/pom.xml
index 8cee314..385081b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
 
 	<groupId>de.hhu.ba</groupId>
 	<artifactId>yoshikoWrapper</artifactId>
-	<version>0.0.3</version>
+	<version>0.1.0</version>
 	
 	<name>YoshikoWrapper</name>
 
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java b/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java
index 8e19125..8cb417e 100644
--- a/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java
@@ -55,6 +55,7 @@ import de.hhu.ba.yoshikoWrapper.core.CyCore;
 import de.hhu.ba.yoshikoWrapper.core.Hint;
 import de.hhu.ba.yoshikoWrapper.core.LocalizationManager;
 import de.hhu.ba.yoshikoWrapper.core.NetChangeListener;
+import de.hhu.ba.yoshikoWrapper.core.YoshUtil;
 import de.hhu.ba.yoshikoWrapper.core.YoshikoLoader;
 import de.hhu.ba.yoshikoWrapper.gui.HintManager;
 import de.hhu.ba.yoshikoWrapper.gui.MainPanel;
@@ -92,6 +93,9 @@ public class CyActivator extends AbstractCyActivator {
 		CyCore.renderingEngineFactory = getService(context,RenderingEngineFactory.class);
 		CyCore.cloneNetworkTaskFactory = getService(context,CloneNetworkTaskFactory.class);
 
+		//Store a reference to the Version
+		YoshUtil.version = context.getBundle().getVersion();
+		
 		//Set language according to settings
 		LocalizationManager.switchLanguage(cm.getProperties().getProperty("locale", "enUS"));
 
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java
index a79b9ad..0cdd0cd 100644
--- a/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java
@@ -152,7 +152,7 @@ public class AlgorithmTask extends AbstractTask {
 			
 			@Override
 			public void updateGap(double gap) {
-				taskMonitor.setStatusMessage(LocalizationManager.get("currentGap")+": "+Util.twoDecimals.format(gap)+"%");
+				taskMonitor.setStatusMessage(LocalizationManager.get("currentGap")+": "+YoshUtil.twoDecimals.format(gap)+"%");
 			}
 		}
 		
@@ -161,8 +161,14 @@ public class AlgorithmTask extends AbstractTask {
 		result  = ca.run();
 		
 		taskMonitor.setProgress(0.9);
-		
+		if (result == null) {
+			throw new Exception(LocalizationManager.get("noFeasible"));
+		}
 		long numberOfSolutions = result.getNumberOfSolutions();
+		
+		if (numberOfSolutions == 0) {
+			throw new Exception(LocalizationManager.get("noFeasible"));
+		}
 		taskMonitor.setStatusMessage("Found: "+numberOfSolutions+" solutions!"); //TODO localize
 				
 		YoshikoResult yoshikoResult = new YoshikoResult();
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java
index c747a16..fe123b2 100644
--- a/src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java
@@ -35,6 +35,7 @@ public class GraphicsLoader {
 	private static BufferedImage yoshikoLogo;
 	private static BufferedImage yoshikoLogo_solved;
 	private static BufferedImage yoshikoText;
+	private static BufferedImage infoIcon;
 	
 	public final static Color yoshikoGreen = new Color(0,128,0);
 	
@@ -57,6 +58,19 @@ public class GraphicsLoader {
 		return new ImageIcon(flags.get(lcl).getScaledInstance(width, height, Image.SCALE_SMOOTH));
 	}
 	
+	public static ImageIcon getInfoIcon(int size) {
+		if (infoIcon == null) {
+			try {
+				infoIcon = ImageIO.read(
+						classLoader.getResource("graphics/Info.png")
+				);
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		return new ImageIcon(infoIcon.getScaledInstance(size, size, Image.SCALE_SMOOTH));
+	}
+	
 	public static ImageIcon getLogo(int size) {
 		if (yoshikoLogo == null) {
 			try {
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/Util.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/YoshUtil.java
similarity index 60%
rename from src/main/java/de/hhu/ba/yoshikoWrapper/core/Util.java
rename to src/main/java/de/hhu/ba/yoshikoWrapper/core/YoshUtil.java
index 99fed80..9f195d0 100644
--- a/src/main/java/de/hhu/ba/yoshikoWrapper/core/Util.java
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/YoshUtil.java
@@ -2,6 +2,9 @@ package de.hhu.ba.yoshikoWrapper.core;
 
 import java.text.DecimalFormat;
 
-public class Util {
+import org.osgi.framework.Version;
+
+public class YoshUtil {
 	final static DecimalFormat twoDecimals =new DecimalFormat("0.00");
+	public static Version version;
 }
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/AboutDialog.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/AboutDialog.java
new file mode 100644
index 0000000..4c3c3be
--- /dev/null
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/AboutDialog.java
@@ -0,0 +1,56 @@
+package de.hhu.ba.yoshikoWrapper.gui;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import de.hhu.ba.yoshikoWrapper.core.LocalizationManager;
+import de.hhu.ba.yoshikoWrapper.core.YoshUtil;
+
+/**Factory for a simple About-Dialog that provides some basic info about the software
+ *
+ */
+public class AboutDialog{
+	
+	private static JPanel getDialogPanel() {
+		
+		JPanel ret = new JPanel();
+		
+		final YoshikoHeader header;
+		final JLabel version;
+		final JLabel text;
+		
+		header = new YoshikoHeader();
+		version = new JLabel(LocalizationManager.get("wrapperVersion")+": "+YoshUtil.version);
+		text = new JLabel(LocalizationManager.get("about"));
+		
+		SwingUtil.addAll(ret, header,version,text);
+		
+		GroupLayout layout = new GroupLayout(ret);
+		layout.setAutoCreateGaps(true);
+		layout.setHorizontalGroup(layout.createParallelGroup(Alignment.CENTER)
+			.addComponent(header)
+			.addComponent(version)
+			.addComponent(text)
+		);
+		layout.setVerticalGroup(layout.createSequentialGroup()
+			.addComponent(header)
+			.addComponent(version)
+			.addComponent(text)
+		);
+		
+		ret.setLayout(layout);
+					
+		return ret;
+	}
+
+	public static void showDialog() {
+		JOptionPane.showMessageDialog(
+				null,
+				getDialogPanel(),
+				LocalizationManager.get("aboutTitle"),
+				JOptionPane.PLAIN_MESSAGE);
+	}
+}
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java
index 350150c..b6c4d40 100644
--- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java
@@ -42,6 +42,7 @@ import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.LayoutStyle;
 
 import org.cytoscape.application.swing.CytoPanelComponent;
 import org.cytoscape.application.swing.CytoPanelName;
@@ -67,6 +68,8 @@ public class MainPanel extends JPanel implements CytoPanelComponent {
 		
 	private final YoshikoHeader header;
 	
+	private final JButton about;
+	
 	private final JCheckBox showAdvancedOptions;
 	private final ArrayList<JComponent> advancedOptions;
 
@@ -93,6 +96,16 @@ public class MainPanel extends JPanel implements CytoPanelComponent {
 		//Initialize Swing components		
 		header = new YoshikoHeader();
 		
+		about = new JButton(GraphicsLoader.getInfoIcon(16));
+		about.addActionListener(new ActionListener() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				AboutDialog.showDialog();
+			}
+			
+		});
+		
 		showAdvancedOptions = new JCheckBox(LocalizationManager.get("showAdvanced"));
 		showAdvancedOptions.addActionListener(toggleAdvancedOptionsListener);
 		
@@ -123,6 +136,7 @@ public class MainPanel extends JPanel implements CytoPanelComponent {
 		//Add components to main panel
 		SwingUtil.addAll(this,
 				header,
+				about,
 				showAdvancedOptions,
 				langPanel,
 				libraryPanel,
@@ -145,28 +159,40 @@ public class MainPanel extends JPanel implements CytoPanelComponent {
 		
 		//Layout
 		GroupLayout layout = new GroupLayout(this);
+		
 		layout.setAutoCreateGaps(true);
 		layout.setAutoCreateContainerGaps(true);
+		
 		layout.setHorizontalGroup(layout.createParallelGroup(Alignment.LEADING,true)
-				.addComponent(header,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(showAdvancedOptions,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(langPanel,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(libraryPanel,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(ecPanelWrapper,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(reductionWrapper,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(opWrapper,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(runButton,DEFAULT_SIZE, PREFERRED_SIZE,PREFERRED_SIZE)
+				.addGroup(layout.createSequentialGroup()
+					.addComponent(header,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+					//"SPRING" Functionality ; eats all the space that is available
+					.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, DEFAULT_SIZE, Short.MAX_VALUE)
+					.addComponent(about,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+				)
+				.addGap(4)
+				.addComponent(showAdvancedOptions,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+				.addComponent(langPanel,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+				.addComponent(libraryPanel,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+				.addComponent(ecPanelWrapper,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+				.addComponent(reductionWrapper,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+				.addComponent(opWrapper,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
+				.addComponent(runButton,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
 		);
 		
 		layout.setVerticalGroup(layout.createSequentialGroup()
-				.addComponent(header,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(showAdvancedOptions,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(langPanel,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(libraryPanel,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(ecPanelWrapper,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(reductionWrapper,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(opWrapper,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)
-				.addComponent(runButton,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE)	
+				.addGroup(layout.createParallelGroup()
+						.addComponent(header,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+						.addComponent(about,Alignment.TRAILING,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+				)
+				.addGap(4)
+				.addComponent(showAdvancedOptions,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+				.addComponent(langPanel,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+				.addComponent(libraryPanel,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+				.addComponent(ecPanelWrapper,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+				.addComponent(reductionWrapper,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+				.addComponent(opWrapper,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
+				.addComponent(runButton,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)	
 		);
 		
 		this.setLayout(layout);
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ReductionRulesChooser.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ReductionRulesChooser.java
index ef62a8b..c24ead3 100644
--- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ReductionRulesChooser.java
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ReductionRulesChooser.java
@@ -117,7 +117,7 @@ public class ReductionRulesChooser extends JPanel{
 			.addComponent(useHERule, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
 			.addComponent(usePDRRule, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
 			.addComponent(useSNRule, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
-			.addComponent(SNPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)						
+			.addComponent(SNPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
 		);
 		
 		this.setLayout(layout);
diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SwingUtil.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SwingUtil.java
index 2761282..e2d3fa8 100644
--- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SwingUtil.java
+++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SwingUtil.java
@@ -21,13 +21,14 @@
  ******************************************************************************/
 package de.hhu.ba.yoshikoWrapper.gui;
 
+import java.awt.Container;
+
 import javax.swing.JComponent;
-import javax.swing.JPanel;
 
 public class SwingUtil {
-	static void addAll(JPanel panel, JComponent ... components) {
+	static void addAll(Container container, JComponent ... components) {
 		for (JComponent c: components) {
-			panel.add(c);
+			container.add(c);
 		}
 	}
 }
diff --git a/src/main/resources/YoshikoStrings.properties b/src/main/resources/YoshikoStrings.properties
index 463f1f8..70c004b 100644
--- a/src/main/resources/YoshikoStrings.properties
+++ b/src/main/resources/YoshikoStrings.properties
@@ -21,6 +21,7 @@
 #-------------------------------------------------------------------------------
 resultsPanelTitle = Yoshiko Results
 yoshVersion = Yoshiko Version
+wrapperVersion = Yoshiko Plugin for Cytoscape Version
 resolveLibPath = Resolve Yoshiko Library Path
 yoshTask = Performing Yoshiko Algorithm
 solution = Solution
@@ -65,6 +66,9 @@ gap = Gap
 currentGap = [ILP] Current Instance Gap
 disableMultiThreading = Disable Multithreading
 yoshikoHint = Yoshiko Hint
+aboutTitle = Yoshiko Plugin Info
 getYoshiko = Get Yoshiko Library
+noFeasible = No feasible solution found!
 noMappingHint = You haven't mapped the cost value to a column in your edge table.\nYoshiko runs significantly faster and generates better solutions if you map values.
-firstStart = Thanks for using the Yoshiko Clustering Tool!\nIt appears, that this is your first time using this tool.\nIf you want an in-depth explanation of the algorithm please refer to: [INSERT COOL LINK HERE]
\ No newline at end of file
+firstStart = Thanks for using the Yoshiko Clustering Tool!\nIt appears, that this is your first time using this tool.\nIf you want an in-depth explanation of the algorithm please refer to: [INSERT COOL LINK HERE]
+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>
\ No newline at end of file
diff --git a/src/main/resources/graphics/Info.png b/src/main/resources/graphics/Info.png
new file mode 100644
index 0000000000000000000000000000000000000000..80c5ba866d94baf4db4ff95f6fc7e511dc6fd2ef
GIT binary patch
literal 4115
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

literal 0
HcmV?d00001

-- 
GitLab