From d544797047954b9a73f6c135cb71efeaf0560192 Mon Sep 17 00:00:00 2001 From: Branislav Stojkovic Date: Sat, 9 Mar 2019 10:42:39 +0100 Subject: [PATCH] Ability to tag components and building blocks as favorites --- .../src/org/diylc/common/Favorite.java | 88 +++++++++++ .../src/org/diylc/common/IPlugInPort.java | 3 +- .../src/org/diylc/images/IconLoader.java | 2 +- .../src/org/diylc/images/star_blue.png | Bin 0 -> 877 bytes .../diylc/swing/plugins/tree/TreePanel.java | 138 +++++++++++++++++- diylc/diylc-swing/update.xml | 6 +- 6 files changed, 229 insertions(+), 8 deletions(-) create mode 100644 diylc/diylc-core/src/org/diylc/common/Favorite.java create mode 100644 diylc/diylc-swing/src/org/diylc/images/star_blue.png diff --git a/diylc/diylc-core/src/org/diylc/common/Favorite.java b/diylc/diylc-core/src/org/diylc/common/Favorite.java new file mode 100644 index 00000000..b102c12f --- /dev/null +++ b/diylc/diylc-core/src/org/diylc/common/Favorite.java @@ -0,0 +1,88 @@ +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2018 held jointly by the individual authors. + + This file is part of DIYLC. + + DIYLC is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DIYLC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DIYLC. If not, see . + +*/ +package org.diylc.common; + +import java.io.Serializable; + +public class Favorite implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + private FavoriteType type; + private String name; + + public Favorite(FavoriteType type, String name) { + super(); + this.type = type; + this.name = name; + } + + public FavoriteType getType() { + return type; + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Favorite other = (Favorite) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (type != other.type) + return false; + return true; + } + + @Override + public String toString() { + return type + ":" + name; + } + + public enum FavoriteType { + Component, Block + } + + @Override + public int compareTo(Favorite o) { + return name.compareToIgnoreCase(o.getName()); + } +} diff --git a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java index 4972d299..c1871f81 100644 --- a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java +++ b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java @@ -74,7 +74,8 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP public static final String SHOW_GRID_KEY = "showGrid"; public static final String HIGHLIGHT_CONTINUITY_AREA = "highlightContinuityArea"; public static final String HARDWARE_ACCELERATION = "hardwareAcceleration"; - public static final String EXTRA_SPACE_KEY = "extraSpace"; + public static final String EXTRA_SPACE_KEY = "extraSpace"; + public static final String FAVORITES_KEY = "favorites"; public static final int DND_TOGGLE_STICKY = 0x1; public static final int DND_TOGGLE_SNAP = 0x40000000; diff --git a/diylc/diylc-swing/src/org/diylc/images/IconLoader.java b/diylc/diylc-swing/src/org/diylc/images/IconLoader.java index 127c37dd..dade75d4 100644 --- a/diylc/diylc-swing/src/org/diylc/images/IconLoader.java +++ b/diylc/diylc-swing/src/org/diylc/images/IconLoader.java @@ -63,7 +63,7 @@ public enum IconLoader { "component_add.png"), History("history.png"), DocumentPlain("document_plain.png"), FitToSize("fit_to_size.png"), DocumentsGear( "documents_gear.png"), SplashResistor("splash_resistor.png"), SplashCeramic("splash_ceramic.png"), SplashElectrolytic( "splash_electrolytic.png"), SplashFilm("splash_film.png"), Splash("splash.png"), Help("help2.png"), ScrollInformation("scroll_information.png"), - Node("node.png"), Web("web.png"), Guitar("guitar.png"), Scientist("scientist.png"); + Node("node.png"), Web("web.png"), Guitar("guitar.png"), Scientist("scientist.png"), StarGrey("star_grey.png"), StarBlue("star_blue.png"); protected String name; diff --git a/diylc/diylc-swing/src/org/diylc/images/star_blue.png b/diylc/diylc-swing/src/org/diylc/images/star_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..711f71550c16b55d68b68e532c3d533cf0b770fe GIT binary patch literal 877 zcmV-z1CsoSP)WdKBPATcx`PH%P~GB7YQATlyKGBY|bHy|r8F)%PGAKq60000McNliru z)&&<0Gc?eew-NvV010qNS#tmY3lRVS3lRZ-WM7d0000DMK}|sb0I`n?{9y$E00PBH zL_t(|+Le=8NK|1I$N%@5R)vnhR5kgbR{BlvuPA8buMk^io0umGss_Jp>U1 z!Vta~fnWq$kXd0_5+TV%3yR@Z<}#(G(>UYIcxQ3$(z!O3lo5UKgO79m=X~dU-}!*Q ztjs2{(bnL1(AG?7@L$UjuDa>;%GaKGWRx5^P8KV{t|nd8Xw$N%H}Z>2MUueqrH5+B zWGD3hO2900(U)7D?mIBGs9;u5u(zUYJB-$1@}rM1 zL}aw|`S9jb2;QgyA0>U>?-9Ekb+h;m zG(B>xJfcE)3A3+NZ4dF1aI3LDCQL+SeO`HiiCLGyV<{$sqy9l%#zYCco<-4yWPaFW z4|wgGp{Tg;Rok<{ED z6IFC&qH{)3lv8ak5hZo^!Rng9862p%)PAmgQu;zZ^UnIGBt07cA3vw>`{rQB8Jpf+ zGt+T-6u~iiOuQoomo=8Et(oQf_f7Xb9Kl?-lWdRUckn9#tu;g`kwr`qqw!u recentComponents; + private List favorites; private List blocks; private IPlugInPort plugInPort; private ISwingUI swingUI; + private boolean initializing = false; private JPopupMenu popup; @@ -142,7 +148,7 @@ public class TreePanel extends JPanel { LOG.info("Detected recent component change"); refreshRecentComponents(newComponents); } else - LOG.info("Detected no recent component change"); + LOG.info("Detected no recent component change"); TreePanel.this.recentComponents = new ArrayList(newComponents); } }); @@ -174,6 +180,20 @@ public class TreePanel extends JPanel { repaint(); } }); + + ConfigurationManager.getInstance().addConfigListener(IPlugInPort.FAVORITES_KEY, new IConfigListener() { + + @SuppressWarnings("unchecked") + @Override + public void valueChanged(String key, Object value) { + List newFavorites = (List) value; + if (newFavorites != null && !newFavorites.equals(TreePanel.this.favorites)) { + LOG.info("Detected favorites change"); + refreshFavorites(newFavorites); + } else + LOG.info("Detected no favorites change"); + } + }); getTree().expandRow(0); @@ -199,6 +219,7 @@ public class TreePanel extends JPanel { public DefaultMutableTreeNode getRecentNode() { if (this.recentNode == null) { this.recentNode = new DefaultMutableTreeNode(new Payload("(Recently Used)", null), true); + @SuppressWarnings("unchecked") List recent = (List) ConfigurationManager.getInstance().readObject(IPlugInPort.RECENT_COMPONENTS_KEY, null); @@ -215,6 +236,7 @@ public class TreePanel extends JPanel { public DefaultMutableTreeNode getBlocksNode() { if (this.blocksNode == null) { this.blocksNode = new DefaultMutableTreeNode(new Payload("(Building Blocks)", null), true); + @SuppressWarnings("unchecked") Map>> newBlocks = (Map>>) ConfigurationManager.getInstance().readObject( @@ -223,13 +245,27 @@ public class TreePanel extends JPanel { List blockNames = new ArrayList(newBlocks.keySet()); Collections.sort(blockNames); refreshBuildingBlocks(blockNames); - this.blocks = blockNames; } else { this.blocks = new ArrayList(); } } return this.blocksNode; } + + public DefaultMutableTreeNode getFavoritesNode() { + if (this.favoritesNode == null) { + this.favoritesNode = new DefaultMutableTreeNode(new Payload("(Favorites)", null), true); + + @SuppressWarnings("unchecked") + List favorites = (List) ConfigurationManager.getInstance().readObject(IPlugInPort.FAVORITES_KEY, null); + if (favorites != null) { + refreshFavorites(favorites); + } else { + this.favorites = new ArrayList(); + } + } + return this.favoritesNode; + } @SuppressWarnings("unchecked") private void refreshRecentComponents(List recentComponentClassList) { @@ -260,7 +296,8 @@ public class TreePanel extends JPanel { LOG.error("Could not create recent component button for " + componentClassName, e); } } - getTreeModel().nodeStructureChanged(getRecentNode()); + if (!initializing) + getTreeModel().nodeStructureChanged(getRecentNode()); } private void refreshBuildingBlocks(List blocks) { @@ -291,14 +328,72 @@ public class TreePanel extends JPanel { payload.setVisible(visible); getBlocksNode().add(componentNode); } - getTreeModel().nodeStructureChanged(getBlocksNode()); + if (!initializing) + getTreeModel().nodeStructureChanged(getBlocksNode()); + } + + private void refreshFavorites(List favorites) { + this.favorites = new ArrayList(favorites); + + getFavoritesNode().removeAllChildren(); + + Map> types = plugInPort.getComponentTypes(); + Map typesByClass = new HashMap(); + for (Map.Entry> e : types.entrySet()) + for (ComponentType c : e.getValue()) + typesByClass.put(c.getInstanceClass().getCanonicalName(), c); + + for (Favorite f : favorites) { + if (f.getType() == FavoriteType.Component) { + final ComponentType type = typesByClass.get(f.getName()); + if (type != null) { + DefaultMutableTreeNode componentNode = new DefaultMutableTreeNode(new Payload(type, new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + plugInPort.setNewComponentTypeSlot(type, null, false); + } + }), false); + getFavoritesNode().add(componentNode); + } + } else if (f.getType() == FavoriteType.Block) { + final String block = f.getName(); + Payload payload = new Payload(block, new MouseAdapter() { + + long previousActionTime = 0; + + @Override + public void mouseClicked(MouseEvent e) { + if (e == null || SwingUtilities.isLeftMouseButton(e) && System.currentTimeMillis() - previousActionTime > 100) { + previousActionTime = System.currentTimeMillis(); + try { + plugInPort.loadBlock(block); + } catch (InvalidBlockException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + }); + final DefaultMutableTreeNode componentNode = new DefaultMutableTreeNode(payload, false); + String text = getSearchField().getText(); + boolean visible = text.trim().length() == 0 || block.toLowerCase().contains(text.toLowerCase()); + payload.setVisible(visible); + getFavoritesNode().add(componentNode); + } + } + if (!initializing) + getTreeModel().nodeStructureChanged(getFavoritesNode()); } public DefaultTreeModel getTreeModel() { if (treeModel == null) { final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Components", true); + initializing = true; + rootNode.add(getFavoritesNode()); rootNode.add(getRecentNode()); rootNode.add(getBlocksNode()); + initializing = false; Map> componentTypes = plugInPort.getComponentTypes(); List categories = new ArrayList(componentTypes.keySet()); Collections.sort(categories); @@ -317,6 +412,18 @@ public class TreePanel extends JPanel { } } treeModel = new DefaultTreeModel(rootNode); + treeModel.addTreeModelListener(new TreeModelAdapter() { + @Override + public void treeNodesRemoved(TreeModelEvent e) { + super.treeNodesRemoved(e); + } + + @Override + public void treeNodesChanged(TreeModelEvent e) { + // TODO Auto-generated method stub + super.treeNodesChanged(e); + } + }); } return treeModel; } @@ -459,6 +566,27 @@ public class TreePanel extends JPanel { }); shortcutSubmenu.add(item); } + + final Favorite fav = new Favorite(componentType == null ? FavoriteType.Block : FavoriteType.Component, componentType == null ? payload.toString() : componentType.getInstanceClass() + .getCanonicalName()); + final boolean isFavorite = favorites != null && favorites.indexOf(fav) >= 0; + final JMenuItem favoritesItem = new JMenuItem(isFavorite ? "Remove From Favorites" : "Add To Favorites", + isFavorite ? IconLoader.StarBlue.getIcon() : IconLoader.StarGrey.getIcon()); + favoritesItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + List favorites = new ArrayList(TreePanel.this.favorites); + if (isFavorite) { + favorites.remove(fav); + } else { + favorites.add(fav); + Collections.sort(favorites); + } + ConfigurationManager.getInstance().writeValue(IPlugInPort.FAVORITES_KEY, favorites); + } + }); + popup.add(favoritesItem); if (componentType != null) { popup.add(new SelectAllAction(plugInPort, componentType)); diff --git a/diylc/diylc-swing/update.xml b/diylc/diylc-swing/update.xml index 58398335..29a62f28 100644 --- a/diylc/diylc-swing/update.xml +++ b/diylc/diylc-swing/update.xml @@ -2577,7 +2577,11 @@ 2019-03-02 00:00:00.000 CET - + + + NEW_FEATURE + Ability to tag components and building blocks as favorites + BUG_FIX "Highlight Connected Areas" doesn't follow multiple chained wires and jumpers