1 package jalview.io.cache;
3 import jalview.bin.Cache;
4 import jalview.util.MessageManager;
7 import java.awt.Dimension;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.awt.event.KeyEvent;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collections;
14 import java.util.LinkedHashSet;
15 import java.util.List;
18 import javax.swing.BorderFactory;
19 import javax.swing.JComboBox;
20 import javax.swing.JLabel;
21 import javax.swing.JMenuItem;
22 import javax.swing.JPanel;
23 import javax.swing.JPopupMenu;
24 import javax.swing.JTextField;
25 import javax.swing.SwingUtilities;
26 import javax.swing.text.AttributeSet;
27 import javax.swing.text.BadLocationException;
28 import javax.swing.text.PlainDocument;
30 public class JvCacheableInputBox<E> extends JComboBox<String>
33 private static final long serialVersionUID = 5774610435079326695L;
35 private static final int INPUT_LIMIT = 2;
37 private static final int LEFT_BOARDER_WIDTH = 16;
39 private String cacheKey;
41 private AppCache appCache;
43 private JPanel pnlDefaultCache = new JPanel();
45 private JLabel lblDefaultCacheSize = new JLabel();
47 private JTextField txtDefaultCacheSize = new JTextField();
49 private JPopupMenu popup = new JPopupMenu();
51 private JMenuItem menuItemClearCache = new JMenuItem();
53 public JvCacheableInputBox(String newCacheKey)
56 this.cacheKey = newCacheKey;
58 setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
59 appCache = AppCache.getInstance();
61 initCache(newCacheKey);
66 * Method for initialising cache items for a given cache key and populating
67 * the in-memory cache with persisted cache items
71 private void initCache(String cacheKey)
73 // obtain persisted cache items from properties file as a delimited string
74 String delimitedCacheStr = Cache.getProperty(cacheKey);
75 if (delimitedCacheStr == null || delimitedCacheStr.isEmpty())
79 // convert delimited cache items to a list of strings
80 List<String> persistedCacheItems = Arrays.asList(delimitedCacheStr
81 .split(AppCache.CACHE_DELIMITER));
83 LinkedHashSet<String> foundCacheItems = appCache
84 .getAllCachedItemsFor(cacheKey);
85 if (foundCacheItems == null)
87 foundCacheItems = new LinkedHashSet<String>();
89 // populate memory cache
90 for (String cacheItem : persistedCacheItems)
92 foundCacheItems.add(cacheItem);
94 appCache.putCache(cacheKey, foundCacheItems);
98 * Initialise this cache's pop-up menu
100 private void initCachePopupMenu()
102 pnlDefaultCache.setBackground(Color.WHITE);
103 // pad panel so as to align with other menu items
104 pnlDefaultCache.setBorder(BorderFactory.createEmptyBorder(0,
105 LEFT_BOARDER_WIDTH, 0, 0));
106 txtDefaultCacheSize.setPreferredSize(new Dimension(45, 20));
107 txtDefaultCacheSize.setFont(new java.awt.Font("Verdana", 0, 12));
108 lblDefaultCacheSize.setText(MessageManager
109 .getString("label.default_cache_size"));
110 lblDefaultCacheSize.setFont(new java.awt.Font("Verdana", 0, 12));
111 // Force input to accept only Integer entries up to length - INPUT_LIMIT
112 txtDefaultCacheSize.setDocument(new PlainDocument()
114 private static final long serialVersionUID = 1L;
117 public void insertString(int offs, String str, AttributeSet a)
118 throws BadLocationException
120 if (getLength() + str.length() <= INPUT_LIMIT && isInteger(str))
122 super.insertString(offs, str, a);
126 txtDefaultCacheSize.addKeyListener(new java.awt.event.KeyAdapter()
129 public void keyPressed(KeyEvent e)
131 if (e.getKeyCode() == KeyEvent.VK_ENTER)
140 txtDefaultCacheSize.setText(appCache.getCacheLimit(cacheKey));
141 pnlDefaultCache.add(lblDefaultCacheSize);
142 menuItemClearCache.setFont(new java.awt.Font("Verdana", 0, 12));
143 pnlDefaultCache.add(txtDefaultCacheSize);
144 menuItemClearCache.setText(MessageManager
145 .getString("action.clear_cached_items"));
146 menuItemClearCache.addActionListener(new ActionListener()
149 public void actionPerformed(ActionEvent e)
151 // System.out.println(">>>>> Clear cache items");
153 appCache.deleteCacheItems(cacheKey);
158 popup.insert(pnlDefaultCache, 0);
159 popup.add(menuItemClearCache);
160 setComponentPopupMenu(popup);
164 private void closePopup()
166 popup.setVisible(false);
167 popup.transferFocus();
171 * Answers true if input text is an integer
176 static boolean isInteger(String text)
180 Integer.parseInt(text);
182 } catch (NumberFormatException e)
189 * Method called to update the cache with the last user input
191 public void updateCache()
193 SwingUtilities.invokeLater(new Runnable()
198 int userLimit = txtDefaultCacheSize.getText().trim().isEmpty() ? Integer
199 .valueOf(AppCache.DEFAULT_LIMIT) : Integer
200 .valueOf(txtDefaultCacheSize.getText());
201 int cacheLimit = appCache.updateCacheLimit(cacheKey, userLimit);
202 String userInput = getUserInput();
203 if (userInput != null && !userInput.isEmpty())
205 LinkedHashSet<String> foundCache = appCache
206 .getAllCachedItemsFor(cacheKey);
207 // remove old cache item so as to place current input at the top of
209 foundCache.remove(userInput);
210 foundCache.add(userInput);
211 appCache.putCache(cacheKey, foundCache);
214 String lastSearch = userInput;
215 if (getItemCount() > 0)
219 Set<String> cacheItems = appCache.getAllCachedItemsFor(cacheKey);
220 List<String> reversedCacheItems = new ArrayList<String>();
221 reversedCacheItems.addAll(cacheItems);
223 Collections.reverse(reversedCacheItems);
224 if (lastSearch.isEmpty())
229 if (reversedCacheItems != null && !reversedCacheItems.isEmpty())
231 LinkedHashSet<String> foundCache = appCache
232 .getAllCachedItemsFor(cacheKey);
233 boolean prune = reversedCacheItems.size() > cacheLimit;
235 boolean limitExceeded = false;
236 for (String cacheItem : reversedCacheItems)
238 limitExceeded = (count++ > cacheLimit);
243 foundCache.remove(cacheItem);
255 appCache.putCache(cacheKey, foundCache);
257 setSelectedItem(lastSearch.isEmpty() ? "" : lastSearch);
264 * This method should be called to persist the in-memory cache when this
265 * components parent frame is closed / exited
267 public void persistCache()
269 appCache.persistCache(cacheKey);
270 int userLimit = txtDefaultCacheSize.getText().trim().isEmpty() ? Integer
271 .valueOf(AppCache.DEFAULT_LIMIT) : Integer
272 .valueOf(txtDefaultCacheSize.getText());
273 appCache.updateCacheLimit(cacheKey, userLimit);
277 * Method to obtain input text from the cache box
281 public String getUserInput()
283 return getEditor().getItem() == null ? "" : getEditor().getItem()