1 /* 2 * Copyright (c) 2016 Helmut Neemann 3 * Use of this source code is governed by the GPL v3 license 4 * that can be found in the LICENSE file. 5 */ 6 package de.neemann.digital.gui; 7 8 import de.neemann.digital.draw.library.ElementLibrary; 9 import de.neemann.digital.draw.library.LibraryListener; 10 import de.neemann.digital.draw.library.LibraryNode; 11 12 import javax.swing.*; 13 import java.awt.event.ActionEvent; 14 import java.util.ArrayList; 15 import java.util.Iterator; 16 17 /** 18 * The InsertHistory puts the most frequently used elements to the toolbar of the main window. 19 * So its easier to build circuits. 20 */ 21 public class InsertHistory implements LibraryListener { 22 private static final int MAX_ICONS = 6; 23 private final JToolBar bar; 24 private final ElementLibrary library; 25 private final ArrayList<WrapperAction> wrappers; 26 private int mainTime; 27 private InsertAction lastInsertAction; 28 29 /** 30 * Creates a new instance 31 * 32 * @param bar the toolbar to put the elements to 33 * @param library the library to use 34 */ InsertHistory(JToolBar bar, ElementLibrary library)35 public InsertHistory(JToolBar bar, ElementLibrary library) { 36 this.bar = bar; 37 this.library = library; 38 wrappers = new ArrayList<>(); 39 } 40 41 /** 42 * Add an action to the toolbar. 43 * The given action is wrapped by an action which counts the usage. 44 * So its possible to remove the item which is not used the longest time when the toolbar becomes to large. 45 * 46 * @param action the action 47 */ add(InsertAction action)48 public void add(InsertAction action) { 49 lastInsertAction = action; 50 if (!contains(action)) { 51 WrapperAction wrapper = new WrapperAction(action, bar.getComponentCount()); 52 wrappers.add(wrapper); 53 bar.add(wrapper).setToolTipText(action.getNode().getToolTipText()); 54 if (wrappers.size() > MAX_ICONS) { 55 int oldest = findOldestIndex(); 56 removeWrapperFromToolBar(wrappers.get(oldest)); 57 wrappers.remove(oldest); 58 } 59 } 60 } 61 removeWrapperFromToolBar(WrapperAction wrapper)62 private void removeWrapperFromToolBar(WrapperAction wrapper) { 63 final int position = wrapper.componentPosition; 64 bar.remove(position); 65 for (WrapperAction w : wrappers) 66 if (w.componentPosition > position) 67 w.componentPosition--; 68 } 69 findOldestIndex()70 private int findOldestIndex() { 71 int found = -1; 72 int oldestTime = mainTime; 73 for (int i = 0; i < wrappers.size(); i++) { 74 WrapperAction wrapper = wrappers.get(i); 75 if (wrapper.time < oldestTime) { 76 found = i; 77 oldestTime = wrapper.time; 78 } 79 } 80 return found; 81 } 82 contains(InsertAction action)83 private boolean contains(InsertAction action) { 84 for (WrapperAction wrapper : wrappers) 85 if (wrapper.action.getName().equals(action.getName())) 86 return true; 87 return false; 88 } 89 90 /** 91 * @return the last insert action 92 */ getLastInsertAction()93 public InsertAction getLastInsertAction() { 94 return lastInsertAction; 95 } 96 97 @Override libraryChanged(LibraryNode node)98 public void libraryChanged(LibraryNode node) { 99 updateCustomComponents(); 100 } 101 102 /** 103 * Updates all custom components. 104 * If the component no longer exists, it is deleted from the history toolbar. 105 */ updateCustomComponents()106 private void updateCustomComponents() { 107 Iterator<WrapperAction> it = wrappers.iterator(); 108 while (it.hasNext()) { 109 WrapperAction w = it.next(); 110 if (w.action.isCustom()) { 111 LibraryNode n = library.getElementNodeOrNull(w.action.getName()); 112 if (n == null) { // is'nt there, so delete 113 removeWrapperFromToolBar(w); 114 it.remove(); 115 } else 116 w.update(n); 117 } 118 } 119 bar.revalidate(); 120 } 121 122 private final class WrapperAction extends AbstractAction { 123 private final InsertAction action; 124 private int componentPosition; 125 private int time; 126 WrapperAction(InsertAction action, int componentPosition)127 private WrapperAction(InsertAction action, int componentPosition) { 128 super(action.getValue(Action.NAME).toString(), (Icon) action.getValue(Action.SMALL_ICON)); 129 this.action = action; 130 this.componentPosition = componentPosition; 131 time = mainTime++; 132 } 133 134 @Override actionPerformed(ActionEvent e)135 public void actionPerformed(ActionEvent e) { 136 action.actionPerformed(e); 137 time = mainTime++; 138 } 139 update(LibraryNode n)140 public void update(LibraryNode n) { 141 action.update(n); 142 putValue(Action.SMALL_ICON, action.getValue(Action.SMALL_ICON)); 143 } 144 } 145 } 146