diff dwtx/jface/text/formatter/MultiPassContentFormatter.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/formatter/MultiPassContentFormatter.d	Sat Aug 23 19:10:48 2008 +0200
@@ -0,0 +1,322 @@
+/*******************************************************************************
+ * 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.jface.text.formatter.MultiPassContentFormatter;
+
+import dwt.dwthelper.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import dwtx.core.runtime.Assert;
+import dwtx.jface.text.BadLocationException;
+import dwtx.jface.text.DefaultPositionUpdater;
+import dwtx.jface.text.IDocument;
+import dwtx.jface.text.IRegion;
+import dwtx.jface.text.ITypedRegion;
+import dwtx.jface.text.TextUtilities;
+import dwtx.jface.text.TypedPosition;
+
+/**
+ * Content formatter for edit-based formatting strategies.
+ * <p>
+ * Two kinds of formatting strategies can be registered with this formatter:
+ * <ul>
+ * <li>one master formatting strategy for the default content type</li>
+ * <li>one formatting strategy for each non-default content type</li>
+ * </ul>
+ * The master formatting strategy always formats the whole region to be
+ * formatted in the first pass. In a second pass, all partitions of the region
+ * to be formatted that are not of master content type are formatted using the
+ * slave formatting strategy registered for the underlying content type. All
+ * formatting strategies must implement {@link IFormattingStrategyExtension}.
+ * <p>
+ * Regions to be formatted with the master formatting strategy always have
+ * an offset aligned to the line start. Regions to be formatted with slave formatting
+ * strategies are aligned on partition boundaries.
+ *
+ * @see IFormattingStrategyExtension
+ * @since 3.0
+ */
+public class MultiPassContentFormatter : IContentFormatter, IContentFormatterExtension {
+
+    /**
+     * Position updater that shifts otherwise deleted positions to the next
+     * non-whitespace character. The length of the positions are truncated to
+     * one if the position was shifted.
+     */
+    protected class NonDeletingPositionUpdater : DefaultPositionUpdater {
+
+        /**
+         * Creates a new non-deleting position updater.
+         *
+         * @param category The position category to update its positions
+         */
+        public NonDeletingPositionUpdater(final String category) {
+            super(category);
+        }
+
+        /*
+         * @see dwtx.jface.text.DefaultPositionUpdater#notDeleted()
+         */
+        protected final bool notDeleted() {
+
+            if (fOffset < fPosition.offset && (fPosition.offset + fPosition.length < fOffset + fLength)) {
+
+                int offset= fOffset + fLength;
+                if (offset < fDocument.getLength()) {
+
+                    try {
+
+                        bool moved= false;
+                        char character= fDocument.getChar(offset);
+
+                        while (offset < fDocument.getLength() && Character.isWhitespace(character)) {
+
+                            moved= true;
+                            character= fDocument.getChar(offset++);
+                        }
+
+                        if (moved)
+                            offset--;
+
+                    } catch (BadLocationException exception) {
+                        // Can not happen
+                    }
+
+                    fPosition.offset= offset;
+                    fPosition.length= 0;
+                }
+            }
+            return true;
+        }
+    }
+
+    /** The master formatting strategy */
+    private IFormattingStrategyExtension fMaster= null;
+    /** The partitioning of this content formatter */
+    private final String fPartitioning;
+    /** The slave formatting strategies */
+    private final Map fSlaves= new HashMap();
+    /** The default content type */
+    private final String fType;
+
+    /**
+     * Creates a new content formatter.
+     *
+     * @param partitioning the document partitioning for this formatter
+     * @param type the default content type
+     */
+    public MultiPassContentFormatter(final String partitioning, final String type) {
+        fPartitioning= partitioning;
+        fType= type;
+    }
+
+    /*
+     * @see dwtx.jface.text.formatter.IContentFormatterExtension#format(dwtx.jface.text.IDocument, dwtx.jface.text.formatter.IFormattingContext)
+     */
+    public final void format(final IDocument medium, final IFormattingContext context) {
+
+        context.setProperty(FormattingContextProperties.CONTEXT_MEDIUM, medium);
+
+        final Boolean document= (Boolean)context.getProperty(FormattingContextProperties.CONTEXT_DOCUMENT);
+        if (document is null || !document.booleanValue()) {
+
+            final IRegion region= (IRegion)context.getProperty(FormattingContextProperties.CONTEXT_REGION);
+            if (region !is null) {
+                try {
+                    formatMaster(context, medium, region.getOffset(), region.getLength());
+                } finally {
+                    formatSlaves(context, medium, region.getOffset(), region.getLength());
+                }
+            }
+        } else {
+            try {
+                formatMaster(context, medium, 0, medium.getLength());
+            } finally {
+                formatSlaves(context, medium, 0, medium.getLength());
+            }
+        }
+    }
+
+    /*
+     * @see dwtx.jface.text.formatter.IContentFormatter#format(dwtx.jface.text.IDocument, dwtx.jface.text.IRegion)
+     */
+    public final void format(final IDocument medium, final IRegion region) {
+
+        final FormattingContext context= new FormattingContext();
+
+        context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.FALSE);
+        context.setProperty(FormattingContextProperties.CONTEXT_REGION, region);
+
+        format(medium, context);
+    }
+
+    /**
+     * Formats the document specified in the formatting context with the master
+     * formatting strategy.
+     * <p>
+     * The master formatting strategy covers all regions of the document. The
+     * offset of the region to be formatted is aligned on line start boundaries,
+     * whereas the end index of the region remains the same. For this formatting
+     * type the document partitioning is not taken into account.
+     *
+     * @param context The formatting context to use
+     * @param document The document to operate on
+     * @param offset The offset of the region to format
+     * @param length The length of the region to format
+     */
+    protected void formatMaster(final IFormattingContext context, final IDocument document, int offset, int length) {
+
+        try {
+
+            final int delta= offset - document.getLineInformationOfOffset(offset).getOffset();
+            offset -= delta;
+            length += delta;
+
+        } catch (BadLocationException exception) {
+            // Do nothing
+        }
+
+        if (fMaster !is null) {
+
+            context.setProperty(FormattingContextProperties.CONTEXT_PARTITION, new TypedPosition(offset, length, fType));
+
+            fMaster.formatterStarts(context);
+            fMaster.format();
+            fMaster.formatterStops();
+        }
+    }
+
+    /**
+     * Formats the document specified in the formatting context with the
+     * formatting strategy registered for the content type.
+     * <p>
+     * For this formatting type only slave strategies are used. The region to be
+     * formatted is aligned on partition boundaries of the underlying content
+     * type. The exact formatting strategy is determined by the underlying
+     * content type of the document partitioning.
+     *
+     * @param context The formatting context to use
+     * @param document The document to operate on
+     * @param offset The offset of the region to format
+     * @param length The length of the region to format
+     * @param type The content type of the region to format
+     */
+    protected void formatSlave(final IFormattingContext context, final IDocument document, final int offset, final int length, final String type) {
+
+        final IFormattingStrategyExtension strategy= (IFormattingStrategyExtension)fSlaves.get(type);
+        if (strategy !is null) {
+
+            context.setProperty(FormattingContextProperties.CONTEXT_PARTITION, new TypedPosition(offset, length, type));
+
+            strategy.formatterStarts(context);
+            strategy.format();
+            strategy.formatterStops();
+        }
+    }
+
+    /**
+     * Formats the document specified in the formatting context with the slave
+     * formatting strategies.
+     * <p>
+     * For each content type of the region to be formatted in the document
+     * partitioning, the registered slave formatting strategy is used to format
+     * that particular region. The region to be formatted is aligned on
+     * partition boundaries of the underlying content type. If the content type
+     * is the document's default content type, nothing happens.
+     *
+     * @param context The formatting context to use
+     * @param document The document to operate on
+     * @param offset The offset of the region to format
+     * @param length The length of the region to format
+     */
+    protected void formatSlaves(final IFormattingContext context, final IDocument document, final int offset, final int length) {
+
+        Map partitioners= new HashMap(0);
+        try {
+
+            final ITypedRegion[] partitions= TextUtilities.computePartitioning(document, fPartitioning, offset, length, false);
+
+            if (!fType.equals(partitions[0].getType()))
+                partitions[0]= TextUtilities.getPartition(document, fPartitioning, partitions[0].getOffset(), false);
+
+            if (partitions.length > 1) {
+
+                if (!fType.equals(partitions[partitions.length - 1].getType()))
+                    partitions[partitions.length - 1]= TextUtilities.getPartition(document, fPartitioning, partitions[partitions.length - 1].getOffset(), false);
+            }
+
+            String type= null;
+            ITypedRegion partition= null;
+
+            partitioners= TextUtilities.removeDocumentPartitioners(document);
+
+            for (int index= partitions.length - 1; index >= 0; index--) {
+
+                partition= partitions[index];
+                type= partition.getType();
+
+                if (!fType.equals(type))
+                    formatSlave(context, document, partition.getOffset(), partition.getLength(), type);
+            }
+
+        } catch (BadLocationException exception) {
+            // Should not happen
+        } finally {
+            TextUtilities.addDocumentPartitioners(document, partitioners);
+        }
+    }
+
+    /*
+     * @see dwtx.jface.text.formatter.IContentFormatter#getFormattingStrategy(java.lang.String)
+     */
+    public final IFormattingStrategy getFormattingStrategy(final String type) {
+        return null;
+    }
+
+    /**
+     * Registers a master formatting strategy.
+     * <p>
+     * The strategy may already be registered with a certain content type as
+     * slave strategy. The master strategy is registered for the default content
+     * type of documents. If a master strategy has already been registered, it
+     * is overridden by the new one.
+     *
+     * @param strategy The master formatting strategy, must implement
+     *  {@link IFormattingStrategyExtension}
+     */
+    public final void setMasterStrategy(final IFormattingStrategy strategy) {
+        Assert.isTrue(strategy instanceof IFormattingStrategyExtension);
+        fMaster= (IFormattingStrategyExtension) strategy;
+    }
+
+    /**
+     * Registers a slave formatting strategy for a certain content type.
+     * <p>
+     * The strategy may already be registered as master strategy. An
+     * already registered slave strategy for the specified content type
+     * will be replaced. However, the same strategy may be registered with
+     * several content types. Slave strategies cannot be registered for the
+     * default content type of documents.
+     *
+     * @param strategy The slave formatting strategy
+     * @param type The content type to register this strategy with,
+     *  must implement {@link IFormattingStrategyExtension}
+     */
+    public final void setSlaveStrategy(final IFormattingStrategy strategy, final String type) {
+        Assert.isTrue(strategy instanceof IFormattingStrategyExtension);
+        if (!fType.equals(type))
+            fSlaves.put(type, strategy);
+    }
+}