Mercurial > projects > dwt-addons
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 } |