Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libUIComponent / src / org / gvsig / gui / beans / editabletextcomponent / EditableTextDecorator.java @ 18669

History | View | Annotate | Download (14.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.editabletextcomponent;
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.ComboBoxEditor;
52
import javax.swing.event.UndoableEditEvent;
53
import javax.swing.event.UndoableEditListener;
54
import javax.swing.text.BadLocationException;
55
import javax.swing.text.JTextComponent;
56
import javax.swing.text.PlainDocument;
57
import javax.swing.undo.CannotRedoException;
58
import javax.swing.undo.CannotUndoException;
59
import javax.swing.undo.UndoManager;
60

    
61
import org.gvsig.gui.beans.editionpopupmenu.JOptionsEditionByMousePopupMenu;
62

    
63
/**
64
 * <p>Extra functionality that allows a {@link JTextComponent JTextComponent} having graphical edition options,
65
 * which allows user to select any: <i>COPY, CUT, PASTE, SELECT ALL, REMOVE, UNDO, REDO</i> in a popup menu.</p>
66
 * 
67
 * <p>All options will be about the edition of the text in the component.</p>
68
 *  
69
 * <p><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>
70
 * <b><i>How select an edition option using the keyboard:</i></b> 
71
 * <ul>
72
 *  <li><b>COPY:</b> </li> CTRL + C. Copies from the text field to the clipboard.
73
 *  <li><b>CUT:</b> </li> CTRL + X. Cuts from the text field to the clipboad.
74
 *  <li><b>PASTE:</b> </li> CTRL + V. Copies from the clipboard to the text field.
75
 *  <li><b>REMOVE:</b> </li> SUPR (in spanish keyboard, and the equivalent in others). Removes the selected text.
76
 *  <li><b>SELECT ALL:</b> </li> CTRL + A. Selects all the text.
77
 *  <li><b>UNDO:</b> </li> CTRL + Z. Undoes.
78
 *  <li><b>REDO:</b> </li> SHIFT + CTRL + Z. Redoes.
79
 * </ul></p>
80
 * 
81
 * <p>This component by default stores 100 undo/redo actions. This value can be modified.</p>
82
 * 
83
 * @version 03/01/2008
84
 * @author Pablo Piqueras Bartolom? (pablo.piqueras@iver.es)
85
 */
86
public class EditableTextDecorator {
87
        // CONSTANTS
88
        public static final int DEFAULT_UNDO_REDO_LIMIT_ACTIONS = 100;
89
        // END CONSTANTS
90

    
91
        // A POPUPMENU FOR EDITION OPTIONS
92
        private JOptionsEditionByMousePopupMenu optionsEditionByMouse;
93
    // END A POPUPMENU FOR EDITION OPTIONS
94
        
95
        // UNDO-REDO
96
        private UndoManager undoManager;
97
        private int undoRedoLimitActions;
98
        // END UNDO-REDO
99
        
100
        // LISTENERS
101
        private KeyListener editorKeyListener;
102
        private MouseAdapter editorMouseListener;
103
        private PropertyChangeListener editionMenuListener;
104
        // END LISTENERS
105
        
106
        // REFERENCE TO THE JTEXTCOMPONENT
107
        private JTextComponent jTextComponent;
108
        // END REFERENCE TO THE JTEXTCOMPONENT
109
        
110
        /**
111
         * Default constructor
112
         */
113
        public EditableTextDecorator(JTextComponent jTextComponent) {
114
                super();
115

    
116
                // Reference to the JTextComponent
117
                this.jTextComponent = jTextComponent;
118
                
119
                initialize();
120
                
121
                // Other configuration tasks
122
                this.createDefaultListeners();
123
                this.configure();
124
        }
125
        
126
        /**
127
         * This method sets the start values of inner attributes and creates the necessary inner objects
128
         */
129
        private void initialize() {
130
        // Allows user to edit
131
                jTextComponent.setEditable(true);
132
                
133
                // Text options edition popupmenu initialization
134
                optionsEditionByMouse = new JOptionsEditionByMousePopupMenu();
135
                
136
                // Undo-Redo initialization
137
                undoManager = new UndoManager();
138
                undoRedoLimitActions = DEFAULT_UNDO_REDO_LIMIT_ACTIONS; // By default is 1
139
                undoManager.setLimit(undoRedoLimitActions);
140
        }
141
        
142
        /**
143
         * Creation of default listeners that will use the component
144
         */
145
        private void createDefaultListeners() {
146
                // Defines a listener for the PopupMenu of text edition options: when a change is produced in that component, it fires an event
147
                //   and this listener captures it
148
                defineEditionMenuPropertyChangeListener();
149

    
150
        // Defines a key listener for the editor of this component
151
        defineEditorKeyListener();
152

    
153
        // Defines a mouse listener for the editor of this component
154
        defineEditorMouseListener();
155
        }
156
        
157
        /**
158
         * Defines a listener for the PopupMenu of text edition options: when a change is produced in that component, it fires an event
159
         *    and this listener captures and treats it
160
         */
161
        private void defineEditionMenuPropertyChangeListener() {
162
                editionMenuListener = new PropertyChangeListener() {
163
                        /*
164
                         * (non-Javadoc)
165
                         * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
166
                         */
167
                        public void propertyChange(PropertyChangeEvent arg0) {
168
                                if (arg0.getPropertyName().equals(JOptionsEditionByMousePopupMenu.SELECTEDOPTION)) {
169
                                                                    
170
                                  switch(Integer.parseInt(arg0.getNewValue().toString()))
171
                                  {
172
                                          case JOptionsEditionByMousePopupMenu.UNDO:
173
                                                  undoOperationLogic();
174
                                                  break;
175
                                          case JOptionsEditionByMousePopupMenu.REDO:
176
                                                  redoOperationLogic();
177
                                                  break;
178
                                          case JOptionsEditionByMousePopupMenu.CUT:
179
                                                  jTextComponent.cut();
180
                                                  break;
181
                                          case JOptionsEditionByMousePopupMenu.COPY:
182
                                                  jTextComponent.copy();
183
                                                  break;
184
                                          case JOptionsEditionByMousePopupMenu.PASTE:
185
                                                  jTextComponent.paste();
186
                                                  break;
187
                                          case JOptionsEditionByMousePopupMenu.DELETE:
188
                                                  deleteTextLogic();
189
                                                  break;
190
                                          case JOptionsEditionByMousePopupMenu.SELECT_ALL:
191
                                                  jTextComponent.selectAll();
192
                                                  break;
193
                                          default: // do anything
194
                                  }
195
                                }
196
/*
197
                                else
198
                                {
199
                                        if (arg0.getPropertyName().equals(JOptionsEditionByMousePopupMenu.VISIBILITYCHANGED))
200
                                        {
201
                                                // First True, after False (when false -> optionsEditorWasVisible = true)
202
                                                if (!optionsEditionByMouse.isVisible())
203
                                                        optionsEditorWasVisible = true;
204
                                                else
205
                                                        optionsEditorWasVisible = false;
206

207
                                        }
208
                                }
209
*/
210
                        }                        
211
                };
212
        }
213

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

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

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

    
333
                // Configures the editor (ComboBoxEditor) of this component
334
                configureEditor(document);
335
                
336
                // Configures the text-edition-options popupmenu
337
                configureOptionsEditionByMouse();
338
        }
339
        
340

    
341
        /**
342
         * Configures the document of the editor of the text component
343
         */
344
        private PlainDocument configureDocument() {
345
                // Creates the document of the editor of this component
346
                PlainDocument document = new PlainDocument();
347
        
348
                // Configures the document
349
                configureUndoManager(document);
350
                
351
                return document;
352
        }
353
        
354
        /**
355
         * Configures the editor {@link ComboBoxEditor ComboBoxEditor} of the text component.
356
         * 
357
         * @param document the document to display/edit
358
         */
359
        private void configureEditor(PlainDocument document) {
360
        if (jTextComponent != null) {
361
                   // Removes some previous listeners and adds some new others:     
362
                
363
                // Adds the new Key Listener (tries to remove it if it existed before)
364
                jTextComponent.removeKeyListener(this.editorKeyListener);
365
                jTextComponent.addKeyListener(this.editorKeyListener);
366
                
367
                   // Adds the new Mouse Listener (tries to remove it if it existed before)
368
                jTextComponent.removeMouseListener(this.editorMouseListener);
369
                jTextComponent.addMouseListener(this.editorMouseListener);
370
                
371
                // Adds the new document (tries to remove it if it existed before)
372
                jTextComponent.setDocument(document);
373
        }
374
        }
375

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