From b310a9a2e3efc69a884beb3f1b4bbfb7a643a69d Mon Sep 17 00:00:00 2001 From: hneemann Date: Tue, 28 Mar 2017 21:09:05 +0200 Subject: [PATCH] Simplification of event handling. --- .../draw/library/DescriptionCreator.java | 20 ----- .../digital/draw/library/ElementLibrary.java | 59 +++++++------ .../digital/draw/library/LibraryNode.java | 32 ++++--- .../de/neemann/digital/gui/InsertAction.java | 3 +- .../java/de/neemann/digital/gui/Main.java | 86 +++++++++---------- .../de/neemann/digital/gui/SavedListener.java | 15 ---- .../gui/components/CircuitComponent.java | 27 +++--- 7 files changed, 110 insertions(+), 132 deletions(-) delete mode 100644 src/main/java/de/neemann/digital/draw/library/DescriptionCreator.java delete mode 100644 src/main/java/de/neemann/digital/gui/SavedListener.java diff --git a/src/main/java/de/neemann/digital/draw/library/DescriptionCreator.java b/src/main/java/de/neemann/digital/draw/library/DescriptionCreator.java deleted file mode 100644 index 9c3c8db9f..000000000 --- a/src/main/java/de/neemann/digital/draw/library/DescriptionCreator.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.neemann.digital.draw.library; - -import de.neemann.digital.core.element.ElementTypeDescription; - -import java.io.IOException; - -/** - * Used for lazy loading of the circuits - * Created by hneemann on 25.03.17. - */ -public interface DescriptionCreator { - /** - * Is called if the description is needed in the circuit. - * Is not called to create the menus - * - * @return the description - * @throws IOException IOException - */ - ElementTypeDescription createDescription() throws IOException; -} diff --git a/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java b/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java index d0c3086b0..62717b004 100644 --- a/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java +++ b/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java @@ -302,7 +302,7 @@ public class ElementLibrary implements Iterable for (File f : orderedList) { final String name = f.getName(); if (f.isFile() && name.endsWith(".dig")) - node.add(importElement(f)); + node.add(new LibraryNode(f)); } } } @@ -362,8 +362,10 @@ public class ElementLibrary implements Iterable * * @param name the elements name */ - public void removeElement(File name) { - map.remove(name.getName()); + public void invalidateElement(File name) { + LibraryNode n = map.get(name.getName()); + if (n != null) + n.invalidate(); } /** @@ -382,31 +384,36 @@ public class ElementLibrary implements Iterable return root; } - private LibraryNode importElement(File file) { - return new LibraryNode(file.getName(), () -> { + /** + * Imports the given file + * + * @param file the file to load + * @return the description + * @throws IOException IOException + */ + ElementTypeDescription importElement(File file) throws IOException { + try { + LOGGER.debug("load element " + file); + Circuit circuit; try { - LOGGER.debug("load element " + file); - Circuit circuit; - try { - circuit = Circuit.loadCircuit(file, shapeFactory); - } catch (IOException e) { - throw new IOException(Lang.get("err_couldNotFindIncludedFile_N0", file)); - } - ElementTypeDescriptionCustom description = - new ElementTypeDescriptionCustom(file, - attributes -> new CustomElement(circuit, ElementLibrary.this, file), - circuit.getAttributes(), circuit.getInputNames()); - description.setShortName(createShortName(file)); - - String descriptionText = circuit.getAttributes().get(Keys.DESCRIPTION); - if (descriptionText != null && descriptionText.length() > 0) { - description.setDescription(descriptionText); - } - return description; - } catch (PinException e) { - throw new IOException(Lang.get("msg_errorImportingModel"), e); + circuit = Circuit.loadCircuit(file, shapeFactory); + } catch (IOException e) { + throw new IOException(Lang.get("err_couldNotFindIncludedFile_N0", file)); } - }); + ElementTypeDescriptionCustom description = + new ElementTypeDescriptionCustom(file, + attributes -> new CustomElement(circuit, ElementLibrary.this, file), + circuit.getAttributes(), circuit.getInputNames()); + description.setShortName(createShortName(file)); + + String descriptionText = circuit.getAttributes().get(Keys.DESCRIPTION); + if (descriptionText != null && descriptionText.length() > 0) { + description.setDescription(descriptionText); + } + return description; + } catch (PinException e) { + throw new IOException(Lang.get("msg_errorImportingModel"), e); + } } private String createShortName(File file) { diff --git a/src/main/java/de/neemann/digital/draw/library/LibraryNode.java b/src/main/java/de/neemann/digital/draw/library/LibraryNode.java index 2f8a658d1..c47e9336c 100644 --- a/src/main/java/de/neemann/digital/draw/library/LibraryNode.java +++ b/src/main/java/de/neemann/digital/draw/library/LibraryNode.java @@ -5,6 +5,7 @@ import de.neemann.digital.draw.elements.VisualElement; import de.neemann.digital.draw.shapes.ShapeFactory; import javax.swing.*; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; @@ -18,7 +19,7 @@ public class LibraryNode implements Iterable { private final ArrayList children; private final String translatedName; private final String name; - private final DescriptionCreator creator; + private final File file; private ElementTypeDescription description; private ImageIcon icon; private ElementLibrary library; @@ -35,7 +36,7 @@ public class LibraryNode implements Iterable { this.translatedName = name; this.children = new ArrayList<>(); this.description = null; - this.creator = null; + this.file = null; } /** @@ -48,20 +49,19 @@ public class LibraryNode implements Iterable { this.description = description; this.name = description.getName(); this.translatedName = description.getTranslatedName(); - this.creator = null; + this.file = null; } /** * Creates a new leaf * - * @param name the name of the leaf - * @param creator used to create the {@link ElementTypeDescription} if necessary + * @param file the file containing the leaf */ - LibraryNode(String name, DescriptionCreator creator) { + LibraryNode(File file) { this.children = null; - this.name = name; + this.name = file.getName(); this.translatedName = name; - this.creator = creator; + this.file = file; } /** @@ -100,7 +100,7 @@ public class LibraryNode implements Iterable { * @return trie if this is a leaf */ public boolean isLeaf() { - return description != null || creator != null; + return description != null || file != null; } /** @@ -118,7 +118,7 @@ public class LibraryNode implements Iterable { */ public ElementTypeDescription getDescription() throws IOException { if (description == null) { - description = creator.createDescription(); + description = library.importElement(file); library.fireLibraryChanged(this); } return description; @@ -163,8 +163,8 @@ public class LibraryNode implements Iterable { /** * @return returns the description if present, null otherwise */ - public ElementTypeDescription getDescriptionOrNull() { - return description; + public boolean isCustom() { + return file != null; } /** @@ -263,4 +263,12 @@ public class LibraryNode implements Iterable { return path.toArray(new Object[path.size()]); } + /** + * Invalidate this node + */ + public void invalidate() { + description = null; + icon = null; + library.fireLibraryChanged(this); + } } diff --git a/src/main/java/de/neemann/digital/gui/InsertAction.java b/src/main/java/de/neemann/digital/gui/InsertAction.java index ab8b681fe..52fda6d56 100644 --- a/src/main/java/de/neemann/digital/gui/InsertAction.java +++ b/src/main/java/de/neemann/digital/gui/InsertAction.java @@ -2,7 +2,6 @@ package de.neemann.digital.gui; import de.neemann.digital.draw.elements.VisualElement; import de.neemann.digital.draw.graphics.Vector; -import de.neemann.digital.draw.library.ElementLibrary; import de.neemann.digital.draw.library.LibraryNode; import de.neemann.digital.draw.shapes.ShapeFactory; import de.neemann.digital.gui.components.CircuitComponent; @@ -59,7 +58,7 @@ public final class InsertAction extends ToolTipAction { * @return true if element to insert is a custom element */ public boolean isCustom() { - return node.getDescriptionOrNull() instanceof ElementLibrary.ElementTypeDescriptionCustom; + return node.isCustom(); } /** diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 4ffa1554d..c2d558699 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -101,18 +101,18 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E private static final Icon ICON_HELP = IconCreator.create("help.png"); private final CircuitComponent circuitComponent; private final ToolTipAction save; - private ToolTipAction doStep; - private ToolTipAction runToBreakAction; private final ElementLibrary library; private final ShapeFactory shapeFactory; - private final SavedListener savedListener; private final JLabel statusLabel; private final StateManager stateManager = new StateManager(); private final ElementAttributes settings = new ElementAttributes(); private final ScheduledThreadPoolExecutor timerExecuter = new ScheduledThreadPoolExecutor(1); private final WindowPosManager windowPosManager = new WindowPosManager(); private final InsertHistory insertHistory; - private final boolean isParentsLibrary; + private final boolean isNestedFile; + + private ToolTipAction doStep; + private ToolTipAction runToBreakAction; private File lastFilename; private File filename; @@ -135,54 +135,53 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E } /** - * Creates a new instance + * Creates a new instance. + * Used to open a nested circuit. * - * @param parent the parent component - * @param fileToOpen a file to open - * @param savedListener a listener which is notified if the file is changed on disk + * @param parent the parent component + * @param fileToOpen a file to open + * @param library the library to use, if not null a nested circuit is opened */ - public Main(Component parent, File fileToOpen, SavedListener savedListener, ElementLibrary library) { - this(parent, fileToOpen, savedListener, library, null); + public Main(Component parent, File fileToOpen, ElementLibrary library) { + this(parent, fileToOpen, library, null); } /** - * Creates a new instance + * Creates a new instance. + * Used to show a generated circuit. * * @param parent the parent component * @param circuit circuit to show */ public Main(Component parent, Circuit circuit) { - this(parent, null, null, null, circuit); + this(parent, null, null, circuit); } /** * Creates a new instance * - * @param parent the parent component - * @param fileToOpen a file to open - * @param savedListener a listener which is notified if the file is changed on disk - * @param circuit circuit to show + * @param parent the parent component + * @param fileToOpen a file to open + * @param parentsLibrary the parents library. If not null means opening a nested circuit + * @param circuit circuit to show */ - private Main(Component parent, File fileToOpen, SavedListener savedListener, ElementLibrary parentsLibrary, Circuit circuit) { + private Main(Component parent, File fileToOpen, ElementLibrary parentsLibrary, Circuit circuit) { super(Lang.get("digital")); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); setIconImages(IconCreator.createImages("icon32.png", "icon64.png", "icon128.png")); - this.savedListener = savedListener; - isParentsLibrary = parentsLibrary != null; - if (isParentsLibrary) this.library = parentsLibrary; + isNestedFile = parentsLibrary != null; + if (isNestedFile) this.library = parentsLibrary; else library = new ElementLibrary(); shapeFactory = new ShapeFactory(library, Settings.getInstance().get(Keys.SETTINGS_IEEE_SHAPES)); fileHistory = new FileHistory(this); - final boolean normalMode = savedListener == null; - if (circuit != null) { - circuitComponent = new CircuitComponent(this, library, shapeFactory, savedListener); + circuitComponent = new CircuitComponent(this, library, shapeFactory); SwingUtilities.invokeLater(() -> circuitComponent.setCircuit(circuit)); } else { - circuitComponent = new CircuitComponent(this, library, shapeFactory, savedListener); + circuitComponent = new CircuitComponent(this, library, shapeFactory); if (fileToOpen != null) { SwingUtilities.invokeLater(() -> loadFile(fileToOpen, false)); } else { @@ -193,6 +192,8 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E } } + library.addListener(circuitComponent); + getContentPane().add(circuitComponent); componentOnPane = circuitComponent; @@ -204,7 +205,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E JMenuBar menuBar = new JMenuBar(); JToolBar toolBar = new JToolBar(); - save = createFileMenu(menuBar, toolBar, normalMode); + save = createFileMenu(menuBar, toolBar); toolBar.addSeparator(); createViewMenu(menuBar, toolBar); @@ -236,6 +237,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E timerExecuter.shutdown(); library.removeListener(librarySelector); library.removeListener(insertHistory); + library.removeListener(circuitComponent); if (treeModel != null) library.removeListener(treeModel); } @@ -344,12 +346,11 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E /** * Creates the file menu and adds it to menu and toolbar * - * @param menuBar the menuBar - * @param toolBar the toolBar - * @param normalMode if false, menu is added in nested mode + * @param menuBar the menuBar + * @param toolBar the toolBar * @return the save action */ - private ToolTipAction createFileMenu(JMenuBar menuBar, JToolBar toolBar, boolean normalMode) { + private ToolTipAction createFileMenu(JMenuBar menuBar, JToolBar toolBar) { ToolTipAction newFile = new ToolTipAction(Lang.get("menu_new"), ICON_NEW) { @Override public void actionPerformed(ActionEvent e) { @@ -359,7 +360,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E windowPosManager.closeAll(); } } - }.setActive(normalMode); + }.setActive(!isNestedFile); ToolTipAction open = new ToolTipAction(Lang.get("menu_open"), ICON_OPEN) { @Override @@ -371,33 +372,33 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E } } } - }.setActive(normalMode); + }.setActive(!isNestedFile); ToolTipAction openWin = new ToolTipAction(Lang.get("menu_openWin"), ICON_OPEN_WIN) { @Override public void actionPerformed(ActionEvent e) { JFileChooser fc = getJFileChooser(lastFilename); if (fc.showOpenDialog(Main.this) == JFileChooser.APPROVE_OPTION) { - Main m = new Main(Main.this, fc.getSelectedFile(), null, null); + Main m = new Main(Main.this, fc.getSelectedFile(), null); m.setLocationRelativeTo(Main.this); m.setVisible(true); } } - }.setToolTip(Lang.get("menu_openWin_tt")).setActive(normalMode); + }.setToolTip(Lang.get("menu_openWin_tt")).setActive(!isNestedFile); JMenu openRecent = new JMenu(Lang.get("menu_openRecent")); fileHistory.setMenu(openRecent); - openRecent.setEnabled(normalMode); + openRecent.setEnabled(!isNestedFile); ToolTipAction saveas = new ToolTipAction(Lang.get("menu_saveAs"), ICON_SAVE_AS) { @Override public void actionPerformed(ActionEvent e) { JFileChooser fc = getJFileChooser(lastFilename); if (fc.showSaveDialog(Main.this) == JFileChooser.APPROVE_OPTION) { - saveFile(fc.getSelectedFile(), normalMode); + saveFile(fc.getSelectedFile()); } } - }.setActive(normalMode); + }.setActive(!isNestedFile); ToolTipAction save = new ToolTipAction(Lang.get("menu_save"), ICON_SAVE) { @Override @@ -405,7 +406,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E if (filename == null) saveas.actionPerformed(e); else - saveFile(filename, normalMode); + saveFile(filename); } }; @@ -913,14 +914,13 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E } } - private void saveFile(File filename, boolean toPrefs) { + private void saveFile(File filename) { filename = checkSuffix(filename, "dig"); try { circuitComponent.getCircuit().save(filename); - if (savedListener != null) - savedListener.saved(filename); stoppedState.enter(); - setFilename(filename, toPrefs); + setFilename(filename, !isNestedFile); + library.invalidateElement(filename); } catch (IOException e) { new ErrorMessage(Lang.get("msg_errorWritingFile")).addCause(e).show(); } @@ -931,12 +931,12 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E this.filename = filename; if (filename != null) { this.lastFilename = filename; - if (!isParentsLibrary) library.setFilePath(filename.getParentFile()); + if (!isNestedFile) library.setFilePath(filename.getParentFile()); if (toPrefs) fileHistory.add(filename); setTitle(filename + " - " + Lang.get("digital")); } else { - if (!isParentsLibrary) library.setFilePath(null); + if (!isNestedFile) library.setFilePath(null); setTitle(Lang.get("digital")); } } catch (IOException e) { diff --git a/src/main/java/de/neemann/digital/gui/SavedListener.java b/src/main/java/de/neemann/digital/gui/SavedListener.java deleted file mode 100644 index 52466d49a..000000000 --- a/src/main/java/de/neemann/digital/gui/SavedListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.neemann.digital.gui; - -import java.io.File; - -/** - * @author hneemann - */ -public interface SavedListener { - /** - * Method is called if file is changed - * - * @param filename the changed file - */ - void saved(File filename); -} diff --git a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java index 60b7023c6..e6a66a1e1 100644 --- a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java +++ b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java @@ -14,10 +14,11 @@ import de.neemann.digital.draw.elements.*; import de.neemann.digital.draw.graphics.*; import de.neemann.digital.draw.library.ElementLibrary; import de.neemann.digital.draw.library.ElementNotFoundException; +import de.neemann.digital.draw.library.LibraryListener; +import de.neemann.digital.draw.library.LibraryNode; import de.neemann.digital.draw.shapes.Drawable; import de.neemann.digital.draw.shapes.ShapeFactory; import de.neemann.digital.gui.Main; -import de.neemann.digital.gui.SavedListener; import de.neemann.digital.gui.sync.NoSync; import de.neemann.digital.gui.sync.Sync; import de.neemann.digital.lang.Lang; @@ -50,7 +51,7 @@ import static java.awt.event.InputEvent.CTRL_DOWN_MASK; * * @author hneemann */ -public class CircuitComponent extends JComponent implements Circuit.ChangedListener { +public class CircuitComponent extends JComponent implements Circuit.ChangedListener, LibraryListener { /** * The delete icon, also used from {@link de.neemann.digital.gui.components.terminal.TerminalDialog} */ @@ -62,7 +63,6 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe private final Main parent; private final ElementLibrary library; - private final SavedListener parentsSavedListener; private final HashSet highLighted; private final ToolTipAction deleteAction; @@ -97,10 +97,9 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe * @param library the library used to edit the attributes of the elements * @param shapeFactory the shapeFactory used for copied elements */ - public CircuitComponent(Main parent, ElementLibrary library, ShapeFactory shapeFactory, SavedListener parentsSavedListener) { + public CircuitComponent(Main parent, ElementLibrary library, ShapeFactory shapeFactory) { this.parent = parent; this.library = library; - this.parentsSavedListener = parentsSavedListener; highLighted = new HashSet<>(); rotateAction = new AbstractAction(Lang.get("menu_rotate")) { @@ -456,7 +455,7 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe circuit.drawTo(gr, highLighted, modelSync); highlightedPaintedSize = highLighted.size(); hasChanged = false; -// System.out.println(System.currentTimeMillis() - time); // -agentlib:hprof=cpu=samples +// LOGGER.debug("repaint: " + Long.toString(System.currentTimeMillis() - time) + "ms"); } g.drawImage(buffer, 0, 0, null); @@ -593,14 +592,7 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe public void actionPerformed(ActionEvent e) { attributeDialog.dispose(); SwingUtilities.invokeLater(() -> new Main(CircuitComponent.this, - ((ElementLibrary.ElementTypeDescriptionCustom) elementType).getFile(), - filename -> { - if (parentsSavedListener != null) - parentsSavedListener.saved(filename); - library.removeElement(filename); - circuit.clearState(); - hasChanged(); - }, library).setVisible(true)); + ((ElementLibrary.ElementTypeDescriptionCustom) elementType).getFile(), library).setVisible(true)); } }.setToolTip(Lang.get("attr_openCircuit_tt"))); } @@ -624,6 +616,13 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe } } + @Override + public void libraryChanged(LibraryNode node) { + circuit.clearState(); + hasChanged = true; + repaint(); + } + private class MouseDispatcher extends MouseAdapter implements MouseMotionListener { private Vector pos; private boolean isMoved;