root / branches / v10 / libraries / libUI / src / org / gvsig / gui / beans / comboBoxItemsSeeker / JComboBoxItemsSeekerConfigurable.java @ 8996
History | View | Annotate | Download (77.3 KB)
1 | 6721 | ppiqueras | package org.gvsig.gui.beans.comboBoxItemsSeeker; |
---|---|---|---|
2 | |||
3 | import java.awt.Color; |
||
4 | import java.awt.event.ActionEvent; |
||
5 | import java.awt.event.FocusAdapter; |
||
6 | import java.awt.event.FocusEvent; |
||
7 | import java.awt.event.FocusListener; |
||
8 | import java.awt.event.KeyAdapter; |
||
9 | import java.awt.event.KeyEvent; |
||
10 | import java.awt.event.KeyListener; |
||
11 | 6793 | ppiqueras | import java.awt.event.MouseAdapter; |
12 | import java.awt.event.MouseEvent; |
||
13 | 8765 | jjdelcerro | import java.awt.event.MouseWheelEvent; |
14 | import java.awt.event.MouseWheelListener; |
||
15 | 6721 | ppiqueras | import java.beans.PropertyChangeEvent; |
16 | import java.beans.PropertyChangeListener; |
||
17 | |||
18 | import javax.swing.ComboBoxEditor; |
||
19 | import javax.swing.ComboBoxModel; |
||
20 | import javax.swing.JComboBox; |
||
21 | import javax.swing.JOptionPane; |
||
22 | 8765 | jjdelcerro | import javax.swing.event.CaretListener; |
23 | 6721 | ppiqueras | import javax.swing.event.DocumentEvent; |
24 | import javax.swing.event.DocumentListener; |
||
25 | import javax.swing.event.ListDataEvent; |
||
26 | import javax.swing.event.ListDataListener; |
||
27 | import javax.swing.event.PopupMenuEvent; |
||
28 | import javax.swing.event.PopupMenuListener; |
||
29 | 6793 | ppiqueras | import javax.swing.event.UndoableEditEvent; |
30 | import javax.swing.event.UndoableEditListener; |
||
31 | 6721 | ppiqueras | import javax.swing.text.AttributeSet; |
32 | import javax.swing.text.BadLocationException; |
||
33 | import javax.swing.text.JTextComponent; |
||
34 | import javax.swing.text.PlainDocument; |
||
35 | 6816 | ppiqueras | import javax.swing.undo.CannotRedoException; |
36 | import javax.swing.undo.CannotUndoException; |
||
37 | 6793 | ppiqueras | import javax.swing.undo.UndoManager; |
38 | 6721 | ppiqueras | |
39 | 6732 | ppiqueras | import org.apache.log4j.Logger; |
40 | 7244 | cesar | import org.gvsig.gui.beans.Messages; |
41 | 6816 | ppiqueras | import org.gvsig.gui.beans.optionsEditionByMousePopupMenu.JOptionsEditionByMousePopupMenu; |
42 | 6721 | ppiqueras | |
43 | /* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
||
44 | *
|
||
45 | * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
|
||
46 | *
|
||
47 | * This program is free software; you can redistribute it and/or
|
||
48 | * modify it under the terms of the GNU General Public License
|
||
49 | * as published by the Free Software Foundation; either version 2
|
||
50 | * of the License, or (at your option) any later version.
|
||
51 | *
|
||
52 | * This program is distributed in the hope that it will be useful,
|
||
53 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
54 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
55 | * GNU General Public License for more details.
|
||
56 | *
|
||
57 | * You should have received a copy of the GNU General Public License
|
||
58 | * along with this program; if not, write to the Free Software
|
||
59 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
||
60 | *
|
||
61 | * For more information, contact:
|
||
62 | *
|
||
63 | * Generalitat Valenciana
|
||
64 | * Conselleria d'Infraestructures i Transport
|
||
65 | * Av. Blasco Ib??ez, 50
|
||
66 | * 46010 VALENCIA
|
||
67 | * SPAIN
|
||
68 | *
|
||
69 | * +34 963862235
|
||
70 | * gvsig@gva.es
|
||
71 | * www.gvsig.gva.es
|
||
72 | *
|
||
73 | * or
|
||
74 | *
|
||
75 | * IVER T.I. S.A
|
||
76 | * Salamanca 50
|
||
77 | * 46005 Valencia
|
||
78 | * Spain
|
||
79 | *
|
||
80 | * +34 963163400
|
||
81 | * dac@iver.es
|
||
82 | */
|
||
83 | |||
84 | 8765 | jjdelcerro | /** ?? EN DESARROLLO !!
|
85 | * A component that is a modification of JComboBox, of which inherits.
|
||
86 | * This component allows:
|
||
87 | * - To show item/s that the start of their string value matches with the text written in the editable field
|
||
88 | * - To be configured it's behavior.
|
||
89 | *
|
||
90 | * This component has been done according the MVC (Model-View-Control) pattern, and is a 'Bean'.
|
||
91 | *
|
||
92 | * There are 10 configuration flags/attributes: 3 for the Model and the others for the Control and/or View.
|
||
93 | * ? Model flags/attributes (for more information see the 'AbstractDefaultComboBoxItemsSeekerConfigurableModel' class documentation):
|
||
94 | * - Start Behavior -> Configure how return items at beginning (always returns all items).
|
||
95 | * - Search Behavior -> Configure how return items when it's searching an item.
|
||
96 | * - Case Sensitive -> Discriminates capital letters from small letters or not when seeks items
|
||
97 | * ? Control and/or View flags (all flags can be 'true' or 'false'):
|
||
98 | * - Only One Color On Text:
|
||
99 | * + true -> always uses black color on text
|
||
100 | * + false -> by default uses black color on text, but if text written by user doesn't match with any item, text will be on red color
|
||
101 | * - Complete Matched Item:
|
||
102 | * + true -> When user writes, shows also the rest of the current matched item that user hasn't written.
|
||
103 | * + false -> Only shows the text written by the user when user is writting.
|
||
104 | * - Beep Enabled:
|
||
105 | * + true -> a beep-sound is listened when no item matches with the text written.
|
||
106 | * + false -> no sound is listened.
|
||
107 | * - Allowed Mouse Edition Popup Menu:
|
||
108 | * + true -> a 'PopupMenu' for text edition that appears when the user clicks on the text-edition-field with the right
|
||
109 | * button of the mouse.
|
||
110 | * + false -> that 'PopupMenu' won't appear.
|
||
111 | * - To Force To Only Coincidences In The Search:
|
||
112 | * + true -> If the user has written some text that doesn't mach with any item, and press the 'Enter' key for close the popup the user will
|
||
113 | * see written in the text-edition-field the last item which matched with the text written, or the first item of the model if
|
||
114 | * there wasn't.
|
||
115 | * + false -> If no item matches with the text written and the user presses the 'Enter' key, no item will be selected.
|
||
116 | * - Use Highlight:
|
||
117 | * + true -> marks characters of the text in the text-edition-field with a highlight.
|
||
118 | * + false -> doesn't do that.
|
||
119 | * . Control and Model flag (can be 'true' or 'false'):
|
||
120 | * - Allowed Repeated Items -> Uses one of the two models according the value of this flag:
|
||
121 | * + true -> Uses 'ComboBoxItemsSeekerConfigurableModel' as model (this could work slowly).
|
||
122 | * + false -> Uses 'ComboBoxSingularItemsSeekerConfigurableModel' as model.
|
||
123 | *
|
||
124 | * By default the configuration is:
|
||
125 | * - Start_Behavior = MAINTAIN_ORIGINAL_POSITION_START
|
||
126 | * - Search_Behavior = ORDERED_DYNAMIC_SEARCH
|
||
127 | * - Case_Sensitive = false
|
||
128 | * - Only_One_Color_On_Text = false
|
||
129 | * - Complete_Matched_Item = true
|
||
130 | * - Beep_Enabled = true
|
||
131 | * - Allowed_Repeated_Items = false
|
||
132 | * - Allowed_Mouse_Edition_Popup_Menu = true
|
||
133 | * - To_Force_To_Only_Coincidences_In_The_Search = true
|
||
134 | * - Use_Highlight = true
|
||
135 | *
|
||
136 | * Other functionality:
|
||
137 | * - Similar functionality as JComboBox:
|
||
138 | * + Select an item from the inner popup using the mouse
|
||
139 | * + Show item/items that match in the inner popup
|
||
140 | * + Similar edition operations: Right, left, ...
|
||
141 | * + ...
|
||
142 | * - With the keyboard the user can do the same operations as with the "edition popup menu" :
|
||
143 | * CTRL + A -> Select all text
|
||
144 | * CTRL + Z -> Undo
|
||
145 | * CTRL + SHIFT + Z -> Redo
|
||
146 | * CTRL + C -> Copy selected text
|
||
147 | * CTRL + X -> Cut selected text
|
||
148 | * CTRL + V -> Paste on selected text/position
|
||
149 | * DELETE (SUPR in Spanish Keyboard) -> Remove selected text
|
||
150 | * - ESC key -> Sets the component to its initial state (that user can estimate)
|
||
151 | *
|
||
152 | * Special-Warning characteristics
|
||
153 | * - In same inherit states the view could don't match with the model (this states aren't final states)
|
||
154 | *
|
||
155 | * Limitations:
|
||
156 | * - Items of the model of this component must have a "string" value returned by "toString()" method
|
||
157 | * - If the model of the component has lot of items, this could work slowly.
|
||
158 | * - If the model has repeated items -> set true the flag 'allowedRepeatedItems', this will use the 'ComboBoxItemsSeekerConfigurableModel' model,
|
||
159 | * and will work more slowly than the 'ComboBoxSingularItemsSeekerConfigurableModel' model; more as more items had the model.
|
||
160 | * - It's possible that some combination of configuration would be unmanageable.
|
||
161 | * - It's possible that some configuration or some operation fail !!
|
||
162 | *
|
||
163 | * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
|
||
164 | */
|
||
165 | 6721 | ppiqueras | public class JComboBoxItemsSeekerConfigurable extends JComboBox implements java.io.Serializable { |
166 | 6793 | ppiqueras | |
167 | 8765 | jjdelcerro | // CONSTANTS FOR THE CURRENT STATE OF THE COMPONENT
|
168 | 6721 | ppiqueras | private final int BEGINNING_VIEW_STATE = 0; |
169 | private final int START_VIEW_STATE = 1; |
||
170 | private final int SEARCH_VIEW_STATE = 2; |
||
171 | 8765 | jjdelcerro | // END CONSTANTS FOR THE CURRENT STATE OF THE COMPONENT
|
172 | |||
173 | // ATTRIBUTE FOR THE CURRENT STATE
|
||
174 | 6721 | ppiqueras | private int currentShowState; // 0 -> at the beginning; 1 -> when is showing the start list of items; 2 -> when is showing a search list of items |
175 | 8765 | jjdelcerro | // END ATTRIBUTE FOR THE CURRENT STATE
|
176 | 6721 | ppiqueras | |
177 | 8765 | jjdelcerro | // CONSTANTS FOR CONFIGURE THE BEHAVIOR
|
178 | public static final boolean DEFAULT_ONLY_ONE_COLOR_ON_TEXT_CONFIGURATION = false; |
||
179 | public static final boolean DEFAULT_COMPLETE_MATCHED_ITEM_CONFIGURATION = true; |
||
180 | public static final boolean DEFAULT_BEEP_ENABLED_CONFIGURATION = true; |
||
181 | public static final boolean DEFAULT_ALLOWED_REPEATED_ITEMS_CONFIGURATION = false; |
||
182 | public static final boolean DEFAULT_ALLOWED_MOUSE_EDITION_POPUP_MENU_CONFIGURATION = true; |
||
183 | public static final boolean DEFAULT_TO_FORCE_TO_ONLY_COINCIDENCES_IN_THE_SEARCH_CONFIGURATION = true; |
||
184 | public static final boolean DEFAULT_USE_HIGHLIGHT_CONFIGURATION = true; |
||
185 | // END CONSTANTS FOR CONFIGURE THE BEHAVIOR
|
||
186 | 6721 | ppiqueras | |
187 | // CONFIGURATION FLAGS
|
||
188 | 8765 | jjdelcerro | private boolean onlyOneColorOnText_Flag; |
189 | private boolean completeMatchedItem_Flag; |
||
190 | private boolean beepEnabled_Flag; |
||
191 | private boolean allowedRepeatedItems_Flag; |
||
192 | private boolean allowedMouseEditionPopupMenu_Flag; |
||
193 | private boolean toForceToOnlyCoincidencesInTheSearch_Flag; |
||
194 | private boolean useHighlight_Flag; |
||
195 | 6721 | ppiqueras | // END FLAGS
|
196 | |||
197 | 8765 | jjdelcerro | // STORE THE SELECTED ITEM AND THE LAST SELECTED ITEM
|
198 | private Object lastSelectedItemPopupUse; // This is used for only update (refresh) de popup when a different item is selected |
||
199 | // END STORE THE SELECTED ITEM AND THE LAST SELECTED ITEM
|
||
200 | 6721 | ppiqueras | |
201 | 8765 | jjdelcerro | private int num = 0; //sobra -> se usan en el log -> ?? SE PUEDE BORRAR !! |
202 | 6721 | ppiqueras | |
203 | 8765 | jjdelcerro | // NUMBER OF ITEMS SHOWED AT THE SAME TIME IN THE POPUP
|
204 | 6721 | ppiqueras | private final int POPUP_LIST_ITEMS_HEIGHT = 8; |
205 | 8765 | jjdelcerro | // END NUMBER OF ITEMS SHOWED AT THE SAME TIME IN THE POPUP
|
206 | 6721 | ppiqueras | |
207 | 8765 | jjdelcerro | // MODEL REFERENCE
|
208 | 6755 | ppiqueras | private AbstractDefaultComboBoxItemsSeekerConfigurableModel model;
|
209 | 8765 | jjdelcerro | // END MODEL REFERENCE
|
210 | 6721 | ppiqueras | |
211 | 8765 | jjdelcerro | // LISTENERS
|
212 | 6721 | ppiqueras | private KeyListener editorKeyListener; |
213 | 6793 | ppiqueras | private MouseAdapter editorMouseListener; |
214 | 8765 | jjdelcerro | private MouseWheelListener editorMouseWheelListener; |
215 | 6721 | ppiqueras | private FocusListener editorFocusListener; |
216 | private DocumentListener documentListener; |
||
217 | private ListDataListener modelListDataListener; |
||
218 | private PopupMenuListener popupMenuListener; |
||
219 | 6793 | ppiqueras | private PropertyChangeListener editionMenuListener; |
220 | 8765 | jjdelcerro | private CaretListener caretListener; |
221 | // END LISTENERS
|
||
222 | 6721 | ppiqueras | |
223 | 8765 | jjdelcerro | // EDITOR DOCUMENT REFERENCE
|
224 | private PlainDocumentTextFormatter document;
|
||
225 | // END EDITOR DOCUMENT REFERENCE
|
||
226 | 6721 | ppiqueras | |
227 | 8765 | jjdelcerro | // OTHER FLAGS
|
228 | private boolean allowInsertString; |
||
229 | 6721 | ppiqueras | private boolean lastWasTheBeginningState; |
230 | 6756 | ppiqueras | private boolean lastWasPressedAKeyModifier; |
231 | private boolean popupWillBeVisible; |
||
232 | 6793 | ppiqueras | private boolean optionsEditorWasVisible; |
233 | 8765 | jjdelcerro | private boolean selecting; |
234 | 6721 | ppiqueras | private boolean hidePopupOnFocusLoss; |
235 | 6791 | ppiqueras | private boolean hitBackspace; |
236 | 6721 | ppiqueras | private boolean hitBackspaceOnSelection; |
237 | 8765 | jjdelcerro | private boolean addUndoableEditEvent; |
238 | private boolean firstTimeItGainsFocusWithData; |
||
239 | private boolean specialSelectionByUserState; // In this state it's possible that model couldn't match with view (the selected item) |
||
240 | private boolean cutOperationDone; |
||
241 | private boolean itemSelectedByMouse; |
||
242 | // OTHER FLAGS
|
||
243 | 6732 | ppiqueras | |
244 | 6793 | ppiqueras | // TRACE - DEBUG
|
245 | 6733 | ppiqueras | private Logger logger = Logger.getLogger(JComboBoxItemsSeekerConfigurable.class.getClass()); |
246 | 6793 | ppiqueras | // END TRACE - DEBUG
|
247 | 6721 | ppiqueras | |
248 | 8765 | jjdelcerro | // A POPUPMENU FOR EDITION OPTIONS
|
249 | 6816 | ppiqueras | private JOptionsEditionByMousePopupMenu optionsEditionByMouse;
|
250 | 8765 | jjdelcerro | // END A POPUPMENU FOR EDITION OPTIONS
|
251 | 6793 | ppiqueras | |
252 | // UNDO-REDO
|
||
253 | 6816 | ppiqueras | private UndoManager undoManager; |
254 | private int undoRedoLimitActions; |
||
255 | 6793 | ppiqueras | // END UNDO-REDO
|
256 | |||
257 | 6721 | ppiqueras | /**
|
258 | 8765 | jjdelcerro | * Default Constructor without parameters
|
259 | 6721 | ppiqueras | */
|
260 | public JComboBoxItemsSeekerConfigurable() {
|
||
261 | // Invokes to the parent class constructor
|
||
262 | super();
|
||
263 | |||
264 | // Create attributes and set initial values
|
||
265 | this.initialize();
|
||
266 | |||
267 | // Set the default values of the flags
|
||
268 | 8765 | jjdelcerro | this.setDefaultBehaviorFlagsConfiguration();
|
269 | 6721 | ppiqueras | |
270 | // Other configuration tasks
|
||
271 | this.createDefaultListeners();
|
||
272 | this.configure();
|
||
273 | } |
||
274 | |||
275 | /**
|
||
276 | 8765 | jjdelcerro | * Default Constructor with 3 parameters: for the behavior of the Model
|
277 | 6721 | ppiqueras | *
|
278 | 8765 | jjdelcerro | * @param start_Behavior Start behavior of the Model.
|
279 | * @param search_Behavior Search behavior of the Model.
|
||
280 | * @param case_Sensitive Case sensitive behavior of the Model.
|
||
281 | 6721 | ppiqueras | */
|
282 | 6756 | ppiqueras | public JComboBoxItemsSeekerConfigurable(int start_Behavior, int search_Behavior, boolean case_Sensitive) { |
283 | 6721 | ppiqueras | // Invokes to the parent class constructor
|
284 | 8765 | jjdelcerro | super();
|
285 | |||
286 | // Set the default values of the flags
|
||
287 | this.setDefaultBehaviorFlagsConfiguration();
|
||
288 | |||
289 | 6721 | ppiqueras | // Create attributes and set initial values
|
290 | this.initialize();
|
||
291 | |||
292 | // Sets the options selected by the user
|
||
293 | this.model.setStartBehavior(start_Behavior);
|
||
294 | this.model.setStartBehavior(search_Behavior);
|
||
295 | 8765 | jjdelcerro | this.model.setCaseSensitive_Flag(case_Sensitive);
|
296 | 6721 | ppiqueras | |
297 | if (!testFlagsConfigurationOK())
|
||
298 | 7244 | cesar | JOptionPane.showMessageDialog(this, Messages.getText("errorMessageJComboBoxItemsSeekerConfigurable"), Messages.getText("exportJOP2Title"), JOptionPane.ERROR_MESSAGE); |
299 | 6721 | ppiqueras | else
|
300 | 8765 | jjdelcerro | { |
301 | // Other configuration tasks
|
||
302 | this.createDefaultListeners();
|
||
303 | 6721 | ppiqueras | this.configure();
|
304 | 8765 | jjdelcerro | } |
305 | 6721 | ppiqueras | } |
306 | |||
307 | /**
|
||
308 | 8765 | jjdelcerro | * Default Constructor with 10 parameters
|
309 | 6721 | ppiqueras | *
|
310 | 8765 | jjdelcerro | * @param start_Behavior Start behavior of the Model.
|
311 | * @param search_Behavior Search behavior of the Model.
|
||
312 | * @param case_Sensitive Case sensitive behavior of the Model.
|
||
313 | * @param only_One_Color_On_Text Text color, behavior of the Control/View.
|
||
314 | * @param complete_Matched_Item Complete matched item, behavior of the Control/View.
|
||
315 | * @param use_Beep Use beep, behavior of the Control.
|
||
316 | * @param allowed_Repeated_Items Allowed repeated items, behavior of the Control/Model.
|
||
317 | * @param allowed_Mouse_Edition_Popup_Menu Allowed mouse edition popupmenu, behavior of the Control/View.
|
||
318 | * @param to_Force_To_Only_Coincidences_In_The_Search To force to only coincidences in the search, behavior of the Control/View.
|
||
319 | * @param use_Highlight Use highlight, behavior of the Control/View.
|
||
320 | 6721 | ppiqueras | */
|
321 | 8765 | jjdelcerro | public JComboBoxItemsSeekerConfigurable(int start_Behavior, int search_Behavior, boolean case_Sensitive, boolean only_One_Color_On_Text, boolean complete_Matched_Item, boolean use_Beep, boolean allowed_Repeated_Items, boolean allowed_Mouse_Edition_Popup_Menu, boolean to_Force_To_Only_Coincidences_In_The_Search, boolean use_Highlight) { |
322 | 6721 | ppiqueras | // Invokes to the parent class constructor
|
323 | 8765 | jjdelcerro | super();
|
324 | |||
325 | this.onlyOneColorOnText_Flag = only_One_Color_On_Text;
|
||
326 | this.completeMatchedItem_Flag = complete_Matched_Item;
|
||
327 | this.beepEnabled_Flag = use_Beep;
|
||
328 | this.allowedRepeatedItems_Flag = allowed_Repeated_Items;
|
||
329 | this.allowedMouseEditionPopupMenu_Flag = allowed_Mouse_Edition_Popup_Menu;
|
||
330 | this.toForceToOnlyCoincidencesInTheSearch_Flag = to_Force_To_Only_Coincidences_In_The_Search;
|
||
331 | this.useHighlight_Flag = use_Highlight;
|
||
332 | 6721 | ppiqueras | |
333 | // Create attributes and set initial values
|
||
334 | this.initialize();
|
||
335 | 8765 | jjdelcerro | |
336 | 6721 | ppiqueras | // Sets the options selected by the user
|
337 | this.model.setStartBehavior(start_Behavior);
|
||
338 | 8765 | jjdelcerro | this.model.setSearchBehavior(search_Behavior);
|
339 | this.model.setCaseSensitive_Flag(case_Sensitive);
|
||
340 | 6721 | ppiqueras | |
341 | if (!testFlagsConfigurationOK())
|
||
342 | 7244 | cesar | JOptionPane.showMessageDialog(this, Messages.getText("errorMessageJComboBoxItemsSeekerConfigurable"), Messages.getText("exportJOP2Title"), JOptionPane.ERROR_MESSAGE); |
343 | 6721 | ppiqueras | else
|
344 | 8765 | jjdelcerro | { |
345 | // Other configuration tasks
|
||
346 | this.createDefaultListeners();
|
||
347 | 6721 | ppiqueras | this.configure();
|
348 | 8765 | jjdelcerro | } |
349 | 6721 | ppiqueras | } |
350 | |||
351 | /**
|
||
352 | 8765 | jjdelcerro | * Sets the default values of the flags
|
353 | 6721 | ppiqueras | */
|
354 | 8765 | jjdelcerro | private void setDefaultBehaviorFlagsConfiguration() { |
355 | this.onlyOneColorOnText_Flag = DEFAULT_ONLY_ONE_COLOR_ON_TEXT_CONFIGURATION;
|
||
356 | this.completeMatchedItem_Flag = DEFAULT_COMPLETE_MATCHED_ITEM_CONFIGURATION;
|
||
357 | this.beepEnabled_Flag = DEFAULT_BEEP_ENABLED_CONFIGURATION;
|
||
358 | this.allowedRepeatedItems_Flag = DEFAULT_ALLOWED_REPEATED_ITEMS_CONFIGURATION;
|
||
359 | this.allowedMouseEditionPopupMenu_Flag = DEFAULT_ALLOWED_MOUSE_EDITION_POPUP_MENU_CONFIGURATION;
|
||
360 | this.toForceToOnlyCoincidencesInTheSearch_Flag = DEFAULT_TO_FORCE_TO_ONLY_COINCIDENCES_IN_THE_SEARCH_CONFIGURATION;
|
||
361 | this.useHighlight_Flag = DEFAULT_USE_HIGHLIGHT_CONFIGURATION;
|
||
362 | } |
||
363 | |||
364 | /**
|
||
365 | * This method set the start values of inner attributes and creates the necessary inner objects
|
||
366 | */
|
||
367 | 6721 | ppiqueras | private void initialize() { |
368 | 8765 | jjdelcerro | // Attributes for highlight selection
|
369 | selecting = false;
|
||
370 | hitBackspace = false;
|
||
371 | 6721 | ppiqueras | |
372 | // Creates the model for this component and gets it reference
|
||
373 | 8765 | jjdelcerro | if (this.allowedRepeatedItems_Flag) |
374 | 6755 | ppiqueras | { |
375 | super.setModel(new ComboBoxItemsSeekerConfigurableModel()); |
||
376 | this.model = (ComboBoxItemsSeekerConfigurableModel) super.getModel(); |
||
377 | } |
||
378 | else
|
||
379 | { |
||
380 | super.setModel(new ComboBoxSingularItemsSeekerConfigurableModel()); |
||
381 | this.model = (ComboBoxSingularItemsSeekerConfigurableModel) super.getModel(); |
||
382 | } |
||
383 | 6721 | ppiqueras | |
384 | // Allows user to edit on the combobox
|
||
385 | super.setEditable(true); |
||
386 | |||
387 | // By default the last state of showign items was showing all the items (at the beginning of this component)
|
||
388 | currentShowState = BEGINNING_VIEW_STATE; |
||
389 | |||
390 | // Set the last selected item -> if there isn't any item -> -1; else -> this will be 0
|
||
391 | super.setSelectedIndex(-1); |
||
392 | |||
393 | // By default any text key has been pressed
|
||
394 | 8765 | jjdelcerro | allowInsertString = false;
|
395 | 6721 | ppiqueras | |
396 | 8765 | jjdelcerro | // Attribute for allow composed characters: examples: ?, ?, ?
|
397 | 6756 | ppiqueras | lastWasPressedAKeyModifier = false;
|
398 | 6721 | ppiqueras | |
399 | 6756 | ppiqueras | // By default popup won't be visible when gained the focus the editor associated
|
400 | popupWillBeVisible = false;
|
||
401 | |||
402 | 8765 | jjdelcerro | // Text options edition popupmenu initialization
|
403 | 6816 | ppiqueras | optionsEditionByMouse = new JOptionsEditionByMousePopupMenu();
|
404 | 6793 | ppiqueras | optionsEditorWasVisible = false;
|
405 | |||
406 | 8765 | jjdelcerro | // Undo-Redo initialization
|
407 | addUndoableEditEvent = false; // By default don't add undoable edit events |
||
408 | 6816 | ppiqueras | undoManager = new UndoManager(); |
409 | undoRedoLimitActions = 10; // By default is 1 |
||
410 | undoManager.setLimit(undoRedoLimitActions); |
||
411 | |||
412 | 8765 | jjdelcerro | // By default this flag will be 'true'
|
413 | firstTimeItGainsFocusWithData = true;
|
||
414 | 6721 | ppiqueras | |
415 | 8765 | jjdelcerro | // By default this component won't be in the "SpecialSelectionByUser" state
|
416 | specialSelectionByUserState = false;
|
||
417 | 6721 | ppiqueras | |
418 | 8765 | jjdelcerro | // By default no 'cut' operation has been done
|
419 | cutOperationDone = false;
|
||
420 | 6793 | ppiqueras | |
421 | 8765 | jjdelcerro | // By default no item items has been selected by mouse
|
422 | itemSelectedByMouse = false;
|
||
423 | 6721 | ppiqueras | } |
424 | |||
425 | /**
|
||
426 | 8765 | jjdelcerro | * Creation of default listeneres that will use the component
|
427 | 6721 | ppiqueras | */
|
428 | private void createDefaultListeners() { |
||
429 | 8765 | jjdelcerro | // Defines a listener for the PopupMenu of text edition options: when a change is produced in that component, it fires an event
|
430 | // and this listener captures it
|
||
431 | 6793 | ppiqueras | this.defineEditionMenuPropertyChangeListener(this); |
432 | |||
433 | 8765 | jjdelcerro | // Defines a key listener for the editor of this component
|
434 | 6721 | ppiqueras | this.defineEditorKeyListener(this); |
435 | |||
436 | 8765 | jjdelcerro | // Defines a focus listener for the editor of this component
|
437 | 6721 | ppiqueras | this.defineEditorFocusListener(this); |
438 | |||
439 | 8765 | jjdelcerro | // Defines a mouse listener for the editor of this component
|
440 | 6793 | ppiqueras | this.defineEditorMouseListener(this); |
441 | |||
442 | 8765 | jjdelcerro | // Defines a mouse wheel listener for the editor of this component
|
443 | this.defineEditorMouseWheelListener();
|
||
444 | |||
445 | // Defines a document listener for changes of text
|
||
446 | 6721 | ppiqueras | this.defineDocumentListener();
|
447 | |||
448 | 8765 | jjdelcerro | // Defines a list data listener for the model of this component
|
449 | 6721 | ppiqueras | this.defineModelListDataListener();
|
450 | |||
451 | 8765 | jjdelcerro | // Defines a popup menu listener for the popup of this component
|
452 | this.definePopUpMenuListener();
|
||
453 | 6721 | ppiqueras | } |
454 | |||
455 | 8765 | jjdelcerro | |
456 | 6816 | ppiqueras | /**
|
457 | 8765 | jjdelcerro | * Defines a listener for the PopupMenu of text edition options: when a change is produced in that component, it fires an event
|
458 | * and this listener captures and treats it
|
||
459 | *
|
||
460 | * @param combo_Box A reference of this component
|
||
461 | 6816 | ppiqueras | */
|
462 | 6793 | ppiqueras | private void defineEditionMenuPropertyChangeListener(JComboBoxItemsSeekerConfigurable combo_Box) { |
463 | final JComboBoxItemsSeekerConfigurable comboBoxReference = combo_Box;
|
||
464 | 8765 | jjdelcerro | |
465 | 6793 | ppiqueras | editionMenuListener = new PropertyChangeListener() { |
466 | 8765 | jjdelcerro | /*
|
467 | * (non-Javadoc)
|
||
468 | * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
|
||
469 | */
|
||
470 | 6793 | ppiqueras | public void propertyChange(PropertyChangeEvent arg0) { |
471 | 6816 | ppiqueras | if (arg0.getPropertyName().equals(JOptionsEditionByMousePopupMenu.SELECTEDOPTION)) {
|
472 | 6793 | ppiqueras | JTextComponent editor = (JTextComponent) comboBoxReference.getEditor().getEditorComponent(); |
473 | |||
474 | logger.debug("PropertyChanged: " + arg0.getNewValue().toString());
|
||
475 | |||
476 | switch(Integer.parseInt(arg0.getNewValue().toString())) |
||
477 | 8765 | jjdelcerro | { |
478 | 6816 | ppiqueras | case JOptionsEditionByMousePopupMenu.UNDO:
|
479 | 8765 | jjdelcerro | undoOperationLogic(); |
480 | 6793 | ppiqueras | break;
|
481 | 6816 | ppiqueras | case JOptionsEditionByMousePopupMenu.REDO:
|
482 | 8765 | jjdelcerro | redoOperationLogic(); |
483 | 6793 | ppiqueras | break;
|
484 | 6816 | ppiqueras | case JOptionsEditionByMousePopupMenu.CUT:
|
485 | editor.cut(); |
||
486 | 8765 | jjdelcerro | cutOperationDone = true;
|
487 | deleteTextLogic(editor, false);
|
||
488 | 6793 | ppiqueras | break;
|
489 | 6816 | ppiqueras | case JOptionsEditionByMousePopupMenu.COPY:
|
490 | editor.copy(); |
||
491 | 6793 | ppiqueras | break;
|
492 | 6816 | ppiqueras | case JOptionsEditionByMousePopupMenu.PASTE:
|
493 | editor.paste(); |
||
494 | 8765 | jjdelcerro | |
495 | try {
|
||
496 | String newPattern = document.getText(0, document.getLength()); |
||
497 | model.setWrittenText(newPattern); |
||
498 | updatePopUpView(); |
||
499 | } catch (BadLocationException e) { |
||
500 | e.printStackTrace(); |
||
501 | } |
||
502 | 6793 | ppiqueras | break;
|
503 | 6816 | ppiqueras | case JOptionsEditionByMousePopupMenu.DELETE:
|
504 | 8765 | jjdelcerro | deleteTextLogic(editor, false);
|
505 | 6793 | ppiqueras | break;
|
506 | 6816 | ppiqueras | case JOptionsEditionByMousePopupMenu.SELECT_ALL:
|
507 | 6793 | ppiqueras | editor.selectAll(); |
508 | break;
|
||
509 | default: // do anything |
||
510 | } |
||
511 | } |
||
512 | else
|
||
513 | { |
||
514 | 6816 | ppiqueras | if (arg0.getPropertyName().equals(JOptionsEditionByMousePopupMenu.VISIBILITYCHANGED))
|
515 | 6793 | ppiqueras | { |
516 | logger.debug("PropertyChanged: " + arg0.getNewValue().toString());
|
||
517 | |||
518 | // First True, after False (when false -> optionsEditorWasVisible = true)
|
||
519 | if (!optionsEditionByMouse.isVisible())
|
||
520 | optionsEditorWasVisible = true;
|
||
521 | else
|
||
522 | optionsEditorWasVisible = false;
|
||
523 | } |
||
524 | } |
||
525 | } |
||
526 | }; |
||
527 | 8765 | jjdelcerro | } |
528 | 6793 | ppiqueras | |
529 | 6721 | ppiqueras | /**
|
530 | 8765 | jjdelcerro | * Defines a document listener for changes of text
|
531 | 6721 | ppiqueras | */
|
532 | private void defineDocumentListener() { |
||
533 | 8765 | jjdelcerro | documentListener = new DocumentListener() { |
534 | /*
|
||
535 | * (non-Javadoc)
|
||
536 | * @see javax.swing.event.DocumentListener#changedUpdate(javax.swing.event.DocumentEvent)
|
||
537 | */
|
||
538 | public void changedUpdate(DocumentEvent arg0) { |
||
539 | } |
||
540 | 6721 | ppiqueras | |
541 | 8765 | jjdelcerro | /*
|
542 | * (non-Javadoc)
|
||
543 | * @see javax.swing.event.DocumentListener#insertUpdate(javax.swing.event.DocumentEvent)
|
||
544 | */
|
||
545 | public void insertUpdate(DocumentEvent arg0) { |
||
546 | logger.debug("NUM: " + num + " DocumentListener->insertUpdate"); |
||
547 | num++; |
||
548 | 6756 | ppiqueras | |
549 | 8765 | jjdelcerro | // Indicate to the model that now is disabled the start view
|
550 | // This is used for the first text inserted to the document when the component is loaded and it does setSelectedIndex(0), to avoid use a search view
|
||
551 | if (currentShowState == BEGINNING_VIEW_STATE)
|
||
552 | { |
||
553 | currentShowState = START_VIEW_STATE; |
||
554 | lastWasTheBeginningState = true;
|
||
555 | logger.debug("Pasa al estado 1 (de vista inicial)");
|
||
556 | } |
||
557 | } |
||
558 | 6721 | ppiqueras | |
559 | 8765 | jjdelcerro | /*
|
560 | * (non-Javadoc)
|
||
561 | * @see javax.swing.event.DocumentListener#removeUpdate(javax.swing.event.DocumentEvent)
|
||
562 | */
|
||
563 | public void removeUpdate(DocumentEvent arg0) { |
||
564 | logger.debug("NUM: " + num + " DocumentListener->removeUpdate"); |
||
565 | num++; |
||
566 | } |
||
567 | }; |
||
568 | 6721 | ppiqueras | } |
569 | |||
570 | /**
|
||
571 | 8765 | jjdelcerro | * Defines a list data listener for the model of this component
|
572 | 6721 | ppiqueras | */
|
573 | 8765 | jjdelcerro | private void defineModelListDataListener() { |
574 | 6721 | ppiqueras | this.modelListDataListener = new ListDataListener() { |
575 | 8765 | jjdelcerro | /*
|
576 | * (non-Javadoc)
|
||
577 | * @see javax.swing.event.ListDataListener#contentsChanged(javax.swing.event.ListDataEvent)
|
||
578 | */
|
||
579 | 6721 | ppiqueras | public void contentsChanged(ListDataEvent e) { |
580 | // This flag indicates to the 'insertString' and 'remove' methods of the PlainDocumentSeeker that the text of the item selected or written by the user
|
||
581 | // hasn't been written on the TextEditor of ths component
|
||
582 | selecting = false;
|
||
583 | } |
||
584 | |||
585 | 8765 | jjdelcerro | /*
|
586 | * (non-Javadoc)
|
||
587 | * @see javax.swing.event.ListDataListener#intervalAdded(javax.swing.event.ListDataEvent)
|
||
588 | */
|
||
589 | 6721 | ppiqueras | public void intervalAdded(ListDataEvent e) { |
590 | } |
||
591 | |||
592 | 8765 | jjdelcerro | /*
|
593 | * (non-Javadoc)
|
||
594 | * @see javax.swing.event.ListDataListener#intervalRemoved(javax.swing.event.ListDataEvent)
|
||
595 | */
|
||
596 | 6721 | ppiqueras | public void intervalRemoved(ListDataEvent e) { |
597 | 8765 | jjdelcerro | } |
598 | 6721 | ppiqueras | }; |
599 | } |
||
600 | |||
601 | /**
|
||
602 | 8765 | jjdelcerro | * Defines and add a property change listener for this component (AT MOMENT NOT USED!!)
|
603 | 6721 | ppiqueras | */
|
604 | private void defineAndAddPropertyChangeListener() { |
||
605 | // Define and add a Listener for changes on the editor or the model of the JComboBox
|
||
606 | super.addPropertyChangeListener(new PropertyChangeListener() { |
||
607 | public void propertyChange(PropertyChangeEvent ev) { |
||
608 | if (ev.getPropertyName().equals("editor")) |
||
609 | configureEditor((ComboBoxEditor) ev.getNewValue());
|
||
610 | if (ev.getPropertyName().equals("model")) |
||
611 | 6755 | ppiqueras | { |
612 | 8765 | jjdelcerro | if (isAllowedRepeatedItems_Flag())
|
613 | 6755 | ppiqueras | model = (ComboBoxItemsSeekerConfigurableModel) ev.getNewValue(); |
614 | else
|
||
615 | model = (ComboBoxSingularItemsSeekerConfigurableModel) ev.getNewValue(); |
||
616 | } |
||
617 | 6721 | ppiqueras | } |
618 | }); |
||
619 | } |
||
620 | |||
621 | /**
|
||
622 | 8765 | jjdelcerro | * Defines a focus listener for the editor of this component
|
623 | *
|
||
624 | * @param combo_Box A reference of this component
|
||
625 | 6721 | ppiqueras | */
|
626 | private void defineEditorFocusListener(JComboBoxItemsSeekerConfigurable combo_Box) { |
||
627 | 6756 | ppiqueras | final JComboBoxItemsSeekerConfigurable comboBoxReference = combo_Box;
|
628 | 6721 | ppiqueras | |
629 | 8765 | jjdelcerro | // Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out
|
630 | 6756 | ppiqueras | hidePopupOnFocusLoss=System.getProperty("java.version").startsWith("1.5"); |
631 | 8765 | jjdelcerro | |
632 | 6721 | ppiqueras | // Highlight whole text when gaining focus
|
633 | editorFocusListener = new FocusAdapter() { |
||
634 | 8765 | jjdelcerro | /*
|
635 | * (non-Javadoc)
|
||
636 | * @see java.awt.event.FocusAdapter#focusGained(java.awt.event.FocusEvent)
|
||
637 | */
|
||
638 | 6721 | ppiqueras | public void focusGained(FocusEvent e) { |
639 | 6793 | ppiqueras | if (!optionsEditorWasVisible)
|
640 | 6756 | ppiqueras | { |
641 | 6793 | ppiqueras | logger.debug("currentShowState: " + currentShowState);
|
642 | logger.debug("EDITOR FOCUS GAINED");
|
||
643 | |||
644 | 8765 | jjdelcerro | // This is used for set the text value of the first item added highlighted the first time the component gets the focus
|
645 | if (firstTimeItGainsFocusWithData) {
|
||
646 | if (model.getSize() > 0) { |
||
647 | if (useHighlight_Flag)
|
||
648 | document.highlightCompletedText(0);
|
||
649 | firstTimeItGainsFocusWithData = false;
|
||
650 | } |
||
651 | } |
||
652 | |||
653 | // This is used when the component has lost the focus, the popup was in show state and is restored the focus -> update the popup
|
||
654 | 6793 | ppiqueras | if (popupWillBeVisible)
|
655 | { |
||
656 | logger.debug("UPDATE POPUP DESDE EL FOCUSGAINED");
|
||
657 | comboBoxReference.updatePopUpView(); |
||
658 | } |
||
659 | 6756 | ppiqueras | } |
660 | 6721 | ppiqueras | } |
661 | |||
662 | 8765 | jjdelcerro | /*
|
663 | * (non-Javadoc)
|
||
664 | * @see java.awt.event.FocusAdapter#focusLost(java.awt.event.FocusEvent)
|
||
665 | */
|
||
666 | 6721 | ppiqueras | public void focusLost(FocusEvent e) { |
667 | 6756 | ppiqueras | logger.debug("EDITOR FOCUS LOST");
|
668 | |||
669 | if (isPopupVisible())
|
||
670 | popupWillBeVisible = true;
|
||
671 | else
|
||
672 | popupWillBeVisible = false;
|
||
673 | |||
674 | 6721 | ppiqueras | // Workaround for Bug 5100422 - Hide Popup on focus loss
|
675 | 6756 | ppiqueras | if (hidePopupOnFocusLoss) comboBoxReference.setPopupVisible(false); |
676 | 6721 | ppiqueras | } |
677 | }; |
||
678 | } |
||
679 | 8765 | jjdelcerro | |
680 | /**
|
||
681 | * Defines a mouse listener for the editor of this component
|
||
682 | *
|
||
683 | * @param combo_Box A reference of this component
|
||
684 | */
|
||
685 | 6793 | ppiqueras | private void defineEditorMouseListener(JComboBoxItemsSeekerConfigurable combo_Box) { |
686 | final JComboBoxItemsSeekerConfigurable comboBoxReference = combo_Box;
|
||
687 | |||
688 | 8765 | jjdelcerro | editorMouseListener = new MouseAdapter() { |
689 | /*
|
||
690 | * (non-Javadoc)
|
||
691 | * @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
|
||
692 | */
|
||
693 | 6816 | ppiqueras | public void mouseClicked(MouseEvent e) { |
694 | logger.debug("MOUSE-LISTENER : MOUSE-mouseClicked!" + e.getButton());
|
||
695 | logger.debug("MOUSE-LISTENER : MOUSE-mouseClicked!" +e.isPopupTrigger());
|
||
696 | 8765 | jjdelcerro | |
697 | 6816 | ppiqueras | if (e.getButton() == MouseEvent.BUTTON3) { |
698 | 6793 | ppiqueras | JTextComponent editor = (JTextComponent) comboBoxReference.getEditor().getEditorComponent(); |
699 | |||
700 | // By default disable all options
|
||
701 | optionsEditionByMouse.setEnabledAllOptions(false);
|
||
702 | |||
703 | 6816 | ppiqueras | // Enable the "Undo" option if there is any previous state to restore
|
704 | if (undoManager.canUndo())
|
||
705 | optionsEditionByMouse.setEnabledUndoOption(true);
|
||
706 | |||
707 | // Enable the "Redo" option if there is any later state to restore
|
||
708 | if (undoManager.canRedo())
|
||
709 | optionsEditionByMouse.setEnabledRedoOption(true);
|
||
710 | |||
711 | // Enable the "Copy", "Cut" and "Delete" options if there is text selected
|
||
712 | 6793 | ppiqueras | if (editor.getCaretPosition() != editor.getCaret().getMark())
|
713 | 6816 | ppiqueras | { |
714 | optionsEditionByMouse.setEnabledCopyOption(true);
|
||
715 | optionsEditionByMouse.setEnabledCutOption(true);
|
||
716 | 6793 | ppiqueras | optionsEditionByMouse.setEnabledDeleteOption(true);
|
717 | 6816 | ppiqueras | } |
718 | 6793 | ppiqueras | |
719 | 6816 | ppiqueras | // Enable the "Paste" option if there is text on the system's clipboard
|
720 | if ( getToolkit().getSystemClipboard().getContents(this).toString().length() > 0 ) |
||
721 | optionsEditionByMouse.setEnabledPasteOption(true);
|
||
722 | |||
723 | 6793 | ppiqueras | // Enable the "Select-All" option (by default it's always enabled)
|
724 | optionsEditionByMouse.setEnabledSelectAllOption(true);
|
||
725 | |||
726 | optionsEditionByMouse.setLocation((int)comboBoxReference.getLocationOnScreen().getX() + e.getX(), (int)comboBoxReference.getLocationOnScreen().getY() + e.getY()); |
||
727 | optionsEditionByMouse.setInvoker(comboBoxReference); |
||
728 | optionsEditionByMouse.setVisible(true);
|
||
729 | } |
||
730 | } |
||
731 | }; |
||
732 | } |
||
733 | |||
734 | 6721 | ppiqueras | /**
|
735 | 8765 | jjdelcerro | * Defines a mouse wheel listener for the editor of this component
|
736 | */
|
||
737 | private void defineEditorMouseWheelListener() { |
||
738 | editorMouseWheelListener = new MouseWheelListener() { |
||
739 | /*
|
||
740 | * (non-Javadoc)
|
||
741 | * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
|
||
742 | */
|
||
743 | public void mouseWheelMoved(MouseWheelEvent e) { |
||
744 | specialSelectionByUserState = true;
|
||
745 | |||
746 | if (e.getWheelRotation() < 0) |
||
747 | selectItemUp(); |
||
748 | else
|
||
749 | selectItemDown(); |
||
750 | } |
||
751 | }; |
||
752 | } |
||
753 | |||
754 | /**
|
||
755 | * Defines a key listener for the editor of this component
|
||
756 | * This method is another important difference from the JComboBox; and could work badly with some keymaps
|
||
757 | 6721 | ppiqueras | *
|
758 | 8765 | jjdelcerro | * @param combo_Box A reference of this component
|
759 | 6721 | ppiqueras | */
|
760 | private void defineEditorKeyListener(JComboBoxItemsSeekerConfigurable combo_Box) { |
||
761 | final JComboBoxItemsSeekerConfigurable comboBoxReference = combo_Box;
|
||
762 | |||
763 | 8765 | jjdelcerro | editorKeyListener = new KeyAdapter() { |
764 | /*
|
||
765 | * (non-Javadoc)
|
||
766 | * @see java.awt.event.KeyAdapter#keyPressed(java.awt.event.KeyEvent)
|
||
767 | */
|
||
768 | 6721 | ppiqueras | public void keyPressed(KeyEvent ke) // Executed on the Start view state or Search view state |
769 | { |
||
770 | 6756 | ppiqueras | logger.debug("Tecla apretada: ->" + ke.getKeyChar() + "<- ; Su keyCode es: " + ke.getKeyCode() + " TIPO: " + Character.getType(ke.getKeyChar())); |
771 | |||
772 | 6721 | ppiqueras | if (model.getParentSize() == 0) |
773 | { |
||
774 | 8765 | jjdelcerro | if (beepEnabled_Flag)
|
775 | 6721 | ppiqueras | comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
|
776 | } |
||
777 | else
|
||
778 | 6791 | ppiqueras | { |
779 | 6721 | ppiqueras | // This flag indicates to the 'insertString' and 'remove' methods of the PlainDocumentSeeker that the text of the item selected or written by the user
|
780 | // hasn't been written on the TextEditor of ths component
|
||
781 | selecting = false;
|
||
782 | |||
783 | // This resolves the bug when the popup wasn't seen any time and the uses press a key that updates the view of the popup (the bug is that popup has the items but
|
||
784 | // aren't seen
|
||
785 | if (lastWasTheBeginningState)
|
||
786 | { |
||
787 | // This maintains visible the popup
|
||
788 | if (comboBoxReference.isDisplayable())
|
||
789 | comboBoxReference.setPopupVisible(true);
|
||
790 | lastWasTheBeginningState = false;
|
||
791 | } |
||
792 | |||
793 | 6756 | ppiqueras | if (Character.isLetterOrDigit(ke.getKeyChar())) { |
794 | logger.debug("IS LETTER OR DIGIT");
|
||
795 | } |
||
796 | else
|
||
797 | logger.debug("ISN'T LETTER OR DIGIT");
|
||
798 | |||
799 | 6721 | ppiqueras | JTextComponent editor = (JTextComponent) comboBoxReference.getEditor().getEditorComponent(); |
800 | |||
801 | 8765 | jjdelcerro | // COPY, CUT, PASTE, SELECT ALL, UNDO AND REDO WITH THE KEYBOARD (Combination of keys; REMOVE is implemented after: KV_DELETE (supr spanish key))
|
802 | if (ke.isControlDown())
|
||
803 | { |
||
804 | // COPY
|
||
805 | if (ke.getKeyCode() == KeyEvent.VK_C) { |
||
806 | editor.copy(); |
||
807 | return;
|
||
808 | } |
||
809 | |||
810 | // CUT
|
||
811 | if (ke.getKeyCode() == KeyEvent.VK_X) { |
||
812 | editor.cut(); |
||
813 | |||
814 | cutOperationDone = true;
|
||
815 | deleteTextLogic(editor, false);
|
||
816 | return;
|
||
817 | } |
||
818 | |||
819 | // PASTE
|
||
820 | if (ke.getKeyCode() == KeyEvent.VK_V) { |
||
821 | editor.paste(); |
||
822 | |||
823 | try {
|
||
824 | String newPattern = document.getText(0, document.getLength()); |
||
825 | model.setWrittenText(newPattern); |
||
826 | updatePopUpView(); |
||
827 | } catch (BadLocationException e) { |
||
828 | e.printStackTrace(); |
||
829 | } |
||
830 | return;
|
||
831 | } |
||
832 | |||
833 | // SELECT ALL
|
||
834 | if (ke.getKeyCode() == KeyEvent.VK_A) { |
||
835 | editor.selectAll(); |
||
836 | return;
|
||
837 | } |
||
838 | |||
839 | // UNDO OR REDO
|
||
840 | if (ke.getKeyCode() == KeyEvent.VK_Z) { |
||
841 | if (ke.isShiftDown()) // REDO |
||
842 | redoOperationLogic(); |
||
843 | else //UNDO |
||
844 | undoOperationLogic(); |
||
845 | |||
846 | return;
|
||
847 | } |
||
848 | } |
||
849 | 6756 | ppiqueras | |
850 | 8765 | jjdelcerro | // According the key pressed, do some actions or others
|
851 | switch (ke.getKeyCode())
|
||
852 | { |
||
853 | // determine if the pressed key is backspace (needed by the remove method)
|
||
854 | case KeyEvent.VK_BACK_SPACE : |
||
855 | if (useHighlight_Flag)
|
||
856 | { |
||
857 | hitBackspace = true;
|
||
858 | hitBackspaceOnSelection=editor.getSelectionStart()!=editor.getSelectionEnd(); |
||
859 | } |
||
860 | else
|
||
861 | deleteTextLogic(editor, true);
|
||
862 | break;
|
||
863 | |||
864 | case KeyEvent.VK_DELETE : // 'supr' key in spanish keyboard |
||
865 | specialSelectionByUserState = true;
|
||
866 | |||
867 | deleteTextLogic(editor, false);
|
||
868 | break;
|
||
869 | |||
870 | case KeyEvent.VK_ENTER : |
||
871 | logger.debug("ENTRA EN EL C?DIGO DE ENTER");
|
||
872 | |||
873 | if (getSelectedItem() == null) |
||
874 | logger.debug("SELECTED ITEM: NULL");
|
||
875 | else
|
||
876 | logger.debug("SELECTED ITEM: " + getSelectedItem().toString());
|
||
877 | 6721 | ppiqueras | |
878 | 8765 | jjdelcerro | try {
|
879 | String newText = ""; |
||
880 | 6756 | ppiqueras | |
881 | 8765 | jjdelcerro | Object moreSimilarItemToLastWrittenText = model.getMoreSimilarItemToLastWrittenText();
|
882 | |||
883 | // If the last item selected was null -> select the first
|
||
884 | if (moreSimilarItemToLastWrittenText == null) { |
||
885 | setSelectedItem(model.getParentElementAt(0));
|
||
886 | 6754 | ppiqueras | } |
887 | 8765 | jjdelcerro | else {
|
888 | if (specialSelectionByUserState) {
|
||
889 | setSelectedItem(model.getSelectedItem()); |
||
890 | 6754 | ppiqueras | } |
891 | 8765 | jjdelcerro | else {
|
892 | // Else -> select the last
|
||
893 | setSelectedItem(moreSimilarItemToLastWrittenText); |
||
894 | } |
||
895 | } |
||
896 | 6721 | ppiqueras | |
897 | 8765 | jjdelcerro | newText = getSelectedItem().toString(); |
898 | 6721 | ppiqueras | |
899 | 8765 | jjdelcerro | // Reports about the written text to the model
|
900 | if (model.isDynamicSearch())
|
||
901 | model.setWrittenText(newText); |
||
902 | 6756 | ppiqueras | |
903 | 8765 | jjdelcerro | specialSelectionByUserState = false;
|
904 | 6756 | ppiqueras | |
905 | 8765 | jjdelcerro | document.replace(0, document.getLength(), newText, null); |
906 | } |
||
907 | catch (BadLocationException e1) { |
||
908 | e1.printStackTrace(); |
||
909 | } |
||
910 | |||
911 | // Indicate to the model that now is disabled the start view
|
||
912 | if (currentShowState == START_VIEW_STATE)
|
||
913 | { |
||
914 | model.setStartStateFlag(false);
|
||
915 | currentShowState = SEARCH_VIEW_STATE; |
||
916 | } |
||
917 | hidePopup(); |
||
918 | |||
919 | // Sets the caret position of the text in the document to the end:
|
||
920 | editor.setCaretPosition(document.getLength()); |
||
921 | break;
|
||
922 | |||
923 | case KeyEvent.VK_DOWN : |
||
924 | selectItemDown(); |
||
925 | showPopup(); |
||
926 | break;
|
||
927 | |||
928 | case KeyEvent.VK_UP : |
||
929 | selectItemUp(); |
||
930 | showPopup(); |
||
931 | break;
|
||
932 | |||
933 | case KeyEvent.VK_LEFT : |
||
934 | // Move the caret to left
|
||
935 | int caretPosition = editor.getCaretPosition();
|
||
936 | if (caretPosition > 0) |
||
937 | { |
||
938 | if (useHighlight_Flag) {
|
||
939 | editor.setCaretPosition(document.getLength()); |
||
940 | editor.moveCaretPosition(caretPosition - 1);
|
||
941 | 6721 | ppiqueras | } |
942 | 8765 | jjdelcerro | else
|
943 | editor.setCaretPosition(caretPosition - 1);
|
||
944 | } |
||
945 | else
|
||
946 | { |
||
947 | // User hit backspace with the cursor positioned on the start => beep
|
||
948 | if (beepEnabled_Flag)
|
||
949 | getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
|
||
950 | } |
||
951 | |||
952 | break;
|
||
953 | |||
954 | case KeyEvent.VK_RIGHT : |
||
955 | // Move the caret to right
|
||
956 | caretPosition = editor.getCaretPosition(); |
||
957 | if (caretPosition < document.getLength()) {
|
||
958 | if (useHighlight_Flag) {
|
||
959 | editor.setCaretPosition(document.getLength()); |
||
960 | editor.moveCaretPosition(caretPosition + 1);
|
||
961 | } |
||
962 | else
|
||
963 | editor.setCaretPosition(caretPosition + 1);
|
||
964 | } |
||
965 | else
|
||
966 | { |
||
967 | // User hit backspace with the cursor positioned on the start => beep
|
||
968 | if (beepEnabled_Flag)
|
||
969 | getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
|
||
970 | } |
||
971 | |||
972 | break;
|
||
973 | |||
974 | case KeyEvent.VK_PAGE_DOWN : |
||
975 | if (getItemCount() > 0) |
||
976 | { |
||
977 | int index;
|
||
978 | specialSelectionByUserState = true;
|
||
979 | 6721 | ppiqueras | |
980 | 8765 | jjdelcerro | if (getSelectedIndex() == -1) |
981 | index = 0;
|
||
982 | else
|
||
983 | index = getSelectedIndex() + POPUP_LIST_ITEMS_HEIGHT; |
||
984 | 6721 | ppiqueras | |
985 | 8765 | jjdelcerro | if (index < getItemCount())
|
986 | setSelectedIndex(index); |
||
987 | else
|
||
988 | setSelectedIndex(getItemCount()-1);
|
||
989 | } |
||
990 | break;
|
||
991 | |||
992 | case KeyEvent.VK_PAGE_UP : |
||
993 | if (getItemCount() > 0) |
||
994 | { |
||
995 | int index;
|
||
996 | specialSelectionByUserState = true;
|
||
997 | 6793 | ppiqueras | |
998 | 8765 | jjdelcerro | if (getSelectedIndex() == -1) |
999 | index = getItemCount() - 1;
|
||
1000 | else
|
||
1001 | index = getSelectedIndex() - POPUP_LIST_ITEMS_HEIGHT; |
||
1002 | 6721 | ppiqueras | |
1003 | 8765 | jjdelcerro | if (index > -1) |
1004 | setSelectedIndex(index); |
||
1005 | else
|
||
1006 | setSelectedIndex(0);
|
||
1007 | } |
||
1008 | break;
|
||
1009 | |||
1010 | case KeyEvent.VK_HOME : // 'Inicio' key on the spanish keyboard |
||
1011 | editor.setCaretPosition(0);
|
||
1012 | break;
|
||
1013 | |||
1014 | case KeyEvent.VK_END : // 'Fin' key on the spanish keyboard |
||
1015 | editor.setCaretPosition(document.getLength()); |
||
1016 | break;
|
||
1017 | |||
1018 | case KeyEvent.VK_TAB : |
||
1019 | // This avoids that popup listener could report about it detected item
|
||
1020 | allowInsertString = true;
|
||
1021 | |||
1022 | if (model.getParentSize() > 0) |
||
1023 | { |
||
1024 | Object selectedItem;
|
||
1025 | 6721 | ppiqueras | |
1026 | 8765 | jjdelcerro | if (specialSelectionByUserState)
|
1027 | selectedItem = getSelectedItem(); |
||
1028 | else
|
||
1029 | 8996 | ppiqueras | selectedItem = model.getParentElementAt(0);
|
1030 | 6721 | ppiqueras | |
1031 | 8765 | jjdelcerro | String selectedItemName = ""; |
1032 | 6756 | ppiqueras | |
1033 | try {
|
||
1034 | 8765 | jjdelcerro | |
1035 | if (selectedItem == null) |
||
1036 | selectedItemName = model.getFirstItemAdded().toString(); |
||
1037 | 6756 | ppiqueras | else
|
1038 | 8765 | jjdelcerro | selectedItemName = selectedItem.toString(); |
1039 | |||
1040 | document.replace(0, document.getLength(), selectedItemName, null); |
||
1041 | 6756 | ppiqueras | } catch (BadLocationException e) { |
1042 | e.printStackTrace(); |
||
1043 | } |
||
1044 | 6721 | ppiqueras | |
1045 | 8765 | jjdelcerro | if (model.isDynamicSearch()) {
|
1046 | model.setWrittenText(selectedItemName); |
||
1047 | logger.debug("Texto que se le env?a al modelo: ->" + selectedItemName + "<-"); |
||
1048 | } |
||
1049 | 6756 | ppiqueras | |
1050 | 8765 | jjdelcerro | if (currentShowState == START_VIEW_STATE)
|
1051 | 6756 | ppiqueras | { |
1052 | 8765 | jjdelcerro | model.setStartStateFlag(false);
|
1053 | currentShowState = SEARCH_VIEW_STATE; |
||
1054 | 6756 | ppiqueras | } |
1055 | 8765 | jjdelcerro | |
1056 | // It's supposed that the text on the document is equal as the string value of the selected item -> then text must be on black color
|
||
1057 | comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
|
||
1058 | |||
1059 | 6756 | ppiqueras | updatePopUpView(); |
1060 | 8765 | jjdelcerro | } |
1061 | break;
|
||
1062 | 6721 | ppiqueras | |
1063 | 8765 | jjdelcerro | case KeyEvent.VK_ESCAPE : |
1064 | specialSelectionByUserState = false;
|
||
1065 | |||
1066 | // Force update the popup
|
||
1067 | if (isPopupVisible())
|
||
1068 | hidePopup(); |
||
1069 | 6721 | ppiqueras | |
1070 | 8765 | jjdelcerro | model.setWrittenText("");
|
1071 | |||
1072 | if (currentShowState == SEARCH_VIEW_STATE)
|
||
1073 | { |
||
1074 | try {
|
||
1075 | document.remove(0, document.getLength());
|
||
1076 | } catch (BadLocationException e) { |
||
1077 | e.printStackTrace(); |
||
1078 | 6721 | ppiqueras | } |
1079 | |||
1080 | 8765 | jjdelcerro | // Return to the start view state
|
1081 | model.setStartStateFlag(true);
|
||
1082 | currentShowState = START_VIEW_STATE; |
||
1083 | |||
1084 | // Select the first Item
|
||
1085 | setSelectedIndex(0);
|
||
1086 | 6721 | ppiqueras | |
1087 | 8765 | jjdelcerro | if (useHighlight_Flag)
|
1088 | document.highlightCompletedText(0);
|
||
1089 | 6721 | ppiqueras | } |
1090 | 8765 | jjdelcerro | else
|
1091 | { |
||
1092 | // Select the first Item
|
||
1093 | setSelectedIndex(0);
|
||
1094 | |||
1095 | if (useHighlight_Flag)
|
||
1096 | document.highlightCompletedText(0);
|
||
1097 | } |
||
1098 | updatePopUpView(); |
||
1099 | break;
|
||
1100 | |||
1101 | case KeyEvent.VK_SHIFT : // Do nothing |
||
1102 | break;
|
||
1103 | |||
1104 | case KeyEvent.VK_ALT_GRAPH : // Do nothing |
||
1105 | break;
|
||
1106 | |||
1107 | case KeyEvent.VK_ALT : // Do nothing |
||
1108 | break;
|
||
1109 | |||
1110 | case KeyEvent.VK_CONTROL : // Do nothing |
||
1111 | break;
|
||
1112 | |||
1113 | case KeyEvent.VK_NUM_LOCK : // Do nothing |
||
1114 | break;
|
||
1115 | |||
1116 | case KeyEvent.VK_CAPS_LOCK : // Do nothing |
||
1117 | break;
|
||
1118 | |||
1119 | default:
|
||
1120 | logger.debug("Actualiza view flag a false");
|
||
1121 | |||
1122 | logger.debug("LASTITEM1 :" + lastSelectedItemPopupUse);
|
||
1123 | 6721 | ppiqueras | |
1124 | 8765 | jjdelcerro | logger.debug("GETMARK: " + editor.getCaret().getMark() + "GETCARETPOSITION" + editor.getCaretPosition()); |
1125 | 6793 | ppiqueras | |
1126 | 8765 | jjdelcerro | specialSelectionByUserState = false;
|
1127 | |||
1128 | // If it has been pressed a modifier key (Examples: ^ ` ? ?), not consume the key pressed
|
||
1129 | if ((Character.getType(ke.getKeyChar()) == Character.MODIFIER_LETTER) || (Character.getType(ke.getKeyChar()) == Character.MODIFIER_SYMBOL)) |
||
1130 | { |
||
1131 | logger.debug("CAR?CTER MODIFICADOR");
|
||
1132 | lastWasPressedAKeyModifier = true;
|
||
1133 | } |
||
1134 | else
|
||
1135 | { |
||
1136 | logger.debug("CAR?CTER NO MODIFICADOR");
|
||
1137 | allowInsertString = true;
|
||
1138 | 6793 | ppiqueras | |
1139 | 8765 | jjdelcerro | if (lastWasPressedAKeyModifier)
|
1140 | { |
||
1141 | logger.debug("PRESSED: " + editor.getText().substring(0)); |
||
1142 | lastWasPressedAKeyModifier = false;
|
||
1143 | } |
||
1144 | |||
1145 | if (model.isDynamicSearch())
|
||
1146 | { |
||
1147 | |||
1148 | String text;
|
||
1149 | if (editor.getCaretPosition() == editor.getCaret().getMark())
|
||
1150 | text = editor.getText().substring(0, editor.getCaretPosition()) + ke.getKeyChar() + editor.getText().substring(editor.getCaretPosition(), editor.getText().length());
|
||
1151 | else
|
||
1152 | { |
||
1153 | text = "" + editor.getText().substring(0, (int) Math.min(editor.getCaretPosition(), editor.getCaret().getMark())) + ke.getKeyChar(); |
||
1154 | text += editor.getText().substring((int) Math.max(editor.getCaretPosition(), editor.getCaret().getMark()), editor.getText().length()); |
||
1155 | } |
||
1156 | |||
1157 | // Reports about the written text to the model
|
||
1158 | logger.debug("Texto que se le env?a KEY al modelo: ->" + text + "<-"); |
||
1159 | model.setWrittenText(text); |
||
1160 | |||
1161 | // Indicate to the model that now is disabled the start view
|
||
1162 | if (currentShowState == START_VIEW_STATE)
|
||
1163 | { |
||
1164 | model.setStartStateFlag(false);
|
||
1165 | currentShowState = SEARCH_VIEW_STATE; |
||
1166 | } |
||
1167 | |||
1168 | } |
||
1169 | |||
1170 | updatePopUpView(); |
||
1171 | |||
1172 | logger.debug("Key Pressed:" + ke.getKeyCode());
|
||
1173 | 6793 | ppiqueras | } |
1174 | } |
||
1175 | |||
1176 | 8765 | jjdelcerro | // Consume the key event for not to use the handler of the keyboard of other components
|
1177 | // Only if it has been pressed a modifier key, not consume the key pressed
|
||
1178 | if (!lastWasPressedAKeyModifier)
|
||
1179 | ke.consume(); |
||
1180 | } |
||
1181 | } |
||
1182 | }; |
||
1183 | 6793 | ppiqueras | } |
1184 | |||
1185 | 6721 | ppiqueras | /**
|
1186 | 8765 | jjdelcerro | * Defines a popup menu listener for the popup of this component
|
1187 | 6721 | ppiqueras | */
|
1188 | 8765 | jjdelcerro | private void definePopUpMenuListener() { |
1189 | 6721 | ppiqueras | this.popupMenuListener = new PopupMenuListener() { |
1190 | |||
1191 | /*
|
||
1192 | * (non-Javadoc)
|
||
1193 | * @see javax.swing.event.PopupMenuListener#popupMenuCanceled(javax.swing.event.PopupMenuEvent)
|
||
1194 | */
|
||
1195 | public void popupMenuCanceled(PopupMenuEvent e) { |
||
1196 | 6732 | ppiqueras | logger.debug("MenuCANCELED");
|
1197 | 6721 | ppiqueras | } |
1198 | |||
1199 | /*
|
||
1200 | * (non-Javadoc)
|
||
1201 | * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent)
|
||
1202 | */
|
||
1203 | public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { |
||
1204 | 6732 | ppiqueras | logger.debug("MenuBECOMEINVISIBLE");
|
1205 | 8765 | jjdelcerro | |
1206 | if (!allowInsertString)
|
||
1207 | 6721 | ppiqueras | { |
1208 | 8765 | jjdelcerro | if (!specialSelectionByUserState) {
|
1209 | if ((getSelectedItem() != null) &&(lastSelectedItemPopupUse != null)) |
||
1210 | 6721 | ppiqueras | { |
1211 | 8765 | jjdelcerro | // If the user has select a different item with the mouse, and this is in the Start View State -> change to the Search View State
|
1212 | if (!getSelectedItem().equals(lastSelectedItemPopupUse))
|
||
1213 | 6721 | ppiqueras | { |
1214 | 8765 | jjdelcerro | logger.debug("POPUP: NO SON IGUALES");
|
1215 | 6721 | ppiqueras | |
1216 | 8765 | jjdelcerro | // Reports about the written text to the model
|
1217 | if (model.isDynamicSearch())
|
||
1218 | { |
||
1219 | model.setWrittenText(getSelectedItem().toString()); |
||
1220 | logger.debug("Texto que le envia POPUP al modelo: ->" + getSelectedItem().toString() + "<-"); |
||
1221 | } |
||
1222 | |||
1223 | if (currentShowState == START_VIEW_STATE)
|
||
1224 | { |
||
1225 | model.setStartStateFlag(false);
|
||
1226 | currentShowState = SEARCH_VIEW_STATE; |
||
1227 | } |
||
1228 | logger.debug("Selected index of item: " + lastSelectedItemPopupUse.toString() + " is " + getSelectedIndex()); |
||
1229 | 6721 | ppiqueras | } |
1230 | 8765 | jjdelcerro | else
|
1231 | logger.debug("POPUP: SON IGUALES");
|
||
1232 | 6721 | ppiqueras | } |
1233 | } |
||
1234 | } |
||
1235 | } |
||
1236 | |||
1237 | /*
|
||
1238 | * (non-Javadoc)
|
||
1239 | * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent)
|
||
1240 | */
|
||
1241 | public void popupMenuWillBecomeVisible(PopupMenuEvent e) { |
||
1242 | 6732 | ppiqueras | logger.debug("MenuBECOMEVISIBLE");
|
1243 | 8765 | jjdelcerro | lastSelectedItemPopupUse = getSelectedItem(); // This object is used for know if the user has select a different item with the mouse
|
1244 | allowInsertString = false;
|
||
1245 | 6721 | ppiqueras | } |
1246 | }; |
||
1247 | 8765 | jjdelcerro | } |
1248 | 6721 | ppiqueras | |
1249 | 8765 | jjdelcerro | /**
|
1250 | * Configures the component and some of its parts
|
||
1251 | */
|
||
1252 | private void configure() { |
||
1253 | // Configures the document of the editor of this component
|
||
1254 | this.configureDocument();
|
||
1255 | |||
1256 | // Configures the editor (ComboBoxEditor) of this component
|
||
1257 | this.configureEditor(this.getEditor()); |
||
1258 | |||
1259 | // Configures the model of this component
|
||
1260 | this.configureModel();
|
||
1261 | |||
1262 | // Configures the popup of this component
|
||
1263 | this.configurePopUp();
|
||
1264 | |||
1265 | // Configures the text-edition-options popupmenu
|
||
1266 | this.configureOptionsEditionByMouse();
|
||
1267 | 6721 | ppiqueras | } |
1268 | |||
1269 | 8765 | jjdelcerro | /**
|
1270 | * Configures the text-edition-options popupmenu
|
||
1271 | */
|
||
1272 | private void configureOptionsEditionByMouse() { |
||
1273 | this.optionsEditionByMouse.addPropertyChangeListener(editionMenuListener);
|
||
1274 | } |
||
1275 | 6721 | ppiqueras | |
1276 | /**
|
||
1277 | 8765 | jjdelcerro | * Configures the popup of this component
|
1278 | 6721 | ppiqueras | */
|
1279 | 8765 | jjdelcerro | private void configurePopUp() { |
1280 | this.addPopupMenuListener(this.popupMenuListener); |
||
1281 | 6721 | ppiqueras | } |
1282 | 8765 | jjdelcerro | |
1283 | /**
|
||
1284 | * Configures the model of this component
|
||
1285 | */
|
||
1286 | private void configureModel() { |
||
1287 | this.model.addListDataListener(this.modelListDataListener); |
||
1288 | } |
||
1289 | 6721 | ppiqueras | |
1290 | 8765 | jjdelcerro | /**
|
1291 | * Configures the editor (ComboBoxEditor) of this component
|
||
1292 | *
|
||
1293 | * @param newEditor The new editor to configure
|
||
1294 | */
|
||
1295 | 6721 | ppiqueras | private void configureEditor(ComboBoxEditor newEditor) { |
1296 | 8765 | jjdelcerro | logger.debug("Configura Editor");
|
1297 | 6721 | ppiqueras | |
1298 | if (newEditor != null) { |
||
1299 | 8765 | jjdelcerro | JTextComponent jTextComponentOfEditor = (JTextComponent) newEditor.getEditorComponent(); |
1300 | |||
1301 | // Removes some prevous listeners and adds some new others:
|
||
1302 | |||
1303 | // Adds the new Key Listener (tries to remove it if it existed before)
|
||
1304 | jTextComponentOfEditor.removeKeyListener(this.editorKeyListener);
|
||
1305 | jTextComponentOfEditor.addKeyListener(this.editorKeyListener);
|
||
1306 | 6816 | ppiqueras | |
1307 | 8765 | jjdelcerro | // Disable the focus transversal keys (Example: CTRL+TAB) for enable the TAB key
|
1308 | jTextComponentOfEditor.setFocusTraversalKeysEnabled(false);
|
||
1309 | |||
1310 | if (this.allowedMouseEditionPopupMenu_Flag) |
||
1311 | { |
||
1312 | // Adds the new Mouse Listener (tries to remove it if it existed before)
|
||
1313 | jTextComponentOfEditor.removeMouseListener(this.editorMouseListener);
|
||
1314 | jTextComponentOfEditor.addMouseListener(this.editorMouseListener);
|
||
1315 | } |
||
1316 | |||
1317 | // Adds the new Mouse Wheel Listener (tries to remove it if it existed before)
|
||
1318 | jTextComponentOfEditor.removeMouseWheelListener(this.editorMouseWheelListener);
|
||
1319 | jTextComponentOfEditor.addMouseWheelListener(this.editorMouseWheelListener);
|
||
1320 | |||
1321 | // Adds the new Focus Listener (tries to remove it if it existed before)
|
||
1322 | jTextComponentOfEditor.removeFocusListener(this.editorFocusListener);
|
||
1323 | jTextComponentOfEditor.addFocusListener(this.editorFocusListener);
|
||
1324 | |||
1325 | // Adds a caret listener for undo and redo
|
||
1326 | jTextComponentOfEditor.addCaretListener(this.caretListener);
|
||
1327 | |||
1328 | // Adds the new document (tries to remove it if it existed before)
|
||
1329 | jTextComponentOfEditor.setDocument(this.document);
|
||
1330 | 6721 | ppiqueras | } |
1331 | 8765 | jjdelcerro | } |
1332 | |||
1333 | /**
|
||
1334 | * Configures the document of the editor of this component
|
||
1335 | */
|
||
1336 | private void configureDocument() { |
||
1337 | // Creates the document of the editor of this component
|
||
1338 | document = new PlainDocumentTextFormatter();
|
||
1339 | document.setJComboBoxItemsSeekerDynamicReference(this);
|
||
1340 | 6793 | ppiqueras | |
1341 | 8765 | jjdelcerro | // Defines and add a Document listener for changes on the document of the editor of this component
|
1342 | document.addDocumentListener(this.documentListener);
|
||
1343 | 6721 | ppiqueras | } |
1344 | |||
1345 | 8765 | jjdelcerro | /**
|
1346 | * Selects the next item of the popup
|
||
1347 | */
|
||
1348 | private void selectItemDown() { |
||
1349 | specialSelectionByUserState = true;
|
||
1350 | |||
1351 | if (getItemCount() > 0) |
||
1352 | { |
||
1353 | if (getSelectedIndex() == (getItemCount()-1)) |
||
1354 | this.setSelectedIndex(0); |
||
1355 | else
|
||
1356 | this.setSelectedIndex(getSelectedIndex()+1); |
||
1357 | } |
||
1358 | } |
||
1359 | |||
1360 | 6721 | ppiqueras | /**
|
1361 | 8765 | jjdelcerro | * Selects the previous item of the popup
|
1362 | 6721 | ppiqueras | */
|
1363 | 8765 | jjdelcerro | private void selectItemUp() { |
1364 | specialSelectionByUserState = true;
|
||
1365 | |||
1366 | switch(getSelectedIndex())
|
||
1367 | { |
||
1368 | case -1: case 0: |
||
1369 | this.setSelectedIndex(getItemCount()-1); |
||
1370 | break;
|
||
1371 | default:
|
||
1372 | this.setSelectedIndex(getSelectedIndex()-1); |
||
1373 | } |
||
1374 | } |
||
1375 | |||
1376 | /**
|
||
1377 | * This method is invoked when some text has to be removed: With the 'Delete' option of the text-edition-popupmenu or with the 'delete' ('supr'
|
||
1378 | * in spanish keyboard) key
|
||
1379 | *
|
||
1380 | * @param editor A reference to the editor component
|
||
1381 | */
|
||
1382 | private void deleteTextLogic(JTextComponent editor, boolean backSpace_Delete_Mode) { |
||
1383 | // Remove selected text:
|
||
1384 | logger.debug("GETMARK: " + editor.getCaret().getMark() + "GETCARETPOSITION" + editor.getCaretPosition()); |
||
1385 | int caretPosition = editor.getCaretPosition();
|
||
1386 | int markPosition = editor.getCaret().getMark();
|
||
1387 | specialSelectionByUserState = false;
|
||
1388 | |||
1389 | // Get the new text:
|
||
1390 | try {
|
||
1391 | |||
1392 | int max_index = Math.max(caretPosition, markPosition); |
||
1393 | |||
1394 | if (caretPosition == markPosition)
|
||
1395 | if (caretPosition == document.getLength()) // If no characters have to be removed |
||
1396 | return;
|
||
1397 | else
|
||
1398 | max_index ++; |
||
1399 | |||
1400 | String newText = document.getText(0, Math.min(caretPosition, markPosition)) + document.getText(max_index, document.getLength() - max_index ); |
||
1401 | |||
1402 | // Update model and document, and remove character\s
|
||
1403 | switch(currentShowState)
|
||
1404 | { |
||
1405 | case START_VIEW_STATE :
|
||
1406 | |||
1407 | if (document.getLength() > 0) |
||
1408 | { |
||
1409 | // If dynamic searches:
|
||
1410 | try {
|
||
1411 | // If the search will be dynamic:
|
||
1412 | if (isDynamicSearchConfiguration())
|
||
1413 | { |
||
1414 | model.setWrittenText(newText); |
||
1415 | logger.debug("Texto que se le env?a delete al modelo desde SUPR: ->" + document.getText(0, document.getLength()) + "<-"); |
||
1416 | } |
||
1417 | } catch (BadLocationException e) { |
||
1418 | e.printStackTrace(); |
||
1419 | } |
||
1420 | |||
1421 | model.setStartStateFlag(false);
|
||
1422 | currentShowState = SEARCH_VIEW_STATE; |
||
1423 | |||
1424 | // Remove one or more characters
|
||
1425 | characterEliminationLogic(editor, caretPosition, markPosition); |
||
1426 | } |
||
1427 | break;
|
||
1428 | case SEARCH_VIEW_STATE :
|
||
1429 | |||
1430 | // If there isn't characters
|
||
1431 | if (document.getLength() == 0) |
||
1432 | { |
||
1433 | // This instruction avoids popup could failure when got invisible
|
||
1434 | hidePopup(); |
||
1435 | |||
1436 | // If it's a dynamic search
|
||
1437 | if (isDynamicSearchConfiguration())
|
||
1438 | { |
||
1439 | model.setWrittenText("");
|
||
1440 | logger.debug("Texto que se le env?a delete al modelo desde SUPR: ->\"\"<-");
|
||
1441 | } |
||
1442 | |||
1443 | // Remove one or more characters
|
||
1444 | characterEliminationLogic(editor, caretPosition, markPosition); |
||
1445 | |||
1446 | // Return to the start view state
|
||
1447 | model.setStartStateFlag(true);
|
||
1448 | currentShowState = START_VIEW_STATE; |
||
1449 | |||
1450 | // Select the first Item
|
||
1451 | setSelectedIndex(0);
|
||
1452 | |||
1453 | if (useHighlight_Flag)
|
||
1454 | document.highlightCompletedText(0);
|
||
1455 | } |
||
1456 | else
|
||
1457 | { |
||
1458 | // This instruction avoids popup could failure when got invisible
|
||
1459 | hidePopup(); |
||
1460 | |||
1461 | allowInsertString = true;
|
||
1462 | |||
1463 | if (lastWasPressedAKeyModifier)
|
||
1464 | { |
||
1465 | logger.debug("PRESSED: " + editor.getText().substring(0)); |
||
1466 | lastWasPressedAKeyModifier = false;
|
||
1467 | } |
||
1468 | |||
1469 | // If dynamic searches:
|
||
1470 | try {
|
||
1471 | |||
1472 | // If the search will be dynamic:
|
||
1473 | if (isDynamicSearchConfiguration())
|
||
1474 | { |
||
1475 | model.setWrittenText(newText); |
||
1476 | logger.debug("Texto que se le env?a delete al modelo desde SUPR: ->" + document.getText(0, document.getLength()) + "<-"); |
||
1477 | } |
||
1478 | |||
1479 | // Remove one or more characters
|
||
1480 | characterEliminationLogic(editor, caretPosition, markPosition); |
||
1481 | |||
1482 | // Indicate to the model that now is disabled the start view
|
||
1483 | if (currentShowState == START_VIEW_STATE)
|
||
1484 | { |
||
1485 | model.setStartStateFlag(false);
|
||
1486 | currentShowState = SEARCH_VIEW_STATE; |
||
1487 | } |
||
1488 | } catch (BadLocationException e) { |
||
1489 | // TODO Auto-generated catch block
|
||
1490 | e.printStackTrace(); |
||
1491 | } |
||
1492 | } |
||
1493 | break;
|
||
1494 | } |
||
1495 | |||
1496 | updatePopUpView(); |
||
1497 | |||
1498 | } catch (BadLocationException e1) { |
||
1499 | // TODO Auto-generated catch block
|
||
1500 | e1.printStackTrace(); |
||
1501 | } |
||
1502 | } |
||
1503 | |||
1504 | /**
|
||
1505 | * This method has the logic for remove one or more characters
|
||
1506 | *
|
||
1507 | * @param editor A reference to the editor
|
||
1508 | * @param caretPosition Position of the caret in the text
|
||
1509 | */
|
||
1510 | private void characterEliminationLogic(JTextComponent editor, int caretPosition, int markPosition) { |
||
1511 | // First: Remove character\s (only if hasn't been done a 'cut' mouse operation)
|
||
1512 | if (cutOperationDone) {
|
||
1513 | cutOperationDone = false;
|
||
1514 | } |
||
1515 | else {
|
||
1516 | try {
|
||
1517 | // If no characters are selected
|
||
1518 | if (markPosition == caretPosition) {
|
||
1519 | // Remove the character which is on the right of the caret position
|
||
1520 | if (caretPosition < document.getLength())
|
||
1521 | document.remove(caretPosition, 1);
|
||
1522 | } |
||
1523 | else // If there are characters selected |
||
1524 | { |
||
1525 | // Remove the characters which are selected
|
||
1526 | int length = Math.abs(markPosition - caretPosition); |
||
1527 | |||
1528 | // Remove the characters which are selected
|
||
1529 | document.remove(Math.min(markPosition, caretPosition), length);
|
||
1530 | } |
||
1531 | } catch (BadLocationException e) { |
||
1532 | e.printStackTrace(); |
||
1533 | } |
||
1534 | } |
||
1535 | } |
||
1536 | |||
1537 | /**
|
||
1538 | * Returns true if the model has a dynamic search configuration
|
||
1539 | *
|
||
1540 | * @return 'true' if the model has a dynamic searchh configuration, else returns 'false'.
|
||
1541 | */
|
||
1542 | private boolean isDynamicSearchConfiguration() { |
||
1543 | switch(model.getSearchBehavior())
|
||
1544 | { |
||
1545 | case AbstractDefaultComboBoxItemsSeekerConfigurableModel.MAINTAIN_ORIGINAL_POSITION_DYNAMIC_SEARCH :
|
||
1546 | case AbstractDefaultComboBoxItemsSeekerConfigurableModel.ORDERED_DYNAMIC_SEARCH :
|
||
1547 | case AbstractDefaultComboBoxItemsSeekerConfigurableModel.DISORDERED_DYNAMIC_SEARCH :
|
||
1548 | return true; |
||
1549 | } |
||
1550 | |||
1551 | return false; |
||
1552 | } |
||
1553 | |||
1554 | /**
|
||
1555 | * Selects the first item added to the model
|
||
1556 | */
|
||
1557 | public void selectFirstItemAddedToModel() { |
||
1558 | // Select the first Item added
|
||
1559 | Object item = model.getFirstItemAdded();
|
||
1560 | if (item != null) |
||
1561 | setSelectedItem(item); |
||
1562 | } |
||
1563 | |||
1564 | 6721 | ppiqueras | |
1565 | 8765 | jjdelcerro | /**
|
1566 | * Updates the popup view, this solves the problem of updating items that are showed, but has the problem that could produce winking
|
||
1567 | 6721 | ppiqueras | */
|
1568 | 8765 | jjdelcerro | private void updatePopUpView() { |
1569 | 6721 | ppiqueras | // HidePopUp + ShowPopUp to force update the popup list of items
|
1570 | hidePopup(); |
||
1571 | showPopup(); |
||
1572 | this.setVisible(true); |
||
1573 | 8765 | jjdelcerro | |
1574 | 6721 | ppiqueras | } |
1575 | 8765 | jjdelcerro | |
1576 | /**
|
||
1577 | * This method has the logic for a "undo" operation
|
||
1578 | */
|
||
1579 | private void undoOperationLogic() { |
||
1580 | logger.debug("UNDO PRESSED");
|
||
1581 | try {
|
||
1582 | if (undoManager.canUndo()) {
|
||
1583 | undoManager.undo(); |
||
1584 | |||
1585 | String newPattern = document.getText(0, document.getLength()); |
||
1586 | |||
1587 | model.setWrittenText(newPattern); |
||
1588 | |||
1589 | document.formatText(document.lookupItem(), 0);
|
||
1590 | |||
1591 | if (isPopupVisible())
|
||
1592 | updatePopUpView(); |
||
1593 | |||
1594 | logger.debug("Undo por teclado realizado");
|
||
1595 | } |
||
1596 | } catch (BadLocationException e) { |
||
1597 | e.printStackTrace(); |
||
1598 | } catch (CannotUndoException e) { |
||
1599 | e.printStackTrace(); |
||
1600 | } |
||
1601 | } |
||
1602 | |||
1603 | /**
|
||
1604 | * This method has the logic for a "redo" operation
|
||
1605 | */
|
||
1606 | private void redoOperationLogic() { |
||
1607 | logger.debug("REDO PRESSED");
|
||
1608 | try {
|
||
1609 | if (undoManager.canRedo()) {
|
||
1610 | undoManager.redo(); |
||
1611 | |||
1612 | String newPattern = document.getText(0, document.getLength()); |
||
1613 | |||
1614 | model.setWrittenText(newPattern); |
||
1615 | |||
1616 | document.formatText(document.lookupItem(), 0);
|
||
1617 | |||
1618 | if (isPopupVisible())
|
||
1619 | updatePopUpView(); |
||
1620 | |||
1621 | logger.debug("Redo por teclado realizado");
|
||
1622 | } |
||
1623 | } catch (CannotRedoException e) { |
||
1624 | e.printStackTrace(); |
||
1625 | } catch (BadLocationException e) { |
||
1626 | e.printStackTrace(); |
||
1627 | } |
||
1628 | } |
||
1629 | 6721 | ppiqueras | |
1630 | 8765 | jjdelcerro | ////// REDEFINITION OF SOME METHODS OF JCOMBOBOX //////
|
1631 | 6721 | ppiqueras | |
1632 | /*
|
||
1633 | * (non-Javadoc)
|
||
1634 | * @see javax.swing.JComboBox#actionPerformed(java.awt.event.ActionEvent)
|
||
1635 | */
|
||
1636 | public void actionPerformed(ActionEvent e) |
||
1637 | { |
||
1638 | super.actionPerformed(e);
|
||
1639 | |||
1640 | // This flag indicates to the 'insertString' method of the PlainDocumentSeeker that the text of the item selected or written by the user
|
||
1641 | // hasn't been written on the TextEditor of ths component
|
||
1642 | selecting = false;
|
||
1643 | } |
||
1644 | |||
1645 | 8765 | jjdelcerro | /*
|
1646 | 6721 | ppiqueras | * (non-Javadoc)
|
1647 | * @see javax.swing.JComboBox#addItem(java.lang.Object)
|
||
1648 | */
|
||
1649 | 8765 | jjdelcerro | public void addItem(Object anObject) { |
1650 | 6721 | ppiqueras | // Adds the item to this component
|
1651 | model.addElement(anObject); |
||
1652 | |||
1653 | // Set the last selected item -> by default select the first item:
|
||
1654 | // This is used to show the first item that model returns when we add a new item. This also
|
||
1655 | // corrects the 'mistake' produced by 'ComboBoxModel' when is added a new item and there wasn't
|
||
1656 | // any selected -> that the 'ComboBoxModel' selects by default the first added (that in our case
|
||
1657 | // might not be the same as the first item seen in the popup list)
|
||
1658 | if (this.getSelectedIndex() != 0) |
||
1659 | { |
||
1660 | this.setSelectedIndex(0); |
||
1661 | 8765 | jjdelcerro | // this.selectedItem = this.getSelectedItem();
|
1662 | 6721 | ppiqueras | } |
1663 | } |
||
1664 | |||
1665 | 8765 | jjdelcerro | /*
|
1666 | 6721 | ppiqueras | * (non-Javadoc)
|
1667 | * @see javax.swing.JComboBox#removeAllItems()
|
||
1668 | */
|
||
1669 | 8765 | jjdelcerro | public void removeAllItems() { |
1670 | 6721 | ppiqueras | // Removes all items from the model
|
1671 | model.removeAllElements(); |
||
1672 | |||
1673 | currentShowState = BEGINNING_VIEW_STATE; |
||
1674 | } |
||
1675 | |||
1676 | 8765 | jjdelcerro | /*
|
1677 | 6721 | ppiqueras | * (non-Javadoc)
|
1678 | * @see javax.swing.JComboBox#removeItem(java.lang.Object)
|
||
1679 | */
|
||
1680 | 8765 | jjdelcerro | public void removeItem(Object anObject) { |
1681 | 6721 | ppiqueras | // Removes an object from the model
|
1682 | model.removeElement(anObject); |
||
1683 | |||
1684 | if (model.getSize() == 0) |
||
1685 | currentShowState = BEGINNING_VIEW_STATE; |
||
1686 | } |
||
1687 | |||
1688 | 8765 | jjdelcerro | /*
|
1689 | 6721 | ppiqueras | * (non-Javadoc)
|
1690 | * @see javax.swing.JComboBox#removeItemAt(int)
|
||
1691 | */
|
||
1692 | 8765 | jjdelcerro | public void removeItemAt(int anIndex) { |
1693 | 6721 | ppiqueras | // Removes an object, which is in a determinated position (index), from the model
|
1694 | model.removeElementAt(anIndex); |
||
1695 | |||
1696 | if (model.getSize() == 0) |
||
1697 | currentShowState = BEGINNING_VIEW_STATE; |
||
1698 | } |
||
1699 | |||
1700 | 8765 | jjdelcerro | /*
|
1701 | 6721 | ppiqueras | * (non-Javadoc)
|
1702 | * @see javax.swing.JComboBox#getItemCount()
|
||
1703 | */
|
||
1704 | 8765 | jjdelcerro | public int getItemCount() { |
1705 | 6721 | ppiqueras | return model.getSize();
|
1706 | } |
||
1707 | |||
1708 | 8765 | jjdelcerro | /*
|
1709 | 6721 | ppiqueras | * (non-Javadoc)
|
1710 | * @see javax.swing.JComboBox#getItemAt(int)
|
||
1711 | */
|
||
1712 | 8765 | jjdelcerro | public Object getItemAt(int index) { |
1713 | 6721 | ppiqueras | return model.getElementAt(index);
|
1714 | } |
||
1715 | |||
1716 | 8765 | jjdelcerro | /*
|
1717 | 6721 | ppiqueras | * (non-Javadoc)
|
1718 | * @see javax.swing.JComboBox#setModel(javax.swing.ComboBoxModel)
|
||
1719 | */
|
||
1720 | 8765 | jjdelcerro | public void setModel(ComboBoxModel aModel) { |
1721 | 6721 | ppiqueras | // Depending on the type of class of the current object, this object will execute different code
|
1722 | 6755 | ppiqueras | if ( (aModel instanceof ComboBoxSingularItemsSeekerConfigurableModel) || (aModel instanceof ComboBoxItemsSeekerConfigurableModel) ) |
1723 | 6721 | ppiqueras | { |
1724 | super.setModel(aModel);
|
||
1725 | |||
1726 | 6755 | ppiqueras | if (aModel instanceof ComboBoxSingularItemsSeekerConfigurableModel) |
1727 | model = (ComboBoxSingularItemsSeekerConfigurableModel)super.getModel();
|
||
1728 | else
|
||
1729 | model = (ComboBoxItemsSeekerConfigurableModel)super.getModel();
|
||
1730 | |||
1731 | 6721 | ppiqueras | // If we insert a model with items -> select by default the first
|
1732 | if (aModel.getSize() > 0) |
||
1733 | this.setSelectedIndex(0); |
||
1734 | else
|
||
1735 | { |
||
1736 | // Else -> set the default index (-1) and current showed string ("")
|
||
1737 | this.setSelectedIndex(-1); |
||
1738 | } |
||
1739 | |||
1740 | this.configureModel();
|
||
1741 | } |
||
1742 | else
|
||
1743 | { |
||
1744 | // If it's an instance of DefaultComboBoxModel:
|
||
1745 | super.setModel(aModel);
|
||
1746 | } |
||
1747 | } |
||
1748 | |||
1749 | 8765 | jjdelcerro | /*
|
1750 | 6721 | ppiqueras | * (non-Javadoc)
|
1751 | * @see javax.swing.JComboBox#setSelectedIndex(int)
|
||
1752 | */
|
||
1753 | 8765 | jjdelcerro | public void setSelectedIndex(int anIndex) { |
1754 | 6721 | ppiqueras | super.setSelectedIndex(anIndex);
|
1755 | } |
||
1756 | |||
1757 | 8765 | jjdelcerro | /*
|
1758 | 6721 | ppiqueras | * (non-Javadoc)
|
1759 | * @see javax.swing.JComboBox#getSelectedIndex()
|
||
1760 | */
|
||
1761 | 8765 | jjdelcerro | public int getSelectedIndex() { |
1762 | 6721 | ppiqueras | Object item = this.getSelectedItem(); |
1763 | |||
1764 | if (item == null) |
||
1765 | return -1; |
||
1766 | else
|
||
1767 | return model.getIndexOf(item);
|
||
1768 | } |
||
1769 | |||
1770 | 8765 | jjdelcerro | /*
|
1771 | 6721 | ppiqueras | * (non-Javadoc)
|
1772 | * @see javax.swing.JComboBox#setSelectedItem(java.lang.Object)
|
||
1773 | */
|
||
1774 | 8765 | jjdelcerro | public void setSelectedItem(Object anObject) { |
1775 | 6721 | ppiqueras | super.setSelectedItem(anObject);
|
1776 | } |
||
1777 | |||
1778 | ////// END REDEFINITION OF SOME METHODS OF JCOMBOBOX //////
|
||
1779 | 8765 | jjdelcerro | |
1780 | 6721 | ppiqueras | |
1781 | 8765 | jjdelcerro | |
1782 | 6721 | ppiqueras | ////// METHODS FOR THE BEHAVIOR FLAGS //////
|
1783 | |||
1784 | /**
|
||
1785 | * This method tests the configuration of the flags and returns true or false if its ok or not with the
|
||
1786 | * logical behavior of this component
|
||
1787 | *
|
||
1788 | * @return boolean True if the configuration of the flags is oks, false if not
|
||
1789 | */
|
||
1790 | public boolean testFlagsConfigurationOK() { |
||
1791 | return this.model.testFlagsConfigurationOK(); |
||
1792 | } |
||
1793 | |||
1794 | 8765 | jjdelcerro | /**
|
1795 | * @see AbstractDefaultComboBoxItemsSeekerConfigurableModel#getStartBehavior()
|
||
1796 | */
|
||
1797 | 6721 | ppiqueras | public int getStartBehavior() { |
1798 | return this.model.getStartBehavior(); |
||
1799 | } |
||
1800 | |||
1801 | 8765 | jjdelcerro | /**
|
1802 | * @see AbstractDefaultComboBoxItemsSeekerConfigurableModel#setStartBehavior(int)
|
||
1803 | */
|
||
1804 | 6721 | ppiqueras | public void setStartBehavior(int start_Behavior) { |
1805 | this.model.setStartBehavior(start_Behavior);
|
||
1806 | |||
1807 | if (!this.model.testFlagsConfigurationOK()) |
||
1808 | 7244 | cesar | JOptionPane.showMessageDialog(this, Messages.getText("errorMessageJComboBoxItemsSeekerConfigurable"), Messages.getText("exportJOP2Title"), JOptionPane.ERROR_MESSAGE); |
1809 | 6721 | ppiqueras | } |
1810 | |||
1811 | 8765 | jjdelcerro | /**
|
1812 | * @see AbstractDefaultComboBoxItemsSeekerConfigurableModel#getSearchBehavior()
|
||
1813 | */
|
||
1814 | 6721 | ppiqueras | public int getSearchBehavior() { |
1815 | return this.model.getSearchBehavior(); |
||
1816 | } |
||
1817 | |||
1818 | 8765 | jjdelcerro | /**
|
1819 | * @see AbstractDefaultComboBoxItemsSeekerConfigurableModel#setSearchBehavior(int)
|
||
1820 | */
|
||
1821 | 6721 | ppiqueras | public void setSearchBehavior(int search_Behavior) { |
1822 | this.model.setSearchBehavior(search_Behavior);
|
||
1823 | |||
1824 | if (!this.model.testFlagsConfigurationOK()) |
||
1825 | 7244 | cesar | JOptionPane.showMessageDialog(this, Messages.getText("errorMessageJComboBoxItemsSeekerConfigurable"), Messages.getText("exportJOP2Title"), JOptionPane.ERROR_MESSAGE); |
1826 | 6721 | ppiqueras | } |
1827 | |||
1828 | /**
|
||
1829 | 8765 | jjdelcerro | * @see AbstractDefaultComboBoxItemsSeekerConfigurableModel#isCaseSensitive_Flag()
|
1830 | 6721 | ppiqueras | */
|
1831 | 8765 | jjdelcerro | public boolean isCaseSensitive_Flag() { |
1832 | return this.model.isCaseSensitive_Flag(); |
||
1833 | 6721 | ppiqueras | } |
1834 | |||
1835 | /**
|
||
1836 | 8765 | jjdelcerro | * @see AbstractDefaultComboBoxItemsSeekerConfigurableModel#setCaseSensitive_Flag(boolean)
|
1837 | 6721 | ppiqueras | */
|
1838 | 8765 | jjdelcerro | public void setCaseSensitive_Flag(boolean case_Sensitive) { |
1839 | this.model.setCaseSensitive_Flag(case_Sensitive);
|
||
1840 | 6721 | ppiqueras | |
1841 | if (!this.model.testFlagsConfigurationOK()) |
||
1842 | 7244 | cesar | JOptionPane.showMessageDialog(this, Messages.getText("errorMessageJComboBoxItemsSeekerConfigurable"), Messages.getText("exportJOP2Title"), JOptionPane.ERROR_MESSAGE); |
1843 | 6721 | ppiqueras | } |
1844 | |||
1845 | /**
|
||
1846 | 8765 | jjdelcerro | * Returns the 'only_one_color_on_text' configuration value of this component. Configuration values are:
|
1847 | * + true -> always uses black color on text
|
||
1848 | * + false -> by default uses black color on text, but if text written by user doesn't match with any item, text will be on red color
|
||
1849 | 6721 | ppiqueras | *
|
1850 | 8765 | jjdelcerro | * @return Only-One-Color-On-Text configuration
|
1851 | 6721 | ppiqueras | */
|
1852 | 8765 | jjdelcerro | public boolean isOnlyOneColorOnText_Flag() { |
1853 | return onlyOneColorOnText_Flag;
|
||
1854 | 6721 | ppiqueras | } |
1855 | |||
1856 | /**
|
||
1857 | 8765 | jjdelcerro | * Sets the 'only_one_color_on_text' configuration value for this component. Configuration values are:
|
1858 | * + true -> always uses black color on text
|
||
1859 | * + false -> by default uses black color on text, but if text written by user doesn't match with any item, text will be on red color
|
||
1860 | 6721 | ppiqueras | *
|
1861 | 8765 | jjdelcerro | * @return Only_one_color_on_text configuration
|
1862 | 6721 | ppiqueras | */
|
1863 | 8765 | jjdelcerro | public void setOnlyOneColorOnText_Flag(boolean only_One_Color) { |
1864 | this.onlyOneColorOnText_Flag = only_One_Color;
|
||
1865 | 6721 | ppiqueras | |
1866 | if (!this.model.testFlagsConfigurationOK()) |
||
1867 | 7244 | cesar | JOptionPane.showMessageDialog(this, Messages.getText("errorMessageJComboBoxItemsSeekerConfigurable"), Messages.getText("exportJOP2Title"), JOptionPane.ERROR_MESSAGE); |
1868 | 6721 | ppiqueras | } |
1869 | |||
1870 | 8765 | jjdelcerro | /**
|
1871 | * Returns the 'beep_enabled' configuration value of this component. Configuration values are:
|
||
1872 | * + true -> a beep-sound is listened when no item matches with the text written.
|
||
1873 | * + false -> no sound is listened.
|
||
1874 | *
|
||
1875 | * @return Beep_enabled configuration
|
||
1876 | */
|
||
1877 | public boolean isBeepEnabled_Flag() { |
||
1878 | return this.beepEnabled_Flag; |
||
1879 | 6721 | ppiqueras | } |
1880 | |||
1881 | 8765 | jjdelcerro | /**
|
1882 | * Sets the 'beep_enabled' configuration value for this component. Configuration values are:
|
||
1883 | * + true -> a beep-sound is listened when no item matches with the text written.
|
||
1884 | * + false -> no sound is listened.
|
||
1885 | *
|
||
1886 | * @return Beep_Enabled configuration
|
||
1887 | */
|
||
1888 | public void setBeepEnabled_Flag(boolean beep_Enabled) { |
||
1889 | this.beepEnabled_Flag = beep_Enabled;
|
||
1890 | } |
||
1891 | |||
1892 | /**
|
||
1893 | * Returns the 'complete_matched_item' configuration value of this component. Configuration values are:
|
||
1894 | * + true -> When user writes, shows also the rest of the current matched item that user hasn't written.
|
||
1895 | * + false -> Only shows the text written by the user when user is writting.
|
||
1896 | *
|
||
1897 | * @return Complete_matched_item configuration
|
||
1898 | */
|
||
1899 | public boolean isCompleteMatchedItem_Flag() { |
||
1900 | return this.completeMatchedItem_Flag; |
||
1901 | 6732 | ppiqueras | } |
1902 | |||
1903 | 8765 | jjdelcerro | /**
|
1904 | * Sets the 'complete_matched_item' configuration value for this component. Configuration values are:
|
||
1905 | * + true -> a beep-sound is listened when no item matches with the text written.
|
||
1906 | * + false -> no sound is listened.
|
||
1907 | *
|
||
1908 | * @return Complete_matched_item configuration
|
||
1909 | */
|
||
1910 | public void setCompleteMatchedItem_Flag(boolean Complete_Matched_Item) { |
||
1911 | this.completeMatchedItem_Flag = Complete_Matched_Item;
|
||
1912 | 6732 | ppiqueras | } |
1913 | |||
1914 | 8765 | jjdelcerro | /**
|
1915 | * Returns the 'allowed_repeated_items' configuration value of this component. Configuration values are:
|
||
1916 | * Uses one of the two models according the value of this flag:
|
||
1917 | * + true -> Uses 'ComboBoxItemsSeekerConfigurableModel' as model (this could work slowly).
|
||
1918 | * + false -> Uses 'ComboBoxSingularItemsSeekerConfigurableModel' as model.
|
||
1919 | *
|
||
1920 | * @return Allowed_repeated_items configuration
|
||
1921 | */
|
||
1922 | public boolean isAllowedRepeatedItems_Flag() { |
||
1923 | return this.allowedRepeatedItems_Flag; |
||
1924 | 6732 | ppiqueras | } |
1925 | |||
1926 | 8765 | jjdelcerro | /**
|
1927 | * Sets the 'allowed_repeated_items' configuration value for this component. Configuration values are:
|
||
1928 | * Uses one of the two models according the value of this flag:
|
||
1929 | * + true -> Uses 'ComboBoxItemsSeekerConfigurableModel' as model (this could work slowly).
|
||
1930 | * + false -> Uses 'ComboBoxSingularItemsSeekerConfigurableModel' as model.
|
||
1931 | *
|
||
1932 | * @return Allowed_repeated_items configuration
|
||
1933 | */
|
||
1934 | public void setAllowedRepeatedItems_Flag(boolean allowed_Repeated_Items) { |
||
1935 | this.allowedRepeatedItems_Flag = allowed_Repeated_Items;
|
||
1936 | 6755 | ppiqueras | |
1937 | try {
|
||
1938 | AbstractDefaultComboBoxItemsSeekerConfigurableModel model_temp; |
||
1939 | 8765 | jjdelcerro | |
1940 | // Add the items to the new model
|
||
1941 | if (allowed_Repeated_Items)
|
||
1942 | model_temp = new ComboBoxItemsSeekerConfigurableModel(model.getParentAllData());
|
||
1943 | else
|
||
1944 | model_temp = new ComboBoxSingularItemsSeekerConfigurableModel(model.getParentAllData());
|
||
1945 | |||
1946 | // Copy the behavior of the model
|
||
1947 | model_temp.setStartBehavior(this.getStartBehavior());
|
||
1948 | model_temp.setSearchBehavior(this.getSearchBehavior());
|
||
1949 | model_temp.setCaseSensitive_Flag(this.isCaseSensitive_Flag());
|
||
1950 | |||
1951 | // Set the new model
|
||
1952 | this.setModel(model_temp);
|
||
1953 | 6755 | ppiqueras | } |
1954 | catch(Exception e) |
||
1955 | { |
||
1956 | e.printStackTrace(); |
||
1957 | } |
||
1958 | } |
||
1959 | |||
1960 | 8765 | jjdelcerro | /**
|
1961 | * Returns the 'allowed_mouse_edition_popup_menu' configuration value of this component. Configuration values are:
|
||
1962 | * + true -> a 'PopupMenu' for text edition that appears when the user clicks on the text-edition-field with the right
|
||
1963 | * button of the mouse.
|
||
1964 | * + false -> that 'PopupMenu' won't appear.
|
||
1965 | *
|
||
1966 | * @return Allowed_mouse_edition_popup_menu configuration
|
||
1967 | */
|
||
1968 | public boolean isAllowedMouseEditionPopupMenu_Flag() { |
||
1969 | return this.allowedMouseEditionPopupMenu_Flag; |
||
1970 | } |
||
1971 | |||
1972 | /**
|
||
1973 | * Sets the 'allowed_mouse_edition_popup_menu' configuration value for this component. Configuration values are:
|
||
1974 | * + true -> a 'PopupMenu' for text edition that appears when the user clicks on the text-edition-field with the right
|
||
1975 | * button of the mouse.
|
||
1976 | * + false -> that 'PopupMenu' won't appear.
|
||
1977 | *
|
||
1978 | * @return Allowed_mouse_edition_popup_menu configuration
|
||
1979 | */
|
||
1980 | public void setAllowedMouseEditionPopupMenu_Flag(boolean allowed_Mouse_Edition_Popup_Menu) { |
||
1981 | JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent(); |
||
1982 | |||
1983 | if (this.allowedMouseEditionPopupMenu_Flag != allowed_Mouse_Edition_Popup_Menu) |
||
1984 | { |
||
1985 | // If now is allowed -> adds the mouse listener
|
||
1986 | if (allowed_Mouse_Edition_Popup_Menu)
|
||
1987 | editor.addMouseListener(this.editorMouseListener);
|
||
1988 | else // If now isn't allowed |
||
1989 | editor.removeMouseListener(this.editorMouseListener);
|
||
1990 | } |
||
1991 | |||
1992 | this.allowedMouseEditionPopupMenu_Flag = allowed_Mouse_Edition_Popup_Menu;
|
||
1993 | } |
||
1994 | |||
1995 | /**
|
||
1996 | * Returns the 'to_force_to_only_coincidences_in_the_search' configuration value of this component. Configuration values are:
|
||
1997 | * + true -> If the user has written some text that doesn't mach with any item, and press the 'Enter' key for close the popup the user will
|
||
1998 | * see written in the text-edition-field the last item which matched with the text written, or the first item of the model if
|
||
1999 | * there wasn't.
|
||
2000 | * + false -> If no item matches with the text written and the user presses the 'Enter' key, no item will be selected.
|
||
2001 | *
|
||
2002 | * @return To_force_to_only_coincidences_in_the_search configuration
|
||
2003 | */
|
||
2004 | public boolean isToForceToOnlyCoincidencesInTheSearch_Flag() { |
||
2005 | return this.toForceToOnlyCoincidencesInTheSearch_Flag; |
||
2006 | } |
||
2007 | 6755 | ppiqueras | |
2008 | 8765 | jjdelcerro | /**
|
2009 | * Sets the 'to_force_to_only_coincidences_in_the_search' configuration value for this component. Configuration values are:
|
||
2010 | * + true -> If the user has written some text that doesn't mach with any item, and press the 'Enter' key for close the popup the user will
|
||
2011 | * see written in the text-edition-field the last item which matched with the text written, or the first item of the model if
|
||
2012 | * there wasn't.
|
||
2013 | * + false -> If no item matches with the text written and the user presses the 'Enter' key, no item will be selected.
|
||
2014 | *
|
||
2015 | * @return To_force_to_only_coincidences_in_the_search configuration
|
||
2016 | */
|
||
2017 | public void setToForceToOnlyCoincidencesInTheSearch_Flag(boolean to_Force_To_Only_Coincidences_In_The_Search) { |
||
2018 | this.toForceToOnlyCoincidencesInTheSearch_Flag = to_Force_To_Only_Coincidences_In_The_Search;
|
||
2019 | } |
||
2020 | |||
2021 | /**
|
||
2022 | * Returns the 'use_highlight' configuration value of this component. Configuration values are:
|
||
2023 | * + true -> marks characters of the text in the text-edition-field with a highlight.
|
||
2024 | * + false -> doesn't do that.
|
||
2025 | *
|
||
2026 | * @return Use_highlight configuration
|
||
2027 | */
|
||
2028 | public boolean isUseHighLight_Flag() { |
||
2029 | return this.useHighlight_Flag; |
||
2030 | } |
||
2031 | 6755 | ppiqueras | |
2032 | 8765 | jjdelcerro | /**
|
2033 | * Sets the 'use_highlight' configuration value for this component. Configuration values are:
|
||
2034 | * + true -> marks characters of the text in the text-edition-field with a highlight.
|
||
2035 | * + false -> doesn't do that.
|
||
2036 | *
|
||
2037 | * @return Use_highlight configuration
|
||
2038 | */
|
||
2039 | public void setUseHighLight_Flag(boolean use_Highlight) { |
||
2040 | this.useHighlight_Flag = use_Highlight;
|
||
2041 | } |
||
2042 | |||
2043 | 6721 | ppiqueras | ////// END METHODS FOR THE BEHAVIOR FLAGS //////
|
2044 | |||
2045 | |||
2046 | 8765 | jjdelcerro | |
2047 | ////// OTHER METHODS //////
|
||
2048 | |||
2049 | /**
|
||
2050 | * Sets the limit of actions that can hold the UndoManager of this component
|
||
2051 | *
|
||
2052 | * @param limit
|
||
2053 | */
|
||
2054 | public void setUndoRedoLimitActions(int limit) { |
||
2055 | this.undoRedoLimitActions = limit;
|
||
2056 | undoManager.setLimit(undoRedoLimitActions); |
||
2057 | } |
||
2058 | |||
2059 | /**
|
||
2060 | * Gets the limit of actions that can hold the UndoManager:
|
||
2061 | *
|
||
2062 | * @return int
|
||
2063 | */
|
||
2064 | public int getUndoRedoLimitActions() { |
||
2065 | return this.undoRedoLimitActions; |
||
2066 | } |
||
2067 | |||
2068 | ////// END OTHER METHODS //////
|
||
2069 | |||
2070 | |||
2071 | /**
|
||
2072 | * Inner class that inherits of the class PlainDocument, and is used for manipulate the text that has the document of the editor of this component
|
||
2073 | * This class is also optimized for items seek, changes the color of the text or sets highlight if it's needed.
|
||
2074 | 6721 | ppiqueras | *
|
2075 | * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
|
||
2076 | */
|
||
2077 | 8765 | jjdelcerro | private class PlainDocumentTextFormatter extends PlainDocument { |
2078 | private static final long serialVersionUID = 4158213349939840209L; |
||
2079 | private JComboBoxItemsSeekerConfigurable comboBoxReference;
|
||
2080 | 6721 | ppiqueras | |
2081 | /**
|
||
2082 | * Default Constructor
|
||
2083 | */
|
||
2084 | 8765 | jjdelcerro | public PlainDocumentTextFormatter() {
|
2085 | 6721 | ppiqueras | super();
|
2086 | 8765 | jjdelcerro | this.initialize();
|
2087 | } |
||
2088 | |||
2089 | /**
|
||
2090 | * This method makes some initialize operations
|
||
2091 | */
|
||
2092 | private void initialize() { |
||
2093 | 6816 | ppiqueras | this.configureUndoManager();
|
2094 | 6721 | ppiqueras | } |
2095 | |||
2096 | /**
|
||
2097 | 8765 | jjdelcerro | * Configures the UndoManager for Undo-Redo operations
|
2098 | 6816 | ppiqueras | */
|
2099 | private void configureUndoManager() { |
||
2100 | // Listen for undo and redo events
|
||
2101 | this.addUndoableEditListener(new UndoableEditListener() { |
||
2102 | 8765 | jjdelcerro | /*
|
2103 | * (non-Javadoc)
|
||
2104 | * @see javax.swing.event.UndoableEditListener#undoableEditHappened(javax.swing.event.UndoableEditEvent)
|
||
2105 | */
|
||
2106 | 6816 | ppiqueras | public void undoableEditHappened(UndoableEditEvent evt) { |
2107 | 8765 | jjdelcerro | logger.debug("UNDOABLE EVENT");
|
2108 | undoManager.addEdit(evt.getEdit()); |
||
2109 | 6816 | ppiqueras | } |
2110 | }); |
||
2111 | } |
||
2112 | |||
2113 | /**
|
||
2114 | 6721 | ppiqueras | * Sets a reference of the combo_Box
|
2115 | *
|
||
2116 | 8765 | jjdelcerro | * @param combo_Box A reference to the class that contains this.
|
2117 | 6721 | ppiqueras | */
|
2118 | public void setJComboBoxItemsSeekerDynamicReference(JComboBoxItemsSeekerConfigurable combo_Box) { |
||
2119 | 6816 | ppiqueras | comboBoxReference = combo_Box; |
2120 | 6721 | ppiqueras | } |
2121 | |||
2122 | 8765 | jjdelcerro | /*
|
2123 | 6721 | ppiqueras | * (non-Javadoc)
|
2124 | * @see javax.swing.text.Document#remove(int, int)
|
||
2125 | */
|
||
2126 | public void remove(int offs, int len) throws BadLocationException { |
||
2127 | // return immediately when selecting an item
|
||
2128 | if (selecting) return; |
||
2129 | |||
2130 | if (hitBackspace)
|
||
2131 | { |
||
2132 | // user hit backspace => move the selection backwards
|
||
2133 | // old item keeps being selected
|
||
2134 | if (offs>0) |
||
2135 | { |
||
2136 | if (hitBackspaceOnSelection)
|
||
2137 | offs--; |
||
2138 | } |
||
2139 | else
|
||
2140 | { |
||
2141 | // User hit backspace with the cursor positioned on the start => beep
|
||
2142 | 8765 | jjdelcerro | if (beepEnabled_Flag)
|
2143 | 6816 | ppiqueras | comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
|
2144 | 6721 | ppiqueras | } |
2145 | |||
2146 | 8765 | jjdelcerro | if (useHighlight_Flag)
|
2147 | highlightCompletedText(offs); |
||
2148 | |||
2149 | 6791 | ppiqueras | hitBackspace=false;
|
2150 | 6721 | ppiqueras | } |
2151 | else
|
||
2152 | { |
||
2153 | 8765 | jjdelcerro | logger.debug("REMOVES OFFS: " + offs + ", LEN: " + len); |
2154 | super.remove(offs, len);
|
||
2155 | } |
||
2156 | 6760 | ppiqueras | |
2157 | 8765 | jjdelcerro | formatText(lookupItem(), offs); |
2158 | 6721 | ppiqueras | } |
2159 | 8765 | jjdelcerro | |
2160 | /* NUEVA VERSI?N
|
||
2161 | 6721 | ppiqueras | * (non-Javadoc)
|
2162 | * @see javax.swing.text.Document#insertString(int, java.lang.String, javax.swing.text.AttributeSet)
|
||
2163 | */
|
||
2164 | public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { |
||
2165 | 8765 | jjdelcerro | Object item = lookupItem();
|
2166 | |||
2167 | // If we have to complete the text: only write the part of the item not written
|
||
2168 | if ((completeMatchedItem_Flag) && (item != null) && (!itemSelectedByMouse)) { |
||
2169 | editor.getEditorComponent().setForeground(Color.BLACK);
|
||
2170 | super.insertString(super.getLength(), item.toString().substring(super.getLength(), item.toString().length()), a); |
||
2171 | |||
2172 | if (!specialSelectionByUserState)
|
||
2173 | offs += Math.min(str.length(), document.getLength());
|
||
2174 | } |
||
2175 | else {
|
||
2176 | super.insertString(offs, str, a);
|
||
2177 | itemSelectedByMouse = false;
|
||
2178 | offs += str.length(); |
||
2179 | } |
||
2180 | // offs += Math.min(str.length(), document.getLength());
|
||
2181 | formatText(item, offs); |
||
2182 | 6721 | ppiqueras | } |
2183 | 8765 | jjdelcerro | |
2184 | /**
|
||
2185 | * Marks text since 'start' position to its end on a grey color
|
||
2186 | *
|
||
2187 | * @param start Start position for mark the text
|
||
2188 | */
|
||
2189 | public void highlightCompletedText(int start) { |
||
2190 | JTextComponent editor = (JTextComponent) getEditor().getEditorComponent(); |
||
2191 | 6721 | ppiqueras | |
2192 | 8765 | jjdelcerro | editor.setCaretPosition(document.getLength()); |
2193 | editor.moveCaretPosition(start); |
||
2194 | 6721 | ppiqueras | } |
2195 | 8765 | jjdelcerro | |
2196 | /**
|
||
2197 | * If the pattern doesn't match with the selected/current item changes the color of the text to red if isOnlyOneColorOnText_Flag=true, else
|
||
2198 | * sets the color of the text black.
|
||
2199 | *
|
||
2200 | * @param pattern
|
||
2201 | */
|
||
2202 | private void formatText(Object item, int offs) { |
||
2203 | if (!comboBoxReference.isOnlyOneColorOnText_Flag()) {
|
||
2204 | if ((item == null) && (currentShowState != START_VIEW_STATE)) { |
||
2205 | editor.getEditorComponent().setForeground(Color.RED);
|
||
2206 | logger.debug("Pone a Rojo Lookup");
|
||
2207 | } |
||
2208 | else {
|
||
2209 | editor.getEditorComponent().setForeground(Color.BLACK);
|
||
2210 | logger.debug("Pone a Negro Lookup");
|
||
2211 | } |
||
2212 | |||
2213 | // If it's necessary, produces a "beep" sound
|
||
2214 | if ((beepEnabled_Flag) && (item == null) && (!lastWasTheBeginningState)) { |
||
2215 | comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
|
||
2216 | } |
||
2217 | } |
||
2218 | |||
2219 | if (useHighlight_Flag) {
|
||
2220 | |||
2221 | // Select
|
||
2222 | highlightCompletedText(offs); |
||
2223 | } |
||
2224 | } |
||
2225 | |||
2226 | /**
|
||
2227 | * Returns the current item in the popup of JComboBox or the selected item. If there is no item, returns null
|
||
2228 | *
|
||
2229 | * @return An object
|
||
2230 | */
|
||
2231 | private Object lookupItem() { |
||
2232 | Object item = null; |
||
2233 | if (model.getSize() > 0) { |
||
2234 | if (specialSelectionByUserState) {
|
||
2235 | item = model.getSelectedItem(); |
||
2236 | 6760 | ppiqueras | } |
2237 | else
|
||
2238 | 8765 | jjdelcerro | item = model.getElementAt(0);
|
2239 | } |
||
2240 | |||
2241 | return item;
|
||
2242 | } |
||
2243 | 6721 | ppiqueras | } |
2244 | } |