diff dwtx/text/edits/CopySourceEdit.d @ 129:eb30df5ca28b

Added JFace Text sources
author Frank Benoit <benoit@tionex.de>
date Sat, 23 Aug 2008 19:10:48 +0200
parents
children b56e9be9fe88
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/text/edits/CopySourceEdit.d	Sat Aug 23 19:10:48 2008 +0200
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.text.edits.CopySourceEdit;
+
+import dwt.dwthelper.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dwtx.core.runtime.Assert;
+import dwtx.jface.text.BadLocationException;
+import dwtx.jface.text.IDocument;
+
+/**
+ * A copy source edit denotes the source of a copy operation. Copy
+ * source edits are only valid inside an edit tree if they have a
+ * corresponding target edit. Furthermore the corresponding
+ * target edit can't be a direct or indirect child of the source
+ * edit. Violating one of two requirements will result in a <code>
+ * MalformedTreeException</code> when executing the edit tree.
+ * <p>
+ * A copy source edit can manage an optional source modifier. A
+ * source modifier can provide a set of replace edits which will
+ * to applied to the source before it gets inserted at the target
+ * position.
+ *
+ * @see dwtx.text.edits.CopyTargetEdit
+ *
+ * @since 3.0
+ */
+public final class CopySourceEdit : TextEdit {
+
+    private CopyTargetEdit fTarget;
+    private ISourceModifier fModifier;
+
+    private String fSourceContent;
+    private TextEdit fSourceRoot;
+
+    private static class PartialCopier : TextEditVisitor {
+        TextEdit fResult;
+        List fParents= new ArrayList();
+        TextEdit fCurrentParent;
+
+        public static TextEdit perform(TextEdit source) {
+            PartialCopier copier= new PartialCopier();
+            source.accept(copier);
+            return copier.fResult;
+        }
+        private void manageCopy(TextEdit copy) {
+            if (fResult is null)
+                fResult= copy;
+            if (fCurrentParent !is null) {
+                fCurrentParent.addChild(copy);
+            }
+            fParents.add(fCurrentParent);
+            fCurrentParent= copy;
+        }
+        public void postVisit(TextEdit edit) {
+            fCurrentParent= (TextEdit)fParents.remove(fParents.size() - 1);
+        }
+        public bool visitNode(TextEdit edit) {
+            manageCopy(edit.doCopy());
+            return true;
+        }
+        public bool visit(CopySourceEdit edit) {
+            manageCopy(new RangeMarker(edit.getOffset(), edit.getLength()));
+            return true;
+        }
+        public bool visit(CopyTargetEdit edit) {
+            manageCopy(new InsertEdit(edit.getOffset(), edit.getSourceEdit().getContent()));
+            return true;
+        }
+        public bool visit(MoveSourceEdit edit) {
+            manageCopy(new DeleteEdit(edit.getOffset(), edit.getLength()));
+            return true;
+        }
+        public bool visit(MoveTargetEdit edit) {
+            manageCopy(new InsertEdit(edit.getOffset(), edit.getSourceEdit().getContent()));
+            return true;
+        }
+    }
+
+    /**
+     * Constructs a new copy source edit.
+     *
+     * @param offset the edit's offset
+     * @param length the edit's length
+     */
+    public CopySourceEdit(int offset, int length) {
+        super(offset, length);
+    }
+
+    /**
+     * Constructs a new copy source edit.
+     *
+     * @param offset the edit's offset
+     * @param length the edit's length
+     * @param target the edit's target
+     */
+    public CopySourceEdit(int offset, int length, CopyTargetEdit target) {
+        this(offset, length);
+        setTargetEdit(target);
+    }
+
+    /*
+     * Copy Constructor
+     */
+    private CopySourceEdit(CopySourceEdit other) {
+        super(other);
+        if (other.fModifier !is null)
+            fModifier= other.fModifier.copy();
+    }
+
+    /**
+     * Returns the associated target edit or <code>null</code>
+     * if no target edit is associated yet.
+     *
+     * @return the target edit or <code>null</code>
+     */
+    public CopyTargetEdit getTargetEdit() {
+        return fTarget;
+    }
+
+    /**
+     * Sets the target edit.
+     *
+     * @param edit the new target edit.
+     *
+     * @exception MalformedTreeException is thrown if the target edit
+     *  is a direct or indirect child of the source edit
+     */
+    public void setTargetEdit(CopyTargetEdit edit) throws MalformedTreeException {
+        Assert.isNotNull(edit);
+        if (fTarget !is edit) {
+            fTarget= edit;
+            fTarget.setSourceEdit(this);
+        }
+    }
+
+    /**
+     * Returns the current source modifier or <code>null</code>
+     * if no source modifier is set.
+     *
+     * @return the source modifier
+     */
+    public ISourceModifier getSourceModifier() {
+        return fModifier;
+    }
+
+    /**
+     * Sets the optional source modifier.
+     *
+     * @param modifier the source modifier or <code>null</code>
+     *  if no source modification is need.
+     */
+    public void setSourceModifier(ISourceModifier modifier) {
+        fModifier= modifier;
+    }
+
+    /*
+     * @see TextEdit#doCopy
+     */
+    protected TextEdit doCopy() {
+        return new CopySourceEdit(this);
+    }
+
+    /*
+     * @see TextEdit#accept0
+     */
+    protected void accept0(TextEditVisitor visitor) {
+        bool visitChildren= visitor.visit(this);
+        if (visitChildren) {
+            acceptChildren(visitor);
+        }
+    }
+
+    //---- API for CopyTargetEdit ------------------------------------------------
+
+    String getContent() {
+        // The source content can be null if the edit wasn't executed
+        // due to an exclusion list of the text edit processor. Return
+        // the empty string which can be moved without any harm.
+        if (fSourceContent is null)
+            return ""; //$NON-NLS-1$
+        return fSourceContent;
+    }
+
+    void clearContent() {
+        fSourceContent= null;
+    }
+
+    /*
+     * @see TextEdit#postProcessCopy
+     */
+    protected void postProcessCopy(TextEditCopier copier) {
+        if (fTarget !is null) {
+            CopySourceEdit source= (CopySourceEdit)copier.getCopy(this);
+            CopyTargetEdit target= (CopyTargetEdit)copier.getCopy(fTarget);
+            if (source !is null && target !is null)
+                source.setTargetEdit(target);
+        }
+    }
+
+    //---- consistency check ----------------------------------------------------
+
+    int traverseConsistencyCheck(TextEditProcessor processor, IDocument document, List sourceEdits) {
+        int result= super.traverseConsistencyCheck(processor, document, sourceEdits);
+        // Since source computation takes place in a recursive fashion (see
+        // performSourceComputation) we only do something if we don't have a
+        // computed source already.
+        if (fSourceContent is null) {
+            if (sourceEdits.size() <= result) {
+                List list= new ArrayList();
+                list.add(this);
+                for (int i= sourceEdits.size(); i < result; i++)
+                    sourceEdits.add(null);
+                sourceEdits.add(list);
+            } else {
+                List list= (List)sourceEdits.get(result);
+                if (list is null) {
+                    list= new ArrayList();
+                    sourceEdits.add(result, list);
+                }
+                list.add(this);
+            }
+        }
+        return result;
+    }
+
+    void performConsistencyCheck(TextEditProcessor processor, IDocument document) throws MalformedTreeException {
+        if (fTarget is null)
+            throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("CopySourceEdit.no_target")); //$NON-NLS-1$
+        if (fTarget.getSourceEdit() !is this)
+            throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("CopySourceEdit.different_source")); //$NON-NLS-1$
+        /* causes ASTRewrite to fail
+        if (getRoot() !is fTarget.getRoot())
+            throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("CopySourceEdit.different_tree")); //$NON-NLS-1$
+        */
+    }
+
+    //---- source computation -------------------------------------------------------
+
+    void traverseSourceComputation(TextEditProcessor processor, IDocument document) {
+        // always perform source computation independent of processor.considerEdit
+        // The target might need the source and the source is computed in a
+        // temporary buffer.
+        performSourceComputation(processor, document);
+    }
+
+    void performSourceComputation(TextEditProcessor processor, IDocument document) {
+        try {
+            MultiTextEdit root= new MultiTextEdit(getOffset(), getLength());
+            root.internalSetChildren(internalGetChildren());
+            fSourceContent= document.get(getOffset(), getLength());
+            fSourceRoot= PartialCopier.perform(root);
+            fSourceRoot.internalMoveTree(-getOffset());
+            if (fSourceRoot.hasChildren()) {
+                EditDocument subDocument= new EditDocument(fSourceContent);
+                TextEditProcessor subProcessor= TextEditProcessor.createSourceComputationProcessor(subDocument, fSourceRoot, TextEdit.NONE);
+                subProcessor.performEdits();
+                if (needsTransformation())
+                    applyTransformation(subDocument);
+                fSourceContent= subDocument.get();
+                fSourceRoot= null;
+            } else {
+                if (needsTransformation()) {
+                    EditDocument subDocument= new EditDocument(fSourceContent);
+                    applyTransformation(subDocument);
+                    fSourceContent= subDocument.get();
+                }
+            }
+        } catch (BadLocationException cannotHappen) {
+            Assert.isTrue(false);
+        }
+    }
+
+    private bool needsTransformation() {
+        return fModifier !is null;
+    }
+
+    private void applyTransformation(IDocument document) throws MalformedTreeException {
+        TextEdit newEdit= new MultiTextEdit(0, document.getLength());
+        ReplaceEdit[] replaces= fModifier.getModifications(document.get());
+        for (int i= 0; i < replaces.length; i++) {
+            newEdit.addChild(replaces[i]);
+        }
+        try {
+            newEdit.apply(document, TextEdit.NONE);
+        } catch (BadLocationException cannotHappen) {
+            Assert.isTrue(false);
+        }
+    }
+
+    //---- document updating ----------------------------------------------------------------
+
+    int performDocumentUpdating(IDocument document) throws BadLocationException {
+        fDelta= 0;
+        return fDelta;
+    }
+
+    //---- region updating ----------------------------------------------------------------
+
+    /*
+     * @see TextEdit#deleteChildren
+     */
+    bool deleteChildren() {
+        return false;
+    }
+}