KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > TextViewerUndoManager


1 /*******************************************************************************
2  * Copyright (c) 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jface.text;
13
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.custom.StyledText;
16 import org.eclipse.swt.events.KeyEvent;
17 import org.eclipse.swt.events.KeyListener;
18 import org.eclipse.swt.events.MouseEvent;
19 import org.eclipse.swt.events.MouseListener;
20 import org.eclipse.swt.widgets.Display;
21 import org.eclipse.swt.widgets.Shell;
22
23 import org.eclipse.core.commands.ExecutionException;
24 import org.eclipse.core.commands.operations.IUndoContext;
25
26 import org.eclipse.text.undo.DocumentUndoEvent;
27 import org.eclipse.text.undo.DocumentUndoManager;
28 import org.eclipse.text.undo.DocumentUndoManagerRegistry;
29 import org.eclipse.text.undo.IDocumentUndoListener;
30 import org.eclipse.text.undo.IDocumentUndoManager;
31
32 import org.eclipse.jface.dialogs.MessageDialog;
33
34
35 /**
36  * Implementation of {@link org.eclipse.jface.text.IUndoManager} using the shared
37  * shared document undo manager.
38  * <p>
39  * It registers with the connected text viewer as text input listener, and obtains
40  * its undo manager from the current document. It also monitors mouse and keyboard
41  * activities in order to partition the stream of text changes into undo-able
42  * edit commands.
43  * <p>
44  * This class is not intended to be subclassed.
45  * </p>
46  *
47  * @see ITextViewer
48  * @see ITextInputListener
49  * @see IDocumentUndoManager
50  * @see MouseListener
51  * @see KeyListener
52  * @see DocumentUndoManager
53  *
54  * @since 3.2
55  */

56 public class TextViewerUndoManager implements IUndoManager, IUndoManagerExtension {
57
58     
59     /**
60      * Internal listener to mouse and key events.
61      */

62     private class KeyAndMouseListener implements MouseListener, KeyListener {
63
64         /*
65          * @see MouseListener#mouseDoubleClick
66          */

67         public void mouseDoubleClick(MouseEvent e) {
68         }
69
70         /*
71          * If the right mouse button is pressed, the current editing command is closed
72          * @see MouseListener#mouseDown
73          */

74         public void mouseDown(MouseEvent e) {
75             if (e.button == 1)
76                 if (isConnected())
77                     fDocumentUndoManager.commit();
78         }
79
80         /*
81          * @see MouseListener#mouseUp
82          */

83         public void mouseUp(MouseEvent e) {
84         }
85
86         /*
87          * @see KeyListener#keyPressed
88          */

89         public void keyReleased(KeyEvent e) {
90         }
91
92         /*
93          * On cursor keys, the current editing command is closed
94          * @see KeyListener#keyPressed
95          */

96         public void keyPressed(KeyEvent e) {
97             switch (e.keyCode) {
98                 case SWT.ARROW_UP:
99                 case SWT.ARROW_DOWN:
100                 case SWT.ARROW_LEFT:
101                 case SWT.ARROW_RIGHT:
102                     if (isConnected()) {
103                         fDocumentUndoManager.commit();
104                     }
105                     break;
106             }
107         }
108     }
109
110
111     /**
112      * Internal text input listener.
113      */

114     private class TextInputListener implements ITextInputListener {
115
116         /*
117          * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
118          */

119         public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
120             disconnectDocumentUndoManager();
121         }
122
123         /*
124          * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
125          */

126         public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
127             connectDocumentUndoManager(newInput);
128         }
129     }
130
131
132     /**
133      * Internal document undo listener.
134      */

135     private class DocumentUndoListener implements IDocumentUndoListener {
136
137         /*
138          * @see org.eclipse.jface.text.IDocumentUndoListener#documentUndoNotification(DocumentUndoEvent)
139          */

140         public void documentUndoNotification(DocumentUndoEvent event ){
141             if (!isConnected()) return;
142             
143             int eventType= event.getEventType();
144             if (((eventType & DocumentUndoEvent.ABOUT_TO_UNDO) != 0) || ((eventType & DocumentUndoEvent.ABOUT_TO_REDO) != 0)) {
145                 if (event.isCompound()) {
146                     ITextViewerExtension extension= null;
147                     if (fTextViewer instanceof ITextViewerExtension)
148                         extension= (ITextViewerExtension) fTextViewer;
149
150                     if (extension != null)
151                         extension.setRedraw(false);
152                 }
153                 fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable JavaDoc() {
154                     public void run() {
155                         if (fTextViewer instanceof TextViewer)
156                             ((TextViewer)fTextViewer).ignoreAutoEditStrategies(true);
157                     }
158                 });
159                 
160             } else if (((eventType & DocumentUndoEvent.UNDONE) != 0) || ((eventType & DocumentUndoEvent.REDONE) != 0)) {
161                 fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable JavaDoc() {
162                     public void run() {
163                         if (fTextViewer instanceof TextViewer)
164                             ((TextViewer)fTextViewer).ignoreAutoEditStrategies(false);
165                     }
166                 });
167                 if (event.isCompound()) {
168                     ITextViewerExtension extension= null;
169                     if (fTextViewer instanceof ITextViewerExtension)
170                         extension= (ITextViewerExtension) fTextViewer;
171
172                     if (extension != null)
173                         extension.setRedraw(true);
174                 }
175                 
176                 // Reveal the change if this manager's viewer has the focus.
177
if (fTextViewer != null) {
178                     StyledText widget= fTextViewer.getTextWidget();
179                     if (widget != null && !widget.isDisposed() && (widget.isFocusControl()))// || fTextViewer.getTextWidget() == control))
180
selectAndReveal(event.getOffset(), event.getText() == null ? 0 : event.getText().length());
181                 }
182             }
183         }
184
185     }
186
187     /** The internal key and mouse event listener */
188     private KeyAndMouseListener fKeyAndMouseListener;
189     /** The internal text input listener */
190     private TextInputListener fTextInputListener;
191
192
193     /** The text viewer the undo manager is connected to */
194     private ITextViewer fTextViewer;
195     
196     /** The undo level */
197     private int fUndoLevel;
198     
199     /** The document undo manager that is active. */
200     private IDocumentUndoManager fDocumentUndoManager;
201     
202     /** The document that is active. */
203     private IDocument fDocument;
204     
205     /** The document undo listener */
206     private IDocumentUndoListener fDocumentUndoListener;
207
208     /**
209      * Creates a new undo manager who remembers the specified number of edit commands.
210      *
211      * @param undoLevel the length of this manager's history
212      */

213     public TextViewerUndoManager(int undoLevel) {
214         fUndoLevel= undoLevel;
215     }
216
217     /**
218      * Returns whether this undo manager is connected to a text viewer.
219      *
220      * @return <code>true</code> if connected, <code>false</code> otherwise
221      */

222     private boolean isConnected() {
223         return fTextViewer != null && fDocumentUndoManager != null;
224     }
225
226     /*
227      * @see IUndoManager#beginCompoundChange
228      */

229     public void beginCompoundChange() {
230         if (isConnected()) {
231             fDocumentUndoManager.beginCompoundChange();
232         }
233     }
234
235
236     /*
237      * @see IUndoManager#endCompoundChange
238      */

239     public void endCompoundChange() {
240         if (isConnected()) {
241             fDocumentUndoManager.endCompoundChange();
242         }
243     }
244
245     /**
246      * Registers all necessary listeners with the text viewer.
247      */

248     private void addListeners() {
249         StyledText text= fTextViewer.getTextWidget();
250         if (text != null) {
251             fKeyAndMouseListener= new KeyAndMouseListener();
252             text.addMouseListener(fKeyAndMouseListener);
253             text.addKeyListener(fKeyAndMouseListener);
254             fTextInputListener= new TextInputListener();
255             fTextViewer.addTextInputListener(fTextInputListener);
256         }
257     }
258
259     /**
260      * Unregister all previously installed listeners from the text viewer.
261      */

262     private void removeListeners() {
263         StyledText text= fTextViewer.getTextWidget();
264         if (text != null) {
265             if (fKeyAndMouseListener != null) {
266                 text.removeMouseListener(fKeyAndMouseListener);
267                 text.removeKeyListener(fKeyAndMouseListener);
268                 fKeyAndMouseListener= null;
269             }
270             if (fTextInputListener != null) {
271                 fTextViewer.removeTextInputListener(fTextInputListener);
272                 fTextInputListener= null;
273             }
274         }
275     }
276
277     /**
278      * Shows the given exception in an error dialog.
279      *
280      * @param title the dialog title
281      * @param ex the exception
282      */

283     private void openErrorDialog(final String JavaDoc title, final Exception JavaDoc ex) {
284         Shell shell= null;
285         if (isConnected()) {
286             StyledText st= fTextViewer.getTextWidget();
287             if (st != null && !st.isDisposed())
288                 shell= st.getShell();
289         }
290         if (Display.getCurrent() != null)
291             MessageDialog.openError(shell, title, ex.getLocalizedMessage());
292         else {
293             Display display;
294             final Shell finalShell= shell;
295             if (finalShell != null)
296                 display= finalShell.getDisplay();
297             else
298                 display= Display.getDefault();
299             display.syncExec(new Runnable JavaDoc() {
300                 public void run() {
301                     MessageDialog.openError(finalShell, title, ex.getLocalizedMessage());
302                 }
303             });
304         }
305     }
306
307     /*
308      * @see org.eclipse.jface.text.IUndoManager#setMaximalUndoLevel(int)
309      */

310     public void setMaximalUndoLevel(int undoLevel) {
311         fUndoLevel= Math.max(0, undoLevel);
312         if (isConnected()) {
313             fDocumentUndoManager.setMaximalUndoLevel(fUndoLevel);
314         }
315     }
316
317     /*
318      * @see org.eclipse.jface.text.IUndoManager#connect(org.eclipse.jface.text.ITextViewer)
319      */

320     public void connect(ITextViewer textViewer) {
321         if (fTextViewer == null && textViewer != null) {
322             fTextViewer= textViewer;
323             addListeners();
324         }
325         IDocument doc= fTextViewer.getDocument();
326         connectDocumentUndoManager(doc);
327     }
328
329     /*
330      * @see org.eclipse.jface.text.IUndoManager#disconnect()
331      */

332     public void disconnect() {
333         if (fTextViewer != null) {
334             removeListeners();
335             fTextViewer= null;
336         }
337         disconnectDocumentUndoManager();
338     }
339
340     /*
341      * @see org.eclipse.jface.text.IUndoManager#reset()
342      */

343     public void reset() {
344         if (isConnected())
345             fDocumentUndoManager.reset();
346         
347     }
348
349     /*
350      * @see org.eclipse.jface.text.IUndoManager#redoable()
351      */

352     public boolean redoable() {
353         if (isConnected())
354             return fDocumentUndoManager.redoable();
355         return false;
356     }
357
358     /*
359      * @see org.eclipse.jface.text.IUndoManager#undoable()
360      */

361     public boolean undoable() {
362         if (isConnected())
363             return fDocumentUndoManager.undoable();
364         return false;
365     }
366
367     /*
368      * @see org.eclipse.jface.text.IUndoManager#redo()
369      */

370     public void redo() {
371         if (isConnected()) {
372             try {
373                 fDocumentUndoManager.redo();
374             } catch (ExecutionException ex) {
375                 openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.redoFailed.title"), ex); //$NON-NLS-1$
376
}
377         }
378     }
379
380     /*
381      * @see org.eclipse.jface.text.IUndoManager#undo()
382      */

383     public void undo() {
384         if (isConnected()) {
385             try {
386                 fDocumentUndoManager.undo();
387             } catch (ExecutionException ex) {
388                 openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.undoFailed.title"), ex); //$NON-NLS-1$
389
}
390         }
391     }
392
393     /**
394      * Selects and reveals the specified range.
395      *
396      * @param offset the offset of the range
397      * @param length the length of the range
398      */

399     private void selectAndReveal(int offset, int length) {
400         if (fTextViewer instanceof ITextViewerExtension5) {
401             ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer;
402             extension.exposeModelRange(new Region(offset, length));
403         } else if (!fTextViewer.overlapsWithVisibleRegion(offset, length))
404             fTextViewer.resetVisibleRegion();
405
406         fTextViewer.setSelectedRange(offset, length);
407         fTextViewer.revealRange(offset, length);
408     }
409
410     /*
411      * @see org.eclipse.jface.text.IUndoManagerExtension#getUndoContext()
412      */

413     public IUndoContext getUndoContext() {
414         if (isConnected()) {
415             return fDocumentUndoManager.getUndoContext();
416         }
417         return null;
418     }
419     
420     private void connectDocumentUndoManager(IDocument document) {
421         disconnectDocumentUndoManager();
422         if (document != null) {
423             fDocument= document;
424             DocumentUndoManagerRegistry.connect(fDocument);
425             fDocumentUndoManager= DocumentUndoManagerRegistry.getDocumentUndoManager(fDocument);
426             fDocumentUndoManager.connect(this);
427             setMaximalUndoLevel(fUndoLevel);
428             fDocumentUndoListener= new DocumentUndoListener();
429             fDocumentUndoManager.addDocumentUndoListener(fDocumentUndoListener);
430         }
431     }
432
433     private void disconnectDocumentUndoManager() {
434         if (fDocumentUndoManager != null) {
435             fDocumentUndoManager.disconnect(this);
436             DocumentUndoManagerRegistry.disconnect(fDocument);
437             fDocumentUndoManager.removeDocumentUndoListener(fDocumentUndoListener);
438             fDocumentUndoListener= null;
439             fDocumentUndoManager= null;
440         }
441     }
442 }
443
Popular Tags