Index: editor/arch/arch-editor-util.xml =================================================================== RCS file: editor/arch/arch-editor-util.xml diff -N editor/arch/arch-editor-util.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/arch/arch-editor-util.xml 14 Mar 2005 10:57:28 -0000 @@ -0,0 +1,865 @@ + + +]> + + + + &api-questions; + + + + +Editor Utilities module contains useful utility classes and methods used +by other editor related modules. + + + + + + +The module defines . +
+The present clients are editor/lib and editor/fold modules. +
+ + + + + +Unit tests are present to verify proper functionality of the contained classes. + + + + + + +The module is continuously developed and improved as necessary. + + + + + + + +

+GapList +

+ +

+The GapList class is a java.util.List implementation +similar to java.util.ArrayList but containing a gap in its underlying +array. After a first modification at a particular index +the subsequent modifications around that index are cheap. +
+The class is suitable for storage of any elements related to editing +such as positions, elements, views etc. +

+ +

+PriorityMutex +

+ +

+The PriorityMutex is a simple mutex implementation +allowing to find out that a priority thread (by default Event Dispatch Thread) +is waiting to enter the mutex. +
+It's used e.g. in editor's view hierarchy or in editor fold hierarchy. +

+ +

+GapBranchElement +

+ +

+GapList-based element implementation suitable for line elements +and any other branch element types. +

+ + +
+ + + + + +Yes. + + + + + + +Compatible with standards. + + + + + + +Yes. + + + + + + +JDK1.4 and higher can be used. + + + + + + +JRE is sufficient. + + + + + + +The module does not depend on other NetBeans projects. + + + + + + +No other projects. + + + + + + +All platforms. + + + + + + +
+OpenIDE-Module-Module-Dependencies: org.netbeans.modules.editor.util/1 > @SPECIFICATION-VERSION@
+
+
+ + + + + +No additional files. + + + + + + +Yes. + + + + + + +Yes, where appropriate. + + + + + + +Anywhere. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No special threading models used. + + + + + + +No clipboard support. + + + + + + +No D&D. + + + + + + +No files read or written to the disk. + + + + + + +No + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No practical limits. + + + + + + +Mostly utility classes and methods. Sizeof() tests created where necessary. + + + + + + +No. + + + + + + +No. + + + + + + +No external criteria. + + + + + + +No plugged code. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + + + + + +No. + + +
+ + Index: editor/arch/arch-editor.xml =================================================================== RCS file: /cvs/editor/arch/arch-editor.xml,v retrieving revision 1.21 diff -u -r1.21 arch-editor.xml --- editor/arch/arch-editor.xml 31 Jan 2005 19:46:25 -0000 1.21 +++ editor/arch/arch-editor.xml 14 Mar 2005 10:57:28 -0000 @@ -16,7 +16,7 @@ ]> @@ -1058,9 +1058,6 @@ No. - - - - - + +

+ No.

Index: editor/arch/build.xml =================================================================== RCS file: /cvs/editor/arch/build.xml,v retrieving revision 1.3 diff -u -r1.3 build.xml --- editor/arch/build.xml 8 Nov 2004 13:28:47 -0000 1.3 +++ editor/arch/build.xml 14 Mar 2005 10:57:28 -0000 @@ -28,9 +28,11 @@ + + Index: editor/fold/src/org/netbeans/modules/editor/fold/FoldChildren.java =================================================================== RCS file: /cvs/editor/fold/src/org/netbeans/modules/editor/fold/FoldChildren.java,v retrieving revision 1.2 diff -u -r1.2 FoldChildren.java --- editor/fold/src/org/netbeans/modules/editor/fold/FoldChildren.java 29 Jun 2004 09:31:54 -0000 1.2 +++ editor/fold/src/org/netbeans/modules/editor/fold/FoldChildren.java 14 Mar 2005 10:57:28 -0000 @@ -15,7 +15,7 @@ import org.netbeans.api.editor.fold.Fold; import org.netbeans.modules.editor.fold.ApiPackageAccessor; -import org.netbeans.modules.editor.util.GapList; +import org.netbeans.lib.editor.util.GapList; //import org.netbeans.spi.lexer.util.GapObjectArray; Index: editor/fold/src/org/netbeans/modules/editor/fold/FoldHierarchyExecution.java =================================================================== RCS file: /cvs/editor/fold/src/org/netbeans/modules/editor/fold/FoldHierarchyExecution.java,v retrieving revision 1.4 diff -u -r1.4 FoldHierarchyExecution.java --- editor/fold/src/org/netbeans/modules/editor/fold/FoldHierarchyExecution.java 18 Aug 2004 17:22:13 -0000 1.4 +++ editor/fold/src/org/netbeans/modules/editor/fold/FoldHierarchyExecution.java 14 Mar 2005 10:57:28 -0000 @@ -39,7 +39,7 @@ import org.netbeans.spi.editor.fold.FoldManager; import org.netbeans.spi.editor.fold.FoldManagerFactory; import org.netbeans.spi.editor.fold.FoldOperation; -import org.netbeans.modules.editor.util.PriorityMutex; +import org.netbeans.lib.editor.util.PriorityMutex; import org.openide.ErrorManager; /** Index: editor/libsrc/org/netbeans/editor/LineRootElement.java =================================================================== RCS file: /cvs/editor/libsrc/org/netbeans/editor/LineRootElement.java,v retrieving revision 1.12 diff -u -r1.12 LineRootElement.java --- editor/libsrc/org/netbeans/editor/LineRootElement.java 18 Aug 2004 17:22:17 -0000 1.12 +++ editor/libsrc/org/netbeans/editor/LineRootElement.java 14 Mar 2005 10:57:28 -0000 @@ -23,7 +23,7 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Segment; import javax.swing.text.StyleContext; -import org.netbeans.modules.editor.util.element.GapBranchElement; +import org.netbeans.lib.editor.util.element.GapBranchElement; import org.openide.ErrorManager; /** Index: editor/libsrc/org/netbeans/editor/view/spi/LockView.java =================================================================== RCS file: /cvs/editor/libsrc/org/netbeans/editor/view/spi/LockView.java,v retrieving revision 1.7 diff -u -r1.7 LockView.java --- editor/libsrc/org/netbeans/editor/view/spi/LockView.java 18 Aug 2004 17:22:29 -0000 1.7 +++ editor/libsrc/org/netbeans/editor/view/spi/LockView.java 14 Mar 2005 10:57:28 -0000 @@ -25,7 +25,7 @@ import javax.swing.text.Position; import javax.swing.text.View; import javax.swing.text.ViewFactory; -import org.netbeans.modules.editor.util.PriorityMutex; +import org.netbeans.lib.editor.util.PriorityMutex; /** * View that allow to lock the view hierarchy. Index: editor/libsrc/org/netbeans/lib/editor/view/GapBoxView.java =================================================================== RCS file: /cvs/editor/libsrc/org/netbeans/lib/editor/view/GapBoxView.java,v retrieving revision 1.11 diff -u -r1.11 GapBoxView.java --- editor/libsrc/org/netbeans/lib/editor/view/GapBoxView.java 6 Sep 2004 13:27:10 -0000 1.11 +++ editor/libsrc/org/netbeans/lib/editor/view/GapBoxView.java 14 Mar 2005 10:57:29 -0000 @@ -36,7 +36,7 @@ import org.netbeans.editor.view.spi.ViewLayoutQueue; import org.netbeans.editor.view.spi.ViewLayoutState; import org.netbeans.editor.view.spi.ViewUtilities; -import org.netbeans.modules.editor.util.element.ElementUtilities; +import org.netbeans.lib.editor.util.element.ElementUtilities; //import org.netbeans.spi.lexer.util.GapObjectArray; Index: editor/util/manifest.mf =================================================================== RCS file: /cvs/editor/util/manifest.mf,v retrieving revision 1.4 diff -u -r1.4 manifest.mf --- editor/util/manifest.mf 9 Nov 2004 21:01:03 -0000 1.4 +++ editor/util/manifest.mf 14 Mar 2005 10:57:29 -0000 @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.editor.util/1 -OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/util/Bundle.properties -OpenIDE-Module-Specification-Version: 1.2 +OpenIDE-Module-Localizing-Bundle: org/netbeans/lib/editor/util/Bundle.properties +OpenIDE-Module-Specification-Version: 1.3 Index: editor/util/api/apichanges.xml =================================================================== RCS file: editor/util/api/apichanges.xml diff -N editor/util/api/apichanges.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/util/api/apichanges.xml 14 Mar 2005 10:57:29 -0000 @@ -0,0 +1,140 @@ + + + + + + + + + + + + + Editor Utilities API + + + + + + + Repackaged to org.netbeans.lib.editor.util package + + + + + +

+ The present classes were repackaged from org.netbeans.modules.editor.util + into org.netbeans.lib.editor.util package to fulfil the editor module + split proposal #51486 + according to which the editor classes independent of the NB IDE + should be placed under org.netbeans.lib package. +

+
+ +
+ +
+ + + + + + + Change History for the Editor Utilities API + + + + + + +

Introduction

+ +

This document lists changes made to the Editor Utilities +API. Please ask on the dev@openide.netbeans.org mailing list +if you have any questions about the details of a +change, or are wondering how to convert existing code to be compatible.

+ +

Most module authors should start by reading the Upgrade +Guide for the current release.

+ + + +
+ +

@FOOTER@

+ + +
+ +
Index: editor/util/nbproject/project.properties =================================================================== RCS file: /cvs/editor/util/nbproject/project.properties,v retrieving revision 1.2 diff -u -r1.2 project.properties --- editor/util/nbproject/project.properties 29 Jun 2004 09:32:12 -0000 1.2 +++ editor/util/nbproject/project.properties 14 Mar 2005 10:57:29 -0000 @@ -12,3 +12,5 @@ #javadoc.arch=${basedir}/arch/arch-editor-util.xml javadoc.name=EditorUtilities javadoc.title=Editor Utilities +javadoc.arch=${basedir}/../arch/arch-editor-util.xml +javadoc.apichanges=${basedir}/api/apichanges.xml Index: editor/util/nbproject/project.xml =================================================================== RCS file: /cvs/editor/util/nbproject/project.xml,v retrieving revision 1.3 diff -u -r1.3 project.xml --- editor/util/nbproject/project.xml 9 Aug 2004 08:53:57 -0000 1.3 +++ editor/util/nbproject/project.xml 14 Mar 2005 10:57:29 -0000 @@ -29,8 +29,8 @@ - org.netbeans.modules.editor.util - org.netbeans.modules.editor.util.element + org.netbeans.lib.editor.util + org.netbeans.lib.editor.util.element Index: editor/util/src/org/netbeans/lib/editor/util/Bundle.properties =================================================================== RCS file: editor/util/src/org/netbeans/lib/editor/util/Bundle.properties diff -N editor/util/src/org/netbeans/lib/editor/util/Bundle.properties --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/util/src/org/netbeans/lib/editor/util/Bundle.properties 14 Mar 2005 10:57:29 -0000 @@ -0,0 +1,16 @@ +# Sun Public License Notice +# +# The contents of this file are subject to the Sun Public License +# Version 1.0 (the "License"). You may not use this file except in +# compliance with the License. A copy of the License is available at +# http://www.sun.com/ +# +# The Original Code is NetBeans. The Initial Developer of the Original +# Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun +# Microsystems, Inc. All Rights Reserved. + +OpenIDE-Module-Name=Editor Utilities +OpenIDE-Module-Display-Category=Editing +OpenIDE-Module-Short-Description=Contains various support classes for editor related modules +OpenIDE-Module-Long-Description=Editor Utilities module contains various utility classes and methods for functionality related to editing + Index: editor/util/src/org/netbeans/lib/editor/util/GapList.java =================================================================== RCS file: editor/util/src/org/netbeans/lib/editor/util/GapList.java diff -N editor/util/src/org/netbeans/lib/editor/util/GapList.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/util/src/org/netbeans/lib/editor/util/GapList.java 14 Mar 2005 10:57:29 -0000 @@ -0,0 +1,785 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.lib.editor.util; + +import java.util.AbstractList; +import java.util.Collection; +import java.util.RandomAccess; + +/** + * List implementation that stores items in an array + * with a gap. + * + * @author Miloslav Metelka + * @version 1.00 + */ + +public class GapList extends AbstractList +implements RandomAccess, Cloneable, java.io.Serializable { + + private static final Object[] EMPTY_ELEMENT_ARRAY = new Object[0]; + + /** + * The array buffer into which the elements are stored. + *
+ * The elements are stored in the whole array except + * the indexes starting at gapStart + * till gapStart + gapLength - 1. + */ + private transient Object elementData[]; + + /** + * The start of the gap in the elementData array. + */ + private int gapStart; + + /** + * Length of the gap in the elementData array starting at gapStart. + */ + private int gapLength; + + /** + * Constructs an empty list with the specified initial capacity. + * + * @param initialCapacity the initial capacity of the list. + * @exception IllegalArgumentException if the specified initial capacity + * is negative + */ + public GapList(int initialCapacity) { + if (initialCapacity < 0) { + throw new IllegalArgumentException("Illegal Capacity: " // NOI18N + + initialCapacity); + } + this.elementData = new Object[initialCapacity]; + this.gapLength = initialCapacity; + } + + /** + * Constructs an empty list. + */ + public GapList() { + elementData = EMPTY_ELEMENT_ARRAY; + } + + /** + * Constructs a list containing the elements of the specified + * collection, in the order they are returned by the collection's + * iterator. The GapList instance has an initial capacity of + * 110% the size of the specified collection. + * + * @param c the collection whose elements are to be placed into this list. + * @throws NullPointerException if the specified collection is null. + */ + public GapList(Collection c) { + int size = c.size(); + // Allow 10% room for growth + elementData = new Object[ + (int)Math.min((size*110L)/100,Integer.MAX_VALUE)]; + c.toArray(elementData); + this.gapStart = size; + this.gapLength = elementData.length - size; + } + + /** + * Trims the capacity of this GapList instance to be the + * list's current size. An application can use this operation to minimize + * the storage of an GapList instance. + */ + public void trimToSize() { + modCount++; + if (gapLength > 0) { + int newLength = elementData.length - gapLength; + Object[] newElementData = new Object[newLength]; + copyAllData(newElementData); + elementData = newElementData; + // Leave gapStart as is + gapLength = 0; + } + } + + /** + * Increases the capacity of this GapList instance, if + * necessary, to ensure that it can hold at least the number of elements + * specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity. + */ + public void ensureCapacity(int minCapacity) { + modCount++; // expected to always increment modCount - see add() operations + int oldCapacity = elementData.length; + if (minCapacity > oldCapacity) { + int newCapacity = (oldCapacity * 3)/2 + 1; + if (newCapacity < minCapacity) { + newCapacity = minCapacity; + } + int gapEnd = gapStart + gapLength; + int afterGapLength = (oldCapacity - gapEnd); + // Must ensure the gap will not be logically moved + // (would have to call movedAbove/BeforeGapUpdate() methods) + int newGapEnd = newCapacity - afterGapLength; + Object[] newElementData = new Object[newCapacity]; + System.arraycopy(elementData, 0, newElementData, 0, gapStart); + System.arraycopy(elementData, gapEnd, newElementData, newGapEnd, afterGapLength); + elementData = newElementData; + gapLength = newGapEnd - gapStart; + } + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list. + */ + public int size() { + return elementData.length - gapLength; + } + + /** + * Tests if this list has no elements. + * + * @return true if this list has no elements; + * false otherwise. + */ + public boolean isEmpty() { + return (elementData.length == gapLength); + } + + /** + * Returns true if this list contains the specified element. + * + * @param elem element whose presence in this List is to be tested. + * @return true if the specified element is present; + * false otherwise. + */ + public boolean contains(Object elem) { + return indexOf(elem) >= 0; + } + + /** + * Searches for the first occurence of the given argument, testing + * for equality using the equals method. + * + * @param elem an object. + * @return the index of the first occurrence of the argument in this + * list; returns -1 if the object is not found. + * @see Object#equals(Object) + */ + public int indexOf(Object elem) { + if (elem == null) { + int i = 0; + while (i < gapStart) { + if (elementData[i] == null) { + return i; + } + i++; + } + i += gapLength; + int elementDataLength = elementData.length; + while (i < elementDataLength) { + if (elementData[i] == null) { + return i; + } + i++; + } + + } else { // elem not null + int i = 0; + while (i < gapStart) { + if (elem.equals(elementData[i])) { + return i; + } + i++; + } + i += gapLength; + int elementDataLength = elementData.length; + while (i < elementDataLength) { + if (elem.equals(elementData[i])) { + return i; + } + i++; + } + } + + return -1; + } + + /** + * Returns the index of the last occurrence of the specified object in + * this list. + * + * @param elem the desired element. + * @return the index of the last occurrence of the specified object in + * this list; returns -1 if the object is not found. + */ + public int lastIndexOf(Object elem) { + if (elem == null) { + int i = elementData.length - 1; + int gapEnd = gapStart + gapLength; + while (i >= gapEnd) { + if (elementData[i] == null) { + return i; + } + i--; + } + i -= gapLength; + while (i >= 0) { + if (elementData[i] == null) { + return i; + } + i--; + } + + } else { // elem not null + int i = elementData.length - 1; + int gapEnd = gapStart + gapLength; + while (i >= gapEnd) { + if (elem.equals(elementData[i])) { + return i; + } + i--; + } + i -= gapLength; + while (i >= 0) { + if (elem.equals(elementData[i])) { + return i; + } + i--; + } + } + + return -1; + } + + /** + * Returns a shallow copy of this GapList instance. (The + * elements themselves are not copied.) + * + * @return a clone of this GapList instance. + */ + public Object clone() { + try { + GapList clonedList = (GapList)super.clone(); + int size = size(); + Object[] clonedElementData = new Object[size]; + copyAllData(clonedElementData); + clonedList.elementData = clonedElementData; + // Will retain gapStart - would have to call moved*() otherwise + clonedList.gapStart = size; + clonedList.resetModCount(); + return clonedList; + + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + + public void copyItems(int srcStartIndex, int srcEndIndex, + Object[] dest, int destIndex) { + + if (srcStartIndex < 0 || srcEndIndex < srcStartIndex || srcEndIndex > size()) { + throw new IndexOutOfBoundsException("srcStartIndex=" + srcStartIndex // NOI18N + + ", srcEndIndex=" + srcEndIndex + ", size()=" + size()); // NOI18N + } + + if (srcEndIndex < gapStart) { // fully below gap + System.arraycopy(elementData, srcStartIndex, + dest, destIndex, srcEndIndex - srcStartIndex); + + } else { // above gap or spans the gap + if (srcStartIndex >= gapStart) { // fully above gap + System.arraycopy(elementData, srcStartIndex + gapLength, dest, destIndex, + srcEndIndex - srcStartIndex); + + } else { // spans gap + int beforeGap = gapStart - srcStartIndex; + System.arraycopy(elementData, srcStartIndex, dest, destIndex, beforeGap); + System.arraycopy(elementData, gapStart + gapLength, dest, destIndex + beforeGap, + srcEndIndex - srcStartIndex - beforeGap); + } + } + } + + /** + * Returns an array containing all of the elements in this list + * in the correct order. + * + * @return an array containing all of the elements in this list + * in the correct order. + */ + public Object[] toArray() { + int size = size(); + Object[] result = new Object[size]; + copyAllData(result); + return result; + } + + /** + * Returns an array containing all of the elements in this list in the + * correct order; the runtime type of the returned array is that of the + * specified array. If the list fits in the specified array, it is + * returned therein. Otherwise, a new array is allocated with the runtime + * type of the specified array and the size of this list.

+ * + * If the list fits in the specified array with room to spare (i.e., the + * array has more elements than the list), the element in the array + * immediately following the end of the collection is set to + * null. This is useful in determining the length of the list + * only if the caller knows that the list does not contain any + * null elements. + * + * @param a the array into which the elements of the list are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose. + * @return an array containing the elements of the list. + * @throws ArrayStoreException if the runtime type of a is not a supertype + * of the runtime type of every element in this list. + */ + public Object[] toArray(Object a[]) { + int size = size(); + if (a.length < size) { + a = (Object[])java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size); + } + copyAllData(a); + if (a.length > size) + a[size] = null; + + return a; + } + + // Positional Access Operations + + /** + * Returns the element at the specified position in this list. + * + * @param index index of element to return. + * @return the element at the specified position in this list. + * @throws IndexOutOfBoundsException if index is out of range (index + * < 0 || index >= size()). + */ + public Object get(int index) { + // rangeCheck(index) not necessary - would fail with AIOOBE anyway + return elementData[(index < gapStart) ? index : (index + gapLength)]; + } + + /** + * Replaces the element at the specified position in this list with + * the specified element. + * + * @param index index of element to replace. + * @param element element to be stored at the specified position. + * @return the element previously at the specified position. + * @throws IndexOutOfBoundsException if index out of range + * (index < 0 || index >= size()). + */ + public Object set(int index, Object element) { + // rangeCheck(index) not necessary - would fail with AIOOBE anyway + if (index >= gapStart) { + index += gapLength; + } + Object oldValue = elementData[index]; + elementData[index] = element; + return oldValue; + } + + /** + * Appends the specified element to the end of this list. + * + * @param o element to be appended to this list. + * @return true (as per the general contract of Collection.add). + */ + public boolean add(Object o) { + add(size(), o); + return true; + } + + /** + * Inserts the specified element at the specified position in this + * list. Shifts the element currently at that position (if any) and + * any subsequent elements to the right (adds one to their indices). + * + * @param index index at which the specified element is to be inserted. + * @param element element to be inserted. + * @throws IndexOutOfBoundsException if index is out of range + * (index < 0 || index > size()). + */ + public void add(int index, Object element) { + int size = size(); + if (index > size || index < 0) { + throw new IndexOutOfBoundsException( + "Index: " + index + ", Size: " + size); // NOI18N + } + + ensureCapacity(size + 1); // Increments modCount!! + moveGap(index); + + elementData[gapStart++] = element; + gapLength--; + } + + /** + * Appends all of the elements in the specified Collection to the end of + * this list, in the order that they are returned by the + * specified Collection's Iterator. The behavior of this operation is + * undefined if the specified Collection is modified while the operation + * is in progress. (This implies that the behavior of this call is + * undefined if the specified Collection is this list, and this + * list is nonempty.) + * + * @param c the elements to be inserted into this list. + * @return true if this list changed as a result of the call. + * @throws NullPointerException if the specified collection is null. + */ + public boolean addAll(Collection c) { + return addAll(size(), c); + } + + /** + * Inserts all of the elements in the specified Collection into this + * list, starting at the specified position. Shifts the element + * currently at that position (if any) and any subsequent elements to + * the right (increases their indices). The new elements will appear + * in the list in the order that they are returned by the + * specified Collection's iterator. + * + * @param index index at which to insert first element + * from the specified collection. + * @param c elements to be inserted into this list. + * @return true if this list changed as a result of the call. + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index > size()). + * @throws NullPointerException if the specified Collection is null. + */ + public boolean addAll(int index, Collection c) { + return addArray(index, c.toArray()); + } + + /* + * Inserts all elements from the given array into this list, starting + * at the given index. + * + * @param index index at which to insert first element from the array. + * @param elements array of elements to insert. + */ + public boolean addArray(int index, Object[] elements) { + return addArray(index, elements, 0, elements.length); + } + + /** + * Inserts elements from the given array into this list, starting + * at the given index. + * + * @param index index at which to insert first element. + * @param elements array of elements from which to insert elements. + * @param off offset in the elements pointing to first element to copy. + * @param len number of elements to copy from the elements array. + */ + public boolean addArray(int index, Object[] elements, int off, int len) { + int size = size(); + if (index > size || index < 0) { + throw new IndexOutOfBoundsException( + "Index: " + index + ", Size: " + size); // NOI18N + } + + ensureCapacity(size + len); // Increments modCount + + moveGap(index); + System.arraycopy(elements, off, elementData, gapStart, len); + gapStart += len; + gapLength -= len; + + return (len != 0); + } + + + + /** + * Removes all of the elements from this list. The list will + * be empty after this call returns. + */ + public void clear() { + removeRange(0, size()); + } + + /** + * Removes the element at the specified position in this list. + * Shifts any subsequent elements to the left (subtracts one from their + * indices). + * + * @param index the index of the element to removed. + * @return the element that was removed from the list. + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + public Object remove(int index) { + int size = size(); + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException( + "remove(): Index: " + index + ", Size: " + size); // NOI18N + } + + modCount++; + moveGap(index + 1); // if previous were adds() - this should be no-op + Object oldValue = elementData[index]; + removeUpdate(index, elementData, index, index + 1); + elementData[index] = null; + gapStart--; + gapLength++; + + return oldValue; + } + + /** + * Removes elements at the given index. + * + * @param index index of the first element to be removed. + * @param count number of elements to remove. + */ + public void remove(int index, int count) { + int toIndex = index + count; + if (index < 0 || toIndex < index || toIndex > size()) { + throw new IndexOutOfBoundsException("index=" + index // NOI18N + + ", count=" + count + ", size()=" + size()); // NOI18N + } + removeRange(index, toIndex); + } + + /** + * Removes from this List all of the elements whose index is between + * fromIndex, inclusive and toIndex, exclusive. Shifts any succeeding + * elements to the left (reduces their index). + * This call shortens the list by (toIndex - fromIndex) elements. + * (If toIndex==fromIndex, this operation has no effect.) + * + * @param fromIndex index of first element to be removed. + * @param toIndex index after last element to be removed. + */ + protected void removeRange(int fromIndex, int toIndex) { + modCount++; + if (fromIndex == toIndex) { + return; + } + + int removeCount = toIndex - fromIndex; + if (fromIndex >= gapStart) { // completely over gap + // Move gap to the start of the removed area + // (this should be the minimum necessary count of elements moved) + moveGap(fromIndex); + + // Allow GC of removed items + fromIndex += gapLength; // begining of abandoned area + toIndex += gapLength; + removeUpdate(fromIndex - gapLength, elementData, fromIndex, toIndex); + while (fromIndex < toIndex) { + elementData[fromIndex] = null; + fromIndex++; + } + + } else { // completely below gap or spans the gap + if (toIndex <= gapStart) { + // Move gap to the end of the removed area + // (this should be the minimum necessary count of elements moved) + moveGap(toIndex); + gapStart = fromIndex; + // Call removeUpdate() for items that will be physically removed soon + removeUpdate(fromIndex, elementData, fromIndex, toIndex); + + } else { // spans gap: gapStart > fromIndex but gapStart - fromIndex < removeCount + removeUpdate(fromIndex, elementData, fromIndex, gapStart); + // Allow GC of removed items + for (int clearIndex = fromIndex; clearIndex < gapStart; clearIndex++) { + elementData[clearIndex] = null; + } + + fromIndex = gapStart + gapLength; // part above the gap + gapStart = toIndex - removeCount; // original value of fromIndex + toIndex += gapLength; + removeUpdate(gapStart, elementData, fromIndex, toIndex); + } + + // Allow GC of removed items + while (fromIndex < toIndex) { + elementData[fromIndex++] = null; + } + + } + + gapLength += removeCount; + } + + /** + * Called prior physical removing of the data from the list. + *
+ * The implementation can possibly update the elements in the removed area. + *
+ * After this method finishes the whole removed area will be + * null-ed. + * + * @param index index in the list of the first item being removed. + * @param data array of objects from which the data are being removed. + * The next two parameters define the indexes at which the elements + * can be updated. + *
+ * Absolutely no changes should be done outside of + * <startOff, endOff) area. + * @param startOff offset in the data array of the first element that + * will be removed. + * @param endOff offset in the data array following the last item that will + * be removed. + */ + protected void removeUpdate(int index, Object[] data, int startOff, int endOff) { + } + + /* + protected void movedAboveGapUpdate(Object[] array, int index, int count) { + } + + protected void movedBelowGapUpdate(Object[] array, int index, int count) { + } + */ + + private void moveGap(int index) { + if (index == gapStart) { + return; // do nothing + } + + if (index < gapStart) { // move gap down + int moveSize = gapStart - index; + System.arraycopy(elementData, index, elementData, + gapStart + gapLength - moveSize, moveSize); + clearEmpty(index, Math.min(moveSize, gapLength)); + gapStart = index; + // movedAboveGapUpdate(elementData, gapStart + gapLength, moveSize); + + } else { // above gap + int gapEnd = gapStart + gapLength; + int moveSize = index - gapStart; + System.arraycopy(elementData, gapEnd, elementData, gapStart, moveSize); + if (index < gapEnd) { + clearEmpty(gapEnd, moveSize); + } else { + clearEmpty(index, gapLength); + } + // movedBelowGapUpdate(elementData, gapStart, moveSize); + gapStart += moveSize; + } + } + + private void copyAllData(Object[] toArray) { + if (gapLength != 0) { + int gapEnd = gapStart + gapLength; + System.arraycopy(elementData, 0, toArray, 0, gapStart); + System.arraycopy(elementData, gapEnd, toArray, gapStart, + elementData.length - gapEnd); + } else { // no gap => single copy of everything + System.arraycopy(elementData, 0, toArray, 0, elementData.length); + } + } + + private void clearEmpty(int index, int length) { + while (--length >= 0) { + elementData[index++] = null; // allow GC + } + } + + private void resetModCount() { + modCount = 0; + } + + /** + * Save the state of the GapList instance to a stream (that + * is, serialize it). + * + * @serialData The length of the array backing the GapList + * instance is emitted (int), followed by all of its elements + * (each an Object) in the proper order. + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException{ + // Write out element count, and any hidden stuff + s.defaultWriteObject(); + + // Write out array length + s.writeInt(elementData.length); + + // Write out all elements in the proper order. + int i = 0; + while (i < gapStart) { + s.writeObject(elementData[i]); + i++; + } + i += gapLength; + int elementDataLength = elementData.length; + while (i < elementDataLength) { + s.writeObject(elementData[i]); + i++; + } + } + + /** + * Reconstitute the GapList instance from a stream (that is, + * deserialize it). + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in array length and allocate array + int arrayLength = s.readInt(); + elementData = new Object[arrayLength]; + + // Read in all elements in the proper order. + int i = 0; + while (i < gapStart) { + elementData[i] = s.readObject(); + i++; + } + i += gapLength; + int elementDataLength = elementData.length; + while (i < elementDataLength) { + elementData[i] = s.readObject(); + i++; + } + } + + /** + * Internal consistency check. + */ + void consistencyCheck() { + if (gapStart < 0 || gapLength < 0 + || gapStart + gapLength > elementData.length + ) { + consistencyError("Inconsistent gap"); // NOI18N + } + + // Check whether the whole gap contains only nulls + for (int i = gapStart + gapLength - 1; i >= gapStart; i--) { + if (elementData[i] != null) { + consistencyError("Non-null value at raw-index i"); // NOI18N + } + } + } + + private void consistencyError(String s) { + throw new IllegalStateException(s + ": " + toStringInternals()); // NOI18N + } + + String toStringInternals() { + return "elementData.length=" + elementData.length // NOI18N + + ", gapStart=" + gapStart + ", gapLength=" + gapLength; // NOI18N + } + +} Index: editor/util/src/org/netbeans/lib/editor/util/PriorityMutex.java =================================================================== RCS file: editor/util/src/org/netbeans/lib/editor/util/PriorityMutex.java diff -N editor/util/src/org/netbeans/lib/editor/util/PriorityMutex.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/util/src/org/netbeans/lib/editor/util/PriorityMutex.java 14 Mar 2005 10:57:29 -0000 @@ -0,0 +1,147 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.lib.editor.util; + +/** + * Mutex that allows only one thread to proceed + * other threads must wait until that one finishes. + *
+ * The thread that "holds" the mutex (has the mutex access granted) + * may reenter the mutex arbitrary number of times + * (just increasing a "depth" of the locking). + *
+ * If the priority thread enters waiting on the mutex + * then it will get serviced first once the current thread + * leaves the mutex. + * + * @author Miloslav Metelka + * @version 1.00 + */ + +public class PriorityMutex { + + private Thread lockThread; + + private int lockDepth; + + private Thread waitingPriorityThread; + + /** + * Acquire the ownership of the mutex. + * + *

+ * The following pattern should always be used: + *

+     *   mutex.lock();
+     *   try {
+     *       ...
+     *   } finally {
+     *       mutex.unlock();
+     *   }
+     * 
+ */ + public synchronized void lock() { + Thread thread = Thread.currentThread(); + if (thread != lockThread) { // not nested locking + // Will wait if either there is another thread already holding the lock + // or if there is a priority thread waiting but it's not this thread + while (lockThread != null + || (waitingPriorityThread != null && waitingPriorityThread != thread) + ) { + try { + if (waitingPriorityThread == null && isPriorityThread()) { + waitingPriorityThread = thread; + } + + wait(); + + } catch (InterruptedException e) { + waitingPriorityThread = null; + } + } + + lockThread = thread; + + if (thread == waitingPriorityThread) { + waitingPriorityThread = null; // it's now allowed to enter + } + } + + lockDepth++; + } + + /** + * Release the ownership of the mutex. + * + * @see lock() + */ + public synchronized void unlock() { + if (Thread.currentThread() != lockThread) { + throw new IllegalStateException("Not locker"); // NOI18N + } + + if (--lockDepth == 0) { + lockThread = null; + + notifyAll(); // must all to surely notify waitingPriorityThread too + } + } + + /** + * Can be called by the thread + * that acquired the mutex to check whether there + * is a priority thread (such as AWT event-notification thread) + * waiting. + *
+ * If there is a priority thread waiting the non-priority thread + * should attempt to stop its work as soon and release the ownership + * of the mutex. + *
+ * The method must *not* be called without first taking the ownership + * of the mutex (it is intentionally not synchronized). + */ + public boolean isPriorityThreadWaiting() { + return (waitingPriorityThread != null); + } + + /** + * Return a thread that acquired this mutex. + *
+ * This method is intended for diagnostic purposes only. + * + * @return thread that currently acquired lock the mutex + or null + * if there is currently no thread holding that acquired this mutex. + */ + public final synchronized Thread getLockThread() { + return lockThread; + } + + /** + * Return true if the current thread that is entering this method + * is a priority thread + * and should be allowed to enter as soon as possible. + * + *

+ * The default implementation assumes that + * {@link javax.swing.SwingUtilities#isEventDispatchThread()} + * is a priority thread. + * + * @return true if the entering thread is a priority thread. + */ + protected boolean isPriorityThread() { + return javax.swing.SwingUtilities.isEventDispatchThread(); + } + +} Index: editor/util/src/org/netbeans/lib/editor/util/element/ElementUtilities.java =================================================================== RCS file: editor/util/src/org/netbeans/lib/editor/util/element/ElementUtilities.java diff -N editor/util/src/org/netbeans/lib/editor/util/element/ElementUtilities.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/util/src/org/netbeans/lib/editor/util/element/ElementUtilities.java 14 Mar 2005 10:57:29 -0000 @@ -0,0 +1,39 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.lib.editor.util.element; + +import javax.swing.text.Element; + +/** + * Various utility methods related to elements. + * + * @author Miloslav Metelka + * @version 1.00 + */ + +public final class ElementUtilities { + + private ElementUtilities() { + // No instances + } + + public static void updateOffsetRange(Element[] elements, int[] offsetRange) { + int elementsLength = elements.length; + if (elementsLength > 0) { + offsetRange[0] = Math.min(offsetRange[0], elements[0].getStartOffset()); + offsetRange[1] = Math.max(offsetRange[1], elements[elementsLength - 1].getEndOffset()); + } + } + +} Index: editor/util/src/org/netbeans/lib/editor/util/element/GapBranchElement.java =================================================================== RCS file: editor/util/src/org/netbeans/lib/editor/util/element/GapBranchElement.java diff -N editor/util/src/org/netbeans/lib/editor/util/element/GapBranchElement.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/util/src/org/netbeans/lib/editor/util/element/GapBranchElement.java 14 Mar 2005 10:57:29 -0000 @@ -0,0 +1,245 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.lib.editor.util.element; + +import javax.swing.text.Element; +import javax.swing.event.DocumentEvent; +import javax.swing.undo.AbstractUndoableEdit; +import javax.swing.undo.CannotUndoException; +import javax.swing.undo.CannotRedoException; +import org.netbeans.lib.editor.util.GapList; + +/** + * Branch element that uses gap list to maintain its child elements. + * + * @author Miloslav Metelka + * @version 1.00 + */ + +public abstract class GapBranchElement implements Element { + + protected static final Element[] EMPTY_ELEMENT_ARRAY = new Element[0]; + + private GapList children; + + public GapBranchElement() { + children = new GapList(); + } + + public int getElementCount() { + return children.size(); + } + + public Element getElement(int index) { + return (Element)children.get(index); + } + + public void copyElements(int srcBegin, int srcEnd, Element dst[], int dstBegin) { + children.copyItems(srcBegin, srcEnd, dst, dstBegin); + } + + /** + * Gets the child element index closest to the given offset. + * The offset is specified relative to the beginning of the + * document. Returns -1 if the + * Element is a leaf, otherwise returns + * the index of the Element that best represents + * the given location. Returns 0 if the location + * is less than the start offset. Returns + * getElementCount() - 1 if the location is + * greater than or equal to the end offset. + * + *

+ * This implementation is in sync with the original + * Element.getElementIndex() specification + * but it differs + * from AbstractDocument.BranchElement.getElementIndex() + * which returns 0 in case it does not have any children. + *
+ * This implementation returns -1 in that case because in fact + * the element act as a leaf element in such case. + *
+ * Nonetheless there should be no difference in functionality + * if this implementation is used for line elements + * because there is always at least one line element even + * for empty doc because of the extra '\n' after the end + * of the AbstractDocument-based implementations. + * + * @param offset the specified offset >= 0 + * @return the element index >= 0 + */ + public int getElementIndex(int offset) { + int low = 0; + int high = getElementCount() - 1; + + if (high == -1) { // no children => return -1 + return -1; + } + + while (low <= high) { + int mid = (low + high) / 2; + int elemStartOffset = getElement(mid).getStartOffset(); + + if (elemStartOffset < offset) { + low = mid + 1; + } else if (elemStartOffset > offset) { + high = mid - 1; + } else { // element starts at offset + return mid; + } + } + + if (high < 0) { // if offset < getElement(0).getStartOffset() + high = 0; + } + return high; + } + + public boolean isLeaf() { + return false; + } + + protected void replace(int index, int removeCount, Element[] addedElems) { + if (removeCount > 0) { + children.remove(index, removeCount); + } + if (addedElems != null) { + children.addArray(index, addedElems); + } + } + + /** Get info about DocMarks. */ + public String toString() { + return children.toString(); + } + + public class Edit extends AbstractUndoableEdit + implements DocumentEvent.ElementChange { + + private int index; + + private Element[] childrenAdded; + + private Element[] childrenRemoved; + + public Edit(int index, Element[] childrenRemoved, Element[] childrenAdded) { + this.index = index; + this.childrenRemoved = childrenRemoved; + this.childrenAdded = childrenAdded; + } + + public Element getElement() { + return GapBranchElement.this; + } + + public int getIndex() { + return index; + } + + public Element[] getChildrenRemoved() { + return childrenRemoved; + } + + public Element[] getChildrenAdded() { + return childrenAdded; + } + + public void undo() throws CannotUndoException { + super.undo(); + + replace(index, childrenAdded.length, childrenRemoved); + + // Switch childrenAdded with childrenRemoved + Element[] tmp = childrenRemoved; + childrenRemoved = childrenAdded; + childrenAdded = tmp; + } + + public void redo() throws CannotRedoException { + super.redo(); + + // Switch childrenAdded with childrenRemoved + Element[] tmp = childrenRemoved; + childrenRemoved = childrenAdded; + childrenAdded = tmp; + + replace(index, childrenRemoved.length, childrenAdded); + } + + } + + /** + * Extension of {@link GapBranchElement} + * that overrides {@link #getElementIndex(int)} + * which remembers the last returned element index. + */ + public abstract class LastIndex { + + private int lastReturnedElementIndex; + + /** + * Implementation that remembers the last returned element index + * and checks the element at the last index when next called. + *
+ * This may improve performance if there are typically many repetitive calls + * with offset values hitting the last returned element index. + */ + public int getElementIndex(int offset) { + int low = 0; + int high = getElementCount() - 1; + + if (high == -1) { // no children => return -1 + return -1; + } + + int lastIndex = lastReturnedElementIndex; // make copy to be thread-safe + if (lastIndex >= low && lastIndex <= high) { + Element lastElem = getElement(lastIndex); + int lastElemStartOffset = lastElem.getStartOffset(); + if (offset >= lastElemStartOffset) { + int lastElemEndOffset = lastElem.getEndOffset(); + if (offset < lastElemEndOffset) { // hit + return lastIndex; + } else { // above + low = lastIndex + 1; + } + } else { // below lastIndex + high = lastIndex - 1; + } + } + + while (low <= high) { + int mid = (low + high) / 2; + int elemStartOffset = ((Element)children.get(mid)).getStartOffset(); + + if (elemStartOffset < offset) { + low = mid + 1; + } else if (elemStartOffset > offset) { + high = mid - 1; + } else { // element starts at offset + lastReturnedElementIndex = mid; + return mid; + } + } + + if (high < 0) { + high = 0; + } + lastReturnedElementIndex = high; + return high; + } + + } + +} Index: editor/util/src/org/netbeans/modules/editor/util/Bundle.properties =================================================================== RCS file: editor/util/src/org/netbeans/modules/editor/util/Bundle.properties diff -N editor/util/src/org/netbeans/modules/editor/util/Bundle.properties --- editor/util/src/org/netbeans/modules/editor/util/Bundle.properties 29 Jun 2004 09:32:13 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,16 +0,0 @@ -# Sun Public License Notice -# -# The contents of this file are subject to the Sun Public License -# Version 1.0 (the "License"). You may not use this file except in -# compliance with the License. A copy of the License is available at -# http://www.sun.com/ -# -# The Original Code is NetBeans. The Initial Developer of the Original -# Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun -# Microsystems, Inc. All Rights Reserved. - -OpenIDE-Module-Name=Editor Utilities -OpenIDE-Module-Display-Category=Editing -OpenIDE-Module-Short-Description=Contains various support classes for editor related modules -OpenIDE-Module-Long-Description=Editor Utilities module contains various utility classes and methods for functionality related to editing - Index: editor/util/src/org/netbeans/modules/editor/util/GapList.java =================================================================== RCS file: editor/util/src/org/netbeans/modules/editor/util/GapList.java diff -N editor/util/src/org/netbeans/modules/editor/util/GapList.java --- editor/util/src/org/netbeans/modules/editor/util/GapList.java 18 Aug 2004 17:22:37 -0000 1.3 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,785 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.modules.editor.util; - -import java.util.AbstractList; -import java.util.Collection; -import java.util.RandomAccess; - -/** - * List implementation that stores items in an array - * with a gap. - * - * @author Miloslav Metelka - * @version 1.00 - */ - -public class GapList extends AbstractList -implements RandomAccess, Cloneable, java.io.Serializable { - - private static final Object[] EMPTY_ELEMENT_ARRAY = new Object[0]; - - /** - * The array buffer into which the elements are stored. - *
- * The elements are stored in the whole array except - * the indexes starting at gapStart - * till gapStart + gapLength - 1. - */ - private transient Object elementData[]; - - /** - * The start of the gap in the elementData array. - */ - private int gapStart; - - /** - * Length of the gap in the elementData array starting at gapStart. - */ - private int gapLength; - - /** - * Constructs an empty list with the specified initial capacity. - * - * @param initialCapacity the initial capacity of the list. - * @exception IllegalArgumentException if the specified initial capacity - * is negative - */ - public GapList(int initialCapacity) { - if (initialCapacity < 0) { - throw new IllegalArgumentException("Illegal Capacity: " // NOI18N - + initialCapacity); - } - this.elementData = new Object[initialCapacity]; - this.gapLength = initialCapacity; - } - - /** - * Constructs an empty list. - */ - public GapList() { - elementData = EMPTY_ELEMENT_ARRAY; - } - - /** - * Constructs a list containing the elements of the specified - * collection, in the order they are returned by the collection's - * iterator. The GapList instance has an initial capacity of - * 110% the size of the specified collection. - * - * @param c the collection whose elements are to be placed into this list. - * @throws NullPointerException if the specified collection is null. - */ - public GapList(Collection c) { - int size = c.size(); - // Allow 10% room for growth - elementData = new Object[ - (int)Math.min((size*110L)/100,Integer.MAX_VALUE)]; - c.toArray(elementData); - this.gapStart = size; - this.gapLength = elementData.length - size; - } - - /** - * Trims the capacity of this GapList instance to be the - * list's current size. An application can use this operation to minimize - * the storage of an GapList instance. - */ - public void trimToSize() { - modCount++; - if (gapLength > 0) { - int newLength = elementData.length - gapLength; - Object[] newElementData = new Object[newLength]; - copyAllData(newElementData); - elementData = newElementData; - // Leave gapStart as is - gapLength = 0; - } - } - - /** - * Increases the capacity of this GapList instance, if - * necessary, to ensure that it can hold at least the number of elements - * specified by the minimum capacity argument. - * - * @param minCapacity the desired minimum capacity. - */ - public void ensureCapacity(int minCapacity) { - modCount++; // expected to always increment modCount - see add() operations - int oldCapacity = elementData.length; - if (minCapacity > oldCapacity) { - int newCapacity = (oldCapacity * 3)/2 + 1; - if (newCapacity < minCapacity) { - newCapacity = minCapacity; - } - int gapEnd = gapStart + gapLength; - int afterGapLength = (oldCapacity - gapEnd); - // Must ensure the gap will not be logically moved - // (would have to call movedAbove/BeforeGapUpdate() methods) - int newGapEnd = newCapacity - afterGapLength; - Object[] newElementData = new Object[newCapacity]; - System.arraycopy(elementData, 0, newElementData, 0, gapStart); - System.arraycopy(elementData, gapEnd, newElementData, newGapEnd, afterGapLength); - elementData = newElementData; - gapLength = newGapEnd - gapStart; - } - } - - /** - * Returns the number of elements in this list. - * - * @return the number of elements in this list. - */ - public int size() { - return elementData.length - gapLength; - } - - /** - * Tests if this list has no elements. - * - * @return true if this list has no elements; - * false otherwise. - */ - public boolean isEmpty() { - return (elementData.length == gapLength); - } - - /** - * Returns true if this list contains the specified element. - * - * @param elem element whose presence in this List is to be tested. - * @return true if the specified element is present; - * false otherwise. - */ - public boolean contains(Object elem) { - return indexOf(elem) >= 0; - } - - /** - * Searches for the first occurence of the given argument, testing - * for equality using the equals method. - * - * @param elem an object. - * @return the index of the first occurrence of the argument in this - * list; returns -1 if the object is not found. - * @see Object#equals(Object) - */ - public int indexOf(Object elem) { - if (elem == null) { - int i = 0; - while (i < gapStart) { - if (elementData[i] == null) { - return i; - } - i++; - } - i += gapLength; - int elementDataLength = elementData.length; - while (i < elementDataLength) { - if (elementData[i] == null) { - return i; - } - i++; - } - - } else { // elem not null - int i = 0; - while (i < gapStart) { - if (elem.equals(elementData[i])) { - return i; - } - i++; - } - i += gapLength; - int elementDataLength = elementData.length; - while (i < elementDataLength) { - if (elem.equals(elementData[i])) { - return i; - } - i++; - } - } - - return -1; - } - - /** - * Returns the index of the last occurrence of the specified object in - * this list. - * - * @param elem the desired element. - * @return the index of the last occurrence of the specified object in - * this list; returns -1 if the object is not found. - */ - public int lastIndexOf(Object elem) { - if (elem == null) { - int i = elementData.length - 1; - int gapEnd = gapStart + gapLength; - while (i >= gapEnd) { - if (elementData[i] == null) { - return i; - } - i--; - } - i -= gapLength; - while (i >= 0) { - if (elementData[i] == null) { - return i; - } - i--; - } - - } else { // elem not null - int i = elementData.length - 1; - int gapEnd = gapStart + gapLength; - while (i >= gapEnd) { - if (elem.equals(elementData[i])) { - return i; - } - i--; - } - i -= gapLength; - while (i >= 0) { - if (elem.equals(elementData[i])) { - return i; - } - i--; - } - } - - return -1; - } - - /** - * Returns a shallow copy of this GapList instance. (The - * elements themselves are not copied.) - * - * @return a clone of this GapList instance. - */ - public Object clone() { - try { - GapList clonedList = (GapList)super.clone(); - int size = size(); - Object[] clonedElementData = new Object[size]; - copyAllData(clonedElementData); - clonedList.elementData = clonedElementData; - // Will retain gapStart - would have to call moved*() otherwise - clonedList.gapStart = size; - clonedList.resetModCount(); - return clonedList; - - } catch (CloneNotSupportedException e) { - // this shouldn't happen, since we are Cloneable - throw new InternalError(); - } - } - - public void copyItems(int srcStartIndex, int srcEndIndex, - Object[] dest, int destIndex) { - - if (srcStartIndex < 0 || srcEndIndex < srcStartIndex || srcEndIndex > size()) { - throw new IndexOutOfBoundsException("srcStartIndex=" + srcStartIndex // NOI18N - + ", srcEndIndex=" + srcEndIndex + ", size()=" + size()); // NOI18N - } - - if (srcEndIndex < gapStart) { // fully below gap - System.arraycopy(elementData, srcStartIndex, - dest, destIndex, srcEndIndex - srcStartIndex); - - } else { // above gap or spans the gap - if (srcStartIndex >= gapStart) { // fully above gap - System.arraycopy(elementData, srcStartIndex + gapLength, dest, destIndex, - srcEndIndex - srcStartIndex); - - } else { // spans gap - int beforeGap = gapStart - srcStartIndex; - System.arraycopy(elementData, srcStartIndex, dest, destIndex, beforeGap); - System.arraycopy(elementData, gapStart + gapLength, dest, destIndex + beforeGap, - srcEndIndex - srcStartIndex - beforeGap); - } - } - } - - /** - * Returns an array containing all of the elements in this list - * in the correct order. - * - * @return an array containing all of the elements in this list - * in the correct order. - */ - public Object[] toArray() { - int size = size(); - Object[] result = new Object[size]; - copyAllData(result); - return result; - } - - /** - * Returns an array containing all of the elements in this list in the - * correct order; the runtime type of the returned array is that of the - * specified array. If the list fits in the specified array, it is - * returned therein. Otherwise, a new array is allocated with the runtime - * type of the specified array and the size of this list.

- * - * If the list fits in the specified array with room to spare (i.e., the - * array has more elements than the list), the element in the array - * immediately following the end of the collection is set to - * null. This is useful in determining the length of the list - * only if the caller knows that the list does not contain any - * null elements. - * - * @param a the array into which the elements of the list are to - * be stored, if it is big enough; otherwise, a new array of the - * same runtime type is allocated for this purpose. - * @return an array containing the elements of the list. - * @throws ArrayStoreException if the runtime type of a is not a supertype - * of the runtime type of every element in this list. - */ - public Object[] toArray(Object a[]) { - int size = size(); - if (a.length < size) { - a = (Object[])java.lang.reflect.Array.newInstance( - a.getClass().getComponentType(), size); - } - copyAllData(a); - if (a.length > size) - a[size] = null; - - return a; - } - - // Positional Access Operations - - /** - * Returns the element at the specified position in this list. - * - * @param index index of element to return. - * @return the element at the specified position in this list. - * @throws IndexOutOfBoundsException if index is out of range (index - * < 0 || index >= size()). - */ - public Object get(int index) { - // rangeCheck(index) not necessary - would fail with AIOOBE anyway - return elementData[(index < gapStart) ? index : (index + gapLength)]; - } - - /** - * Replaces the element at the specified position in this list with - * the specified element. - * - * @param index index of element to replace. - * @param element element to be stored at the specified position. - * @return the element previously at the specified position. - * @throws IndexOutOfBoundsException if index out of range - * (index < 0 || index >= size()). - */ - public Object set(int index, Object element) { - // rangeCheck(index) not necessary - would fail with AIOOBE anyway - if (index >= gapStart) { - index += gapLength; - } - Object oldValue = elementData[index]; - elementData[index] = element; - return oldValue; - } - - /** - * Appends the specified element to the end of this list. - * - * @param o element to be appended to this list. - * @return true (as per the general contract of Collection.add). - */ - public boolean add(Object o) { - add(size(), o); - return true; - } - - /** - * Inserts the specified element at the specified position in this - * list. Shifts the element currently at that position (if any) and - * any subsequent elements to the right (adds one to their indices). - * - * @param index index at which the specified element is to be inserted. - * @param element element to be inserted. - * @throws IndexOutOfBoundsException if index is out of range - * (index < 0 || index > size()). - */ - public void add(int index, Object element) { - int size = size(); - if (index > size || index < 0) { - throw new IndexOutOfBoundsException( - "Index: " + index + ", Size: " + size); // NOI18N - } - - ensureCapacity(size + 1); // Increments modCount!! - moveGap(index); - - elementData[gapStart++] = element; - gapLength--; - } - - /** - * Appends all of the elements in the specified Collection to the end of - * this list, in the order that they are returned by the - * specified Collection's Iterator. The behavior of this operation is - * undefined if the specified Collection is modified while the operation - * is in progress. (This implies that the behavior of this call is - * undefined if the specified Collection is this list, and this - * list is nonempty.) - * - * @param c the elements to be inserted into this list. - * @return true if this list changed as a result of the call. - * @throws NullPointerException if the specified collection is null. - */ - public boolean addAll(Collection c) { - return addAll(size(), c); - } - - /** - * Inserts all of the elements in the specified Collection into this - * list, starting at the specified position. Shifts the element - * currently at that position (if any) and any subsequent elements to - * the right (increases their indices). The new elements will appear - * in the list in the order that they are returned by the - * specified Collection's iterator. - * - * @param index index at which to insert first element - * from the specified collection. - * @param c elements to be inserted into this list. - * @return true if this list changed as a result of the call. - * @throws IndexOutOfBoundsException if index out of range (index - * < 0 || index > size()). - * @throws NullPointerException if the specified Collection is null. - */ - public boolean addAll(int index, Collection c) { - return addArray(index, c.toArray()); - } - - /* - * Inserts all elements from the given array into this list, starting - * at the given index. - * - * @param index index at which to insert first element from the array. - * @param elements array of elements to insert. - */ - public boolean addArray(int index, Object[] elements) { - return addArray(index, elements, 0, elements.length); - } - - /** - * Inserts elements from the given array into this list, starting - * at the given index. - * - * @param index index at which to insert first element. - * @param elements array of elements from which to insert elements. - * @param off offset in the elements pointing to first element to copy. - * @param len number of elements to copy from the elements array. - */ - public boolean addArray(int index, Object[] elements, int off, int len) { - int size = size(); - if (index > size || index < 0) { - throw new IndexOutOfBoundsException( - "Index: " + index + ", Size: " + size); // NOI18N - } - - ensureCapacity(size + len); // Increments modCount - - moveGap(index); - System.arraycopy(elements, off, elementData, gapStart, len); - gapStart += len; - gapLength -= len; - - return (len != 0); - } - - - - /** - * Removes all of the elements from this list. The list will - * be empty after this call returns. - */ - public void clear() { - removeRange(0, size()); - } - - /** - * Removes the element at the specified position in this list. - * Shifts any subsequent elements to the left (subtracts one from their - * indices). - * - * @param index the index of the element to removed. - * @return the element that was removed from the list. - * @throws IndexOutOfBoundsException if index out of range (index - * < 0 || index >= size()). - */ - public Object remove(int index) { - int size = size(); - if (index >= size || index < 0) { - throw new IndexOutOfBoundsException( - "remove(): Index: " + index + ", Size: " + size); // NOI18N - } - - modCount++; - moveGap(index + 1); // if previous were adds() - this should be no-op - Object oldValue = elementData[index]; - removeUpdate(index, elementData, index, index + 1); - elementData[index] = null; - gapStart--; - gapLength++; - - return oldValue; - } - - /** - * Removes elements at the given index. - * - * @param index index of the first element to be removed. - * @param count number of elements to remove. - */ - public void remove(int index, int count) { - int toIndex = index + count; - if (index < 0 || toIndex < index || toIndex > size()) { - throw new IndexOutOfBoundsException("index=" + index // NOI18N - + ", count=" + count + ", size()=" + size()); // NOI18N - } - removeRange(index, toIndex); - } - - /** - * Removes from this List all of the elements whose index is between - * fromIndex, inclusive and toIndex, exclusive. Shifts any succeeding - * elements to the left (reduces their index). - * This call shortens the list by (toIndex - fromIndex) elements. - * (If toIndex==fromIndex, this operation has no effect.) - * - * @param fromIndex index of first element to be removed. - * @param toIndex index after last element to be removed. - */ - protected void removeRange(int fromIndex, int toIndex) { - modCount++; - if (fromIndex == toIndex) { - return; - } - - int removeCount = toIndex - fromIndex; - if (fromIndex >= gapStart) { // completely over gap - // Move gap to the start of the removed area - // (this should be the minimum necessary count of elements moved) - moveGap(fromIndex); - - // Allow GC of removed items - fromIndex += gapLength; // begining of abandoned area - toIndex += gapLength; - removeUpdate(fromIndex - gapLength, elementData, fromIndex, toIndex); - while (fromIndex < toIndex) { - elementData[fromIndex] = null; - fromIndex++; - } - - } else { // completely below gap or spans the gap - if (toIndex <= gapStart) { - // Move gap to the end of the removed area - // (this should be the minimum necessary count of elements moved) - moveGap(toIndex); - gapStart = fromIndex; - // Call removeUpdate() for items that will be physically removed soon - removeUpdate(fromIndex, elementData, fromIndex, toIndex); - - } else { // spans gap: gapStart > fromIndex but gapStart - fromIndex < removeCount - removeUpdate(fromIndex, elementData, fromIndex, gapStart); - // Allow GC of removed items - for (int clearIndex = fromIndex; clearIndex < gapStart; clearIndex++) { - elementData[clearIndex] = null; - } - - fromIndex = gapStart + gapLength; // part above the gap - gapStart = toIndex - removeCount; // original value of fromIndex - toIndex += gapLength; - removeUpdate(gapStart, elementData, fromIndex, toIndex); - } - - // Allow GC of removed items - while (fromIndex < toIndex) { - elementData[fromIndex++] = null; - } - - } - - gapLength += removeCount; - } - - /** - * Called prior physical removing of the data from the list. - *
- * The implementation can possibly update the elements in the removed area. - *
- * After this method finishes the whole removed area will be - * null-ed. - * - * @param index index in the list of the first item being removed. - * @param data array of objects from which the data are being removed. - * The next two parameters define the indexes at which the elements - * can be updated. - *
- * Absolutely no changes should be done outside of - * <startOff, endOff) area. - * @param startOff offset in the data array of the first element that - * will be removed. - * @param endOff offset in the data array following the last item that will - * be removed. - */ - protected void removeUpdate(int index, Object[] data, int startOff, int endOff) { - } - - /* - protected void movedAboveGapUpdate(Object[] array, int index, int count) { - } - - protected void movedBelowGapUpdate(Object[] array, int index, int count) { - } - */ - - private void moveGap(int index) { - if (index == gapStart) { - return; // do nothing - } - - if (index < gapStart) { // move gap down - int moveSize = gapStart - index; - System.arraycopy(elementData, index, elementData, - gapStart + gapLength - moveSize, moveSize); - clearEmpty(index, Math.min(moveSize, gapLength)); - gapStart = index; - // movedAboveGapUpdate(elementData, gapStart + gapLength, moveSize); - - } else { // above gap - int gapEnd = gapStart + gapLength; - int moveSize = index - gapStart; - System.arraycopy(elementData, gapEnd, elementData, gapStart, moveSize); - if (index < gapEnd) { - clearEmpty(gapEnd, moveSize); - } else { - clearEmpty(index, gapLength); - } - // movedBelowGapUpdate(elementData, gapStart, moveSize); - gapStart += moveSize; - } - } - - private void copyAllData(Object[] toArray) { - if (gapLength != 0) { - int gapEnd = gapStart + gapLength; - System.arraycopy(elementData, 0, toArray, 0, gapStart); - System.arraycopy(elementData, gapEnd, toArray, gapStart, - elementData.length - gapEnd); - } else { // no gap => single copy of everything - System.arraycopy(elementData, 0, toArray, 0, elementData.length); - } - } - - private void clearEmpty(int index, int length) { - while (--length >= 0) { - elementData[index++] = null; // allow GC - } - } - - private void resetModCount() { - modCount = 0; - } - - /** - * Save the state of the GapList instance to a stream (that - * is, serialize it). - * - * @serialData The length of the array backing the GapList - * instance is emitted (int), followed by all of its elements - * (each an Object) in the proper order. - */ - private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException{ - // Write out element count, and any hidden stuff - s.defaultWriteObject(); - - // Write out array length - s.writeInt(elementData.length); - - // Write out all elements in the proper order. - int i = 0; - while (i < gapStart) { - s.writeObject(elementData[i]); - i++; - } - i += gapLength; - int elementDataLength = elementData.length; - while (i < elementDataLength) { - s.writeObject(elementData[i]); - i++; - } - } - - /** - * Reconstitute the GapList instance from a stream (that is, - * deserialize it). - */ - private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { - // Read in size, and any hidden stuff - s.defaultReadObject(); - - // Read in array length and allocate array - int arrayLength = s.readInt(); - elementData = new Object[arrayLength]; - - // Read in all elements in the proper order. - int i = 0; - while (i < gapStart) { - elementData[i] = s.readObject(); - i++; - } - i += gapLength; - int elementDataLength = elementData.length; - while (i < elementDataLength) { - elementData[i] = s.readObject(); - i++; - } - } - - /** - * Internal consistency check. - */ - void consistencyCheck() { - if (gapStart < 0 || gapLength < 0 - || gapStart + gapLength > elementData.length - ) { - consistencyError("Inconsistent gap"); // NOI18N - } - - // Check whether the whole gap contains only nulls - for (int i = gapStart + gapLength - 1; i >= gapStart; i--) { - if (elementData[i] != null) { - consistencyError("Non-null value at raw-index i"); // NOI18N - } - } - } - - private void consistencyError(String s) { - throw new IllegalStateException(s + ": " + toStringInternals()); // NOI18N - } - - String toStringInternals() { - return "elementData.length=" + elementData.length // NOI18N - + ", gapStart=" + gapStart + ", gapLength=" + gapLength; // NOI18N - } - -} Index: editor/util/src/org/netbeans/modules/editor/util/PriorityMutex.java =================================================================== RCS file: editor/util/src/org/netbeans/modules/editor/util/PriorityMutex.java diff -N editor/util/src/org/netbeans/modules/editor/util/PriorityMutex.java --- editor/util/src/org/netbeans/modules/editor/util/PriorityMutex.java 29 Jun 2004 09:32:13 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,147 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.modules.editor.util; - -/** - * Mutex that allows only one thread to proceed - * other threads must wait until that one finishes. - *
- * The thread that "holds" the mutex (has the mutex access granted) - * may reenter the mutex arbitrary number of times - * (just increasing a "depth" of the locking). - *
- * If the priority thread enters waiting on the mutex - * then it will get serviced first once the current thread - * leaves the mutex. - * - * @author Miloslav Metelka - * @version 1.00 - */ - -public class PriorityMutex { - - private Thread lockThread; - - private int lockDepth; - - private Thread waitingPriorityThread; - - /** - * Acquire the ownership of the mutex. - * - *

- * The following pattern should always be used: - *

-     *   mutex.lock();
-     *   try {
-     *       ...
-     *   } finally {
-     *       mutex.unlock();
-     *   }
-     * 
- */ - public synchronized void lock() { - Thread thread = Thread.currentThread(); - if (thread != lockThread) { // not nested locking - // Will wait if either there is another thread already holding the lock - // or if there is a priority thread waiting but it's not this thread - while (lockThread != null - || (waitingPriorityThread != null && waitingPriorityThread != thread) - ) { - try { - if (waitingPriorityThread == null && isPriorityThread()) { - waitingPriorityThread = thread; - } - - wait(); - - } catch (InterruptedException e) { - waitingPriorityThread = null; - } - } - - lockThread = thread; - - if (thread == waitingPriorityThread) { - waitingPriorityThread = null; // it's now allowed to enter - } - } - - lockDepth++; - } - - /** - * Release the ownership of the mutex. - * - * @see lock() - */ - public synchronized void unlock() { - if (Thread.currentThread() != lockThread) { - throw new IllegalStateException("Not locker"); // NOI18N - } - - if (--lockDepth == 0) { - lockThread = null; - - notifyAll(); // must all to surely notify waitingPriorityThread too - } - } - - /** - * Can be called by the thread - * that acquired the mutex to check whether there - * is a priority thread (such as AWT event-notification thread) - * waiting. - *
- * If there is a priority thread waiting the non-priority thread - * should attempt to stop its work as soon and release the ownership - * of the mutex. - *
- * The method must *not* be called without first taking the ownership - * of the mutex (it is intentionally not synchronized). - */ - public boolean isPriorityThreadWaiting() { - return (waitingPriorityThread != null); - } - - /** - * Return a thread that acquired this mutex. - *
- * This method is intended for diagnostic purposes only. - * - * @return thread that currently acquired lock the mutex - or null - * if there is currently no thread holding that acquired this mutex. - */ - public final synchronized Thread getLockThread() { - return lockThread; - } - - /** - * Return true if the current thread that is entering this method - * is a priority thread - * and should be allowed to enter as soon as possible. - * - *

- * The default implementation assumes that - * {@link javax.swing.SwingUtilities#isEventDispatchThread()} - * is a priority thread. - * - * @return true if the entering thread is a priority thread. - */ - protected boolean isPriorityThread() { - return javax.swing.SwingUtilities.isEventDispatchThread(); - } - -} Index: editor/util/src/org/netbeans/modules/editor/util/element/ElementUtilities.java =================================================================== RCS file: editor/util/src/org/netbeans/modules/editor/util/element/ElementUtilities.java diff -N editor/util/src/org/netbeans/modules/editor/util/element/ElementUtilities.java --- editor/util/src/org/netbeans/modules/editor/util/element/ElementUtilities.java 9 Aug 2004 08:53:57 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,39 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.modules.editor.util.element; - -import javax.swing.text.Element; - -/** - * Various utility methods related to elements. - * - * @author Miloslav Metelka - * @version 1.00 - */ - -public final class ElementUtilities { - - private ElementUtilities() { - // No instances - } - - public static void updateOffsetRange(Element[] elements, int[] offsetRange) { - int elementsLength = elements.length; - if (elementsLength > 0) { - offsetRange[0] = Math.min(offsetRange[0], elements[0].getStartOffset()); - offsetRange[1] = Math.max(offsetRange[1], elements[elementsLength - 1].getEndOffset()); - } - } - -} Index: editor/util/src/org/netbeans/modules/editor/util/element/GapBranchElement.java =================================================================== RCS file: editor/util/src/org/netbeans/modules/editor/util/element/GapBranchElement.java diff -N editor/util/src/org/netbeans/modules/editor/util/element/GapBranchElement.java --- editor/util/src/org/netbeans/modules/editor/util/element/GapBranchElement.java 17 Aug 2004 16:58:37 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,245 +0,0 @@ -/* - * Sun Public License Notice - * - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/ - * - * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun - * Microsystems, Inc. All Rights Reserved. - */ - -package org.netbeans.modules.editor.util.element; - -import javax.swing.text.Element; -import javax.swing.event.DocumentEvent; -import javax.swing.undo.AbstractUndoableEdit; -import javax.swing.undo.CannotUndoException; -import javax.swing.undo.CannotRedoException; -import org.netbeans.modules.editor.util.*; - -/** - * Branch element that uses gap list to maintain its child elements. - * - * @author Miloslav Metelka - * @version 1.00 - */ - -public abstract class GapBranchElement implements Element { - - protected static final Element[] EMPTY_ELEMENT_ARRAY = new Element[0]; - - private GapList children; - - public GapBranchElement() { - children = new GapList(); - } - - public int getElementCount() { - return children.size(); - } - - public Element getElement(int index) { - return (Element)children.get(index); - } - - public void copyElements(int srcBegin, int srcEnd, Element dst[], int dstBegin) { - children.copyItems(srcBegin, srcEnd, dst, dstBegin); - } - - /** - * Gets the child element index closest to the given offset. - * The offset is specified relative to the beginning of the - * document. Returns -1 if the - * Element is a leaf, otherwise returns - * the index of the Element that best represents - * the given location. Returns 0 if the location - * is less than the start offset. Returns - * getElementCount() - 1 if the location is - * greater than or equal to the end offset. - * - *

- * This implementation is in sync with the original - * Element.getElementIndex() specification - * but it differs - * from AbstractDocument.BranchElement.getElementIndex() - * which returns 0 in case it does not have any children. - *
- * This implementation returns -1 in that case because in fact - * the element act as a leaf element in such case. - *
- * Nonetheless there should be no difference in functionality - * if this implementation is used for line elements - * because there is always at least one line element even - * for empty doc because of the extra '\n' after the end - * of the AbstractDocument-based implementations. - * - * @param offset the specified offset >= 0 - * @return the element index >= 0 - */ - public int getElementIndex(int offset) { - int low = 0; - int high = getElementCount() - 1; - - if (high == -1) { // no children => return -1 - return -1; - } - - while (low <= high) { - int mid = (low + high) / 2; - int elemStartOffset = getElement(mid).getStartOffset(); - - if (elemStartOffset < offset) { - low = mid + 1; - } else if (elemStartOffset > offset) { - high = mid - 1; - } else { // element starts at offset - return mid; - } - } - - if (high < 0) { // if offset < getElement(0).getStartOffset() - high = 0; - } - return high; - } - - public boolean isLeaf() { - return false; - } - - protected void replace(int index, int removeCount, Element[] addedElems) { - if (removeCount > 0) { - children.remove(index, removeCount); - } - if (addedElems != null) { - children.addArray(index, addedElems); - } - } - - /** Get info about DocMarks. */ - public String toString() { - return children.toString(); - } - - public class Edit extends AbstractUndoableEdit - implements DocumentEvent.ElementChange { - - private int index; - - private Element[] childrenAdded; - - private Element[] childrenRemoved; - - public Edit(int index, Element[] childrenRemoved, Element[] childrenAdded) { - this.index = index; - this.childrenRemoved = childrenRemoved; - this.childrenAdded = childrenAdded; - } - - public Element getElement() { - return GapBranchElement.this; - } - - public int getIndex() { - return index; - } - - public Element[] getChildrenRemoved() { - return childrenRemoved; - } - - public Element[] getChildrenAdded() { - return childrenAdded; - } - - public void undo() throws CannotUndoException { - super.undo(); - - replace(index, childrenAdded.length, childrenRemoved); - - // Switch childrenAdded with childrenRemoved - Element[] tmp = childrenRemoved; - childrenRemoved = childrenAdded; - childrenAdded = tmp; - } - - public void redo() throws CannotRedoException { - super.redo(); - - // Switch childrenAdded with childrenRemoved - Element[] tmp = childrenRemoved; - childrenRemoved = childrenAdded; - childrenAdded = tmp; - - replace(index, childrenRemoved.length, childrenAdded); - } - - } - - /** - * Extension of {@link GapBranchElement} - * that overrides {@link #getElementIndex(int)} - * which remembers the last returned element index. - */ - public abstract class LastIndex { - - private int lastReturnedElementIndex; - - /** - * Implementation that remembers the last returned element index - * and checks the element at the last index when next called. - *
- * This may improve performance if there are typically many repetitive calls - * with offset values hitting the last returned element index. - */ - public int getElementIndex(int offset) { - int low = 0; - int high = getElementCount() - 1; - - if (high == -1) { // no children => return -1 - return -1; - } - - int lastIndex = lastReturnedElementIndex; // make copy to be thread-safe - if (lastIndex >= low && lastIndex <= high) { - Element lastElem = getElement(lastIndex); - int lastElemStartOffset = lastElem.getStartOffset(); - if (offset >= lastElemStartOffset) { - int lastElemEndOffset = lastElem.getEndOffset(); - if (offset < lastElemEndOffset) { // hit - return lastIndex; - } else { // above - low = lastIndex + 1; - } - } else { // below lastIndex - high = lastIndex - 1; - } - } - - while (low <= high) { - int mid = (low + high) / 2; - int elemStartOffset = ((Element)children.get(mid)).getStartOffset(); - - if (elemStartOffset < offset) { - low = mid + 1; - } else if (elemStartOffset > offset) { - high = mid - 1; - } else { // element starts at offset - lastReturnedElementIndex = mid; - return mid; - } - } - - if (high < 0) { - high = 0; - } - lastReturnedElementIndex = high; - return high; - } - - } - -} Index: editor/util/test/unit/src/org/netbeans/lib/editor/util/GapListRandomTest.java =================================================================== RCS file: editor/util/test/unit/src/org/netbeans/lib/editor/util/GapListRandomTest.java diff -N editor/util/test/unit/src/org/netbeans/lib/editor/util/GapListRandomTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/util/test/unit/src/org/netbeans/lib/editor/util/GapListRandomTest.java 14 Mar 2005 10:57:29 -0000 @@ -0,0 +1,187 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.lib.editor.util; + +import java.util.ArrayList; +import java.util.Random; +import junit.framework.*; + + +/** + * Random test of GapList correctness. + * + * @author mmetelka + */ +public class GapListRandomTest extends TestCase { + + private static final boolean debug = false; + + private static final int OP_COUNT_1 = 10000; + private static final int ADD_RATIO_1 = 100; + private static final int ADD_ALL_RATIO_1 = 10; + private static final int ADD_ALL_MAX_COUNT_1 = 10; + private static final int REMOVE_RATIO_1 = 100; + private static final int REMOVE_RANGE_RATIO_1 = 10; + private static final int CLEAR_RATIO_1 = 5; + private static final int SET_RATIO_1 = 50; + + private static final int OP_COUNT_2 = 10000; + private static final int ADD_RATIO_2 = 50; + private static final int ADD_ALL_RATIO_2 = 20; + private static final int ADD_ALL_MAX_COUNT_2 = 5; + private static final int REMOVE_RATIO_2 = 100; + private static final int REMOVE_RANGE_RATIO_2 = 10; + private static final int CLEAR_RATIO_2 = 3; + private static final int SET_RATIO_2 = 50; + + private ArrayList al; + + private GapList gl; + + public GapListRandomTest(java.lang.String testName) { + super(testName); + } + + public static Test suite() { + TestSuite suite = new TestSuite(GapListRandomTest.class); + return suite; + } + + protected void setUp() throws java.lang.Exception { + } + + protected void tearDown() throws java.lang.Exception { + } + + public void test() { + testFresh(0); + } + + public void testFresh(long seed) { + Random random = new Random(); + if (seed != 0) { + System.err.println("TESTING with SEED=" + seed); + random.setSeed(seed); + } + + gl = new GapList(); + al = new ArrayList(); + + + testRound(random, OP_COUNT_1, ADD_RATIO_1, ADD_ALL_RATIO_1, ADD_ALL_MAX_COUNT_1, + REMOVE_RATIO_1, REMOVE_RANGE_RATIO_1, CLEAR_RATIO_1, SET_RATIO_1); + testRound(random, OP_COUNT_2, ADD_RATIO_2, ADD_ALL_RATIO_2, ADD_ALL_MAX_COUNT_2, + REMOVE_RATIO_2, REMOVE_RANGE_RATIO_2, CLEAR_RATIO_2, SET_RATIO_2); + } + + private void testRound(Random random, int opCount, + int addRatio, int addAllRatio, int addAllMaxCount, + int removeRatio, int removeRangeRatio, int clearRatio, int setRatio) { + + int ratioSum = addRatio + addAllRatio + removeRatio + removeRangeRatio + + clearRatio + setRatio; + + for (int op = 0; op < opCount; op++) { + double r = random.nextDouble() * ratioSum; + + if ((r -= addRatio) < 0) { + Object o = new Object(); + int index = (int)(al.size() * random.nextDouble()); + al.add(index, o); + if (debug) { + debugOp(op, "add() at index=" + index); // NOI18N + } + gl.add(index, o); + + } else if ((r -= addAllRatio) < 0) { + int count = (int)(random.nextDouble() * addAllMaxCount); + ArrayList l = new ArrayList(); + for (int i = count; i > 0; i--) { + l.add(new Object()); + } + + Object o = new Object(); + int index = (int)(al.size() * random.nextDouble()); + al.addAll(index, l); + if (debug) { + debugOp(op, "addAll() at index=" + index); // NOI18N + } + gl.addAll(index, l); + + } else if ((r -= removeRatio) < 0) { + if (al.size() > 0) { // is anything to remove + int index = (int)(al.size() * random.nextDouble()); + al.remove(index); + if (debug) { + debugOp(op, "remove() at index=" + index); // NOI18N + } + gl.remove(index); + } + + } else if ((r -= removeRangeRatio) < 0) { + if (al.size() > 0) { // is anything to remove + int index = (int)(al.size() * random.nextDouble()); + int length = (int)((al.size() - index + 1) * random.nextDouble()); + for (int count = length; count > 0; count--) { + al.remove(index); + } + if (debug) { + debugOp(op, "remove() at index=" + index + ", length=" + length); // NOI18N + } + gl.remove(index, length); + } + + } else if ((r -= clearRatio) < 0) { + al.clear(); + if (debug) { + debugOp(op, "clear()"); // NOI18N + } + gl.clear(); + + } else if ((r -= setRatio) < 0) { + if (al.size() > 0) { // is anything to remove + int index = (int)(al.size() * random.nextDouble()); + Object o = new Object(); + al.set(index, o); + if (debug) { + debugOp(op, "set() at index=" + index); // NOI18N + } + gl.set(index, o); + } + } + + checkConsistency(); + } + + } + + private void debugOp(int op, String s) { + System.err.println("op: " + op + ", " + s + ", " + gl.toStringInternals()); + } + + private void checkConsistency() { + gl.consistencyCheck(); + + assertEquals(gl.size(), al.size()); + + int size = al.size(); + for (int i = 0; i < size; i++) { + assertTrue("Contents differ at index " + i + ", gl: " + gl.get(i) // NOI18N + + ", al:" + al.get(i), // NOI18N + (gl.get(i) == al.get(i))); + } + } + + +} Index: editor/util/test/unit/src/org/netbeans/modules/editor/util/GapListRandomTest.java =================================================================== RCS file: editor/util/test/unit/src/org/netbeans/modules/editor/util/GapListRandomTest.java diff -N editor/util/test/unit/src/org/netbeans/modules/editor/util/GapListRandomTest.java --- editor/util/test/unit/src/org/netbeans/modules/editor/util/GapListRandomTest.java 18 Aug 2004 17:22:38 -0000 1.3 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,180 +0,0 @@ -package org.netbeans.modules.editor.util; -/* - * GapListTest.java - * JUnit based test - * - * Created on June 26, 2004, 8:37 AM - */ - - -import java.util.ArrayList; -import java.util.Random; -import junit.framework.*; -import junit.framework.*; - -/** - * - * @author mmetelka - */ -public class GapListRandomTest extends TestCase { - - private static final boolean debug = false; - - private static final int OP_COUNT_1 = 10000; - private static final int ADD_RATIO_1 = 100; - private static final int ADD_ALL_RATIO_1 = 10; - private static final int ADD_ALL_MAX_COUNT_1 = 10; - private static final int REMOVE_RATIO_1 = 100; - private static final int REMOVE_RANGE_RATIO_1 = 10; - private static final int CLEAR_RATIO_1 = 5; - private static final int SET_RATIO_1 = 50; - - private static final int OP_COUNT_2 = 10000; - private static final int ADD_RATIO_2 = 50; - private static final int ADD_ALL_RATIO_2 = 20; - private static final int ADD_ALL_MAX_COUNT_2 = 5; - private static final int REMOVE_RATIO_2 = 100; - private static final int REMOVE_RANGE_RATIO_2 = 10; - private static final int CLEAR_RATIO_2 = 3; - private static final int SET_RATIO_2 = 50; - - private ArrayList al; - - private GapList gl; - - public GapListRandomTest(java.lang.String testName) { - super(testName); - } - - public static Test suite() { - TestSuite suite = new TestSuite(GapListRandomTest.class); - return suite; - } - - protected void setUp() throws java.lang.Exception { - } - - protected void tearDown() throws java.lang.Exception { - } - - public void test() { - testFresh(0); - } - - public void testFresh(long seed) { - Random random = new Random(); - if (seed != 0) { - System.err.println("TESTING with SEED=" + seed); - random.setSeed(seed); - } - - gl = new GapList(); - al = new ArrayList(); - - - testRound(random, OP_COUNT_1, ADD_RATIO_1, ADD_ALL_RATIO_1, ADD_ALL_MAX_COUNT_1, - REMOVE_RATIO_1, REMOVE_RANGE_RATIO_1, CLEAR_RATIO_1, SET_RATIO_1); - testRound(random, OP_COUNT_2, ADD_RATIO_2, ADD_ALL_RATIO_2, ADD_ALL_MAX_COUNT_2, - REMOVE_RATIO_2, REMOVE_RANGE_RATIO_2, CLEAR_RATIO_2, SET_RATIO_2); - } - - private void testRound(Random random, int opCount, - int addRatio, int addAllRatio, int addAllMaxCount, - int removeRatio, int removeRangeRatio, int clearRatio, int setRatio) { - - int ratioSum = addRatio + addAllRatio + removeRatio + removeRangeRatio - + clearRatio + setRatio; - - for (int op = 0; op < opCount; op++) { - double r = random.nextDouble() * ratioSum; - - if ((r -= addRatio) < 0) { - Object o = new Object(); - int index = (int)(al.size() * random.nextDouble()); - al.add(index, o); - if (debug) { - debugOp(op, "add() at index=" + index); // NOI18N - } - gl.add(index, o); - - } else if ((r -= addAllRatio) < 0) { - int count = (int)(random.nextDouble() * addAllMaxCount); - ArrayList l = new ArrayList(); - for (int i = count; i > 0; i--) { - l.add(new Object()); - } - - Object o = new Object(); - int index = (int)(al.size() * random.nextDouble()); - al.addAll(index, l); - if (debug) { - debugOp(op, "addAll() at index=" + index); // NOI18N - } - gl.addAll(index, l); - - } else if ((r -= removeRatio) < 0) { - if (al.size() > 0) { // is anything to remove - int index = (int)(al.size() * random.nextDouble()); - al.remove(index); - if (debug) { - debugOp(op, "remove() at index=" + index); // NOI18N - } - gl.remove(index); - } - - } else if ((r -= removeRangeRatio) < 0) { - if (al.size() > 0) { // is anything to remove - int index = (int)(al.size() * random.nextDouble()); - int length = (int)((al.size() - index + 1) * random.nextDouble()); - for (int count = length; count > 0; count--) { - al.remove(index); - } - if (debug) { - debugOp(op, "remove() at index=" + index + ", length=" + length); // NOI18N - } - gl.remove(index, length); - } - - } else if ((r -= clearRatio) < 0) { - al.clear(); - if (debug) { - debugOp(op, "clear()"); // NOI18N - } - gl.clear(); - - } else if ((r -= setRatio) < 0) { - if (al.size() > 0) { // is anything to remove - int index = (int)(al.size() * random.nextDouble()); - Object o = new Object(); - al.set(index, o); - if (debug) { - debugOp(op, "set() at index=" + index); // NOI18N - } - gl.set(index, o); - } - } - - checkConsistency(); - } - - } - - private void debugOp(int op, String s) { - System.err.println("op: " + op + ", " + s + ", " + gl.toStringInternals()); - } - - private void checkConsistency() { - gl.consistencyCheck(); - - assertEquals(gl.size(), al.size()); - - int size = al.size(); - for (int i = 0; i < size; i++) { - assertTrue("Contents differ at index " + i + ", gl: " + gl.get(i) // NOI18N - + ", al:" + al.get(i), // NOI18N - (gl.get(i) == al.get(i))); - } - } - - -} Index: ide/golden/public-packages.txt =================================================================== RCS file: /cvs/ide/golden/public-packages.txt,v retrieving revision 1.15 diff -u -r1.15 public-packages.txt --- ide/golden/public-packages.txt 25 Jan 2005 13:04:50 -0000 1.15 +++ ide/golden/public-packages.txt 14 Mar 2005 10:57:30 -0000 @@ -144,6 +144,8 @@ org.netbeans.lib.cvsclient.response org.netbeans.lib.cvsclient.util org.netbeans.lib.editor.hyperlink.spi +org.netbeans.lib.editor.util +org.netbeans.lib.editor.util.element org.netbeans.lib.editor.view org.netbeans.modules.ant.freeform.spi org.netbeans.modules.ant.freeform.spi.support @@ -154,8 +156,6 @@ org.netbeans.modules.editor.java org.netbeans.modules.editor.options org.netbeans.modules.editor.plain -org.netbeans.modules.editor.util -org.netbeans.modules.editor.util.element org.netbeans.modules.form org.netbeans.modules.i18n org.netbeans.modules.i18n.java