diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 0e5f4a810..f7c004da2 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -29,7 +29,7 @@ import de.neemann.digital.gui.components.modification.Modifications; import de.neemann.digital.gui.components.modification.ModifyAttribute; import de.neemann.digital.gui.components.modification.ModifyMeasurementOrdering; import de.neemann.digital.gui.components.table.TableDialog; -import de.neemann.digital.gui.components.testing.TestResultDialog; +import de.neemann.digital.gui.components.testing.ValueTableDialog; import de.neemann.digital.gui.components.tree.LibraryTreeModel; import de.neemann.digital.gui.components.tree.SelectTree; import de.neemann.digital.gui.remote.DigitalHandler; @@ -828,17 +828,17 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS */ public void startTests() { try { - ArrayList tsl = new ArrayList<>(); + ArrayList tsl = new ArrayList<>(); for (VisualElement el : circuitComponent.getCircuit().getElements()) if (el.equalsDescription(TestCaseElement.TESTCASEDESCRIPTION)) - tsl.add(new TestResultDialog.TestSet( + tsl.add(new ValueTableDialog.TestSet( el.getElementAttributes().get(TestCaseElement.TESTDATA), el.getElementAttributes().getCleanLabel())); if (tsl.isEmpty()) throw new TestingDataException(Lang.get("err_noTestData")); - windowPosManager.register("testResult", new TestResultDialog(Main.this, tsl, circuitComponent.getCircuit(), library)).setVisible(true); + windowPosManager.register("testResult", new ValueTableDialog(Main.this).addTestResult(tsl, circuitComponent.getCircuit(), library)).setVisible(true); ensureModelIsStopped(); } catch (NodeException | ElementNotFoundException | PinException | TestingDataException | RuntimeException e1) { diff --git a/src/main/java/de/neemann/digital/gui/components/data/GraphDialog.java b/src/main/java/de/neemann/digital/gui/components/data/GraphDialog.java index e55599505..3f1e2ff57 100644 --- a/src/main/java/de/neemann/digital/gui/components/data/GraphDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/data/GraphDialog.java @@ -7,6 +7,7 @@ import de.neemann.digital.core.Signal; import de.neemann.digital.data.ValueTable; import de.neemann.digital.gui.SaveAsHelper; import de.neemann.digital.gui.components.OrderMerger; +import de.neemann.digital.gui.components.testing.ValueTableDialog; import de.neemann.digital.gui.sync.NoSync; import de.neemann.digital.gui.sync.Sync; import de.neemann.digital.lang.Lang; @@ -33,6 +34,7 @@ public class GraphDialog extends JDialog implements ModelStateObserver { private final GraphComponent dsc; private final JScrollPane scrollPane; private final Sync modelSync; + private final ToolTipAction showTable; private ValueTableObserver valueTableObserver; private static final Icon ICON_EXPAND = IconCreator.create("View-zoom-fit.png"); @@ -50,7 +52,7 @@ public class GraphDialog extends JDialog implements ModelStateObserver { * @param modelSync the lock to access the model * @return the created instance */ - public static GraphDialog createLiveDialog(Frame owner, Model model, boolean microStep, List ordering, Sync modelSync) { + public static GraphDialog createLiveDialog(JFrame owner, Model model, boolean microStep, List ordering, Sync modelSync) { String title; if (microStep) title = Lang.get("win_measures_microstep"); @@ -78,7 +80,7 @@ public class GraphDialog extends JDialog implements ModelStateObserver { * @param title the frame title * @param logData the data to visualize */ - public GraphDialog(Frame owner, String title, ValueTable logData) { + public GraphDialog(JFrame owner, String title, ValueTable logData) { this(owner, title, null, logData, null, NoSync.INST); } @@ -91,7 +93,7 @@ public class GraphDialog extends JDialog implements ModelStateObserver { * @param logData the data to visualize * @param modelSync used to access the running model */ - private GraphDialog(Frame owner, String title, Model model, ValueTable logData, ValueTableObserver valueTableObserver, Sync modelSync) { + private GraphDialog(JFrame owner, String title, Model model, ValueTable logData, ValueTableObserver valueTableObserver, Sync modelSync) { super(owner, title, false); this.valueTableObserver = valueTableObserver; this.modelSync = modelSync; @@ -125,6 +127,13 @@ public class GraphDialog extends JDialog implements ModelStateObserver { } }.setAccelerator("control MINUS"); + showTable = new ToolTipAction(Lang.get("menu_showDataAsTable")) { + @Override + public void actionPerformed(ActionEvent e) { + new ValueTableDialog(owner).addValueTable("Data", logData).disableGraph().setVisible(true); + } + }.setToolTip(Lang.get("menu_showDataAsTable_tt")); + toolBar.add(zoomIn.createJButtonNoText()); toolBar.add(zoomOut.createJButtonNoText()); toolBar.add(maximize.createJButtonNoText()); @@ -165,6 +174,8 @@ public class GraphDialog extends JDialog implements ModelStateObserver { view.add(maximize.createJMenuItem()); view.add(zoomOut.createJMenuItem()); view.add(zoomIn.createJMenuItem()); + view.addSeparator(); + view.add(showTable.createJMenuItem()); setJMenuBar(bar); pack(); @@ -185,4 +196,14 @@ public class GraphDialog extends JDialog implements ModelStateObserver { }); }); } + + /** + * Disable the show as table function + * + * @return this for chained calls + */ + public GraphDialog disableTable() { + showTable.setActive(false); + return this; + } } diff --git a/src/main/java/de/neemann/digital/gui/components/testing/TestResultDialog.java b/src/main/java/de/neemann/digital/gui/components/testing/ValueTableDialog.java similarity index 70% rename from src/main/java/de/neemann/digital/gui/components/testing/TestResultDialog.java rename to src/main/java/de/neemann/digital/gui/components/testing/ValueTableDialog.java index 692f02bd5..7ae50cf40 100644 --- a/src/main/java/de/neemann/digital/gui/components/testing/TestResultDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/testing/ValueTableDialog.java @@ -10,15 +10,14 @@ import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.library.ElementLibrary; import de.neemann.digital.draw.library.ElementNotFoundException; import de.neemann.digital.draw.model.ModelCreator; +import de.neemann.digital.gui.SaveAsHelper; import de.neemann.digital.gui.components.data.GraphDialog; import de.neemann.digital.lang.Lang; import de.neemann.digital.testing.*; -import de.neemann.gui.ErrorMessage; -import de.neemann.gui.IconCreator; -import de.neemann.gui.LineBreaker; -import de.neemann.gui.ToolTipAction; +import de.neemann.gui.*; import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.DefaultTableCellRenderer; import java.awt.*; import java.awt.event.ActionEvent; @@ -30,7 +29,7 @@ import java.util.Collections; * * @author hneemann */ -public class TestResultDialog extends JDialog { +public class ValueTableDialog extends JDialog { private static final Color FAILED_COLOR = new Color(255, 200, 200); private static final Color PASSED_COLOR = new Color(200, 255, 200); private static final Icon ICON_FAILED = IconCreator.create("testFailed.png"); @@ -39,28 +38,73 @@ public class TestResultDialog extends JDialog { private final ArrayList resultTableData; + private final JTabbedPane tp; + private final JFrame owner; + private final ToolTipAction asGraph; /** * Creates a new result dialog. * - * @param owner the parent frame + * @param owner the parent frame + */ + public ValueTableDialog(JFrame owner) { + super(owner, Lang.get("msg_testResult"), false); + this.owner = owner; + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + setAlwaysOnTop(true); + + resultTableData = new ArrayList<>(); + tp = new JTabbedPane(); + + JMenuBar bar = new JMenuBar(); + JMenu file = new JMenu(Lang.get("menu_file")); + bar.add(file); + file.add(new ToolTipAction(Lang.get("menu_saveData")) { + @Override + public void actionPerformed(ActionEvent e) { + int tab = tp.getSelectedIndex(); + if (tab < 0) tab = 0; + JFileChooser fileChooser = new MyFileChooser(); + fileChooser.setFileFilter(new FileNameExtensionFilter("Comma Separated Values", "csv")); + new SaveAsHelper(ValueTableDialog.this, fileChooser, "csv") + .checkOverwrite(resultTableData.get(tab)::saveCSV); + } + }.setToolTip(Lang.get("menu_saveData_tt")).createJMenuItem()); + + JMenu view = new JMenu(Lang.get("menu_view")); + asGraph = new ToolTipAction(Lang.get("menu_showDataAsGraph"), ICON_GRAPH) { + @Override + public void actionPerformed(ActionEvent actionEvent) { + int tab = tp.getSelectedIndex(); + if (tab < 0) tab = 0; + new GraphDialog(owner, Lang.get("win_testdata_N", tp.getTitleAt(tab)), resultTableData.get(tab)).disableTable().setVisible(true); + } + }.setToolTip(Lang.get("menu_showDataAsGraph_tt")); + view.add(asGraph.createJMenuItem()); + bar.add(view); + setJMenuBar(bar); + + JToolBar toolBar = new JToolBar(); + toolBar.add(asGraph.createJButtonNoText()); + getContentPane().add(toolBar, BorderLayout.NORTH); + + getContentPane().add(tp); + } + + /** + * Add test results + * * @param tsl list of test sets * @param circuit the circuit * @param library the library to use + * @return this for chained calls * @throws NodeException NodeException * @throws TestingDataException DataException * @throws PinException PinException * @throws ElementNotFoundException ElementNotFoundException */ - public TestResultDialog(JFrame owner, ArrayList tsl, Circuit circuit, ElementLibrary library) throws NodeException, TestingDataException, PinException, ElementNotFoundException { - super(owner, Lang.get("msg_testResult"), false); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - + public ValueTableDialog addTestResult(ArrayList tsl, Circuit circuit, ElementLibrary library) throws PinException, NodeException, ElementNotFoundException, TestingDataException { Collections.sort(tsl); - - resultTableData = new ArrayList<>(); - - JTabbedPane tp = new JTabbedPane(); int i = 0; int errorTabIndex = -1; for (TestSet ts : tsl) { @@ -71,14 +115,6 @@ public class TestResultDialog extends JDialog { if (testExecutor.getException() != null) SwingUtilities.invokeLater(new ErrorMessage(Lang.get("msg_errorWhileExecutingTests_N0", ts.name)).addCause(testExecutor.getException()).setComponent(this)); - JTable table = new JTable(new ValueTableModel(testExecutor.getResult())); - table.setDefaultRenderer(Value.class, new ValueRenderer()); - table.setDefaultRenderer(Integer.class, new NumberRenderer()); - final Font font = table.getFont(); - table.getColumnModel().getColumn(0).setMaxWidth(font.getSize() * 4); - table.setRowHeight(font.getSize() * 6 / 5); - resultTableData.add(testExecutor.getResult()); - String tabName; Icon tabIcon; if (testExecutor.allPassed()) { @@ -92,36 +128,54 @@ public class TestResultDialog extends JDialog { if (testExecutor.toManyResults()) tabName += " " + Lang.get("msg_test_missingLines"); - tp.addTab(tabName, tabIcon, new JScrollPane(table)); + tp.addTab(tabName, tabIcon, new JScrollPane(createTable(testExecutor.getResult()))); if (testExecutor.toManyResults()) tp.setToolTipTextAt(i, new LineBreaker().toHTML().breakLines(Lang.get("msg_test_missingLines_tt"))); + resultTableData.add(testExecutor.getResult()); i++; } if (errorTabIndex >= 0) tp.setSelectedIndex(errorTabIndex); - - JMenuBar bar = new JMenuBar(); - JMenu view = new JMenu(Lang.get("menu_view")); - ToolTipAction asGraph = new ToolTipAction(Lang.get("menu_showDataAsGraph"), ICON_GRAPH) { - @Override - public void actionPerformed(ActionEvent actionEvent) { - int tab = tp.getSelectedIndex(); - if (tab < 0) tab = 0; - new GraphDialog(owner, Lang.get("win_testdata_N", tp.getTitleAt(tab)), resultTableData.get(tab)).setVisible(true); - } - }.setToolTip(Lang.get("menu_showDataAsGraph_tt")); - view.add(asGraph.createJMenuItem()); - bar.add(view); - setJMenuBar(bar); - - JToolBar toolBar = new JToolBar(); - toolBar.add(asGraph.createJButtonNoText()); - getContentPane().add(toolBar, BorderLayout.NORTH); - - getContentPane().add(tp); pack(); setLocationRelativeTo(owner); + return this; + } + + /** + * Add a table to this dialog + * + * @param name the name of the tab + * @param valueTable the values + * @return this for chained calls + */ + public ValueTableDialog addValueTable(String name, ValueTable valueTable) { + tp.addTab(name, new JScrollPane(createTable(valueTable))); + resultTableData.add(valueTable); + + pack(); + setLocationRelativeTo(owner); + return this; + } + + private JTable createTable(ValueTable valueTable) { + JTable table = new JTable(new ValueTableModel(valueTable)); + table.setDefaultRenderer(Value.class, new ValueRenderer()); + table.setDefaultRenderer(Integer.class, new NumberRenderer()); + final Font font = table.getFont(); + table.getColumnModel().getColumn(0).setMaxWidth(font.getSize() * 4); + table.setRowHeight(font.getSize() * 6 / 5); + return table; + } + + /** + * Disable the show as graph function + * + * @return this for chained calls + */ + public ValueTableDialog disableGraph() { + asGraph.setActive(false); + return this; } /** diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index f7cc6c6d1..f462a3d3a 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -865,6 +865,8 @@ Sind evtl. die Namen der Variablen nicht eindeutig? Letzte rückgängig gemachte Aktion wieder herstellen. Zeige Graph Zeigt die Daten als Graph an. + Zeige Tabelle + Zeigt die Daten als Tabelle an. Digital diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index edf409d0e..851a863e3 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -853,6 +853,8 @@ The names of the variables may not be unique. Apply last reverted modification again. Show graph Show the data as a Graph. + Show table + Shows values as a table. Digital diff --git a/src/main/resources/measurement-graph.png b/src/main/resources/measurement-graph.png index 605724d3a..39946219d 100644 Binary files a/src/main/resources/measurement-graph.png and b/src/main/resources/measurement-graph.png differ diff --git a/src/main/resources/measurement-graph_hi.png b/src/main/resources/measurement-graph_hi.png index 8e69216d5..94241bea3 100644 Binary files a/src/main/resources/measurement-graph_hi.png and b/src/main/resources/measurement-graph_hi.png differ diff --git a/src/main/svg/measurement-graph.svg b/src/main/svg/measurement-graph.svg index 22d1bb2d8..793fe3684 100644 --- a/src/main/svg/measurement-graph.svg +++ b/src/main/svg/measurement-graph.svg @@ -1,7 +1,7 @@ - + + id="metadata122"> @@ -31,7 +31,7 @@ + id="defs120" /> - - - - - - - - - - - A - B - C + id="g4679" + transform="translate(0,-0.32345319)"> + + + + + + + + + + A + B + +