Mercurial > projects > dwt-addons
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/text/TextViewerUndoManager.d Sat Aug 23 19:10:48 2008 +0200 @@ -0,0 +1,448 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ + +module dwtx.jface.text.TextViewerUndoManager; + +import dwt.dwthelper.utils; + + + + + +import dwt.DWT; +import dwt.custom.StyledText; +import dwt.events.KeyEvent; +import dwt.events.KeyListener; +import dwt.events.MouseEvent; +import dwt.events.MouseListener; +import dwt.widgets.Display; +import dwt.widgets.Shell; +import dwtx.core.commands.ExecutionException; +import dwtx.core.commands.operations.IUndoContext; +import dwtx.jface.dialogs.MessageDialog; +import dwtx.text.undo.DocumentUndoEvent; +import dwtx.text.undo.DocumentUndoManager; +import dwtx.text.undo.DocumentUndoManagerRegistry; +import dwtx.text.undo.IDocumentUndoListener; +import dwtx.text.undo.IDocumentUndoManager; + + +/** + * Implementation of {@link dwtx.jface.text.IUndoManager} using the shared + * document undo manager. + * <p> + * It registers with the connected text viewer as text input listener, and obtains + * its undo manager from the current document. It also monitors mouse and keyboard + * activities in order to partition the stream of text changes into undo-able + * edit commands. + * <p> + * This class is not intended to be subclassed. + * </p> + * + * @see ITextViewer + * @see ITextInputListener + * @see IDocumentUndoManager + * @see MouseListener + * @see KeyListener + * @see DocumentUndoManager + * + * @since 3.2 + * @noextend This class is not intended to be subclassed by clients. + */ +public class TextViewerUndoManager : IUndoManager, IUndoManagerExtension { + + + /** + * Internal listener to mouse and key events. + */ + private class KeyAndMouseListener : MouseListener, KeyListener { + + /* + * @see MouseListener#mouseDoubleClick + */ + public void mouseDoubleClick(MouseEvent e) { + } + + /* + * If the right mouse button is pressed, the current editing command is closed + * @see MouseListener#mouseDown + */ + public void mouseDown(MouseEvent e) { + if (e.button is 1) + if (isConnected()) + fDocumentUndoManager.commit(); + } + + /* + * @see MouseListener#mouseUp + */ + public void mouseUp(MouseEvent e) { + } + + /* + * @see KeyListener#keyPressed + */ + public void keyReleased(KeyEvent e) { + } + + /* + * On cursor keys, the current editing command is closed + * @see KeyListener#keyPressed + */ + public void keyPressed(KeyEvent e) { + switch (e.keyCode) { + case DWT.ARROW_UP: + case DWT.ARROW_DOWN: + case DWT.ARROW_LEFT: + case DWT.ARROW_RIGHT: + if (isConnected()) { + fDocumentUndoManager.commit(); + } + break; + } + } + } + + + /** + * Internal text input listener. + */ + private class TextInputListener : ITextInputListener { + + /* + * @see dwtx.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(dwtx.jface.text.IDocument, dwtx.jface.text.IDocument) + */ + public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { + disconnectDocumentUndoManager(); + } + + /* + * @see dwtx.jface.text.ITextInputListener#inputDocumentChanged(dwtx.jface.text.IDocument, dwtx.jface.text.IDocument) + */ + public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + connectDocumentUndoManager(newInput); + } + } + + + /** + * Internal document undo listener. + */ + private class DocumentUndoListener : IDocumentUndoListener { + + /* + * @see dwtx.jface.text.IDocumentUndoListener#documentUndoNotification(DocumentUndoEvent) + */ + public void documentUndoNotification(DocumentUndoEvent event ){ + if (!isConnected()) return; + + int eventType= event.getEventType(); + if (((eventType & DocumentUndoEvent.ABOUT_TO_UNDO) !is 0) || ((eventType & DocumentUndoEvent.ABOUT_TO_REDO) !is 0)) { + if (event.isCompound()) { + ITextViewerExtension extension= null; + if (fTextViewer instanceof ITextViewerExtension) + extension= (ITextViewerExtension) fTextViewer; + + if (extension !is null) + extension.setRedraw(false); + } + fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable() { + public void run() { + if (fTextViewer instanceof TextViewer) + ((TextViewer)fTextViewer).ignoreAutoEditStrategies(true); + } + }); + + } else if (((eventType & DocumentUndoEvent.UNDONE) !is 0) || ((eventType & DocumentUndoEvent.REDONE) !is 0)) { + fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable() { + public void run() { + if (fTextViewer instanceof TextViewer) + ((TextViewer)fTextViewer).ignoreAutoEditStrategies(false); + } + }); + if (event.isCompound()) { + ITextViewerExtension extension= null; + if (fTextViewer instanceof ITextViewerExtension) + extension= (ITextViewerExtension) fTextViewer; + + if (extension !is null) + extension.setRedraw(true); + } + + // Reveal the change if this manager's viewer has the focus. + if (fTextViewer !is null) { + StyledText widget= fTextViewer.getTextWidget(); + if (widget !is null && !widget.isDisposed() && (widget.isFocusControl()))// || fTextViewer.getTextWidget() is control)) + selectAndReveal(event.getOffset(), event.getText() is null ? 0 : event.getText().length()); + } + } + } + + } + + /** The internal key and mouse event listener */ + private KeyAndMouseListener fKeyAndMouseListener; + /** The internal text input listener */ + private TextInputListener fTextInputListener; + + + /** The text viewer the undo manager is connected to */ + private ITextViewer fTextViewer; + + /** The undo level */ + private int fUndoLevel; + + /** The document undo manager that is active. */ + private IDocumentUndoManager fDocumentUndoManager; + + /** The document that is active. */ + private IDocument fDocument; + + /** The document undo listener */ + private IDocumentUndoListener fDocumentUndoListener; + + /** + * Creates a new undo manager who remembers the specified number of edit commands. + * + * @param undoLevel the length of this manager's history + */ + public TextViewerUndoManager(int undoLevel) { + fUndoLevel= undoLevel; + } + + /** + * Returns whether this undo manager is connected to a text viewer. + * + * @return <code>true</code> if connected, <code>false</code> otherwise + */ + private bool isConnected() { + return fTextViewer !is null && fDocumentUndoManager !is null; + } + + /* + * @see IUndoManager#beginCompoundChange + */ + public void beginCompoundChange() { + if (isConnected()) { + fDocumentUndoManager.beginCompoundChange(); + } + } + + + /* + * @see IUndoManager#endCompoundChange + */ + public void endCompoundChange() { + if (isConnected()) { + fDocumentUndoManager.endCompoundChange(); + } + } + + /** + * Registers all necessary listeners with the text viewer. + */ + private void addListeners() { + StyledText text= fTextViewer.getTextWidget(); + if (text !is null) { + fKeyAndMouseListener= new KeyAndMouseListener(); + text.addMouseListener(fKeyAndMouseListener); + text.addKeyListener(fKeyAndMouseListener); + fTextInputListener= new TextInputListener(); + fTextViewer.addTextInputListener(fTextInputListener); + } + } + + /** + * Unregister all previously installed listeners from the text viewer. + */ + private void removeListeners() { + StyledText text= fTextViewer.getTextWidget(); + if (text !is null) { + if (fKeyAndMouseListener !is null) { + text.removeMouseListener(fKeyAndMouseListener); + text.removeKeyListener(fKeyAndMouseListener); + fKeyAndMouseListener= null; + } + if (fTextInputListener !is null) { + fTextViewer.removeTextInputListener(fTextInputListener); + fTextInputListener= null; + } + } + } + + /** + * Shows the given exception in an error dialog. + * + * @param title the dialog title + * @param ex the exception + */ + private void openErrorDialog(final String title, final Exception ex) { + Shell shell= null; + if (isConnected()) { + StyledText st= fTextViewer.getTextWidget(); + if (st !is null && !st.isDisposed()) + shell= st.getShell(); + } + if (Display.getCurrent() !is null) + MessageDialog.openError(shell, title, ex.getLocalizedMessage()); + else { + Display display; + final Shell finalShell= shell; + if (finalShell !is null) + display= finalShell.getDisplay(); + else + display= Display.getDefault(); + display.syncExec(new Runnable() { + public void run() { + MessageDialog.openError(finalShell, title, ex.getLocalizedMessage()); + } + }); + } + } + + /* + * @see dwtx.jface.text.IUndoManager#setMaximalUndoLevel(int) + */ + public void setMaximalUndoLevel(int undoLevel) { + fUndoLevel= Math.max(0, undoLevel); + if (isConnected()) { + fDocumentUndoManager.setMaximalUndoLevel(fUndoLevel); + } + } + + /* + * @see dwtx.jface.text.IUndoManager#connect(dwtx.jface.text.ITextViewer) + */ + public void connect(ITextViewer textViewer) { + if (fTextViewer is null && textViewer !is null) { + fTextViewer= textViewer; + addListeners(); + } + IDocument doc= fTextViewer.getDocument(); + connectDocumentUndoManager(doc); + } + + /* + * @see dwtx.jface.text.IUndoManager#disconnect() + */ + public void disconnect() { + if (fTextViewer !is null) { + removeListeners(); + fTextViewer= null; + } + disconnectDocumentUndoManager(); + } + + /* + * @see dwtx.jface.text.IUndoManager#reset() + */ + public void reset() { + if (isConnected()) + fDocumentUndoManager.reset(); + + } + + /* + * @see dwtx.jface.text.IUndoManager#redoable() + */ + public bool redoable() { + if (isConnected()) + return fDocumentUndoManager.redoable(); + return false; + } + + /* + * @see dwtx.jface.text.IUndoManager#undoable() + */ + public bool undoable() { + if (isConnected()) + return fDocumentUndoManager.undoable(); + return false; + } + + /* + * @see dwtx.jface.text.IUndoManager#redo() + */ + public void redo() { + if (isConnected()) { + try { + fDocumentUndoManager.redo(); + } catch (ExecutionException ex) { + openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.redoFailed.title"), ex); //$NON-NLS-1$ + } + } + } + + /* + * @see dwtx.jface.text.IUndoManager#undo() + */ + public void undo() { + if (isConnected()) { + try { + fDocumentUndoManager.undo(); + } catch (ExecutionException ex) { + openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.undoFailed.title"), ex); //$NON-NLS-1$ + } + } + } + + /** + * Selects and reveals the specified range. + * + * @param offset the offset of the range + * @param length the length of the range + */ + private void selectAndReveal(int offset, int length) { + if (fTextViewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; + extension.exposeModelRange(new Region(offset, length)); + } else if (!fTextViewer.overlapsWithVisibleRegion(offset, length)) + fTextViewer.resetVisibleRegion(); + + fTextViewer.setSelectedRange(offset, length); + fTextViewer.revealRange(offset, length); + } + + /* + * @see dwtx.jface.text.IUndoManagerExtension#getUndoContext() + */ + public IUndoContext getUndoContext() { + if (isConnected()) { + return fDocumentUndoManager.getUndoContext(); + } + return null; + } + + private void connectDocumentUndoManager(IDocument document) { + disconnectDocumentUndoManager(); + if (document !is null) { + fDocument= document; + DocumentUndoManagerRegistry.connect(fDocument); + fDocumentUndoManager= DocumentUndoManagerRegistry.getDocumentUndoManager(fDocument); + fDocumentUndoManager.connect(this); + setMaximalUndoLevel(fUndoLevel); + fDocumentUndoListener= new DocumentUndoListener(); + fDocumentUndoManager.addDocumentUndoListener(fDocumentUndoListener); + } + } + + private void disconnectDocumentUndoManager() { + if (fDocumentUndoManager !is null) { + fDocumentUndoManager.disconnect(this); + DocumentUndoManagerRegistry.disconnect(fDocument); + fDocumentUndoManager.removeDocumentUndoListener(fDocumentUndoListener); + fDocumentUndoListener= null; + fDocumentUndoManager= null; + } + } +}