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