From 489d3f9f6c5b4f9a98901c065c0df6e0440e5638 Mon Sep 17 00:00:00 2001 From: Philipp Spohr <spohr.philipp@web.de> Date: Wed, 30 Aug 2017 20:56:00 +0200 Subject: [PATCH] Some refactoring // cleanup --- .../de/hhu/ba/yoshikoWrapper/CyActivator.java | 2 + .../yoshikoWrapper/core/GraphicsLoader.java | 22 +++ .../core/NetChangeListener.java | 10 +- .../ba/yoshikoWrapper/gui/ColumnMapper.java | 66 +++++--- .../ba/yoshikoWrapper/gui/EditCostPanel.java | 23 ++- .../gui/EnableWhenSelectedListener.java | 30 ++++ .../hhu/ba/yoshikoWrapper/gui/MainPanel.java | 149 ++++++++++-------- .../gui/OperationModePanel.java | 98 ++++++++++++ .../gui/SolutionNumberChooser.java | 8 +- .../yoshikoWrapper/gui/TimeLimitSetter.java | 1 + .../ba/yoshikoWrapper/gui/YoshikoHeader.java | 24 +++ src/main/resources/YoshikoStrings.properties | 9 +- .../resources/graphics/YoshikoAlphaLogo.png | Bin 0 -> 6862 bytes .../resources/graphics/YoshikoAlphaText.png | Bin 0 -> 7125 bytes src/main/resources/graphics/package-info.java | 1 + 15 files changed, 343 insertions(+), 100 deletions(-) create mode 100644 src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java create mode 100644 src/main/java/de/hhu/ba/yoshikoWrapper/gui/EnableWhenSelectedListener.java create mode 100644 src/main/java/de/hhu/ba/yoshikoWrapper/gui/OperationModePanel.java create mode 100644 src/main/java/de/hhu/ba/yoshikoWrapper/gui/YoshikoHeader.java create mode 100644 src/main/resources/graphics/YoshikoAlphaLogo.png create mode 100644 src/main/resources/graphics/YoshikoAlphaText.png create mode 100644 src/main/resources/graphics/package-info.java diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java b/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java index e663ccd..1f4f60e 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/CyActivator.java @@ -3,6 +3,7 @@ package de.hhu.ba.yoshikoWrapper; import java.util.Properties; import org.cytoscape.application.CyApplicationManager; +import org.cytoscape.application.events.SetCurrentNetworkListener; import org.cytoscape.application.swing.CySwingApplication; import org.cytoscape.application.swing.CytoPanelComponent; import org.cytoscape.model.CyNetworkFactory; @@ -88,6 +89,7 @@ public class CyActivator extends AbstractCyActivator { registerService(context,netChangeListener, ColumnCreatedListener.class, new Properties()); registerService(context,netChangeListener, ColumnDeletedListener.class, new Properties()); registerService(context,netChangeListener, SessionLoadedListener.class, new Properties()); + registerService(context,netChangeListener, SetCurrentNetworkListener.class, new Properties()); } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java new file mode 100644 index 0000000..77ba436 --- /dev/null +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/GraphicsLoader.java @@ -0,0 +1,22 @@ +package de.hhu.ba.yoshikoWrapper.core; + +import javax.swing.ImageIcon; + +public class GraphicsLoader { + private static ImageIcon yoshikoLogo; + private static ImageIcon yoshikoText; + + public static ImageIcon getLogo() { + if (yoshikoLogo == null) { + yoshikoLogo = new ImageIcon("/resources/graphics/YoshikoAlphaLogo.png"); + } + return yoshikoLogo; + } + + public static ImageIcon getText() { + if (yoshikoLogo == null) { + yoshikoLogo = new ImageIcon("/graphics/YoshikoAlphaText.png"); + } + return yoshikoText; + } +} diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetChangeListener.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetChangeListener.java index cfb4620..49da3d0 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetChangeListener.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetChangeListener.java @@ -1,5 +1,7 @@ package de.hhu.ba.yoshikoWrapper.core; +import org.cytoscape.application.events.SetCurrentNetworkEvent; +import org.cytoscape.application.events.SetCurrentNetworkListener; import org.cytoscape.model.events.AddedEdgesEvent; import org.cytoscape.model.events.AddedEdgesListener; import org.cytoscape.model.events.ColumnCreatedEvent; @@ -22,7 +24,8 @@ AddedEdgesListener, RemovedEdgesListener, ColumnCreatedListener, ColumnDeletedListener, -SessionLoadedListener +SessionLoadedListener, +SetCurrentNetworkListener { private ColumnMapper columnMapper; @@ -60,4 +63,9 @@ SessionLoadedListener columnMapper.updateValues(); } + @Override + public void handleEvent(SetCurrentNetworkEvent e) { + columnMapper.updateValues(); + } + } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ColumnMapper.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ColumnMapper.java index f87c739..7d1c83b 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ColumnMapper.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ColumnMapper.java @@ -1,10 +1,9 @@ package de.hhu.ba.yoshikoWrapper.gui; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.FlowLayout; + import javax.swing.BoxLayout; -import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; @@ -18,43 +17,64 @@ public class ColumnMapper extends ComfortPanel{ //Swing components - private JComboBox<CyColumn> editingCostMapper; - private JComboBox<CyColumn> permanentMapper; - private JComboBox<CyColumn> forbiddenMapper; + private final JComboBox<CyColumn> editingCostMapper; + private final JComboBox<CyColumn> permanentMapper; + private final JComboBox<CyColumn> forbiddenMapper; - private JCheckBox useMappingCost; - private JCheckBox useMappingPerm; - private JCheckBox useMappingForb; - - private JButton updateColumns; + private final JCheckBox useMappingCost; + private final JCheckBox useMappingPerm; + private final JCheckBox useMappingForb; + private final ComfortPanel costGroup; + private final ComfortPanel permGroup; + private final ComfortPanel forbGroup; + public ColumnMapper() { this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); //SWING COMPONENTS + + //Combo-Boxes that map to the CyColumns editingCostMapper = new JComboBox<CyColumn>(); permanentMapper = new JComboBox<CyColumn>(); forbiddenMapper = new JComboBox<CyColumn>(); + + //Should only be enabled if the option is checked + editingCostMapper.setEnabled(false); + permanentMapper.setEnabled(false); + forbiddenMapper.setEnabled(false); useMappingCost = new JCheckBox("Map modification costs"); useMappingPerm = new JCheckBox("Map edges as permanent"); useMappingForb = new JCheckBox("Map edges as forbidden"); - updateColumns = new JButton("Update Columns!"); + useMappingCost.addActionListener( + new EnableWhenSelectedListener(useMappingCost, editingCostMapper) + ); + useMappingPerm.addActionListener( + new EnableWhenSelectedListener(useMappingPerm, permanentMapper) + ); + useMappingForb.addActionListener( + new EnableWhenSelectedListener(useMappingForb, forbiddenMapper) + ); - this.addAll(useMappingCost,editingCostMapper,useMappingPerm,permanentMapper,useMappingForb,forbiddenMapper,updateColumns); - //Initial call to get table values - updateValues(); - //Add a focus listener to update values - updateColumns.addActionListener(new ActionListener() { + costGroup = new ComfortPanel(); + permGroup = new ComfortPanel(); + forbGroup = new ComfortPanel(); + + costGroup.setLayout(new FlowLayout()); + permGroup.setLayout(new FlowLayout()); + forbGroup.setLayout(new FlowLayout()); - @Override - public void actionPerformed(ActionEvent e) { - updateValues(); //shitty temporary solution - } - - }); + costGroup.addAll(useMappingCost,editingCostMapper); + permGroup.addAll(useMappingPerm,permanentMapper); + forbGroup.addAll(useMappingForb,forbiddenMapper); + + this.addAll(costGroup,permGroup,forbGroup); + + //Initial call to get table values + updateValues(); } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/EditCostPanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/EditCostPanel.java index aa6d26d..e8b6192 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/EditCostPanel.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/EditCostPanel.java @@ -1,19 +1,26 @@ package de.hhu.ba.yoshikoWrapper.gui; +import java.awt.FlowLayout; + import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JLabel; +import javax.swing.border.Border; import javax.swing.border.EtchedBorder; import org.cytoscape.model.CyColumn; +import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; + @SuppressWarnings("serial") //Will never be serialized public class EditCostPanel extends ComfortPanel { //SWING COMPONENTS private ColumnMapper columnMapper; + private DoubleInputField icField; private DoubleInputField dcField; + private JLabel icLabel; private JLabel dcLabel; @@ -25,23 +32,33 @@ public class EditCostPanel extends ComfortPanel { this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); //Initialize components columnMapper = new ColumnMapper(); + icField = new DoubleInputField(Double.NEGATIVE_INFINITY,0); dcField = new DoubleInputField(0,Double.POSITIVE_INFINITY); + icField.setText("-1.0"); + icField.setToolTipText(LocalizationManager.get("icTooltip")); dcField.setText("1.0"); - icLabel = new JLabel("Insertion Cost:"); - dcLabel = new JLabel("Deletion Cost:"); + + icLabel = new JLabel(LocalizationManager.get("defaultInsertion")); + dcLabel = new JLabel(LocalizationManager.get("defaultDeletion")); //Group the labels with their text fields groupIC = new ComfortPanel(); groupDC = new ComfortPanel(); + groupIC.setLayout(new FlowLayout()); + groupDC.setLayout(new FlowLayout()); + groupIC.addAll(icLabel,icField); groupDC.addAll(dcLabel,dcField); this.addAll(columnMapper,groupIC,groupDC); //Decoration/Visual - this.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED)); + Border border = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); + border = BorderFactory.createTitledBorder(border,LocalizationManager.get("editingCostPanel")); + + this.setBorder(border); } //SETTER / GETTER diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/EnableWhenSelectedListener.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/EnableWhenSelectedListener.java new file mode 100644 index 0000000..1caa526 --- /dev/null +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/EnableWhenSelectedListener.java @@ -0,0 +1,30 @@ +package de.hhu.ba.yoshikoWrapper.gui; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JCheckBox; +import javax.swing.JComponent; + + +public class EnableWhenSelectedListener implements ActionListener { + + private final JComponent component; + private final JCheckBox checkBox; + + public EnableWhenSelectedListener(JCheckBox cb, JComponent c) { + this.component = c; + this.checkBox = cb; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (checkBox.isSelected()) { + component.setEnabled(true); + } + else { + component.setEnabled(false); + } + } + +} 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 059fca6..a328edf 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java @@ -1,16 +1,18 @@ package de.hhu.ba.yoshikoWrapper.gui; import java.awt.Component; +import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; -import javax.swing.BoxLayout; -import javax.swing.ButtonGroup; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JLabel; import javax.swing.JOptionPane; -import javax.swing.JRadioButton; import org.cytoscape.application.swing.CytoPanelComponent; import org.cytoscape.application.swing.CytoPanelName; @@ -19,6 +21,7 @@ import org.cytoscape.work.TaskIterator; import de.hhu.ba.yoshikoWrapper.core.AlgorithmTask; import de.hhu.ba.yoshikoWrapper.core.CyCore; +import de.hhu.ba.yoshikoWrapper.core.GraphicsLoader; import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; import de.hhu.ba.yoshikoWrapper.core.YoshikoLoader; @@ -30,80 +33,100 @@ import de.hhu.ba.yoshikoWrapper.core.YoshikoLoader; public class MainPanel extends ComfortPanel implements CytoPanelComponent { //SWING COMPONENTS + + private final YoshikoHeader header; + + /** + * Swing is a bit special sometimes, so a panel is used to wrap the lang-switcher. + * This prevents stretching of the component + */ + private final ComfortPanel langSwitcherWrapper; private final LanguageSwitcher langSwitcher; private final LibraryPanel libraryPanel; private final EditCostPanel ecPanel; - private final ButtonGroup heuristicGroup; - private final JRadioButton useHeuristic; - private final JRadioButton useILP; - - private final TimeLimitSetter timeLimitSetter; private final ReductionRulesChooser reductionRulesChooser; + + private final OperationModePanel opModePanel; - private final JCheckBox useTriangleCutsBox; - private final JCheckBox usePartitionCutsBox; + private final JCheckBox showAdvancedOptions; - private final SolutionNumberChooser solutionNumberChooser; + private final ArrayList<JComponent> advancedOptions; /** * Main constructor, creates a new Panel and initializes subcomponents - * @param solPanel */ - public MainPanel( ) { + public MainPanel() { //SWING INIT - this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS)); + this.setLayout(new FlowLayout()); //Initialize Swing components + header = new YoshikoHeader(); + + langSwitcherWrapper = new ComfortPanel(); langSwitcher = new LanguageSwitcher(); + langSwitcherWrapper.addAll(new JLabel(LocalizationManager.get("switchLanguage")),langSwitcher); + langSwitcherWrapper.setLayout(new FlowLayout()); + libraryPanel = new LibraryPanel(); ecPanel = new EditCostPanel(); - heuristicGroup = new ButtonGroup(); - useILP = new JRadioButton("Use Integer Linear Programming"); - useILP.setSelected(true); - - useHeuristic = new JRadioButton("Use Heuristic"); - heuristicGroup.add(useILP); - heuristicGroup.add(useHeuristic); - - solutionNumberChooser = new SolutionNumberChooser(); + opModePanel = new OperationModePanel(); reductionRulesChooser = new ReductionRulesChooser(); - timeLimitSetter = new TimeLimitSetter(); - - useTriangleCutsBox = new JCheckBox("Use Triangle Cuts"); - usePartitionCutsBox = new JCheckBox("Use Partition Cuts"); - JButton runButton = new JButton("RUN"); runButton.addActionListener(buttonListener); - //Link time limit option to ILP - useILP.addActionListener(ilpHeuristicSwitch); - useHeuristic.addActionListener(ilpHeuristicSwitch); + + + showAdvancedOptions = new JCheckBox(LocalizationManager.get("showAdvanced")); + showAdvancedOptions.addActionListener(toggleAdvancedOptionsListener); this.addAll( - langSwitcher, + header, + langSwitcherWrapper, + showAdvancedOptions, libraryPanel, ecPanel, - useILP, - useHeuristic, - timeLimitSetter, reductionRulesChooser, - useTriangleCutsBox, - usePartitionCutsBox, - solutionNumberChooser, + opModePanel, runButton ); + advancedOptions = new ArrayList<JComponent>(); + //Manage all advanced components separately to enable toggling + advancedOptions.addAll( + Arrays.asList( + opModePanel, + reductionRulesChooser + ) + ); + + showAdvancedOptions(false); + this.setVisible(true); } + + private ActionListener toggleAdvancedOptionsListener = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + showAdvancedOptions(showAdvancedOptions.isSelected()); + } + + }; + + private void showAdvancedOptions(boolean show) { + for (JComponent j : advancedOptions) { + j.setVisible(show); + } + } /** * ButtonListener for the "Run" Button @@ -116,7 +139,7 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { if (YoshikoLoader.isLibraryLoaded()){ AbstractTask yoshiko = new AlgorithmTask( CyCore.cy.getCurrentNetwork(), - timeLimitSetter.getTimeLimit(), + opModePanel.getTimeLimit(), ecPanel.getWeightColumn(), ecPanel.getPermanentColumn(), ecPanel.getForbiddenColumn(), @@ -124,41 +147,25 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { ecPanel.getDefaultDeletionCost(), reductionRulesChooser.getBitMask(), reductionRulesChooser.getMultFactor(), - useTriangleCutsBox.isSelected(), - usePartitionCutsBox.isSelected(), - useHeuristic.isSelected(), - solutionNumberChooser.getSolCount() + opModePanel.useTriangleCuts(), + opModePanel.usePartitionCuts(), + opModePanel.useHeuristic(), + opModePanel.getSolCount() ); CyCore.dialogTaskManager.execute(new TaskIterator(1,yoshiko)); } else { - JOptionPane.showMessageDialog( - - null, - LocalizationManager.get("noLibTitle"), - LocalizationManager.get("noLibMessage"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog( + null, + LocalizationManager.get("noLibTitle"), + LocalizationManager.get("noLibMessage"), + JOptionPane.ERROR_MESSAGE + ); } } }; - ActionListener ilpHeuristicSwitch = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (useILP.isSelected()) { - timeLimitSetter.setEnabled(true); - } - else { - timeLimitSetter.setEnabled(false); - } - } - }; - - public ColumnMapper getColumnMapper() { - return ecPanel.getColumnMapper(); - } - + //GETTER / SETTER @@ -178,11 +185,13 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { //TODO: Be creative I guess return "Yoshiko"; } - - + + public ColumnMapper getColumnMapper() { + return ecPanel.getColumnMapper(); + } + public Icon getIcon() { - //TODO: - return null; + return GraphicsLoader.getLogo(); } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/OperationModePanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/OperationModePanel.java new file mode 100644 index 0000000..133db24 --- /dev/null +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/OperationModePanel.java @@ -0,0 +1,98 @@ +package de.hhu.ba.yoshikoWrapper.gui; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JCheckBox; +import javax.swing.JRadioButton; +import javax.swing.border.Border; +import javax.swing.border.EtchedBorder; + +import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; + +@SuppressWarnings("serial") +public class OperationModePanel extends ComfortPanel{ + private final JRadioButton useHeuristic; + private final JRadioButton useILP; + private final TimeLimitSetter timeLimitSetter; + private final SolutionNumberChooser solutionNumberChooser; + private final JCheckBox useTriangleCutsBox; + private final JCheckBox usePartitionCutsBox; + + private final ButtonGroup heuristicGroup; + + public OperationModePanel() { + + this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); + + heuristicGroup = new ButtonGroup(); + useILP = new JRadioButton("Use Integer Linear Programming"); + useILP.setSelected(true); + + useHeuristic = new JRadioButton("Use Heuristic"); + heuristicGroup.add(useILP); + heuristicGroup.add(useHeuristic); + + solutionNumberChooser = new SolutionNumberChooser(); + + + timeLimitSetter = new TimeLimitSetter(); + + useTriangleCutsBox = new JCheckBox("Use Triangle Cuts"); + usePartitionCutsBox = new JCheckBox("Use Partition Cuts"); + + //Link time limit option to ILP + useILP.addActionListener(ilpHeuristicSwitch); + useHeuristic.addActionListener(ilpHeuristicSwitch); + + + this.addAll(useILP,useHeuristic,solutionNumberChooser,timeLimitSetter,useTriangleCutsBox,usePartitionCutsBox); + + Border border = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); + border = BorderFactory.createTitledBorder(border,LocalizationManager.get("operationMode")); + this.setBorder(border); + } + + ActionListener ilpHeuristicSwitch = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (useILP.isSelected()) { + timeLimitSetter.setEnabled(true); + useTriangleCutsBox.setEnabled(true); + usePartitionCutsBox.setEnabled(true); + solutionNumberChooser.setEnabled(true); + } + else { + timeLimitSetter.setEnabled(false); + useTriangleCutsBox.setEnabled(false); + usePartitionCutsBox.setEnabled(false); + solutionNumberChooser.setEnabled(false); + } + } + }; + + //SETTER GETTER + + public int getTimeLimit() { + return timeLimitSetter.getTimeLimit(); + } + + public boolean useTriangleCuts() { + return useTriangleCutsBox.isSelected(); + } + + public boolean usePartitionCuts() { + return usePartitionCutsBox.isSelected(); + } + + public boolean useHeuristic() { + return useHeuristic.isSelected(); + } + + public int getSolCount() { + return solutionNumberChooser.getSolCount(); + } +} diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java index dc90480..c75006a 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java @@ -16,8 +16,12 @@ public class SolutionNumberChooser extends ComfortPanel { numSolutionsSetter = new JSpinner(); numSolutionsSetter.setModel(new SpinnerNumberModel(1,1,Integer.MAX_VALUE,1)); label = new JLabel(LocalizationManager.get("nrSolutions")); - this.addAll(label, numSolutionsSetter); - + this.addAll(label, numSolutionsSetter); + } + + @Override + public void setEnabled(boolean enabled) { + numSolutionsSetter.setEnabled(enabled); } public int getSolCount() { diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java index 993afbb..abb2ea2 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java @@ -32,6 +32,7 @@ public class TimeLimitSetter extends ComfortPanel{ this.addAll(checkBox,numberField); } + @Override public void setEnabled(boolean enabled) { if (enabled) { this.checkBox.setEnabled(enabled); diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/YoshikoHeader.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/YoshikoHeader.java new file mode 100644 index 0000000..220ddcf --- /dev/null +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/YoshikoHeader.java @@ -0,0 +1,24 @@ +package de.hhu.ba.yoshikoWrapper.gui; + + +import javax.swing.BoxLayout; +import javax.swing.JLabel; + +import de.hhu.ba.yoshikoWrapper.core.GraphicsLoader; + +@SuppressWarnings("serial") +public class YoshikoHeader extends ComfortPanel { + + private JLabel logo; + private JLabel text; + + public YoshikoHeader() { + this.setLayout(new BoxLayout(this,BoxLayout.X_AXIS)); + + logo = new JLabel(GraphicsLoader.getLogo()); + text = new JLabel(GraphicsLoader.getText()); + + this.addAll(logo,text); + + } +} diff --git a/src/main/resources/YoshikoStrings.properties b/src/main/resources/YoshikoStrings.properties index d443a6a..bf621de 100644 --- a/src/main/resources/YoshikoStrings.properties +++ b/src/main/resources/YoshikoStrings.properties @@ -21,4 +21,11 @@ nrSolutions = Number of Solutions: redRuleChooserTitle = Reduction Rules discardSolution = Discard createMetaGraph = Create Meta-Graph -metaGraph = Meta Graph \ No newline at end of file +metaGraph = Meta Graph +showAdvanced = Show advanced options +editingCostPanel = Editing Costs +defaultInsertion = Default insertion cost: +defaultDeletion = Default deletion cost: +switchLanguage = Plugin language: +icTooltip = This value is used to determine what the algorithm pays when inserting an edge. Existing mappings overwrite this value. A higher value means that the algorithm is less likely to insert edges in order to generate a cluster. +operationMode = Operation Mode \ No newline at end of file diff --git a/src/main/resources/graphics/YoshikoAlphaLogo.png b/src/main/resources/graphics/YoshikoAlphaLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..526809e194d1b5ba94fe2c78c0f0d884d409d30d GIT binary patch literal 6862 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/graphics/YoshikoAlphaText.png b/src/main/resources/graphics/YoshikoAlphaText.png new file mode 100644 index 0000000000000000000000000000000000000000..eafac8c6726b9433584f17cc41eb11290e4cf5a0 GIT binary patch literal 7125 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/graphics/package-info.java b/src/main/resources/graphics/package-info.java new file mode 100644 index 0000000..0a04afd --- /dev/null +++ b/src/main/resources/graphics/package-info.java @@ -0,0 +1 @@ +package graphics; \ No newline at end of file -- GitLab