Statistics
| Revision:

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

History | View | Annotate | Download (15.9 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
        /**
107
         * Default constructor
108
         */
109
        public JTextFieldEditable() {
110
                super();
111
                
112
                initialize();
113
                
114
                // Other configuration tasks
115
                this.createDefaultListeners();
116
                this.configure();
117
        }
118
        
119
        /**
120
         * This method sets the start values of inner attributes and creates the necessary inner objects
121
         */
122
        private void initialize() {
123
        // Allows user to edit
124
                super.setEditable(true);
125
                
126
                // Text options edition popupmenu initialization
127
                optionsEditionByMouse = new JOptionsEditionByMousePopupMenu();
128
                
129
                // Undo-Redo initialization
130
                undoManager = new UndoManager();
131
                undoRedoLimitActions = DEFAULT_UNDO_REDO_LIMIT_ACTIONS; // By default is 1
132
                undoManager.setLimit(undoRedoLimitActions);
133
        }
134
        
135
        /**
136
         * Creation of default listeneres that will use the component
137
         */
138
        private void createDefaultListeners() {
139
                // Defines a listener for the PopupMenu of text edition options: when a change is produced in that component, it fires an event
140
                //   and this listener captures it
141
                this.defineEditionMenuPropertyChangeListener(this);
142

    
143
        // Defines a key listener for the editor of this component
144
        this.defineEditorKeyListener(this);
145

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

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

204
                                        }
205
                                }
206
*/
207
                        }                        
208
                };
209
        }
210

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

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

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

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

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

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