Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.io.cache

File JvCacheableInputBox.java

 

Coverage histogram

../../../img/srcFileCovDistChart7.png
29% of files have more coverage

Code metrics

50
112
22
1
420
297
51
0.46
5.09
22
2.32

Classes

Class Line # Actions
JvCacheableInputBox 63 112 51
0.641304464.1%
 

Contributing tests

This file is covered by 6 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.io.cache;
22   
23    import java.awt.Dimension;
24    import java.awt.FontMetrics;
25    import java.awt.event.ActionEvent;
26    import java.awt.event.ActionListener;
27    import java.awt.event.FocusListener;
28    import java.awt.event.KeyAdapter;
29    import java.awt.event.KeyEvent;
30    import java.awt.event.KeyListener;
31    import java.util.ArrayList;
32    import java.util.Arrays;
33    import java.util.Collections;
34    import java.util.LinkedHashSet;
35    import java.util.List;
36    import java.util.Set;
37   
38    import javax.swing.JComboBox;
39    import javax.swing.JComponent;
40    import javax.swing.JMenuItem;
41    import javax.swing.JPopupMenu;
42    import javax.swing.JTextField;
43    import javax.swing.SwingUtilities;
44    import javax.swing.event.CaretListener;
45    import javax.swing.event.DocumentListener;
46    import javax.swing.text.JTextComponent;
47   
48    import jalview.bin.Cache;
49    import jalview.util.MessageManager;
50    import jalview.util.Platform;
51   
52    /**
53    * A class that provides an editable combobox with a memory of previous entries
54    * that may be persisted
55    *
56    * @author tcofoegbu
57    *
58    * @param <E>
59    */
60    /*
61    * (temporary?) patches to wrap a JTextField instead when running as Javascript
62    */
 
63    public class JvCacheableInputBox<E>
64    {
65    protected JComboBox<String> comboBox; // used for Jalview
66   
67    protected JTextField textField; // used for JalviewJS
68   
69    protected JTextComponent textComponent; // used for both
70   
71    protected String cacheKey;
72   
73    protected AppCache appCache;
74   
75    private JPopupMenu popup = new JPopupMenu();
76   
77    private JMenuItem menuItemClearCache = new JMenuItem();
78   
79    volatile boolean enterWasPressed = false;
80   
81    private String prototypeDisplayValue;
82   
83    /**
84    * @return flag indicating if the most recent keypress was enter
85    */
 
86  0 toggle public boolean wasEnterPressed()
87    {
88  0 return enterWasPressed;
89    }
90   
91    /**
92    * Constructor given the key to cached values, and the (approximate) length in
93    * characters of the input field
94    *
95    * @param newCacheKey
96    * @param length
97    */
 
98  8 toggle public JvCacheableInputBox(String newCacheKey, int length)
99    {
100    // super();
101  8 cacheKey = newCacheKey;
102  8 prototypeDisplayValue = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
103  8 if (length > 0)
104    {
105  8 StringBuilder sb = new StringBuilder();
106  224 for (int i = 0; i < length; i++)
107    {
108  216 sb.append("X");
109    }
110  8 setPrototypeDisplayValue(sb.toString());
111    }
112  8 boolean useTextField = Platform.isJS();
113    // BH 2019.03 only switch for JavaScript here
114    // SwingJS TODO implement editable combo box
115  8 if (useTextField)
116    {
117  0 appCache = null;
118  0 textComponent = textField = new JTextField();
119  0 FontMetrics fm = textField.getFontMetrics(textField.getFont());
120  0 textField.setPreferredSize(new Dimension(
121    fm.stringWidth(prototypeDisplayValue), fm.getHeight() + 4));
122    // {
123    // @Override
124    // public Dimension getPreferredSize() {
125    // return super.getPreferredSize();
126    //// FontMetrics fm = getFontMetrics(getFont());
127    //// return new Dimension(fm.stringWidth(prototypeDisplayValue),
128    // fm.getHeight());
129    // }
130    // };
131    }
132    else
133    {
134  8 appCache = AppCache.getInstance();
135  8 comboBox = new JComboBox<>();
136  8 textComponent = (JTextComponent) comboBox.getEditor()
137    .getEditorComponent();
138  8 comboBox.setEditable(true);
139  8 comboBox.addKeyListener(new KeyAdapter()
140    {
 
141  0 toggle @Override
142    public void keyTyped(KeyEvent e)
143    {
144  0 enterWasPressed = false;
145  0 if (e.getKeyCode() == KeyEvent.VK_ENTER)
146    {
147  0 enterWasPressed = true;
148    }
149    // let event bubble up
150    }
151    });
152  8 comboBox.setPrototypeDisplayValue(prototypeDisplayValue);
153  8 initCachePopupMenu();
154  8 initCache(newCacheKey);
155  8 updateCache();
156    }
157    }
158   
159    /**
160    * Method for initialising cache items for a given cache key and populating
161    * the in-memory cache with persisted cache items
162    *
163    * @param cacheKey
164    */
 
165  8 toggle private void initCache(String cacheKey)
166    {
167  8 if (appCache == null)
168    {
169  0 return;
170    }
171    // obtain persisted cache items from properties file as a delimited string
172  8 String delimitedCacheStr = Cache.getProperty(cacheKey);
173  8 if (delimitedCacheStr == null || delimitedCacheStr.isEmpty())
174    {
175  8 return;
176    }
177    // convert delimited cache items to a list of strings
178  0 List<String> persistedCacheItems = Arrays
179    .asList(delimitedCacheStr.split(AppCache.CACHE_DELIMITER));
180   
181  0 LinkedHashSet<String> foundCacheItems = appCache
182    .getAllCachedItemsFor(cacheKey);
183  0 if (foundCacheItems == null)
184    {
185  0 foundCacheItems = new LinkedHashSet<>();
186    }
187    // populate memory cache
188  0 for (String cacheItem : persistedCacheItems)
189    {
190  0 foundCacheItems.add(cacheItem);
191    }
192  0 appCache.putCache(cacheKey, foundCacheItems);
193    }
194   
195    /**
196    * Initialise this cache's pop-up menu
197    */
 
198  8 toggle private void initCachePopupMenu()
199    {
200  8 if (appCache == null)
201    {
202  0 return;
203    }
204  8 menuItemClearCache.setFont(new java.awt.Font("Verdana", 0, 12));
205  8 menuItemClearCache
206    .setText(MessageManager.getString("action.clear_cached_items"));
207  8 menuItemClearCache.addActionListener(new ActionListener()
208    {
 
209  0 toggle @Override
210    public void actionPerformed(ActionEvent e)
211    {
212    // jalview.bin.Console.outPrintln(">>>>> Clear cache items");
213  0 setSelectedItem("");
214  0 appCache.deleteCacheItems(cacheKey);
215  0 updateCache();
216    }
217    });
218   
219  8 popup.add(menuItemClearCache);
220  8 comboBox.setComponentPopupMenu(popup);
221  8 comboBox.add(popup);
222    }
223   
224    /**
225    * Answers true if input text is an integer
226    *
227    * @param text
228    * @return
229    */
 
230  0 toggle static boolean isInteger(String text)
231    {
232  0 try
233    {
234  0 Integer.parseInt(text);
235  0 return true;
236    } catch (NumberFormatException e)
237    {
238  0 return false;
239    }
240    }
241   
242    /**
243    * Method called to update the cache with the last user input
244    */
 
245  11 toggle public void updateCache()
246    {
247  11 if (appCache == null)
248    {
249  0 return;
250    }
251  11 SwingUtilities.invokeLater(new Runnable()
252    {
 
253  11 toggle @Override
254    public void run()
255    {
256  11 int cacheLimit = Integer.parseInt(appCache.getCacheLimit(cacheKey));
257  11 String userInput = getUserInput();
258  11 if (userInput != null && !userInput.isEmpty())
259    {
260  1 LinkedHashSet<String> foundCache = appCache
261    .getAllCachedItemsFor(cacheKey);
262    // remove old cache item so as to place current input at the top of
263    // the result
264  1 foundCache.remove(userInput);
265  1 foundCache.add(userInput);
266  1 appCache.putCache(cacheKey, foundCache);
267    }
268   
269  11 String lastSearch = userInput;
270  11 if (comboBox.getItemCount() > 0)
271    {
272  3 comboBox.removeAllItems();
273    }
274  11 Set<String> cacheItems = appCache.getAllCachedItemsFor(cacheKey);
275  11 List<String> reversedCacheItems = new ArrayList<>();
276  11 reversedCacheItems.addAll(cacheItems);
277  11 cacheItems = null;
278  11 Collections.reverse(reversedCacheItems);
279  11 if (lastSearch.isEmpty())
280    {
281  10 comboBox.addItem("");
282    }
283   
284  11 if (reversedCacheItems != null && !reversedCacheItems.isEmpty())
285    {
286  1 LinkedHashSet<String> foundCache = appCache
287    .getAllCachedItemsFor(cacheKey);
288  1 boolean prune = reversedCacheItems.size() > cacheLimit;
289  1 int count = 1;
290  1 boolean limitExceeded = false;
291  1 for (String cacheItem : reversedCacheItems)
292    {
293  1 limitExceeded = (count++ > cacheLimit);
294  1 if (prune)
295    {
296  0 if (limitExceeded)
297    {
298  0 foundCache.remove(cacheItem);
299    }
300    else
301    {
302  0 comboBox.addItem(cacheItem);
303    }
304    }
305    else
306    {
307  1 comboBox.addItem(cacheItem);
308    }
309    }
310  1 appCache.putCache(cacheKey, foundCache);
311    }
312  11 setSelectedItem(lastSearch.isEmpty() ? "" : lastSearch);
313    }
314    });
315    }
316   
317    /**
318    * This method should be called to persist the in-memory cache when this
319    * components parent frame is closed / exited
320    */
 
321  2 toggle public void persistCache()
322    {
323  2 if (appCache == null)
324    {
325  0 return;
326    }
327  2 appCache.persistCache(cacheKey);
328    }
329   
330    /**
331    * Returns the trimmed text in the input field
332    *
333    * @return
334    */
 
335  15 toggle public String getUserInput()
336    {
337  15 if (comboBox == null)
338    {
339  0 return textField.getText().trim();
340    }
341  15 Object item = comboBox.getEditor().getItem();
342  15 return item == null ? "" : item.toString().trim();
343    }
344   
 
345  10 toggle public JComponent getComponent()
346    {
347  10 return (comboBox == null ? textField : comboBox);
348    }
349   
 
350  2 toggle public void addActionListener(ActionListener actionListener)
351    {
352  2 if (comboBox == null)
353    {
354  0 textField.addActionListener(actionListener);
355    }
356    else
357    {
358  2 comboBox.addActionListener(actionListener);
359    }
360    }
361   
 
362  2 toggle public void addDocumentListener(DocumentListener listener)
363    {
364  2 textComponent.getDocument().addDocumentListener(listener);
365    }
366   
 
367  4 toggle public void addFocusListener(FocusListener focusListener)
368    {
369  4 textComponent.addFocusListener(focusListener);
370    }
371   
 
372  4 toggle public void addKeyListener(KeyListener kl)
373    {
374  4 textComponent.addKeyListener(kl);
375    }
376   
 
377  0 toggle public void addCaretListener(CaretListener caretListener)
378    {
379  0 textComponent.addCaretListener(caretListener);
380    }
381   
 
382  0 toggle public void setEditable(boolean b)
383    {
384  0 if (comboBox != null)
385    {
386  0 comboBox.setEditable(b);
387    }
388    }
389   
 
390  8 toggle public void setPrototypeDisplayValue(String string)
391    {
392  8 prototypeDisplayValue = string;
393  8 if (comboBox != null)
394    {
395  0 comboBox.setPrototypeDisplayValue(string);
396    }
397    }
398   
 
399  13 toggle public void setSelectedItem(String userInput)
400    {
401  13 if (comboBox != null)
402    {
403  13 comboBox.setSelectedItem(userInput);
404    }
405    }
406   
 
407  0 toggle public boolean isPopupVisible()
408    {
409  0 return (comboBox != null && comboBox.isPopupVisible());
410    }
411   
 
412  2 toggle public void addItem(String item)
413    {
414  2 if (comboBox != null)
415    {
416  2 comboBox.addItem(item);
417    }
418    }
419   
420    }