+ Editor Indentation module defines
+
+ providing indentation and reformatting services to the clients.
+
+ It also contains SPI allowing the modules to register language-specific
+ indenters and formatters into
+ MimeLookup
+ through XML layers.
+
+
+
+
+
+
+
+
+ Unit tests are provided for checking correctness of infrastructure and delegation
+ from the legacy editor actions to the new API.
+
+
+
+
+
+
+
+
+ Available for NetBeans 6.0.
+
+
+
+
+
+
+
+
+API Usecases
+
+
+
+Fix indentation of a single or multiple lines of a document.
+
+
+Altghough there are formatting actions already there may be clients
+wishing to explicitly fix indentation of e.g. a newly inserted code into a Swing document.
+
+
+The same code is used after inserting a newline into a document.
+
+The
+Indent
+is an entry point for performing reindentation. The following code should be used by clients:
+
+Code beautification of a selected area of a document.
+
+
+Code beautification should not only fix line indentation but it may also perform
+extra changes to code according to formatting rules. For example add newlines
+ or additional whitespace or add/remove extra braces etc.
+
+ Editor indentation performs reindentation and code beautification of Swing document.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The new API should coexist with existing APIs mainly
+ IndentEngine
+ Formatter
+ but in the future we would like to deprecate the mentioned APIs.
+
+
+
+
+
+
+
+
+ Yes.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Yes.
+
+
+
+
+
+
+
+
+ JRE 1.5.
+
+
+
+
+
+
+
+
+ JRE is enough.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ None.
+
+
+
+
+
+
+
+
+ All platforms.
+
+
+
+
+
+
+
+
+ Nothing.
+
+
+
+
+
+
+
+
+ Jar only.
+
+
+
+
+
+
+
+
+ Yes.
+
+
+
+
+
+
+
+
+ Only API and SPI packages are public.
+
+
+
+
+
+
+
+
+ Anywhere.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Both reindentation and reformatting are executed synchronously in a thread that calls
+ the API classes (typically AWT thread).
+
+
+
+
+
+
+
+
+ None.
+
+
+
+
+
+
+
+
+ None.
+
+
+
+
+
+
+
+
+ None.
+
+
+
+
+
+
+
+
+ It uses MimeLookup to search for registered indentation and reformatting task factories.
+
+
+
+
+
+
+
+
+ The module registers org.netbeans.modules.editor.lib.FormatterOverride
+ implementation so that it gets callback-ed from Editor Library formatter's infrastructure.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No significant memory consumption. Only line indent strings are reasonably cached.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Reformatting or reindentation of a large block of text can be time-consuming.
+
+ The API is however not tied to be called in AWT thread only so the caller may reschedule
+ the processing into another thread. It should ensure that the user won't be typing
+ (or otherwise modifying) the document being reformatted.
+
+
+
+
+
+
+
+
+ Size of the code block being reformatted and complexity of the reformatters.
+
+
+
+
+
+
+
+
+ The plugged in code should control its complexity. The indentation infrastructure
+ may provide a logger for displaying of the time spent in the reformatting
+ and reindenting tasks.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ Not directly. Only through MimeLookup.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
+
+
+
+
+ No.
+
+
+
+
Index: indent/build.xml
===================================================================
RCS file: indent/build.xml
diff -N indent/build.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/build.xml 5 Jun 2007 10:15:26 -0000 1.1.2.1
@@ -0,0 +1,23 @@
+
+
+
+
+
+
Index: indent/manifest.mf
===================================================================
RCS file: indent/manifest.mf
diff -N indent/manifest.mf
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/manifest.mf 5 Jun 2007 10:15:25 -0000 1.1.2.1
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+OpenIDE-Module: org.netbeans.modules.editor.indent/1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/indent/Bundle.properties
+OpenIDE-Module-Layer: org/netbeans/modules/editor/indent/resources/layer.xml
Index: indent/nbproject/.cvsignore
===================================================================
RCS file: indent/nbproject/.cvsignore
diff -N indent/nbproject/.cvsignore
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/nbproject/.cvsignore 5 Jun 2007 10:15:30 -0000 1.1.2.1
@@ -0,0 +1 @@
+private
Index: indent/nbproject/project.properties
===================================================================
RCS file: indent/nbproject/project.properties
diff -N indent/nbproject/project.properties
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/nbproject/project.properties 7 Jun 2007 14:54:01 -0000 1.1.2.2
@@ -0,0 +1,24 @@
+# The contents of this file are subject to the terms of the Common Development
+# and Distribution License (the License). You may not use this file except in
+# compliance with the License.
+#
+# You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+# or http://www.netbeans.org/cddl.txt.
+#
+# When distributing Covered Code, include this CDDL Header Notice in each file
+# and include the License file at http://www.netbeans.org/cddl.txt.
+# If applicable, add the following below the CDDL Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# The Original Software is NetBeans. The Initial Developer of the Original
+# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+# Microsystems, Inc. All Rights Reserved.
+
+javac.source=1.5
+javac.compilerargs=-Xlint:unchecked
+spec.version.base=1.0
+
+javadoc.arch=${basedir}/arch.xml
+javadoc.apichanges=${basedir}/apichanges.xml
+javadoc.title=Editor Indentation
Index: indent/nbproject/project.xml
===================================================================
RCS file: indent/nbproject/project.xml
diff -N indent/nbproject/project.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/nbproject/project.xml 7 Jun 2007 15:48:29 -0000 1.1.2.2
@@ -0,0 +1,98 @@
+
+
+
+ org.netbeans.modules.apisupport.project
+
+
+ org.netbeans.modules.editor.indent
+
+
+ org.netbeans.modules.editor.lib
+
+
+
+ 1
+
+
+
+
+ org.netbeans.modules.editor.mimelookup
+
+
+
+ 1
+ 1.5
+
+
+
+ org.netbeans.modules.editor.util
+
+
+
+ 1
+ 1.17
+
+
+
+ org.netbeans.modules.lexer
+
+
+
+ 2
+ 1.19
+
+
+
+ org.openide.util
+
+
+
+ 7.9
+
+
+
+
+
+ unit
+
+ org.netbeans.modules.editor.indent
+
+
+
+
+ org.netbeans.modules.editor
+
+
+
+ org.netbeans.modules.editor.lib
+
+
+
+
+ qa-functional
+
+
+
+ org.netbeans.api.editor.indent
+ org.netbeans.spi.editor.indent
+
+
+
+
Index: indent/src/META-INF/services/org.netbeans.modules.editor.lib.FormatterOverride
===================================================================
RCS file: indent/src/META-INF/services/org.netbeans.modules.editor.lib.FormatterOverride
diff -N indent/src/META-INF/services/org.netbeans.modules.editor.lib.FormatterOverride
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/META-INF/services/org.netbeans.modules.editor.lib.FormatterOverride 7 Jun 2007 14:54:01 -0000 1.1.2.1
@@ -0,0 +1 @@
+org.netbeans.modules.editor.indent.FormatterOverrideImpl
Index: indent/src/org/netbeans/api/editor/indent/Indent.java
===================================================================
RCS file: indent/src/org/netbeans/api/editor/indent/Indent.java
diff -N indent/src/org/netbeans/api/editor/indent/Indent.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/api/editor/indent/Indent.java 14 Jun 2007 08:06:01 -0000 1.1.2.3
@@ -0,0 +1,149 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.api.editor.indent;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import org.netbeans.modules.editor.indent.IndentImpl;
+
+/**
+ * Reindentation of a single or multiple lines in the document
+ * means fixing of the line's indent only but does not do any other
+ * code beautification.
+ *
+ * The following pattern should be used:
+ *
+ */
+ public void lock() {
+ impl.indentLock();
+ }
+
+ /**
+ * Clients should call this method after releasing of document's write lock.
+ *
+ * The following pattern should be used:
+ *
+ */
+ public void unlock() {
+ impl.indentUnlock();
+ }
+
+ /**
+ * Correct indentation on a single line determined by the given offset.
+ *
+ * Typically it is called after newline gets inserted
+ * or when a line is reindented explicitly (e.g. by pressing TAB key in emacs mode).
+ *
+ * This method will fallback to the editor formatting infrastructure
+ * in case there are no registered indent or reformat factories.
+ *
+ * @param offset >=0 any offset on the line to be reformatted.
+ * @throws BadLocationException in case the indenter attempted to insert/remove
+ * at an invalid offset or e.g. into a guarded section.
+ */
+ public void reindent(int offset) throws BadLocationException {
+ reindent(offset, offset);
+ }
+
+ /**
+ * Correct indentation of all lines in the given offset range.
+ *
+ * This method will fallback to the editor formatting infrastructure
+ * in case there are no registered indent or reformat factories.
+ *
+ * @param startOffset >=0 any offset on a first line to be reformatted.
+ * @param endOffset >=startOffset any offset (including end offset)
+ * on a last line to be reformatted.
+ * @throws BadLocationException in case the indenter attempted to insert/remove
+ * at an invalid offset or e.g. into a guarded section.
+ */
+ public void reindent(int startOffset, int endOffset) throws BadLocationException {
+ impl.reindent(startOffset, endOffset);
+ }
+
+}
Index: indent/src/org/netbeans/api/editor/indent/IndentUtils.java
===================================================================
RCS file: indent/src/org/netbeans/api/editor/indent/IndentUtils.java
diff -N indent/src/org/netbeans/api/editor/indent/IndentUtils.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/api/editor/indent/IndentUtils.java 14 Jun 2007 08:06:02 -0000 1.1.2.2
@@ -0,0 +1,240 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.api.editor.indent;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.PlainDocument;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.editor.BaseKit;
+import org.netbeans.editor.Formatter;
+import org.netbeans.editor.Settings;
+import org.netbeans.editor.SettingsNames;
+import org.netbeans.lib.editor.util.ArrayUtilities;
+import org.netbeans.lib.editor.util.swing.DocumentUtilities;
+import org.netbeans.modules.editor.indent.IndentImpl;
+
+/**
+ * Utility methods related to indentation and reformatting.
+ *
+ * @author Miloslav Metelka
+ */
+public final class IndentUtils {
+
+ private static final int MAX_CACHED_INDENT = 80;
+
+ private static final String[] cachedSpacesStrings = new String[MAX_CACHED_INDENT + 1];
+ static {
+ cachedSpacesStrings[0] = "";
+ }
+
+ private static final int MAX_CACHED_TAB_SIZE = 8; // Should mostly be <= 8
+
+ /**
+ * Cached indentation string containing tabs.
+ *
+ * The cache does not contain indents smaller than the particular tabSize
+ * since they are only spaces contained in cachedSpacesStrings.
+ */
+ private static final String[][] cachedTabIndents = new String[MAX_CACHED_TAB_SIZE][];
+
+ private IndentUtils() {
+ // no instances
+ }
+
+ /**
+ * Get number of spaces that form a single indentation level.
+ *
+ * @return >=0 size of indentation level in spaces.
+ */
+ public static int indentLevelSize(Document doc) {
+ int indentLevel;
+ if (doc instanceof BaseDocument) {
+ indentLevel = ((BaseDocument)doc).getShiftWidth();
+ } else {
+ Object val = Settings.getValue(BaseKit.class, SettingsNames.INDENT_SHIFT_WIDTH);
+ indentLevel = (val instanceof Integer) ? ((Integer)val).intValue() : tabSize(doc);
+ }
+ return indentLevel;
+ }
+
+ /**
+ * Get number of spaces that visually substitute '\t' character.
+ *
+ * @return >=0 size corresponding to '\t' character in spaces.
+ */
+ public static int tabSize(Document doc) {
+ int tabSize;
+ if (doc instanceof BaseDocument) {
+ tabSize = ((BaseDocument)doc).getTabSize();
+ } else {
+ Object val = doc.getProperty(PlainDocument.tabSizeAttribute);
+ tabSize = (val instanceof Integer) ? ((Integer)val).intValue() : 8;
+ }
+ assert (tabSize >= 0) : "Retrieved tabSize=" + tabSize + " < 0"; // NOI18N
+ return tabSize;
+ }
+
+ /**
+ * Get whether the indentation strings should contain hard tabs '\t'
+ * or whether they should only contain spaces.
+ *
+ * @return true if the tabs should be expanded or false if not.
+ */
+ public static boolean isExpandTabs(Document doc) {
+ if (doc instanceof BaseDocument) {
+ Formatter formatter = ((BaseDocument)doc).getFormatter();
+ return (formatter != null) ? formatter.expandTabs() : true;
+ } else
+ return true;
+ }
+
+ /**
+ * Get start offset of a line in a document.
+ *
+ * @param doc non-null document.
+ * @param offset >= 0 offset anywhere on the line.
+ * @throws BadLocationException for invalid offset
+ */
+ public static int lineStartOffset(Document doc, int offset) throws BadLocationException {
+ checkOffsetInDocument(doc, offset);
+ Element lineRootElement = IndentImpl.lineRootElement(doc);
+ return lineRootElement.getElement(lineRootElement.getElementIndex(offset)).getStartOffset();
+ }
+
+ /**
+ * Get indentation of a line in a document as a number of spaces.
+ *
+ * @param doc non-null document.
+ * @param lineStartOffset >= 0 start offset of a line in the document.
+ * @throws BadLocationException for invalid offset
+ */
+ public static int lineIndent(Document doc, int lineStartOffset) throws BadLocationException {
+ checkOffsetInDocument(doc, lineStartOffset);
+ CharSequence docText = DocumentUtilities.getText(doc);
+ int indent = 0;
+ int tabSize = -1;
+ while (lineStartOffset < docText.length()) {
+ char ch;
+ switch (ch = docText.charAt(lineStartOffset)) {
+ case '\n':
+ return indent;
+
+ case '\t':
+ if (tabSize == -1)
+ tabSize = tabSize(doc);
+ // Round to next tab stop
+ indent = (indent + tabSize) / tabSize * tabSize;
+
+ default:
+ if (Character.isWhitespace(ch))
+ indent++;
+ else
+ return indent;
+ }
+ }
+ return indent;
+ }
+
+ /**
+ * Create (or get from cache) indentation string for the given indent.
+ *
+ * The indentation settings (tab-size etc. are determined based on the given
+ * document).
+ *
+ * @param doc document from which the indentation settings will be retrieved.
+ * @param indent >=0 indentation in number of spaces.
+ * @return indentation string containing tabs and spaces according to the document's
+ * settings (tab-size etc.).
+ */
+ public static String createIndentString(Document doc, int indent) {
+ if (indent < 0)
+ throw new IllegalArgumentException("indent=" + indent + " < 0"); // NOI18N
+ return cachedOrCreatedIndentString(indent, isExpandTabs(doc), tabSize(doc));
+ }
+
+ static String cachedOrCreatedIndentString(int indent, boolean expandTabs, int tabSize) {
+ String indentString;
+ if (expandTabs || (indent < tabSize)) {
+ if (indent <= MAX_CACHED_INDENT) {
+ synchronized (cachedSpacesStrings) {
+ indentString = cachedSpacesStrings[indent];
+ if (indentString == null) {
+ // Create string with MAX_CACHED_SPACES spaces first if not cached yet
+ indentString = cachedSpacesStrings[MAX_CACHED_INDENT];
+ if (indentString == null) {
+ indentString = createSpacesString(MAX_CACHED_INDENT);
+ cachedSpacesStrings[MAX_CACHED_INDENT] = indentString;
+ }
+ indentString = indentString.substring(0, indent);
+ cachedSpacesStrings[indent] = indentString;
+ }
+ }
+ } else {
+ indentString = createSpacesString(indent);
+ }
+
+ } else { // Do not expand tabs
+ if (indent <= MAX_CACHED_INDENT && tabSize <= MAX_CACHED_TAB_SIZE) {
+ synchronized (cachedTabIndents) {
+ String[] tabIndents = cachedTabIndents[tabSize];
+ if (tabIndents == null) {
+ // Do not cache spaces-only strings
+ tabIndents = new String[MAX_CACHED_INDENT - tabSize];
+ cachedTabIndents[tabSize] = tabIndents;
+ }
+ indentString = tabIndents[indent - tabSize];
+ if (indentString == null) {
+ indentString = createTabIndentString(indent, tabSize);
+ tabIndents[indent - tabSize] = indentString;
+ }
+ }
+ } else {
+ indentString = createTabIndentString(indent, tabSize);
+ }
+ }
+ return indentString;
+ }
+
+ private static String createSpacesString(int spaceCount) {
+ StringBuilder sb = new StringBuilder(spaceCount);
+ ArrayUtilities.appendSpaces(sb, spaceCount);
+ return sb.toString();
+ }
+
+ private static String createTabIndentString(int indent, int tabSize) {
+ StringBuilder sb = new StringBuilder();
+ while (indent >= tabSize) {
+ sb.append('\t');
+ indent -= tabSize;
+ }
+ ArrayUtilities.appendSpaces(sb, indent);
+ return sb.toString();
+ }
+
+ private static void checkOffsetInDocument(Document doc, int offset) throws BadLocationException {
+ if (offset < 0)
+ throw new BadLocationException("offset=" + offset + " < 0", offset); // NOI18N
+ if (offset > doc.getLength())
+ throw new BadLocationException("offset=" + offset + " > doc.getLength()=" + doc.getLength(), offset);
+ }
+
+}
Index: indent/src/org/netbeans/api/editor/indent/Reformat.java
===================================================================
RCS file: indent/src/org/netbeans/api/editor/indent/Reformat.java
diff -N indent/src/org/netbeans/api/editor/indent/Reformat.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/api/editor/indent/Reformat.java 14 Jun 2007 08:06:02 -0000 1.1.2.3
@@ -0,0 +1,132 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.api.editor.indent;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import org.netbeans.modules.editor.indent.IndentImpl;
+
+/**
+ * Reformatting of a block of code in a document.
+ *
+ * The following pattern should be used:
+ *
+ */
+ public void lock() {
+ impl.reformatLock();
+ }
+
+ /**
+ * Clients should call this method after releasing of document's write lock.
+ *
+ * The following pattern should be used:
+ *
+ */
+ public void unlock() {
+ impl.reformatUnlock();
+ }
+
+ /**
+ * Reformat a given range of code in the given document.
+ *
+ * It includes possible fixing of indentation and possible code beautification
+ * dependent on the implementation of the reformatter.
+ *
+ *
+ * If the reformatter implementation is not available the reindentation
+ * will be performed (i.e. just the line indentation will be fixed)
+ * as a closest match.
+ *
+ * @param startOffset start offset of the area to be reformatted.
+ * @param endOffset end offset of the area to be reformatted.
+ */
+ public void reformat(int startOffset, int endOffset) throws BadLocationException {
+ impl.reformat(startOffset, endOffset);
+ }
+
+}
Index: indent/src/org/netbeans/modules/editor/indent/Bundle.properties
===================================================================
RCS file: indent/src/org/netbeans/modules/editor/indent/Bundle.properties
diff -N indent/src/org/netbeans/modules/editor/indent/Bundle.properties
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/modules/editor/indent/Bundle.properties 5 Jun 2007 10:15:28 -0000 1.1.2.1
@@ -0,0 +1,22 @@
+# The contents of this file are subject to the terms of the Common Development
+# and Distribution License (the License). You may not use this file except in
+# compliance with the License.
+#
+# You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+# or http://www.netbeans.org/cddl.txt.
+#
+# When distributing Covered Code, include this CDDL Header Notice in each file
+# and include the License file at http://www.netbeans.org/cddl.txt.
+# If applicable, add the following below the CDDL Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyrighted [year] [name of copyright owner]"
+#
+# The Original Software is NetBeans. The Initial Developer of the Original
+# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+# Microsystems, Inc. All Rights Reserved.
+
+OpenIDE-Module-Name=Editor Indentation
+OpenIDE-Module-Display-Category=Editing
+OpenIDE-Module-Short-Description=Contains indentation APIs and SPIs.
+OpenIDE-Module-Long-Description=The module includes indenation and code formatting APIs and infrastructure.
+
Index: indent/src/org/netbeans/modules/editor/indent/FormatterImpl.java
===================================================================
RCS file: indent/src/org/netbeans/modules/editor/indent/FormatterImpl.java
diff -N indent/src/org/netbeans/modules/editor/indent/FormatterImpl.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/modules/editor/indent/FormatterImpl.java 14 Jun 2007 08:06:02 -0000 1.1.2.2
@@ -0,0 +1,122 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.modules.editor.indent;
+
+import java.io.IOException;
+import java.io.Writer;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.editor.Formatter;
+import org.netbeans.editor.GuardedException;
+import org.netbeans.editor.ext.ExtFormatter;
+import org.netbeans.spi.editor.indent.Context;
+
+/**
+ * Indentation and code reformatting services for a swing text document.
+ *
+ * @author Miloslav Metelka
+ */
+public final class FormatterImpl extends ExtFormatter {
+
+ private Formatter defaultFormatter;
+
+ private IndentImpl indentImpl;
+
+ FormatterImpl(Formatter defaultFormatter, Document doc) {
+ super(defaultFormatter.getKitClass());
+ this.indentImpl = IndentImpl.get(doc);
+ }
+
+ public int[] getReformatBlock(JTextComponent target, String typedText) {
+ return (defaultFormatter instanceof ExtFormatter)
+ ? ((ExtFormatter)defaultFormatter).getReformatBlock(target, typedText)
+ : null;
+ }
+
+ public void indentLock() {
+ indentImpl.indentLock();
+ }
+
+ public void indentUnlock() {
+ indentImpl.indentUnlock();
+ }
+
+ public void reformatLock() {
+ indentImpl.reformatLock();
+ }
+
+ public void reformatUnlock() {
+ indentImpl.reformatUnlock();
+ }
+
+ public int indentLine(Document doc, int offset) {
+ try {
+ indentImpl.reindent(offset, offset);
+ return offset;
+ } catch (GuardedException e) {
+ java.awt.Toolkit.getDefaultToolkit().beep();
+ } catch (BadLocationException e) {
+ throw new IllegalStateException(e);
+ }
+ return offset;
+ }
+
+ /** Inserts new line at given position and indents the new line with
+ * spaces.
+ *
+ * @param doc the document to work on
+ * @param offset the offset of a character on the line
+ * @return new offset to place cursor to
+ */
+ public int indentNewLine(Document doc, int offset) {
+ try {
+ doc.insertString(offset, "\n", null); // NOI18N
+ offset++;
+ return indentLine(doc, offset);
+ } catch (GuardedException e) {
+ java.awt.Toolkit.getDefaultToolkit().beep();
+ } catch (BadLocationException e) {
+ throw new IllegalStateException(e);
+ }
+ return offset;
+ }
+
+ public Writer reformat(BaseDocument doc, int startOffset, int endOffset,
+ boolean indentOnly) throws BadLocationException, IOException {
+ // TBD delegate somehow
+ return (defaultFormatter instanceof ExtFormatter)
+ ? ((ExtFormatter)defaultFormatter).reformat(doc, startOffset, endOffset, indentOnly)
+ : null;
+ }
+
+ public int reformat(BaseDocument doc, int startOffset, int endOffset)
+ throws BadLocationException {
+ if (doc != indentImpl.document())
+ return endOffset - startOffset; // should not happen in reality
+ indentImpl.reformat(startOffset, endOffset);
+ Context ctx = indentImpl.reformatContext();
+ return (ctx != null)
+ ? ctx.endOffset() - ctx.startOffset()
+ : endOffset - startOffset;
+ }
+
+}
Index: indent/src/org/netbeans/modules/editor/indent/FormatterOverrideImpl.java
===================================================================
RCS file: indent/src/org/netbeans/modules/editor/indent/FormatterOverrideImpl.java
diff -N indent/src/org/netbeans/modules/editor/indent/FormatterOverrideImpl.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/modules/editor/indent/FormatterOverrideImpl.java 7 Jun 2007 14:54:00 -0000 1.1.2.1
@@ -0,0 +1,41 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.modules.editor.indent;
+
+import javax.swing.text.Document;
+import org.netbeans.editor.Formatter;
+import org.netbeans.modules.editor.lib.FormatterOverride;
+
+/**
+ * Indentation and code reformatting services for a swing text document.
+ *
+ * @author Miloslav Metelka
+ */
+public final class FormatterOverrideImpl implements FormatterOverride {
+
+ public Formatter getFormatter(Document doc, Formatter defaultFormatter) {
+ IndentImpl indentImpl = IndentImpl.get(doc);
+ if (indentImpl.hasIndentOrReformatFactories()) {
+ defaultFormatter = new FormatterImpl(defaultFormatter, doc);
+ }
+ return defaultFormatter;
+ }
+
+}
Index: indent/src/org/netbeans/modules/editor/indent/IndentImpl.java
===================================================================
RCS file: indent/src/org/netbeans/modules/editor/indent/IndentImpl.java
diff -N indent/src/org/netbeans/modules/editor/indent/IndentImpl.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/modules/editor/indent/IndentImpl.java 14 Jun 2007 08:06:02 -0000 1.1.2.3
@@ -0,0 +1,406 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.modules.editor.indent;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.StyledDocument;
+import org.netbeans.api.editor.indent.Indent;
+import org.netbeans.api.editor.indent.Reformat;
+import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.lexer.LanguagePath;
+import org.netbeans.api.lexer.TokenHierarchy;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.spi.editor.indent.Context;
+import org.netbeans.spi.editor.indent.ExtraLock;
+import org.netbeans.spi.editor.indent.IndentTask;
+import org.netbeans.spi.editor.indent.ReformatTask;
+import org.openide.util.Lookup;
+
+/**
+ * Indentation and code reformatting services for a swing text document.
+ *
+ * @author Miloslav Metelka
+ */
+public final class IndentImpl {
+
+ // -J-Dorg.netbeans.modules.editor.indent.IndentImpl=FINE
+ private static final Logger LOG = Logger.getLogger(IndentImpl.class.getName());
+
+ public static IndentImpl get(Document doc) {
+ IndentImpl indentImpl = (IndentImpl)doc.getProperty(IndentImpl.class);
+ if (indentImpl == null) {
+ indentImpl = new IndentImpl(doc);
+ doc.putProperty(IndentImpl.class, indentImpl);
+ }
+ return indentImpl;
+ }
+
+ private final Document doc;
+
+ private Indent indent;
+
+ private Reformat reformat;
+
+ private TaskHandler indentHandler;
+
+ private TaskHandler reformatHandler;
+
+ public IndentImpl(Document doc) {
+ this.doc = doc;
+ }
+
+ public Document document() {
+ return doc;
+ }
+
+ public Indent getIndent() {
+ return indent;
+ }
+
+ public void setIndent(Indent indent) {
+ this.indent = indent;
+ }
+
+ public Reformat getReformat() {
+ return reformat;
+ }
+
+ public void setReformat(Reformat reformat) {
+ this.reformat = reformat;
+ }
+
+ public boolean hasIndentOrReformatFactories() {
+ return new TaskHandler(true, doc).hasFactories();
+ }
+
+ public synchronized void indentLock() {
+ if (indentHandler != null)
+ throw new IllegalStateException("Already locked");
+ indentHandler = new TaskHandler(true, doc);
+ if (indentHandler.collectTasks()) {
+ indentHandler.lock();
+ }
+ }
+
+ public synchronized void indentUnlock() {
+ if (indentHandler == null)
+ throw new IllegalStateException("Already unlocked");
+ indentHandler.unlock();
+ indentHandler = null;
+ }
+
+ public Context indentContext() {
+ return indentHandler.context();
+ }
+
+ public synchronized void reformatLock() {
+ if (reformatHandler != null)
+ throw new IllegalStateException("Already locked");
+ reformatHandler = new TaskHandler(false, doc);
+ if (reformatHandler.collectTasks()) {
+ reformatHandler.lock();
+ }
+ }
+
+ public synchronized void reformatUnlock() {
+ if (reformatHandler == null)
+ throw new IllegalStateException("Already unlocked");
+ reformatHandler.unlock();
+ reformatHandler = null;
+ }
+
+ public Context reformatContext() {
+ return reformatHandler.context();
+ }
+
+ public void reindent(int startOffset, int endOffset) throws BadLocationException {
+ assert (indentHandler != null) : "Not locked. Use Indent.lock()"; // NOI18N
+ assert (startOffset <= endOffset) : "startOffset=" + startOffset + " > endOffset=" + endOffset; // NOI18N
+ // Find begining of line
+ Element lineRootElem = lineRootElement(doc);
+ // Correct the start offset to point to the begining of the start line
+ int startLineIndex = lineRootElem.getElementIndex(startOffset);
+ if (startLineIndex < 0)
+ return; // Invalid line index => do nothing
+ Element lineElem = lineRootElem.getElement(startLineIndex);
+ int startLineOffset = lineElem.getStartOffset();
+ boolean done = false;
+ if (indentHandler.hasItems()) {
+ // Find ending line element - by default use the same as for start offset
+ if (endOffset > lineElem.getEndOffset()) { // need to get a different line element
+ int endLineIndex = lineRootElem.getElementIndex(endOffset);
+ lineElem = lineRootElem.getElement(endLineIndex);
+ // Check if the given endOffset ends right after line's newline (in fact at the begining of the next line)
+ if (endLineIndex > 0 && lineElem.getStartOffset() == endOffset) {
+ endLineIndex--;
+ lineElem = lineRootElem.getElement(endLineIndex);
+ }
+ }
+
+ // Create context from begining of the start line till the end of the end line.
+ IndentSpiPackageAccessor.get().resetBounds(
+ indentHandler.context(),
+ doc.createPosition(startLineOffset),
+ doc.createPosition(lineElem.getEndOffset()));
+
+ // Perform whole reindent on top and possibly embedded levels
+ indentHandler.runTasks();
+ done = true;
+ }
+
+ // Fallback to Formatter
+ if (!done && doc instanceof BaseDocument) {
+ // Original formatter does not have reindentation of multiple lines
+ // so reformat start line and continue for each line.
+ do {
+ ((BaseDocument)doc).getFormatter().indentLine(doc, startOffset);
+ startOffset = lineElem.getEndOffset(); // Move to next line
+ } while (startOffset < endOffset);
+
+ }
+ }
+
+ public void reformat(int startOffset, int endOffset) throws BadLocationException {
+ assert (reformatHandler != null) : "Not locked. Use Reformat.lock()"; // NOI18N
+ assert (startOffset <= endOffset) : "startOffset=" + startOffset + " > endOffset=" + endOffset; // NOI18N
+ boolean done = false;
+ if (reformatHandler.hasItems()) {
+ IndentSpiPackageAccessor.get().resetBounds(
+ reformatHandler.context(),
+ doc.createPosition(startOffset),
+ doc.createPosition(endOffset));
+
+ // Run top and embedded reformatting
+ reformatHandler.runTasks();
+
+ // Perform reformatting of the top section and possible embedded sections
+ done = true;
+ }
+
+ // Fallback to Formatter
+ if (!done && doc instanceof BaseDocument) {
+ BaseDocument bdoc = (BaseDocument)doc;
+ bdoc.getFormatter().reformat(bdoc, startOffset, endOffset);
+ }
+ }
+
+ public static Element lineRootElement(Document doc) {
+ return (doc instanceof StyledDocument)
+ ? ((StyledDocument)doc).getParagraphElement(0).getParentElement()
+ : doc.getDefaultRootElement();
+ }
+
+ private static final class TaskHandler {
+
+ private boolean indent;
+
+ private Context context;
+
+ private List items;
+
+ private Map mime2Item;
+
+ private int maxMimePathSize;
+
+ TaskHandler(boolean indent, Document doc) {
+ this.indent = indent;
+ context = IndentSpiPackageAccessor.get().createContext(indent, doc);
+ }
+
+ boolean isIndent() {
+ return indent;
+ }
+
+ Context context() {
+ return context;
+ }
+
+ Document document() {
+ return context.document();
+ }
+
+ int maxMimePathSize() {
+ return maxMimePathSize;
+ }
+
+ boolean collectTasks() {
+ String mimeType = docMimeType();
+ if (mimeType != null) {
+ // Get base indent task for the document.
+ // Only if it exists also get the ones for possible embedded sections.
+ MimePath mimePath = MimePath.get(mimeType);
+ if (addItem(mimePath)) {
+ // Also add the embedded ones
+ TokenHierarchy> hi = TokenHierarchy.get(document());
+ if (hi != null) {
+ Set languagePaths = hi.languagePaths();
+ for (LanguagePath lp : languagePaths) {
+ mimePath = MimePath.parse(lp.mimePath());
+ addItem(mimePath);
+ }
+ }
+ }
+ }
+ return (items != null);
+ }
+
+ void lock() {
+ for (MimeItem item : items) {
+ item.lock();
+ }
+ }
+
+ void unlock() {
+ for (MimeItem item : items) {
+ item.unlock();
+ }
+ }
+
+ boolean hasFactories() {
+ String mimeType = docMimeType();
+ return (mimeType != null && new MimeItem(this, MimePath.get(mimeType)).hasFactories());
+ }
+
+ boolean hasItems() {
+ return (items != null);
+ }
+
+ void runTasks() throws BadLocationException {
+ // Run top-level task and possibly embedded tasks according to the context
+ if (items == null) // Do nothing for no items
+ return;
+
+ // Start with the doc's mime type's task
+ item(0).runTask();
+
+ // Continue by reformatting the embedded sections from top-level to embedded
+ int mimePathSize = 2;
+ while (mimePathSize < maxMimePathSize) {
+ // TBD walk the top-level token sequence and go into it
+ mimePathSize++;
+ }
+
+ }
+
+ private boolean addItem(MimePath mimePath) {
+ maxMimePathSize = Math.max(maxMimePathSize, mimePath.size());
+ MimeItem item = new MimeItem(this, mimePath);
+ if (item.createTask()) {
+ if (items == null) {
+ items = new ArrayList();
+ mime2Item = new HashMap();
+ }
+ if (!mime2Item.containsKey(item.mimePath())) {
+ items.add(item);
+ mime2Item.put(item.mimePath(), item);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private MimeItem item(int index) {
+ return items.get(index);
+ }
+
+ private String docMimeType() {
+ return (String)document().getProperty("mimeType");
+ }
+
+ }
+
+ /**
+ * Item that services indentation/reformatting for a single mime-path.
+ */
+ private static final class MimeItem {
+
+ private final TaskHandler handler;
+
+ private final MimePath mimePath;
+
+ private IndentTask indentTask;
+
+ private ReformatTask reformatTask;
+
+ private ExtraLock extraLock;
+
+ MimeItem(TaskHandler handler, MimePath mimePath) {
+ this.handler = handler;
+ this.mimePath = mimePath;
+ }
+
+ MimePath mimePath() {
+ return mimePath;
+ }
+
+ boolean hasFactories() {
+ Lookup lookup = MimeLookup.getLookup(mimePath);
+ return (lookup.lookup(IndentTask.Factory.class) != null)
+ || (lookup.lookup(ReformatTask.Factory.class) != null);
+ }
+
+ boolean createTask() {
+ Lookup lookup = MimeLookup.getLookup(mimePath);
+ if (!handler.isIndent()) { // Attempt reformat task first
+ ReformatTask.Factory factory = lookup.lookup(ReformatTask.Factory.class);
+ if (factory != null && (reformatTask = factory.createTask(handler.context())) != null) {
+ extraLock = reformatTask.reformatLock();
+ return true;
+ }
+ }
+
+ if (handler.isIndent() || reformatTask == null) { // Possibly fallback to reindent for reformatting
+ IndentTask.Factory factory = lookup.lookup(IndentTask.Factory.class);
+ if (factory != null && (indentTask = factory.createTask(handler.context())) != null) {
+ extraLock = indentTask.indentLock();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void lock() {
+ extraLock.lock();
+ }
+
+ void runTask() throws BadLocationException {
+ if (indentTask != null) {
+ indentTask.reindent();
+ } else {
+ reformatTask.reformat();
+ }
+ }
+
+ void unlock() {
+ extraLock.unlock();
+ }
+
+ }
+
+}
Index: indent/src/org/netbeans/modules/editor/indent/IndentSpiPackageAccessor.java
===================================================================
RCS file: indent/src/org/netbeans/modules/editor/indent/IndentSpiPackageAccessor.java
diff -N indent/src/org/netbeans/modules/editor/indent/IndentSpiPackageAccessor.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/modules/editor/indent/IndentSpiPackageAccessor.java 5 Jun 2007 10:15:28 -0000 1.1.2.1
@@ -0,0 +1,64 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.modules.editor.indent;
+
+import javax.swing.text.Document;
+import javax.swing.text.Position;
+import org.netbeans.spi.editor.indent.Context;
+
+/**
+ * Accessor for the package-private functionality of bookmarks API.
+ *
+ * @author Miloslav Metelka
+ * @version 1.00
+ */
+
+public abstract class IndentSpiPackageAccessor {
+
+ private static IndentSpiPackageAccessor INSTANCE;
+
+ public static IndentSpiPackageAccessor get() {
+ if (INSTANCE == null) {
+ // Enforce the static initializer in Context class to be run
+ try {
+ Class.forName(Context.class.getName(), true, Context.class.getClassLoader());
+ } catch (ClassNotFoundException e) { }
+ }
+ return INSTANCE;
+ }
+
+ /**
+ * Register the accessor. The method can only be called once
+ * - othewise it throws IllegalStateException.
+ *
+ * @param accessor instance.
+ */
+ public static void register(IndentSpiPackageAccessor accessor) {
+ if (INSTANCE != null) {
+ throw new IllegalStateException("Already registered"); // NOI18N
+ }
+ INSTANCE = accessor;
+ }
+
+ public abstract Context createContext(boolean indent, Document doc);
+
+ public abstract void resetBounds(Context ctx, Position startPos, Position endPos);
+
+}
Index: indent/src/org/netbeans/modules/editor/indent/resources/layer.xml
===================================================================
RCS file: indent/src/org/netbeans/modules/editor/indent/resources/layer.xml
diff -N indent/src/org/netbeans/modules/editor/indent/resources/layer.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/modules/editor/indent/resources/layer.xml 5 Jun 2007 10:15:25 -0000 1.1.2.1
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
Index: indent/src/org/netbeans/spi/editor/indent/Context.java
===================================================================
RCS file: indent/src/org/netbeans/spi/editor/indent/Context.java
diff -N indent/src/org/netbeans/spi/editor/indent/Context.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/spi/editor/indent/Context.java 14 Jun 2007 08:06:03 -0000 1.1.2.2
@@ -0,0 +1,123 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.spi.editor.indent;
+
+import javax.swing.text.Document;
+import javax.swing.text.Position;
+import org.netbeans.modules.editor.indent.IndentSpiPackageAccessor;
+
+
+/**
+ * Context information for both indentation and reformatting.
+ *
+ * A common class allows to conveniently share code between indentation and reformatting.
+ * {@link #isIndent()} allows to check whether the actual processing
+ * is indentation or reformatting.
+ *
+ * @author Miloslav Metelka
+ */
+
+public final class Context {
+
+ static {
+ IndentSpiPackageAccessor.register(new PackageAccessor());
+ }
+
+ private final boolean indent;
+
+ private final Document doc;
+
+ private Position startPos;
+
+ private Position endPos;
+
+ Context(boolean indent, Document doc) {
+ this.indent = indent;
+ this.doc = doc;
+ this.startPos = startPos;
+ this.endPos = endPos;
+ }
+
+ /**
+ * Document for which the reformatting or indenting is being done.
+ */
+ public Document document() {
+ return doc;
+ }
+
+ /**
+ * Starting offset of the area to be reformatted or reindented.
+ *
+ * The value gets updated accordingly when the reformatter performs modifications
+ * in the affected area.
+ */
+ public int startOffset() {
+ return (startPos != null) ? startPos.getOffset() : -1;
+ }
+
+ /**
+ * Starting offset of the area to be reformatted or reindented.
+ *
+ * The value gets updated accordingly when the reformatter performs modifications
+ * in the affected area.
+ */
+ public int endOffset() {
+ return (endPos != null) ? endPos.getOffset() : -1;
+ }
+
+ /**
+ * Modify indent of the line at the offset passed as the parameter.
+ */
+ public void modifyIndent(int offset) {
+ // TBD
+ }
+
+ /*
+ * Check whether the actual processing
+ * is indentation or reformatting.
+ *
+ *
+ * Indent tasks may be used for reformatting in case a reformat task
+ * is not available (for the given mimepath) but the indent task is available.
+ *
+ * @return true if indentation is being done or false for reformatting.
+ */
+ public boolean isIndent() {
+ return indent;
+ }
+
+ void resetBounds(Position startPos, Position endPos) {
+ this.startPos = startPos;
+ this.endPos = endPos;
+ }
+
+ private static final class PackageAccessor extends IndentSpiPackageAccessor {
+
+ public Context createContext(boolean indent, Document doc) {
+ return new Context(indent, doc);
+ }
+
+ public void resetBounds(Context ctx, Position startPos, Position endPos) {
+ ctx.resetBounds(startPos, endPos);
+ }
+
+ }
+
+}
Index: indent/src/org/netbeans/spi/editor/indent/ExtraLock.java
===================================================================
RCS file: indent/src/org/netbeans/spi/editor/indent/ExtraLock.java
diff -N indent/src/org/netbeans/spi/editor/indent/ExtraLock.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/spi/editor/indent/ExtraLock.java 14 Jun 2007 13:12:46 -0000 1.1.2.2
@@ -0,0 +1,53 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.spi.editor.indent;
+
+/**
+ * Extra locking may be necessary for indentation/reformatting
+ * before the document gets write-locked and the actual
+ * indentation/reformatting gets started.
+ *
+ * For example java infrastructure requires this.
+ *
+ * The infrastructure guarantees this processing:
+ *
+ *
+ * @author Miloslav Metelka
+ */
+
+public interface ExtraLock {
+
+ void lock();
+
+ void unlock();
+
+}
Index: indent/src/org/netbeans/spi/editor/indent/IndentTask.java
===================================================================
RCS file: indent/src/org/netbeans/spi/editor/indent/IndentTask.java
diff -N indent/src/org/netbeans/spi/editor/indent/IndentTask.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/spi/editor/indent/IndentTask.java 14 Jun 2007 13:12:46 -0000 1.1.2.2
@@ -0,0 +1,74 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.spi.editor.indent;
+
+import javax.swing.text.BadLocationException;
+
+/**
+ * Indent task performs indentation on a single or multiple lines.
+ *
+ * Typically it is used to fix indentation after newline was inserted
+ * or to fix indentation for a selected block of code.
+ *
+ * @author Miloslav Metelka
+ */
+
+public interface IndentTask {
+
+ /**
+ * Perform reindentation of the line(s) of {@link Context#getDocument()}
+ * between {@link Context#startOffset()} and {@link Context#endOffset()}.
+ *
+ * It is called from AWT thread and it should process synchronously. It is used
+ * after a newline is inserted after the user presses Enter
+ * or when a current line must be reindented e.g. when Tab is pressed in emacs mode.
+ *
+ * The method should use information from the context and modify
+ * indentation at the given offset in the document.
+ *
+ * @throws BadLocationException in case the indent task attempted to insert/remove
+ * at an invalid offset or e.g. into a guarded section.
+ */
+ void reindent() throws BadLocationException;
+
+ /**
+ * Get an extra locking or null if no extra locking is necessary.
+ */
+ ExtraLock indentLock();
+
+ /**
+ * Indent task factory produces indent tasks for the given context.
+ *
+ * It should be registered in MimeLookup via xml layer in "/Editors/<mime-type>"
+ * folder.
+ */
+ public interface Factory {
+
+ /**
+ * Create indenting task.
+ *
+ * @param context non-null indentation context.
+ * @return indenting task or null if the factory cannot handle the given context.
+ */
+ IndentTask createTask(Context context);
+
+ }
+
+}
Index: indent/src/org/netbeans/spi/editor/indent/ReformatTask.java
===================================================================
RCS file: indent/src/org/netbeans/spi/editor/indent/ReformatTask.java
diff -N indent/src/org/netbeans/spi/editor/indent/ReformatTask.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/src/org/netbeans/spi/editor/indent/ReformatTask.java 14 Jun 2007 13:12:46 -0000 1.1.2.2
@@ -0,0 +1,74 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.spi.editor.indent;
+
+import javax.swing.text.BadLocationException;
+
+/**
+ * Reformat task performs actual reformatting within offset bounds of the given context.
+ *
+ * @author Miloslav Metelka
+ */
+
+public interface ReformatTask {
+
+ /**
+ * Perform reformatting of the {@link Context#getDocument()}
+ * between {@link Context#startOffset()} and {@link Context#endOffset()}.
+ *
+ * This method may be called several times repetitively for different areas
+ * of a reformatted area.
+ *
+ * It is called from AWT thread and it should process synchronously. It is used
+ * after a newline is inserted after the user presses Enter
+ * or when a current line must be reindented e.g. when Tab is pressed in emacs mode.
+ *
+ * The method should use information from the context and modify
+ * indentation at the given offset in the document.
+ *
+ * @throws BadLocationException in case the formatter attempted to insert/remove
+ * at an invalid offset or e.g. into a guarded section.
+ */
+ void reformat() throws BadLocationException;
+
+ /**
+ * Get an extra locking or null if no extra locking is necessary.
+ */
+ ExtraLock reformatLock();
+
+ /**
+ * Reformat task factory produces reformat tasks for the given context.
+ *
+ * It should be registered in MimeLookup via xml layer in "/Editors/<mime-type>"
+ * folder.
+ */
+ public interface Factory {
+
+ /**
+ * Create reformatting task.
+ *
+ * @param context non-null indentation context.
+ * @return reformatting task or null if the factory cannot handle the given context.
+ */
+ ReformatTask createTask(Context context);
+
+ }
+
+}
Index: indent/test/.cvsignore
===================================================================
RCS file: indent/test/.cvsignore
diff -N indent/test/.cvsignore
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/.cvsignore 5 Jun 2007 10:15:24 -0000 1.1.2.1
@@ -0,0 +1,3 @@
+lib
+results
+work
Index: indent/test/build.xml
===================================================================
RCS file: indent/test/build.xml
diff -N indent/test/build.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/build.xml 5 Jun 2007 10:15:24 -0000 1.1.2.1
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: indent/test/cfg-unit.xml
===================================================================
RCS file: indent/test/cfg-unit.xml
diff -N indent/test/cfg-unit.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/cfg-unit.xml 5 Jun 2007 10:15:24 -0000 1.1.2.1
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: indent/test/unit/src/META-INF/services/org.netbeans.spi.editor.mimelookup.MimeDataProvider
===================================================================
RCS file: indent/test/unit/src/META-INF/services/org.netbeans.spi.editor.mimelookup.MimeDataProvider
diff -N indent/test/unit/src/META-INF/services/org.netbeans.spi.editor.mimelookup.MimeDataProvider
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/unit/src/META-INF/services/org.netbeans.spi.editor.mimelookup.MimeDataProvider 5 Jun 2007 10:15:31 -0000 1.1.2.1
@@ -0,0 +1 @@
+org.netbeans.modules.editor.indent.IndentTestMimeDataProvider
Index: indent/test/unit/src/org/netbeans/api/editor/indent/IndentTest.java
===================================================================
RCS file: indent/test/unit/src/org/netbeans/api/editor/indent/IndentTest.java
diff -N indent/test/unit/src/org/netbeans/api/editor/indent/IndentTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/unit/src/org/netbeans/api/editor/indent/IndentTest.java 5 Jun 2007 10:15:31 -0000 1.1.2.1
@@ -0,0 +1,118 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.api.editor.indent;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.PlainDocument;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.editor.indent.IndentTestMimeDataProvider;
+import org.netbeans.spi.editor.indent.Context;
+import org.netbeans.spi.editor.indent.ExtraLock;
+import org.netbeans.spi.editor.indent.IndentTask;
+
+/**
+ *
+ * @author Miloslav Metelka
+ */
+public class IndentTest extends NbTestCase {
+
+ private static final String MIME_TYPE = "text/x-test";
+
+ public IndentTest(String name) {
+ super(name);
+ }
+
+ public void testFindIndentTaskFactory() throws BadLocationException {
+ TestIndentTask.TestFactory factory = new TestIndentTask.TestFactory();
+ IndentTestMimeDataProvider.addInstances(MIME_TYPE, factory);
+ Document doc = new PlainDocument();
+ doc.putProperty("mimeType", MIME_TYPE);
+ Indent indent = Indent.get(doc);
+ indent.lock();
+ try {
+ //doc.atomicLock();
+ try {
+ indent.reindent(0);
+ } finally {
+ //doc.atomicUnlock();
+ }
+ } finally {
+ indent.unlock();
+ }
+ // Check that the factory was used
+ assertTrue(factory.lastCreatedTask.indentPerformed);
+ }
+
+ private static final class TestIndentTask implements IndentTask {
+
+ private Context context;
+
+ TestExtraLocking lastCreatedLocking;
+
+ boolean indentPerformed;
+
+ TestIndentTask(Context context) {
+ this.context = context;
+ }
+
+ public void reindent() throws BadLocationException {
+ assertTrue(lastCreatedLocking.locked);
+ context.document().insertString(0, " ", null);
+ indentPerformed = true;
+ }
+
+ public ExtraLock indentLock() {
+ return (lastCreatedLocking = new TestExtraLocking());
+ }
+
+ static final class TestFactory implements IndentTask.Factory {
+
+ static TestIndentTask lastCreatedTask;
+
+ public IndentTask createTask(Context context) {
+ return (lastCreatedTask = new TestIndentTask(context));
+ }
+
+ }
+
+ }
+
+ private static final class TestExtraLocking implements ExtraLock {
+
+ Boolean locked;
+
+ public Boolean locked() {
+ return locked;
+ }
+
+ public void lock() {
+ if (locked != null)
+ assertFalse(locked);
+ locked = true;
+ }
+
+ public void unlock() {
+ assertTrue(locked);
+ locked = false;
+ }
+
+ }
+}
Index: indent/test/unit/src/org/netbeans/api/editor/indent/IndentUtilsTest.java
===================================================================
RCS file: indent/test/unit/src/org/netbeans/api/editor/indent/IndentUtilsTest.java
diff -N indent/test/unit/src/org/netbeans/api/editor/indent/IndentUtilsTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/unit/src/org/netbeans/api/editor/indent/IndentUtilsTest.java 14 Jun 2007 08:06:03 -0000 1.1.2.2
@@ -0,0 +1,80 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.api.editor.indent;
+
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.lib.editor.util.ArrayUtilities;
+
+/**
+ *
+ * @author Miloslav Metelka
+ */
+public class IndentUtilsTest extends NbTestCase {
+
+ private static final String MIME_TYPE = "text/x-test";
+
+ public IndentUtilsTest(String name) {
+ super(name);
+ }
+
+ public void testIndentUtils() throws Exception {
+ // Test empty indent
+ assertSame("", IndentUtils.cachedOrCreatedIndentString(0, true, 8));
+ assertSame("", IndentUtils.cachedOrCreatedIndentString(0, false, 4));
+
+ // Test tabSize
+ assertEquals("\t ", s = IndentUtils.cachedOrCreatedIndentString(6, false, 4));
+ assertSame(s, IndentUtils.cachedOrCreatedIndentString(6, false, 4));
+ assertEquals("\t\t\t ", s = IndentUtils.cachedOrCreatedIndentString(15, false, 4));
+ assertSame(s, IndentUtils.cachedOrCreatedIndentString(15, false, 4));
+
+ // Test spaces-only
+ assertEquals(" ", s = IndentUtils.cachedOrCreatedIndentString(10, true, 4));
+ assertEquals(s, IndentUtils.cachedOrCreatedIndentString(10, true, 4));
+
+ // Test many (non-cached) spaces
+ int testUncachedIndent = 90;
+ StringBuilder sb = new StringBuilder(testUncachedIndent);
+ ArrayUtilities.appendSpaces(sb, testUncachedIndent);
+ assertEquals(sb.toString(), IndentUtils.cachedOrCreatedIndentString(testUncachedIndent, true, 4));
+
+ // Test long (non-cached) tab indent
+ int i = testUncachedIndent;
+ sb.setLength(0);
+ while (i >= 8) {
+ sb.append('\t');
+ i -= 8;
+ }
+ ArrayUtilities.appendSpaces(sb, i);
+ assertEquals(sb.toString(), IndentUtils.cachedOrCreatedIndentString(testUncachedIndent, false, 8));
+
+ }
+
+}
Index: indent/test/unit/src/org/netbeans/modules/editor/indent/IndentActionsTest.java
===================================================================
RCS file: indent/test/unit/src/org/netbeans/modules/editor/indent/IndentActionsTest.java
diff -N indent/test/unit/src/org/netbeans/modules/editor/indent/IndentActionsTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/unit/src/org/netbeans/modules/editor/indent/IndentActionsTest.java 7 Jun 2007 15:48:28 -0000 1.1.2.1
@@ -0,0 +1,146 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.modules.editor.indent;
+
+import java.awt.event.ActionEvent;
+import javax.swing.Action;
+import javax.swing.JEditorPane;
+import javax.swing.SwingUtilities;
+import org.netbeans.api.editor.indent.*;
+import javax.swing.text.BadLocationException;
+import org.netbeans.editor.BaseKit;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.editor.NbEditorKit;
+import org.netbeans.modules.editor.indent.IndentTestMimeDataProvider;
+import org.netbeans.spi.editor.indent.Context;
+import org.netbeans.spi.editor.indent.ExtraLock;
+import org.netbeans.spi.editor.indent.IndentTask;
+
+/**
+ *
+ * @author Miloslav Metelka
+ */
+public class IndentActionsTest extends NbTestCase {
+
+ private static final String MIME_TYPE = "text/x-test-actions";
+
+ public IndentActionsTest(String name) {
+ super(name);
+ }
+
+ public void testIndentActions() {
+ // Must run in AWT thread (BaseKit.install() checks for that)
+ if (!SwingUtilities.isEventDispatchThread()) {
+ SwingUtilities.invokeLater(
+ new Runnable() {
+ public void run() {
+ testIndentActions();
+ }
+ }
+ );
+ return;
+ }
+
+ assertTrue(SwingUtilities.isEventDispatchThread());
+ TestIndentTask.TestFactory factory = new TestIndentTask.TestFactory();
+ IndentTestMimeDataProvider.addInstances(MIME_TYPE, factory);
+ TestKit kit = new TestKit();
+ JEditorPane pane = new JEditorPane();
+ pane.setEditorKit(kit);
+ assertEquals(MIME_TYPE, pane.getDocument().getProperty("mimeType"));
+ //doc.putProperty("mimeType", MIME_TYPE);
+
+ // Test insert new line action
+ Action a = kit.getActionByName(BaseKit.insertBreakAction);
+ assertNotNull(a);
+ a.actionPerformed(new ActionEvent(pane, 0, ""));
+ // Check that the factory was used
+ assertTrue(factory.lastCreatedTask.indentPerformed);
+
+ // Test reformat action
+ a = kit.getActionByName(BaseKit.formatAction);
+ assertNotNull(a);
+ a.actionPerformed(new ActionEvent(pane, 0, ""));
+
+ }
+
+ private static final class TestIndentTask implements IndentTask {
+
+ private Context context;
+
+ TestExtraLocking lastCreatedLocking;
+
+ boolean indentPerformed;
+
+ TestIndentTask(Context context) {
+ this.context = context;
+ }
+
+ public void reindent() throws BadLocationException {
+ assertTrue(lastCreatedLocking.locked);
+ context.document().insertString(0, " ", null);
+ indentPerformed = true;
+ }
+
+ public ExtraLock indentLock() {
+ return (lastCreatedLocking = new TestExtraLocking());
+ }
+
+ static final class TestFactory implements IndentTask.Factory {
+
+ static TestIndentTask lastCreatedTask;
+
+ public IndentTask createTask(Context context) {
+ return (lastCreatedTask = new TestIndentTask(context));
+ }
+
+ }
+
+ }
+
+ private static final class TestExtraLocking implements ExtraLock {
+
+ Boolean locked;
+
+ public Boolean locked() {
+ return locked;
+ }
+
+ public void lock() {
+ if (locked != null)
+ assertFalse(locked);
+ locked = true;
+ }
+
+ public void unlock() {
+ assertTrue(locked);
+ locked = false;
+ }
+
+ }
+
+ private static final class TestKit extends NbEditorKit {
+
+ public String getContentType() {
+ return MIME_TYPE;
+ }
+
+ }
+}
Index: indent/test/unit/src/org/netbeans/modules/editor/indent/IndentTestMimeDataProvider.java
===================================================================
RCS file: indent/test/unit/src/org/netbeans/modules/editor/indent/IndentTestMimeDataProvider.java
diff -N indent/test/unit/src/org/netbeans/modules/editor/indent/IndentTestMimeDataProvider.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ indent/test/unit/src/org/netbeans/modules/editor/indent/IndentTestMimeDataProvider.java 5 Jun 2007 10:15:29 -0000 1.1.2.1
@@ -0,0 +1,126 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.modules.editor.indent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.AbstractLookup;
+import org.openide.util.lookup.InstanceContent;
+
+/**
+ * Testing mime data provider.
+ *
+ * @author vita
+ */
+public final class IndentTestMimeDataProvider implements MimeDataProvider {
+
+ private static final HashMap CACHE = new HashMap();
+
+ /** Creates a new instance of MemoryMimeDataProvider */
+ public IndentTestMimeDataProvider() {
+ }
+
+ public Lookup getLookup(MimePath mimePath) {
+ return getLookup(mimePath.getPath(), true);
+ }
+
+ public static void addInstances(String mimePath, Object... instances) {
+ assert mimePath != null : "Mime path can't be null";
+ getLookup(mimePath, true).addInstances(instances);
+ }
+
+ public static void removeInstances(String mimePath, Object... instances) {
+ assert mimePath != null : "Mime path can't be null";
+ getLookup(mimePath, true).removeInstances(instances);
+ }
+
+ public static void reset(String mimePath) {
+ if (mimePath == null) {
+ synchronized (CACHE) {
+ for(Lkp lookup : CACHE.values()) {
+ lookup.reset();
+ }
+ }
+ } else {
+ Lkp lookup = getLookup(mimePath, false);
+ if (lookup != null) {
+ lookup.reset();
+ }
+ }
+ }
+
+ private static Lkp getLookup(String mimePath, boolean create) {
+ synchronized (CACHE) {
+ Lkp lookup = CACHE.get(mimePath);
+ if (lookup == null && create) {
+ lookup = new Lkp();
+ CACHE.put(mimePath, lookup);
+ }
+ return lookup;
+ }
+ }
+
+ private static final class Lkp extends AbstractLookup {
+
+ private ArrayList