comparison dwtx/jface/text/TextViewerUndoManager.d @ 129:eb30df5ca28b

Added JFace Text sources
author Frank Benoit <benoit@tionex.de>
date Sat, 23 Aug 2008 19:10:48 +0200
parents
children c4fb132a086c
comparison
equal deleted inserted replaced
128:8df1d4193877 129:eb30df5ca28b
1 /*******************************************************************************
2 * Copyright (c) 2006, 2008 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 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13
14 module dwtx.jface.text.TextViewerUndoManager;
15
16 import dwt.dwthelper.utils;
17
18
19
20
21
22 import dwt.DWT;
23 import dwt.custom.StyledText;
24 import dwt.events.KeyEvent;
25 import dwt.events.KeyListener;
26 import dwt.events.MouseEvent;
27 import dwt.events.MouseListener;
28 import dwt.widgets.Display;
29 import dwt.widgets.Shell;
30 import dwtx.core.commands.ExecutionException;
31 import dwtx.core.commands.operations.IUndoContext;
32 import dwtx.jface.dialogs.MessageDialog;
33 import dwtx.text.undo.DocumentUndoEvent;
34 import dwtx.text.undo.DocumentUndoManager;
35 import dwtx.text.undo.DocumentUndoManagerRegistry;
36 import dwtx.text.undo.IDocumentUndoListener;
37 import dwtx.text.undo.IDocumentUndoManager;
38
39
40 /**
41 * Implementation of {@link dwtx.jface.text.IUndoManager} using the shared
42 * document undo manager.
43 * <p>
44 * It registers with the connected text viewer as text input listener, and obtains
45 * its undo manager from the current document. It also monitors mouse and keyboard
46 * activities in order to partition the stream of text changes into undo-able
47 * edit commands.
48 * <p>
49 * This class is not intended to be subclassed.
50 * </p>
51 *
52 * @see ITextViewer
53 * @see ITextInputListener
54 * @see IDocumentUndoManager
55 * @see MouseListener
56 * @see KeyListener
57 * @see DocumentUndoManager
58 *
59 * @since 3.2
60 * @noextend This class is not intended to be subclassed by clients.
61 */
62 public class TextViewerUndoManager : IUndoManager, IUndoManagerExtension {
63
64
65 /**
66 * Internal listener to mouse and key events.
67 */
68 private class KeyAndMouseListener : MouseListener, KeyListener {
69
70 /*
71 * @see MouseListener#mouseDoubleClick
72 */
73 public void mouseDoubleClick(MouseEvent e) {
74 }
75
76 /*
77 * If the right mouse button is pressed, the current editing command is closed
78 * @see MouseListener#mouseDown
79 */
80 public void mouseDown(MouseEvent e) {
81 if (e.button is 1)
82 if (isConnected())
83 fDocumentUndoManager.commit();
84 }
85
86 /*
87 * @see MouseListener#mouseUp
88 */
89 public void mouseUp(MouseEvent e) {
90 }
91
92 /*
93 * @see KeyListener#keyPressed
94 */
95 public void keyReleased(KeyEvent e) {
96 }
97
98 /*
99 * On cursor keys, the current editing command is closed
100 * @see KeyListener#keyPressed
101 */
102 public void keyPressed(KeyEvent e) {
103 switch (e.keyCode) {
104 case DWT.ARROW_UP:
105 case DWT.ARROW_DOWN:
106 case DWT.ARROW_LEFT:
107 case DWT.ARROW_RIGHT:
108 if (isConnected()) {
109 fDocumentUndoManager.commit();
110 }
111 break;
112 }
113 }
114 }
115
116
117 /**
118 * Internal text input listener.
119 */
120 private class TextInputListener : ITextInputListener {
121
122 /*
123 * @see dwtx.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(dwtx.jface.text.IDocument, dwtx.jface.text.IDocument)
124 */
125 public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
126 disconnectDocumentUndoManager();
127 }
128
129 /*
130 * @see dwtx.jface.text.ITextInputListener#inputDocumentChanged(dwtx.jface.text.IDocument, dwtx.jface.text.IDocument)
131 */
132 public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
133 connectDocumentUndoManager(newInput);
134 }
135 }
136
137
138 /**
139 * Internal document undo listener.
140 */
141 private class DocumentUndoListener : IDocumentUndoListener {
142
143 /*
144 * @see dwtx.jface.text.IDocumentUndoListener#documentUndoNotification(DocumentUndoEvent)
145 */
146 public void documentUndoNotification(DocumentUndoEvent event ){
147 if (!isConnected()) return;
148
149 int eventType= event.getEventType();
150 if (((eventType & DocumentUndoEvent.ABOUT_TO_UNDO) !is 0) || ((eventType & DocumentUndoEvent.ABOUT_TO_REDO) !is 0)) {
151 if (event.isCompound()) {
152 ITextViewerExtension extension= null;
153 if (fTextViewer instanceof ITextViewerExtension)
154 extension= (ITextViewerExtension) fTextViewer;
155
156 if (extension !is null)
157 extension.setRedraw(false);
158 }
159 fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable() {
160 public void run() {
161 if (fTextViewer instanceof TextViewer)
162 ((TextViewer)fTextViewer).ignoreAutoEditStrategies(true);
163 }
164 });
165
166 } else if (((eventType & DocumentUndoEvent.UNDONE) !is 0) || ((eventType & DocumentUndoEvent.REDONE) !is 0)) {
167 fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable() {
168 public void run() {
169 if (fTextViewer instanceof TextViewer)
170 ((TextViewer)fTextViewer).ignoreAutoEditStrategies(false);
171 }
172 });
173 if (event.isCompound()) {
174 ITextViewerExtension extension= null;
175 if (fTextViewer instanceof ITextViewerExtension)
176 extension= (ITextViewerExtension) fTextViewer;
177
178 if (extension !is null)
179 extension.setRedraw(true);
180 }
181
182 // Reveal the change if this manager's viewer has the focus.
183 if (fTextViewer !is null) {
184 StyledText widget= fTextViewer.getTextWidget();
185 if (widget !is null && !widget.isDisposed() && (widget.isFocusControl()))// || fTextViewer.getTextWidget() is control))
186 selectAndReveal(event.getOffset(), event.getText() is null ? 0 : event.getText().length());
187 }
188 }
189 }
190
191 }
192
193 /** The internal key and mouse event listener */
194 private KeyAndMouseListener fKeyAndMouseListener;
195 /** The internal text input listener */
196 private TextInputListener fTextInputListener;
197
198
199 /** The text viewer the undo manager is connected to */
200 private ITextViewer fTextViewer;
201
202 /** The undo level */
203 private int fUndoLevel;
204
205 /** The document undo manager that is active. */
206 private IDocumentUndoManager fDocumentUndoManager;
207
208 /** The document that is active. */
209 private IDocument fDocument;
210
211 /** The document undo listener */
212 private IDocumentUndoListener fDocumentUndoListener;
213
214 /**
215 * Creates a new undo manager who remembers the specified number of edit commands.
216 *
217 * @param undoLevel the length of this manager's history
218 */
219 public TextViewerUndoManager(int undoLevel) {
220 fUndoLevel= undoLevel;
221 }
222
223 /**
224 * Returns whether this undo manager is connected to a text viewer.
225 *
226 * @return <code>true</code> if connected, <code>false</code> otherwise
227 */
228 private bool isConnected() {
229 return fTextViewer !is null && fDocumentUndoManager !is null;
230 }
231
232 /*
233 * @see IUndoManager#beginCompoundChange
234 */
235 public void beginCompoundChange() {
236 if (isConnected()) {
237 fDocumentUndoManager.beginCompoundChange();
238 }
239 }
240
241
242 /*
243 * @see IUndoManager#endCompoundChange
244 */
245 public void endCompoundChange() {
246 if (isConnected()) {
247 fDocumentUndoManager.endCompoundChange();
248 }
249 }
250
251 /**
252 * Registers all necessary listeners with the text viewer.
253 */
254 private void addListeners() {
255 StyledText text= fTextViewer.getTextWidget();
256 if (text !is null) {
257 fKeyAndMouseListener= new KeyAndMouseListener();
258 text.addMouseListener(fKeyAndMouseListener);
259 text.addKeyListener(fKeyAndMouseListener);
260 fTextInputListener= new TextInputListener();
261 fTextViewer.addTextInputListener(fTextInputListener);
262 }
263 }
264
265 /**
266 * Unregister all previously installed listeners from the text viewer.
267 */
268 private void removeListeners() {
269 StyledText text= fTextViewer.getTextWidget();
270 if (text !is null) {
271 if (fKeyAndMouseListener !is null) {
272 text.removeMouseListener(fKeyAndMouseListener);
273 text.removeKeyListener(fKeyAndMouseListener);
274 fKeyAndMouseListener= null;
275 }
276 if (fTextInputListener !is null) {
277 fTextViewer.removeTextInputListener(fTextInputListener);
278 fTextInputListener= null;
279 }
280 }
281 }
282
283 /**
284 * Shows the given exception in an error dialog.
285 *
286 * @param title the dialog title
287 * @param ex the exception
288 */
289 private void openErrorDialog(final String title, final Exception ex) {
290 Shell shell= null;
291 if (isConnected()) {
292 StyledText st= fTextViewer.getTextWidget();
293 if (st !is null && !st.isDisposed())
294 shell= st.getShell();
295 }
296 if (Display.getCurrent() !is null)
297 MessageDialog.openError(shell, title, ex.getLocalizedMessage());
298 else {
299 Display display;
300 final Shell finalShell= shell;
301 if (finalShell !is null)
302 display= finalShell.getDisplay();
303 else
304 display= Display.getDefault();
305 display.syncExec(new Runnable() {
306 public void run() {
307 MessageDialog.openError(finalShell, title, ex.getLocalizedMessage());
308 }
309 });
310 }
311 }
312
313 /*
314 * @see dwtx.jface.text.IUndoManager#setMaximalUndoLevel(int)
315 */
316 public void setMaximalUndoLevel(int undoLevel) {
317 fUndoLevel= Math.max(0, undoLevel);
318 if (isConnected()) {
319 fDocumentUndoManager.setMaximalUndoLevel(fUndoLevel);
320 }
321 }
322
323 /*
324 * @see dwtx.jface.text.IUndoManager#connect(dwtx.jface.text.ITextViewer)
325 */
326 public void connect(ITextViewer textViewer) {
327 if (fTextViewer is null && textViewer !is null) {
328 fTextViewer= textViewer;
329 addListeners();
330 }
331 IDocument doc= fTextViewer.getDocument();
332 connectDocumentUndoManager(doc);
333 }
334
335 /*
336 * @see dwtx.jface.text.IUndoManager#disconnect()
337 */
338 public void disconnect() {
339 if (fTextViewer !is null) {
340 removeListeners();
341 fTextViewer= null;
342 }
343 disconnectDocumentUndoManager();
344 }
345
346 /*
347 * @see dwtx.jface.text.IUndoManager#reset()
348 */
349 public void reset() {
350 if (isConnected())
351 fDocumentUndoManager.reset();
352
353 }
354
355 /*
356 * @see dwtx.jface.text.IUndoManager#redoable()
357 */
358 public bool redoable() {
359 if (isConnected())
360 return fDocumentUndoManager.redoable();
361 return false;
362 }
363
364 /*
365 * @see dwtx.jface.text.IUndoManager#undoable()
366 */
367 public bool undoable() {
368 if (isConnected())
369 return fDocumentUndoManager.undoable();
370 return false;
371 }
372
373 /*
374 * @see dwtx.jface.text.IUndoManager#redo()
375 */
376 public void redo() {
377 if (isConnected()) {
378 try {
379 fDocumentUndoManager.redo();
380 } catch (ExecutionException ex) {
381 openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.redoFailed.title"), ex); //$NON-NLS-1$
382 }
383 }
384 }
385
386 /*
387 * @see dwtx.jface.text.IUndoManager#undo()
388 */
389 public void undo() {
390 if (isConnected()) {
391 try {
392 fDocumentUndoManager.undo();
393 } catch (ExecutionException ex) {
394 openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.undoFailed.title"), ex); //$NON-NLS-1$
395 }
396 }
397 }
398
399 /**
400 * Selects and reveals the specified range.
401 *
402 * @param offset the offset of the range
403 * @param length the length of the range
404 */
405 private void selectAndReveal(int offset, int length) {
406 if (fTextViewer instanceof ITextViewerExtension5) {
407 ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer;
408 extension.exposeModelRange(new Region(offset, length));
409 } else if (!fTextViewer.overlapsWithVisibleRegion(offset, length))
410 fTextViewer.resetVisibleRegion();
411
412 fTextViewer.setSelectedRange(offset, length);
413 fTextViewer.revealRange(offset, length);
414 }
415
416 /*
417 * @see dwtx.jface.text.IUndoManagerExtension#getUndoContext()
418 */
419 public IUndoContext getUndoContext() {
420 if (isConnected()) {
421 return fDocumentUndoManager.getUndoContext();
422 }
423 return null;
424 }
425
426 private void connectDocumentUndoManager(IDocument document) {
427 disconnectDocumentUndoManager();
428 if (document !is null) {
429 fDocument= document;
430 DocumentUndoManagerRegistry.connect(fDocument);
431 fDocumentUndoManager= DocumentUndoManagerRegistry.getDocumentUndoManager(fDocument);
432 fDocumentUndoManager.connect(this);
433 setMaximalUndoLevel(fUndoLevel);
434 fDocumentUndoListener= new DocumentUndoListener();
435 fDocumentUndoManager.addDocumentUndoListener(fDocumentUndoListener);
436 }
437 }
438
439 private void disconnectDocumentUndoManager() {
440 if (fDocumentUndoManager !is null) {
441 fDocumentUndoManager.disconnect(this);
442 DocumentUndoManagerRegistry.disconnect(fDocument);
443 fDocumentUndoManager.removeDocumentUndoListener(fDocumentUndoListener);
444 fDocumentUndoListener= null;
445 fDocumentUndoManager= null;
446 }
447 }
448 }