From 55be1b283ef33323683fc562f2d2f43d9d90f020 Mon Sep 17 00:00:00 2001 From: hneemann Date: Mon, 23 Nov 2020 09:14:58 +0100 Subject: [PATCH] fixes the TestCaseDescriptionDialog, closes #565 --- .../digital/analyse/SubstituteLibrary.java | 4 - .../de/neemann/digital/core/element/Keys.java | 2 +- .../gui/components/AttributeDialog.java | 42 ++++---- .../testing/TestCaseDescriptionDialog.java | 96 +++++++++++++++---- .../testing/TestCaseDescriptionEditor.java | 20 +++- .../digital/testing/TestCaseDescription.java | 35 ++++--- .../digital/integration/TestInGUI.java | 13 ++- .../neemann/digital/testing/TestDataTest.java | 6 +- 8 files changed, 148 insertions(+), 70 deletions(-) diff --git a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java index c85667a09..837d13c4a 100644 --- a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java +++ b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java @@ -17,7 +17,6 @@ import de.neemann.digital.draw.library.ElementNotFoundException; import de.neemann.digital.draw.library.LibraryInterface; import de.neemann.digital.hdl.hgs.*; import de.neemann.digital.lang.Lang; -import de.neemann.digital.testing.TestCaseDescription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -220,9 +219,6 @@ public class SubstituteLibrary implements LibraryInterface { } private Object doImplicitTypeCasts(Class expectedClass, Object val) { - if (expectedClass == TestCaseDescription.class) - return new TestCaseDescription(val.toString()); - if (expectedClass == Integer.class && val instanceof Long) { long l = (Long) val; if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) diff --git a/src/main/java/de/neemann/digital/core/element/Keys.java b/src/main/java/de/neemann/digital/core/element/Keys.java index 9cceabaf3..231681773 100644 --- a/src/main/java/de/neemann/digital/core/element/Keys.java +++ b/src/main/java/de/neemann/digital/core/element/Keys.java @@ -874,6 +874,6 @@ public final class Keys { * The test data */ public static final Key TESTDATA = - new Key<>("Testdata", () -> new TestCaseDescription("")); + new Key<>("Testdata", TestCaseDescription::new); } diff --git a/src/main/java/de/neemann/digital/gui/components/AttributeDialog.java b/src/main/java/de/neemann/digital/gui/components/AttributeDialog.java index 131eb3da7..80a9eb7e6 100644 --- a/src/main/java/de/neemann/digital/gui/components/AttributeDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/AttributeDialog.java @@ -177,7 +177,7 @@ public class AttributeDialog extends JDialog { final AbstractAction cancel = new AbstractAction(Lang.get("cancel")) { @Override public void actionPerformed(ActionEvent e) { - dispose(); + tryDispose(); } }; @@ -190,24 +190,7 @@ public class AttributeDialog extends JDialog { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - EditorHolder majorModification = null; - for (EditorHolder eh : editors) - if (eh.e.invisibleModification()) - majorModification = eh; - if (majorModification == null) - dispose(); - else { - int r = JOptionPane.showOptionDialog( - AttributeDialog.this, - Lang.get("msg_dataWillBeLost_n", majorModification.key.getName()), - Lang.get("msg_warning"), - JOptionPane.YES_NO_OPTION, - JOptionPane.WARNING_MESSAGE, - null, new String[]{Lang.get("btn_discard"), Lang.get("cancel")}, - Lang.get("cancel")); - if (r == JOptionPane.YES_OPTION) - dispose(); - } + tryDispose(); } }); @@ -217,6 +200,27 @@ public class AttributeDialog extends JDialog { JComponent.WHEN_IN_FOCUSED_WINDOW); } + private void tryDispose() { + EditorHolder majorModification = null; + for (EditorHolder eh : editors) + if (eh.e.invisibleModification()) + majorModification = eh; + if (majorModification == null) + dispose(); + else { + int r = JOptionPane.showOptionDialog( + AttributeDialog.this, + Lang.get("msg_dataWillBeLost_n", majorModification.key.getName()), + Lang.get("msg_warning"), + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, + null, new String[]{Lang.get("btn_discard"), Lang.get("btn_editFurther")}, + Lang.get("cancel")); + if (r == JOptionPane.YES_OPTION) + dispose(); + } + } + private EditorPanel findPanel(ArrayList panels, String panelId) { for (EditorPanel p : panels) if (panelId.equals(p.getPanelId())) diff --git a/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionDialog.java b/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionDialog.java index 70044becb..e9c1ed781 100644 --- a/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionDialog.java @@ -24,6 +24,8 @@ import de.neemann.gui.ToolTipAction; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.IOException; import static de.neemann.digital.gui.components.EditorFactory.addF1Traversal; @@ -33,25 +35,43 @@ import static de.neemann.digital.gui.components.EditorFactory.addF1Traversal; */ public class TestCaseDescriptionDialog extends JDialog { + private final JTextArea text; + private final TestCaseDescription initialData; + private final VisualElement element; + private TestCaseDescription modifiedData; + private boolean circuitModified = false; + /** - * Creates a new data dialog + * Creates a new data dialog. * - * @param parent the parent component - * @param data the data to edit - * @param element the element to be modified + * @param parent the parent component + * @param initialData the data to edit */ - public TestCaseDescriptionDialog(Window parent, TestCaseDescription data, VisualElement element) { + public TestCaseDescriptionDialog(Window parent, TestCaseDescription initialData) { + this(parent, initialData, null); + } + + /** + * Creates a new data dialog. + * This constructor allows to open the dialog in a modeless way. + * + * @param parent the parent component + * @param initialData the data to edit + * @param element the element to be modified + */ + public TestCaseDescriptionDialog(Window parent, TestCaseDescription initialData, VisualElement element) { super(parent, Lang.get("key_Testdata"), element == null ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); + this.element = element; + this.initialData = initialData; + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - - String initialDataString = data.getDataString(); - - JTextArea text = addF1Traversal(new JTextArea(data.getDataString(), 30, 50)); + text = addF1Traversal(new JTextArea(initialData.getDataString(), 30, 50)); text.setFont(new Font(Font.MONOSPACED, Font.PLAIN, Screen.getInstance().getFontSize())); + addWindowListener(new ClosingWindowListener()); + JScrollPane scrollPane = new JScrollPane(text); getContentPane().add(scrollPane); scrollPane.setRowHeaderView(new TextLineNumber(text, 3)); @@ -91,7 +111,7 @@ public class TestCaseDescriptionDialog extends JDialog { buttons.add(new ToolTipAction(Lang.get("cancel")) { @Override public void actionPerformed(ActionEvent actionEvent) { - dispose(); + tryDispose(); } }.createJButton()); @@ -100,10 +120,10 @@ public class TestCaseDescriptionDialog extends JDialog { @Override public void actionPerformed(ActionEvent e) { try { - data.setDataString(text.getText()); if (parent instanceof Main) { CircuitComponent cc = ((Main) parent).getCircuitComponent(); - element.getElementAttributes().set(Keys.TESTDATA, data); + element.getElementAttributes().set(Keys.TESTDATA, new TestCaseDescription(text.getText())); + circuitModified = true; cc.getMain().startTests(); } } catch (ParserException | IOException e1) { @@ -117,12 +137,12 @@ public class TestCaseDescriptionDialog extends JDialog { @Override public void actionPerformed(ActionEvent e) { try { - data.setDataString(text.getText()); + modifiedData = new TestCaseDescription(text.getText()); if (element != null - && !initialDataString.equals(data.getDataString()) + && isStateChanged() && parent instanceof Main) { CircuitComponent cc = ((Main) parent).getCircuitComponent(); - cc.modify(new ModifyAttribute<>(element, Keys.TESTDATA, new TestCaseDescription(data))); + cc.modify(new ModifyAttribute<>(element, Keys.TESTDATA, modifiedData)); } dispose(); } catch (ParserException | IOException e1) { @@ -138,4 +158,48 @@ public class TestCaseDescriptionDialog extends JDialog { setLocationRelativeTo(parent); } + /** + * Shows the dialog and returns the modified data + * + * @return the modified data or null if not modified + */ + public TestCaseDescription showDialog() { + modifiedData = null; + setVisible(true); + return modifiedData; + } + + private boolean isStateChanged() { + return !initialData.getDataString().equals(text.getText()); + } + + private void tryDispose() { + if (isStateChanged()) { + int r = JOptionPane.showOptionDialog( + this, + Lang.get("msg_dataWillBeLost_n", Keys.TESTDATA.getName()), + Lang.get("msg_warning"), + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, + null, new String[]{Lang.get("btn_discard"), Lang.get("btn_editFurther")}, + Lang.get("cancel")); + if (r == JOptionPane.YES_OPTION) + myDispose(); + } else + myDispose(); + } + + private void myDispose() { + dispose(); + if (circuitModified) + element.getElementAttributes().set(Keys.TESTDATA, initialData); + } + + private final class ClosingWindowListener extends WindowAdapter { + @Override + public void windowClosing(WindowEvent e) { + tryDispose(); + } + } + } diff --git a/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionEditor.java b/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionEditor.java index dcf144f60..32fb997f7 100644 --- a/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionEditor.java +++ b/src/main/java/de/neemann/digital/gui/components/testing/TestCaseDescriptionEditor.java @@ -19,10 +19,12 @@ import java.awt.*; import java.awt.event.ActionEvent; /** + * The test case description editor */ public class TestCaseDescriptionEditor extends EditorFactory.LabelEditor { - private final TestCaseDescription data; + private final TestCaseDescription initialData; + private TestCaseDescription data; /** * Creates a new editor @@ -31,7 +33,8 @@ public class TestCaseDescriptionEditor extends EditorFactory.LabelEditor key) { - this.data = new TestCaseDescription(data); + this.data = data; + this.initialData = data; } @Override @@ -46,7 +49,10 @@ public class TestCaseDescriptionEditor extends EditorFactory.LabelEditor names; + + /** + * creates a new instance + */ + public TestCaseDescription() { + this.dataString = ""; + } + /** * creates a new instance * * @param data the test case description + * @throws IOException IOException + * @throws ParserException ParserException */ - public TestCaseDescription(String data) { + public TestCaseDescription(String data) throws IOException, ParserException { this.dataString = data; + Parser tdp = new Parser(data).parse(); + lines = tdp.getLines(); + names = tdp.getNames(); } /** @@ -36,7 +49,7 @@ public class TestCaseDescription { * @param valueToCopy the instance to copy */ public TestCaseDescription(TestCaseDescription valueToCopy) { - this(valueToCopy.dataString); + this.dataString = valueToCopy.dataString; } /** @@ -46,22 +59,6 @@ public class TestCaseDescription { return dataString; } - /** - * Sets the data and checks its validity - * - * @param data the data - * @throws IOException thrown if data is not valid - * @throws ParserException thrown if data is not valid - */ - public void setDataString(String data) throws IOException, ParserException { - if (!data.equals(dataString)) { - Parser tdp = new Parser(data).parse(); - dataString = data; - lines = tdp.getLines(); - names = tdp.getNames(); - } - } - private void check() throws TestingDataException { if (lines == null || names == null) { try { diff --git a/src/test/java/de/neemann/digital/integration/TestInGUI.java b/src/test/java/de/neemann/digital/integration/TestInGUI.java index ec16e9742..783b31fb9 100644 --- a/src/test/java/de/neemann/digital/integration/TestInGUI.java +++ b/src/test/java/de/neemann/digital/integration/TestInGUI.java @@ -46,6 +46,7 @@ import de.neemann.digital.gui.remote.RemoteException; import de.neemann.digital.lang.Lang; import de.neemann.digital.testing.TestCaseDescription; import de.neemann.digital.testing.TestCaseElement; +import de.neemann.digital.testing.parser.ParserException; import de.neemann.gui.ErrorMessage; import junit.framework.TestCase; @@ -1375,10 +1376,14 @@ public class TestInGUI extends TestCase { @Override public void checkWindow(GuiTester gt, Main main) { - main.getCircuitComponent().getCircuit().add( - new VisualElement(TestCaseElement.DESCRIPTION.getName()) - .setAttribute(TESTDATA, new TestCaseDescription(testdata)) - .setShapeFactory(main.getCircuitComponent().getLibrary().getShapeFactory())); + try { + main.getCircuitComponent().getCircuit().add( + new VisualElement(TestCaseElement.DESCRIPTION.getName()) + .setAttribute(TESTDATA, new TestCaseDescription(testdata)) + .setShapeFactory(main.getCircuitComponent().getLibrary().getShapeFactory())); + } catch (IOException | ParserException e) { + throw new RuntimeException(e); + } } } } diff --git a/src/test/java/de/neemann/digital/testing/TestDataTest.java b/src/test/java/de/neemann/digital/testing/TestDataTest.java index 6dd06803d..0e6247aff 100644 --- a/src/test/java/de/neemann/digital/testing/TestDataTest.java +++ b/src/test/java/de/neemann/digital/testing/TestDataTest.java @@ -28,8 +28,8 @@ public class TestDataTest extends TestCase { // try to set a non parsable string try { - td.setDataString(DATA3); - assertTrue(false); + td = new TestCaseDescription(DATA3); + fail(); } catch (IOException | ParserException e) { assertTrue(true); } @@ -46,7 +46,7 @@ public class TestDataTest extends TestCase { assertEquals(DATA1, td.getDataString()); // try to set a parsable string - td.setDataString(DATA2); + td = new TestCaseDescription(DATA2); // TestData has changed! assertEquals(DATA2, td.getDataString()); }