Statistics
| Revision:

root / trunk / libraries / libUIComponent / src / org / gvsig / gui / beans / swing / jTextComponentEditable / JTextFieldEditable.java @ 13136

History | View | Annotate | Download (16 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package org.gvsig.gui.beans.swing.jTextComponentEditable;
42

    
43
import java.awt.event.KeyAdapter;
44
import java.awt.event.KeyEvent;
45
import java.awt.event.KeyListener;
46
import java.awt.event.MouseAdapter;
47
import java.awt.event.MouseEvent;
48
import java.beans.PropertyChangeEvent;
49
import java.beans.PropertyChangeListener;
50

    
51
import javax.swing.JTextField;
52
import javax.swing.event.DocumentListener;
53
import javax.swing.event.UndoableEditEvent;
54
import javax.swing.event.UndoableEditListener;
55
import javax.swing.text.BadLocationException;
56
import javax.swing.text.JTextComponent;
57
import javax.swing.text.PlainDocument;
58
import javax.swing.undo.CannotRedoException;
59
import javax.swing.undo.CannotUndoException;
60
import javax.swing.undo.UndoManager;
61

    
62
import org.gvsig.gui.beans.swing.optionsEditionByMousePopupMenu.JOptionsEditionByMousePopupMenu;
63

    
64
/**
65
 * JTextComponent that allows user to select an option: <i>COPY, CUT, PASTE, SELECT ALL, REMOVE, UNDO, REDO</i> in a popup menu.<br>
66
 * All options will be about the edtion of the text in the component.<br> * 
67
 * <b><i>How select an edition option using the mouse:</i></b> press the right button of the mouse on the text area, and a popup with the options will be displayed. Select and option.<br>
68
 * <b><i>How select an edition option using the keyboard:</i></b> 
69
 * <ul>
70
 *  <li><b>COPY:</b> </li> CTRL + C. Copies from the text field to the clipboard.
71
 *  <li><b>CUT:</b> </li> CTRL + X. Cuts from the text field to the clipboad.
72
 *  <li><b>PASTE:</b> </li> CTRL + V. Copies from the clipboard to the text field.
73
 *  <li><b>REMOVE:</b> </li> SUPR (in spanish keyboard). Removes the selected text.
74
 *  <li><b>SELECT ALL:</b> </li> CTRL + A. Selects all the text.
75
 *  <li><b>UNDO:</b> </li> CTRL + Z. Undoes.
76
 *  <li><b>REDO:</b> </li> SHIFT + CTRL + Z. Redoes.
77
 * </ul>
78
 * 
79
 * This component by default stores 10 undo/redo actions. This value can be modified.
80
 * 
81
 * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
82
 */
83
public class JTextFieldEditable extends JTextField {
84
        private static final long serialVersionUID = 7440699741607998478L;
85

    
86
        // CONSTANTS
87
        public static final int DEFAULT_UNDO_REDO_LIMIT_ACTIONS = 10;
88
        // END CONSTANTS
89

    
90
        // A POPUPMENU FOR EDITION OPTIONS
91
        private JOptionsEditionByMousePopupMenu optionsEditionByMouse;
92
    // END A POPUPMENU FOR EDITION OPTIONS
93
        
94
        // UNDO-REDO
95
        private UndoManager undoManager;
96
        private int undoRedoLimitActions;
97
        // END UNDO-REDO
98
        
99
        // LISTENERS
100
        private KeyListener editorKeyListener;
101
        private MouseAdapter editorMouseListener;
102
        private PropertyChangeListener editionMenuListener;
103
        private DocumentListener documentListener;
104
        // END LISTENERS
105
        
106
        // OTHER ATTRIBUTES
107
        private boolean optionsEditorWasVisible;
108
        // END OTHER ATTRIBUTES
109
        
110
        /**
111
         * Default constructor
112
         */
113
        public JTextFieldEditable() {
114
                super();
115
                
116
                initialize();
117
                
118
                // Other configuration tasks
119
                this.createDefaultListeners();
120
                this.configure();
121
        }
122
        
123
        /**
124
         * This method sets the start values of inner attributes and creates the necessary inner objects
125
         */
126
        private void initialize() {
127
        // Allows user to edit
128
                super.setEditable(true);
129
                
130
                // Text options edition popupmenu initialization
131
                optionsEditionByMouse = new JOptionsEditionByMousePopupMenu();
132
                optionsEditorWasVisible = false;
133
                
134
                // Undo-Redo initialization
135
                undoManager = new UndoManager();
136
                undoRedoLimitActions = DEFAULT_UNDO_REDO_LIMIT_ACTIONS; // By default is 1
137
                undoManager.setLimit(undoRedoLimitActions);
138
        }
139
        
140
        /**
141
         * Creation of default listeneres that will use the component
142
         */
143
        private void createDefaultListeners() {
144
                // Defines a listener for the PopupMenu of text edition options: when a change is produced in that component, it fires an event
145
                //   and this listener captures it
146
                this.defineEditionMenuPropertyChangeListener(this);
147

    
148
        // Defines a key listener for the editor of this component
149
        this.defineEditorKeyListener(this);
150

    
151
        // Defines a mouse listener for the editor of this component
152
        this.defineEditorMouseListener(this);
153
        }
154
        
155
        /**
156
         * Defines a listener for the PopupMenu of text edition options: when a change is produced in that component, it fires an event
157
         *    and this listener captures and treats it
158
         *    
159
         * @param text_component_editable A reference of this component
160
         */
161
        private void defineEditionMenuPropertyChangeListener(JTextFieldEditable text_component_editable) {
162
                final JTextFieldEditable jTextComponentEditable = text_component_editable;
163

    
164
                editionMenuListener = new PropertyChangeListener() {
165
                        /*
166
                         * (non-Javadoc)
167
                         * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
168
                         */
169
                        public void propertyChange(PropertyChangeEvent arg0) {
170
                                if (arg0.getPropertyName().equals(JOptionsEditionByMousePopupMenu.SELECTEDOPTION)) {
171
                                                                    
172
                                  switch(Integer.parseInt(arg0.getNewValue().toString()))
173
                                  {
174
                                          case JOptionsEditionByMousePopupMenu.UNDO:
175
                                                  undoOperationLogic();
176
                                                  break;
177
                                          case JOptionsEditionByMousePopupMenu.REDO:
178
                                                  redoOperationLogic();
179
                                                  break;
180
                                          case JOptionsEditionByMousePopupMenu.CUT:
181
                                                  jTextComponentEditable.cut();
182
                                                  break;
183
                                          case JOptionsEditionByMousePopupMenu.COPY:
184
                                                  jTextComponentEditable.copy();
185
                                                  break;
186
                                          case JOptionsEditionByMousePopupMenu.PASTE:
187
                                                  jTextComponentEditable.paste();
188
                                                  break;
189
                                          case JOptionsEditionByMousePopupMenu.DELETE:
190
                                                  deleteTextLogic(jTextComponentEditable);
191
                                                  break;
192
                                          case JOptionsEditionByMousePopupMenu.SELECT_ALL:
193
                                                  jTextComponentEditable.selectAll();
194
                                                  break;
195
                                          default: // do anything
196
                                  }
197
                                }
198
                                else
199
                                {
200
                                        if (arg0.getPropertyName().equals(JOptionsEditionByMousePopupMenu.VISIBILITYCHANGED))
201
                                        {
202
                                                // First True, after False (when false -> optionsEditorWasVisible = true)
203
                                                if (!optionsEditionByMouse.isVisible())
204
                                                        optionsEditorWasVisible = true;
205
                                                else
206
                                                        optionsEditorWasVisible = false;
207
                                        }
208
                                }
209
                        }                        
210
                };
211
        }
212

    
213
        /**
214
         * Defines a key listener for the editor of this component
215
         * This method is another important difference from the JComboBox; and could work badly with some keymaps
216
         * 
217
         * @param combo_Box A reference of this component
218
         */
219
        private void defineEditorKeyListener(JTextFieldEditable text_component_editable) {
220
                final JTextFieldEditable jTextComponentEditable = text_component_editable;
221
                
222
                editorKeyListener = new KeyAdapter() {
223
                        /*
224
                         * (non-Javadoc)
225
                         * @see java.awt.event.KeyAdapter#keyPressed(java.awt.event.KeyEvent)
226
                         */
227
                        public void keyPressed(KeyEvent ke)  // Executed on the Start view state or Search view state
228
                        {
229
                                // COPY, CUT, PASTE, SELECT ALL, UNDO AND REDO WITH THE KEYBOARD (Combination of keys; REMOVE is implemented after: KV_DELETE (supr spanish key))
230
                                if (ke.isControlDown())
231
                                {
232
                                        // COPY
233
                                    if (ke.getKeyCode() == KeyEvent.VK_C) {
234
                                            jTextComponentEditable.copy();
235
                                            ke.consume();
236
                                            return;
237
                                    }
238
                                    
239
                                    // CUT
240
                                    if (ke.getKeyCode() == KeyEvent.VK_X) {
241
                                            jTextComponentEditable.cut();
242
                                            ke.consume();
243
                                            return;
244
                                    }
245
                                    
246
                                    // PASTE
247
                                    if (ke.getKeyCode() == KeyEvent.VK_V) {
248
                                            jTextComponentEditable.paste();
249
                                            ke.consume();
250
                                            return;
251
                                    }
252
                                    
253
                                    // SELECT ALL
254
                                    if (ke.getKeyCode() == KeyEvent.VK_A) {
255
                                            jTextComponentEditable.selectAll();
256
                                            ke.consume();
257
                                            return;
258
                                    }
259

    
260
                                    // UNDO OR REDO
261
                                    if (ke.getKeyCode() == KeyEvent.VK_Z) {
262
                                            if (ke.isShiftDown()) // REDO
263
                                                    redoOperationLogic();                                                            
264
                                            else //UNDO
265
                                                    undoOperationLogic();
266
                                            
267
                                            ke.consume();
268
                                            return;
269
                                     }
270
                                }
271
                                
272
                                // According the key pressed, do some actions or others
273
                                switch (ke.getKeyCode())
274
                                {
275
                                        case KeyEvent.VK_DELETE : // 'supr' key in spanish keyboard
276
                                                deleteTextLogic(jTextComponentEditable);
277
                                                ke.consume();
278
                                        break;
279
                                }
280
                        }
281
                };
282
        }
283

    
284
        /**
285
         * Defines a mouse listener for the editor of this component
286
         * 
287
         * @param combo_Box A reference of this component
288
         */
289
        private void defineEditorMouseListener(JTextFieldEditable text_component_editable) {
290
                final JTextFieldEditable jTextComponentEditable = text_component_editable;
291
                
292
                editorMouseListener = new MouseAdapter() {
293
                        /*
294
                         * (non-Javadoc)
295
                         * @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
296
                         */
297
                        public void mouseClicked(MouseEvent e) {
298
        
299
                                if (e.getButton() == MouseEvent.BUTTON3) {                            
300
                            // By default disable all options
301
                            optionsEditionByMouse.setEnabledAllOptions(false);
302
                            
303
                            // Enable the "Undo" option if there is any previous state to restore
304
                            if (undoManager.canUndo())
305
                                    optionsEditionByMouse.setEnabledUndoOption(true);
306
                            
307
                            // Enable the "Redo" option if there is any later state to restore
308
                            if (undoManager.canRedo())
309
                                    optionsEditionByMouse.setEnabledRedoOption(true);
310
                            
311
                            // Enable the "Copy", "Cut" and "Delete" options if there is text selected
312
                            if (jTextComponentEditable.getCaretPosition() != jTextComponentEditable.getCaret().getMark())
313
                            {
314
                                    optionsEditionByMouse.setEnabledCopyOption(true);
315
                                    optionsEditionByMouse.setEnabledCutOption(true);
316
                                    optionsEditionByMouse.setEnabledDeleteOption(true);
317
                            }
318
                            
319
                            // Enable the "Paste" option if there is text on the system's clipboard
320
                            if ( getToolkit().getSystemClipboard().getContents(this).toString().length() > 0 )
321
                                    optionsEditionByMouse.setEnabledPasteOption(true);//
322
                            
323
                            // Enable the "Select-All" option (by default it's always enabled)
324
                            optionsEditionByMouse.setEnabledSelectAllOption(true);
325
                            
326
                                        optionsEditionByMouse.setLocation((int)jTextComponentEditable.getLocationOnScreen().getX() + e.getX(), (int)jTextComponentEditable.getLocationOnScreen().getY() + e.getY());
327
                            optionsEditionByMouse.setInvoker(jTextComponentEditable);
328
                            optionsEditionByMouse.setVisible(true);
329
                    }
330
                }
331
                };
332
        }
333
        
334
        /**
335
         * Configures the component and some of its parts
336
         */
337
        private void configure() {
338
                // Configures the document of the editor of this component
339
                PlainDocument document = this.configureDocument();
340

    
341
                // Configures the editor (ComboBoxEditor) of this component
342
                this.configureEditor(this, document);
343
                
344
                // Configures the text-edition-options popupmenu
345
                this.configureOptionsEditionByMouse();
346
        }
347
        
348

    
349
        /**
350
         * Configures the document of the editor of this component
351
         */
352
        private PlainDocument configureDocument() {
353
                // Creates the document of the editor of this component
354
                PlainDocument document = new PlainDocument();
355
        
356
                // Configures the document
357
                configureUndoManager(document);
358
                
359
                // Defines and add a Document listener for changes on the document of the editor of this component
360
                document.addDocumentListener(this.documentListener);
361
                
362
                return document;
363
        }
364
        
365
        /**
366
         * Configures the editor (ComboBoxEditor) of this component
367
         * 
368
         * @param newEditor The new editor to configure
369
         */
370
        private void configureEditor(JTextFieldEditable text_component_editable, PlainDocument document) {
371
                final JTextFieldEditable jTextComponentEditable = text_component_editable;
372
            
373
        if (text_component_editable != null) {
374
                   // Removes some prevous listeners and adds some new others:     
375
                
376
                // Adds the new Key Listener (tries to remove it if it existed before)
377
                jTextComponentEditable.removeKeyListener(this.editorKeyListener);
378
                jTextComponentEditable.addKeyListener(this.editorKeyListener);
379
                
380
                   // Adds the new Mouse Listener (tries to remove it if it existed before)
381
                jTextComponentEditable.removeMouseListener(this.editorMouseListener);
382
                jTextComponentEditable.addMouseListener(this.editorMouseListener);
383
                
384
                // Adds the new document (tries to remove it if it existed before)
385
                jTextComponentEditable.setDocument(document);
386
        }
387
        }
388

    
389
        /** 
390
         * Configures the text-edition-options popupmenu
391
         */
392
        private void configureOptionsEditionByMouse() {
393
                this.optionsEditionByMouse.addPropertyChangeListener(editionMenuListener);
394
        }
395
        
396
        /**
397
         * Configures the UndoManager for Undo-Redo operations
398
         */
399
        public void configureUndoManager(PlainDocument document) {
400
                final UndoManager undo_Manager = undoManager; 
401
                
402
        // Listen for undo and redo events
403
        document.addUndoableEditListener(new UndoableEditListener() {
404
                /*
405
                 * (non-Javadoc)
406
                 * @see javax.swing.event.UndoableEditListener#undoableEditHappened(javax.swing.event.UndoableEditEvent)
407
                 */
408
            public void undoableEditHappened(UndoableEditEvent evt) {
409
                                undo_Manager.addEdit(evt.getEdit());
410
            }
411
        });
412
        }
413
        
414
        /**
415
         * This method has the logic for a "undo" operation
416
         */
417
        private void undoOperationLogic() {
418
                try {
419
            if (undoManager.canUndo()) {
420
                    undoManager.undo();
421
            }
422
                } catch (CannotUndoException e) {
423
                e.printStackTrace();
424
        }
425
        }
426
        
427
        /**
428
         * This method has the logic for a "redo" operation
429
         */
430
        private void redoOperationLogic() {
431
        try {
432
            if (undoManager.canRedo()) {
433
                            undoManager.redo();
434
            }
435
            } catch (CannotRedoException e) {
436
                    e.printStackTrace();
437
            }
438
        }
439
        
440
    ////// OTHER METHODS //////
441
        
442
        /**
443
     * Sets the limit of actions that can hold the UndoManager of this component
444
     * 
445
     * @param limit
446
     */
447
        public void setUndoRedoLimitActions(int limit) {
448
            this.undoRedoLimitActions = limit;
449
            undoManager.setLimit(undoRedoLimitActions);
450
    }
451
    
452
        /**
453
     * Gets the limit of actions that can hold the UndoManager:
454
     * 
455
     * @return int 
456
     */
457
        public int getUndoRedoLimitActions() {
458
            return this.undoRedoLimitActions;
459
    }
460
     
461
        /**
462
         * 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'
463
         *    in spanish keyboard) key
464
         * 
465
         * @param jTextComponentEditable A reference to the editor component
466
         */
467
        private void deleteTextLogic(JTextComponent jTextComponentEditable) {
468
                //                 Get the new text:                
469
                  try {
470
                          PlainDocument document = (PlainDocument)jTextComponentEditable.getDocument();
471
                          int caretPosition = jTextComponentEditable.getCaretPosition();
472
                          int markPosition = jTextComponentEditable.getCaret().getMark();
473
                            
474
                          int min_index = Math.min(caretPosition, markPosition);
475
                          int length = Math.abs(caretPosition - markPosition);
476
                            
477
                          document.remove(min_index, length);
478
                  } catch (BadLocationException e) {
479
                          e.printStackTrace();
480
                  }
481
        }
482
    ////// END OTHER METHODS //////
483
}