|
From: <ls...@us...> - 2006-12-09 18:47:16
|
Revision: 2882
http://jnode.svn.sourceforge.net/jnode/?rev=2882&view=rev
Author: lsantha
Date: 2006-12-09 10:47:15 -0800 (Sat, 09 Dec 2006)
Log Message:
-----------
Classpath patches.
Modified Paths:
--------------
trunk/core/src/classpath/javax/javax/swing/text/AbstractDocument.java
trunk/core/src/classpath/javax/javax/swing/text/BoxView.java
trunk/core/src/classpath/javax/javax/swing/text/ComponentView.java
trunk/core/src/classpath/javax/javax/swing/text/CompositeView.java
trunk/core/src/classpath/javax/javax/swing/text/DefaultCaret.java
trunk/core/src/classpath/javax/javax/swing/text/DefaultEditorKit.java
trunk/core/src/classpath/javax/javax/swing/text/DefaultFormatter.java
trunk/core/src/classpath/javax/javax/swing/text/DefaultStyledDocument.java
trunk/core/src/classpath/javax/javax/swing/text/ElementIterator.java
trunk/core/src/classpath/javax/javax/swing/text/FieldView.java
trunk/core/src/classpath/javax/javax/swing/text/FlowView.java
trunk/core/src/classpath/javax/javax/swing/text/GapContent.java
trunk/core/src/classpath/javax/javax/swing/text/GlyphView.java
trunk/core/src/classpath/javax/javax/swing/text/InternationalFormatter.java
trunk/core/src/classpath/javax/javax/swing/text/MaskFormatter.java
trunk/core/src/classpath/javax/javax/swing/text/ParagraphView.java
trunk/core/src/classpath/javax/javax/swing/text/Position.java
trunk/core/src/classpath/javax/javax/swing/text/StringContent.java
trunk/core/src/classpath/javax/javax/swing/text/StyleConstants.java
trunk/core/src/classpath/javax/javax/swing/text/StyleContext.java
trunk/core/src/classpath/javax/javax/swing/text/TextAction.java
trunk/core/src/classpath/javax/javax/swing/text/Utilities.java
trunk/core/src/classpath/javax/javax/swing/text/View.java
trunk/core/src/classpath/javax/javax/swing/text/WrappedPlainView.java
Modified: trunk/core/src/classpath/javax/javax/swing/text/AbstractDocument.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/AbstractDocument.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/AbstractDocument.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -46,6 +46,7 @@
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.EventListener;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.Vector;
@@ -158,15 +159,11 @@
private int numReaders = 0;
/**
- * Tells if there are one or more writers waiting.
+ * The number of current writers. If this is > 1 then the same thread entered
+ * the write lock more than once.
*/
- private int numWritersWaiting = 0;
+ private int numWriters = 0;
- /**
- * A condition variable that readers and writers wait on.
- */
- private Object documentCV = new Object();
-
/** An instance of a DocumentFilter.FilterBypass which allows calling
* the insert, remove and replace method without checking for an installed
* document filter.
@@ -179,6 +176,12 @@
private BidiRootElement bidiRoot;
/**
+ * True when we are currently notifying any listeners. This is used
+ * to detect illegal situations in writeLock().
+ */
+ private transient boolean notifyListeners;
+
+ /**
* Creates a new <code>AbstractDocument</code> with the specified
* {@link Content} model.
*
@@ -315,7 +318,8 @@
* @throws BadLocationException if <code>offset</code> is not a valid
* location in the documents content model
*/
- public Position createPosition(final int offset) throws BadLocationException
+ public synchronized Position createPosition(final int offset)
+ throws BadLocationException
{
return content.createPosition(offset);
}
@@ -327,11 +331,18 @@
*/
protected void fireChangedUpdate(DocumentEvent event)
{
+ notifyListeners = true;
+ try
+ {
DocumentListener[] listeners = getDocumentListeners();
-
for (int index = 0; index < listeners.length; ++index)
listeners[index].changedUpdate(event);
}
+ finally
+ {
+ notifyListeners = false;
+ }
+ }
/**
* Notifies all registered listeners when content is inserted in the document
@@ -341,11 +352,18 @@
*/
protected void fireInsertUpdate(DocumentEvent event)
{
+ notifyListeners = true;
+ try
+ {
DocumentListener[] listeners = getDocumentListeners();
-
for (int index = 0; index < listeners.length; ++index)
listeners[index].insertUpdate(event);
}
+ finally
+ {
+ notifyListeners = false;
+ }
+ }
/**
* Notifies all registered listeners when content is removed from the
@@ -355,11 +373,18 @@
*/
protected void fireRemoveUpdate(DocumentEvent event)
{
+ notifyListeners = true;
+ try
+ {
DocumentListener[] listeners = getDocumentListeners();
-
for (int index = 0; index < listeners.length; ++index)
listeners[index].removeUpdate(event);
}
+ finally
+ {
+ notifyListeners = false;
+ }
+ }
/**
* Notifies all registered listeners when an <code>UndoableEdit</code> has
@@ -432,7 +457,7 @@
* @return the thread that currently modifies this <code>Document</code>
* if there is one, otherwise <code>null</code>
*/
- protected final Thread getCurrentWriter()
+ protected final synchronized Thread getCurrentWriter()
{
return currentWriter;
}
@@ -1022,33 +1047,29 @@
* Blocks until a read lock can be obtained. Must block if there is
* currently a writer modifying the <code>Document</code>.
*/
- public final void readLock()
+ public final synchronized void readLock()
{
- if (currentWriter != null && currentWriter.equals(Thread.currentThread()))
- return;
- synchronized (documentCV)
- {
- while (currentWriter != null || numWritersWaiting > 0)
- {
-
try
{
- documentCV.wait();
- }
- catch (InterruptedException ie)
+ while (currentWriter != null)
{
- throw new Error("interrupted trying to get a readLock");
- }
+ if (currentWriter == Thread.currentThread())
+ return;
+ wait();
}
numReaders++;
}
+ catch (InterruptedException ex)
+ {
+ throw new Error("Interrupted during grab read lock");
+ }
}
/**
* Releases the read lock. If this was the only reader on this
* <code>Document</code>, writing may begin now.
*/
- public final void readUnlock()
+ public final synchronized void readUnlock()
{
// Note we could have a problem here if readUnlock was called without a
// prior call to readLock but the specs simply warn users to ensure that
@@ -1075,21 +1096,14 @@
// FIXME: the reference implementation throws a
// javax.swing.text.StateInvariantError here
- if (numReaders == 0)
+ if (numReaders <= 0)
throw new IllegalStateException("document lock failure");
- synchronized (documentCV)
- {
// If currentWriter is not null, the application code probably had a
// writeLock and then tried to obtain a readLock, in which case
// numReaders wasn't incremented
- if (currentWriter == null)
- {
- numReaders --;
- if (numReaders == 0 && numWritersWaiting != 0)
- documentCV.notify();
- }
- }
+ numReaders--;
+ notify();
}
/**
@@ -1113,10 +1127,19 @@
*/
public void remove(int offset, int length) throws BadLocationException
{
- if (documentFilter == null)
+ writeLock();
+ try
+ {
+ DocumentFilter f = getDocumentFilter();
+ if (f == null)
removeImpl(offset, length);
else
- documentFilter.remove(getBypass(), offset, length);
+ f.remove(getBypass(), offset, length);
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
void removeImpl(int offset, int length) throws BadLocationException
@@ -1135,10 +1158,6 @@
new DefaultDocumentEvent(offset, length,
DocumentEvent.EventType.REMOVE);
- try
- {
- writeLock();
-
// The order of the operations below is critical!
removeUpdate(event);
UndoableEdit temp = content.remove(offset, length);
@@ -1146,12 +1165,7 @@
postRemoveUpdate(event);
fireRemoveUpdate(event);
}
- finally
- {
- writeUnlock();
- }
}
- }
/**
* Replaces a piece of content in this <code>Document</code> with
@@ -1343,42 +1357,41 @@
* Blocks until a write lock can be obtained. Must wait if there are
* readers currently reading or another thread is currently writing.
*/
- protected final void writeLock()
- {
- if (currentWriter != null && currentWriter.equals(Thread.currentThread()))
- return;
- synchronized (documentCV)
- {
- numWritersWaiting++;
- while (numReaders > 0)
+ protected synchronized final void writeLock()
{
try
{
- documentCV.wait();
- }
- catch (InterruptedException ie)
+ while (numReaders > 0 || currentWriter != null)
+ {
+ if (Thread.currentThread() == currentWriter)
{
- throw new Error("interruped while trying to obtain write lock");
+ if (notifyListeners)
+ throw new IllegalStateException("Mutation during notify");
+ numWriters++;
+ return;
}
+ wait();
}
- numWritersWaiting --;
currentWriter = Thread.currentThread();
+ numWriters = 1;
}
+ catch (InterruptedException ex)
+ {
+ throw new Error("Interupted during grab write lock");
+ }
}
/**
* Releases the write lock. This allows waiting readers or writers to
* obtain the lock.
*/
- protected final void writeUnlock()
+ protected final synchronized void writeUnlock()
{
- synchronized (documentCV)
- {
- if (Thread.currentThread().equals(currentWriter))
+ if (--numWriters <= 0)
{
+ numWriters = 0;
currentWriter = null;
- documentCV.notifyAll();
- }
+ notifyAll();
}
}
@@ -2384,6 +2397,11 @@
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 5230037221564563284L;
+ /**
+ * The threshold that indicates when we switch to using a Hashtable.
+ */
+ private static final int THRESHOLD = 10;
+
/** The starting offset of the change. */
private int offset;
@@ -2394,15 +2412,18 @@
private DocumentEvent.EventType type;
/**
- * Maps <code>Element</code> to their change records.
+ * Maps <code>Element</code> to their change records. This is only
+ * used when the changes array gets too big. We can use an
+ * (unsync'ed) HashMap here, since changes to this are (should) always
+ * be performed inside a write lock.
*/
- Hashtable changes;
+ private HashMap changes;
/**
* Indicates if this event has been modified or not. This is used to
* determine if this event is thrown.
*/
- boolean modified;
+ private boolean modified;
/**
* Creates a new <code>DefaultDocumentEvent</code>.
@@ -2417,7 +2438,6 @@
this.offset = offset;
this.length = length;
this.type = type;
- changes = new Hashtable();
modified = false;
}
@@ -2431,9 +2451,27 @@
public boolean addEdit(UndoableEdit edit)
{
// XXX - Fully qualify ElementChange to work around gcj bug #2499.
- if (edit instanceof DocumentEvent.ElementChange)
+
+ // Start using Hashtable when we pass a certain threshold. This
+ // gives a good memory/performance compromise.
+ if (changes == null && edits.size() > THRESHOLD)
{
- modified = true;
+ changes = new HashMap();
+ int count = edits.size();
+ for (int i = 0; i < count; i++)
+ {
+ Object o = edits.elementAt(i);
+ if (o instanceof DocumentEvent.ElementChange)
+ {
+ DocumentEvent.ElementChange ec =
+ (DocumentEvent.ElementChange) o;
+ changes.put(ec.getElement(), ec);
+ }
+ }
+ }
+
+ if (changes != null && edit instanceof DocumentEvent.ElementChange)
+ {
DocumentEvent.ElementChange elEdit =
(DocumentEvent.ElementChange) edit;
changes.put(elEdit.getElement(), elEdit);
@@ -2492,7 +2530,27 @@
public DocumentEvent.ElementChange getChange(Element elem)
{
// XXX - Fully qualify ElementChange to work around gcj bug #2499.
- return (DocumentEvent.ElementChange) changes.get(elem);
+ DocumentEvent.ElementChange change = null;
+ if (changes != null)
+ {
+ change = (DocumentEvent.ElementChange) changes.get(elem);
+ }
+ else
+ {
+ int count = edits.size();
+ for (int i = 0; i < count && change == null; i++)
+ {
+ Object o = edits.get(i);
+ if (o instanceof DocumentEvent.ElementChange)
+ {
+ DocumentEvent.ElementChange ec =
+ (DocumentEvent.ElementChange) o;
+ if (elem.equals(ec.getElement()))
+ change = ec;
+ }
+ }
+ }
+ return change;
}
/**
Modified: trunk/core/src/classpath/javax/javax/swing/text/BoxView.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/BoxView.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/BoxView.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -38,6 +38,7 @@
package javax.swing.text;
+import java.awt.Container;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
@@ -105,6 +106,8 @@
myAxis = axis;
layoutValid[0] = false;
layoutValid[1] = false;
+ requirementsValid[X_AXIS] = false;
+ requirementsValid[Y_AXIS] = false;
span[0] = 0;
span[1] = 0;
requirements[0] = new SizeRequirements();
@@ -141,7 +144,10 @@
*/
public void setAxis(int axis)
{
+ boolean changed = axis != myAxis;
myAxis = axis;
+ if (changed)
+ preferenceChanged(null, true, true);
}
/**
@@ -222,55 +228,48 @@
*/
public void replace(int offset, int length, View[] views)
{
- int numViews = 0;
- if (views != null)
- numViews = views.length;
+ // Actually perform the replace.
+ super.replace(offset, length, views);
// Resize and copy data for cache arrays.
- // The spansX cache.
- int oldSize = getViewCount();
+ int newItems = views != null ? views.length : 0;
+ int minor = 1 - myAxis;
+ offsets[myAxis] = replaceLayoutArray(offsets[myAxis], offset, newItems);
+ spans[myAxis] = replaceLayoutArray(spans[myAxis], offset, newItems);
+ layoutValid[myAxis] = false;
+ requirementsValid[myAxis] = false;
+ offsets[minor] = replaceLayoutArray(offsets[minor], offset, newItems);
+ spans[minor] = replaceLayoutArray(spans[minor], offset, newItems);
+ layoutValid[minor] = false;
+ requirementsValid[minor] = false;
+ }
- int[] newSpansX = new int[oldSize - length + numViews];
- System.arraycopy(spans[X_AXIS], 0, newSpansX, 0, offset);
- System.arraycopy(spans[X_AXIS], offset + length, newSpansX,
- offset + numViews,
- oldSize - (offset + length));
- spans[X_AXIS] = newSpansX;
+ /**
+ * Helper method. This updates the layout cache arrays in response
+ * to a call to {@link #replace(int, int, View[])}.
+ *
+ * @param oldArray the old array
+ *
+ * @return the replaced array
+ */
+ private int[] replaceLayoutArray(int[] oldArray, int offset, int newItems)
- // The spansY cache.
- int[] newSpansY = new int[oldSize - length + numViews];
- System.arraycopy(spans[Y_AXIS], 0, newSpansY, 0, offset);
- System.arraycopy(spans[Y_AXIS], offset + length, newSpansY,
- offset + numViews,
- oldSize - (offset + length));
- spans[Y_AXIS] = newSpansY;
+ {
+ int num = getViewCount();
+ int[] newArray = new int[num];
+ System.arraycopy(oldArray, 0, newArray, 0, offset);
+ System.arraycopy(oldArray, offset, newArray, offset + newItems,
+ num - newItems - offset);
+ return newArray;
+ }
- // The offsetsX cache.
- int[] newOffsetsX = new int[oldSize - length + numViews];
- System.arraycopy(offsets[X_AXIS], 0, newOffsetsX, 0, offset);
- System.arraycopy(offsets[X_AXIS], offset + length, newOffsetsX,
- offset + numViews,
- oldSize - (offset + length));
- offsets[X_AXIS] = newOffsetsX;
+ /**
+ * A Rectangle instance to be reused in the paint() method below.
+ */
+ private final Rectangle tmpRect = new Rectangle();
- // The offsetsY cache.
- int[] newOffsetsY = new int[oldSize - length + numViews];
- System.arraycopy(offsets[Y_AXIS], 0, newOffsetsY, 0, offset);
- System.arraycopy(offsets[Y_AXIS], offset + length, newOffsetsY,
- offset + numViews,
- oldSize - (offset + length));
- offsets[Y_AXIS] = newOffsetsY;
+ private Rectangle clipRect = new Rectangle();
- // Actually perform the replace.
- super.replace(offset, length, views);
-
- // Invalidate layout information.
- layoutValid[X_AXIS] = false;
- requirementsValid[X_AXIS] = false;
- layoutValid[Y_AXIS] = false;
- requirementsValid[Y_AXIS] = false;
- }
-
/**
* Renders the <code>Element</code> that is associated with this
* <code>View</code>.
@@ -280,26 +279,20 @@
*/
public void paint(Graphics g, Shape a)
{
- Rectangle alloc;
- if (a instanceof Rectangle)
- alloc = (Rectangle) a;
- else
- alloc = a.getBounds();
+ // Try to avoid allocation if possible (almost all cases).
+ Rectangle alloc = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
- int x = alloc.x + getLeftInset();
- int y = alloc.y + getTopInset();
+ // This returns a cached instance.
+ alloc = getInsideAllocation(alloc);
- Rectangle clip = g.getClipBounds();
- Rectangle tmp = new Rectangle();
int count = getViewCount();
- for (int i = 0; i < count; ++i)
+ for (int i = 0; i < count; i++)
{
- tmp.x = x + getOffset(X_AXIS, i);
- tmp.y = y + getOffset(Y_AXIS, i);
- tmp.width = getSpan(X_AXIS, i);
- tmp.height = getSpan(Y_AXIS, i);
- if (tmp.intersects(clip))
- paintChild(g, tmp, i);
+ View child = getView(i);
+ tmpRect.setBounds(alloc);
+ childAllocation(i, tmpRect);
+ if (g.hitClip(tmpRect.x, tmpRect.y, tmpRect.width, tmpRect.height))
+ paintChild(g, tmpRect, i);
}
}
@@ -571,7 +564,7 @@
res.minimum = 0;
res.preferred = 0;
- res.maximum = 0;
+ res.maximum = Integer.MAX_VALUE;
res.alignment = 0.5F;
int n = getViewCount();
for (int i = 0; i < n; i++)
@@ -651,24 +644,54 @@
{
View result = null;
int count = getViewCount();
- Rectangle copy = new Rectangle(r);
-
- for (int i = 0; i < count; ++i)
+ if (myAxis == X_AXIS)
{
- copy.setBounds(r);
- // The next call modifies copy.
- childAllocation(i, copy);
- if (copy.contains(x, y))
+ // Border case. Requested point is left from the box.
+ if (x < r.x + offsets[X_AXIS][0])
{
- // Modify r on success.
- r.setBounds(copy);
- result = getView(i);
- break;
+ childAllocation(0, r);
+ result = getView(0);
}
+ else
+ {
+ // Search views inside box.
+ for (int i = 0; i < count && result == null; i++)
+ {
+ if (x < r.x + offsets[X_AXIS][i])
+ {
+ childAllocation(i - 1, r);
+ result = getView(i - 1);
+ }
}
-
- if (result == null && count > 0)
- return getView(count - 1);
+ }
+ }
+ else // Same algorithm for Y_AXIS.
+ {
+ // Border case. Requested point is above the box.
+ if (y < r.y + offsets[Y_AXIS][0])
+ {
+ childAllocation(0, r);
+ result = getView(0);
+ }
+ else
+ {
+ // Search views inside box.
+ for (int i = 0; i < count && result == null; i++)
+ {
+ if (y < r.y + offsets[Y_AXIS][i])
+ {
+ childAllocation(i - 1, r);
+ result = getView(i - 1);
+ }
+ }
+ }
+ }
+ // Not found, other border case: point is right from or below the box.
+ if (result == null)
+ {
+ childAllocation(count - 1, r);
+ result = getView(count - 1);
+ }
return result;
}
@@ -702,49 +725,32 @@
*/
protected void layout(int width, int height)
{
- int[] newSpan = new int[]{ width, height };
- int count = getViewCount();
-
- // Update minor axis as appropriate. We need to first update the minor
- // axis layout because that might affect the children's preferences along
- // the major axis.
- int minorAxis = myAxis == X_AXIS ? Y_AXIS : X_AXIS;
- if ((! isLayoutValid(minorAxis)) || newSpan[minorAxis] != span[minorAxis])
- {
- layoutValid[minorAxis] = false;
- span[minorAxis] = newSpan[minorAxis];
- layoutMinorAxis(span[minorAxis], minorAxis, offsets[minorAxis],
- spans[minorAxis]);
-
- // Update the child view's sizes.
- for (int i = 0; i < count; ++i)
- {
- getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]);
+ layoutAxis(X_AXIS, width);
+ layoutAxis(Y_AXIS, height);
}
- layoutValid[minorAxis] = true;
- }
-
- // Update major axis as appropriate.
- if ((! isLayoutValid(myAxis)) || newSpan[myAxis] != span[myAxis])
+ private void layoutAxis(int axis, int s)
{
- layoutValid[myAxis] = false;
- span[myAxis] = newSpan[myAxis];
- layoutMajorAxis(span[myAxis], myAxis, offsets[myAxis],
- spans[myAxis]);
+ if (span[axis] != s)
+ layoutValid[axis] = false;
+ if (! layoutValid[axis])
+ {
+ span[axis] = s;
+ updateRequirements(axis);
+ if (axis == myAxis)
+ layoutMajorAxis(span[axis], axis, offsets[axis], spans[axis]);
+ else
+ layoutMinorAxis(span[axis], axis, offsets[axis], spans[axis]);
+ layoutValid[axis] = true;
- // Update the child view's sizes.
- for (int i = 0; i < count; ++i)
+ // Push out child layout.
+ int viewCount = getViewCount();
+ for (int i = 0; i < viewCount; i++)
{
- getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]);
+ View v = getView(i);
+ v.setSize(spans[X_AXIS][i], spans[Y_AXIS][i]);
}
- layoutValid[myAxis] = true;
}
-
- if (layoutValid[myAxis] == false)
- System.err.println("WARNING: Major axis layout must be valid after layout");
- if (layoutValid[minorAxis] == false)
- System.err.println("Minor axis layout must be valid after layout");
}
/**
@@ -767,7 +773,7 @@
{
View child = getView(i);
spans[i] = (int) child.getPreferredSpan(axis);
- sumPref = spans[i];
+ sumPref += spans[i];
}
// Try to adjust the spans so that we fill the targetSpan.
@@ -870,7 +876,9 @@
*/
public int getWidth()
{
- return span[X_AXIS] + getLeftInset() - getRightInset();
+ // The RI returns the following here, however, I'd think that is a bug.
+ // return span[X_AXIS] + getLeftInset() - getRightInset();
+ return span[X_AXIS] + getLeftInset() + getRightInset();
}
/**
@@ -880,7 +888,9 @@
*/
public int getHeight()
{
- return span[Y_AXIS] + getTopInset() - getBottomInset();
+ // The RI returns the following here, however, I'd think that is a bug.
+ // return span[Y_AXIS] + getTopInset() - getBottomInset();
+ return span[Y_AXIS] + getTopInset() + getBottomInset();
}
/**
@@ -1004,9 +1014,11 @@
{
if (axis != X_AXIS && axis != Y_AXIS)
throw new IllegalArgumentException("Illegal axis argument");
- int weight = 1;
- if (axis == myAxis)
- weight = 0;
+ updateRequirements(axis);
+ int weight = 0;
+ if ((requirements[axis].preferred != requirements[axis].minimum)
+ || (requirements[axis].preferred != requirements[axis].maximum))
+ weight = 1;
return weight;
}
@@ -1033,13 +1045,39 @@
protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e,
Shape a, ViewFactory vf)
{
- // FIXME: What to do here?
+ boolean wasValid = isLayoutValid(myAxis);
super.forwardUpdate(ec, e, a, vf);
+ // Trigger repaint when one of the children changed the major axis.
+ if (wasValid && ! isLayoutValid(myAxis))
+ {
+ Container c = getContainer();
+ if (a != null && c != null)
+ {
+ int pos = e.getOffset();
+ int index = getViewIndexAtPosition(pos);
+ Rectangle r = getInsideAllocation(a);
+ if (myAxis == X_AXIS)
+ {
+ r.x += offsets[myAxis][index];
+ r.width -= offsets[myAxis][index];
+ }
+ else
+ {
+ r.y += offsets[myAxis][index];
+ r.height -= offsets[myAxis][index];
+ }
+ c.repaint(r.x, r.y, r.width, r.height);
+ }
+ }
}
public int viewToModel(float x, float y, Shape a, Position.Bias[] bias)
{
- // FIXME: What to do here?
+ if (! isAllocationValid())
+ {
+ Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
+ setSize(r.width, r.height);
+ }
return super.viewToModel(x, y, a, bias);
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/ComponentView.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/ComponentView.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/ComponentView.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -397,7 +397,24 @@
{
public void run()
{
+ Document doc = getDocument();
+ try
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
setParentImpl();
+ Container host = getContainer();
+ if (host != null)
+ {
+ preferenceChanged(null, true, true);
+ host.repaint();
+ }
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
}
});
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/CompositeView.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/CompositeView.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/CompositeView.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -56,14 +56,19 @@
/**
* The child views of this <code>CompositeView</code>.
*/
- View[] children;
+ private View[] children;
/**
+ * The number of child views.
+ */
+ private int numChildren;
+
+ /**
* The allocation of this <code>View</code> minus its insets. This is
* initialized in {@link #getInsideAllocation} and reused and modified in
* {@link #childAllocation(int, Rectangle)}.
*/
- Rectangle insideAllocation;
+ private final Rectangle insideAllocation = new Rectangle();
/**
* The insets of this <code>CompositeView</code>. This is initialized
@@ -101,6 +106,8 @@
*/
protected void loadChildren(ViewFactory f)
{
+ if (f != null)
+ {
Element el = getElement();
int count = el.getElementCount();
View[] newChildren = new View[count];
@@ -115,6 +122,7 @@
// Harmony's tests this is not what the RI does.
replace(0, 0, newChildren);
}
+ }
/**
* Sets the parent of this <code>View</code>.
@@ -126,7 +134,7 @@
public void setParent(View parent)
{
super.setParent(parent);
- if (parent != null && ((children == null) || children.length == 0))
+ if (parent != null && numChildren == 0)
loadChildren(getViewFactory());
}
@@ -137,7 +145,7 @@
*/
public int getViewCount()
{
- return children.length;
+ return numChildren;
}
/**
@@ -169,27 +177,37 @@
if (views == null)
views = new View[0];
- // Check for null views to add.
- for (int i = 0; i < views.length; ++i)
- if (views[i] == null)
- throw new NullPointerException("Added views must not be null");
-
+ // First we set the parent of the removed children to null.
int endOffset = offset + length;
-
- // First we set the parent of the removed children to null.
for (int i = offset; i < endOffset; ++i)
{
if (children[i].getParent() == this)
children[i].setParent(null);
+ children[i] = null;
}
- View[] newChildren = new View[children.length - length + views.length];
+ // Update the children array.
+ int delta = views.length - length;
+ int src = offset + length;
+ int numMove = numChildren - src;
+ int dst = src + delta;
+ if (numChildren + delta > children.length)
+ {
+ // Grow array.
+ int newLength = Math.max(2 * children.length, numChildren + delta);
+ View[] newChildren = new View[newLength];
System.arraycopy(children, 0, newChildren, 0, offset);
System.arraycopy(views, 0, newChildren, offset, views.length);
- System.arraycopy(children, offset + length, newChildren,
- offset + views.length,
- children.length - (offset + length));
+ System.arraycopy(children, src, newChildren, dst, numMove);
children = newChildren;
+ }
+ else
+ {
+ // Patch existing array.
+ System.arraycopy(children, src, children, dst, numMove);
+ System.arraycopy(views, 0, children, offset, views.length);
+ }
+ numChildren += delta;
// Finally we set the parent of the added children to this.
for (int i = 0; i < views.length; ++i)
@@ -264,12 +282,12 @@
}
}
}
- else
- {
+ }
+
+ if (ret == null)
throw new BadLocationException("Position " + pos
+ " is not represented by view.", pos);
- }
- }
+
return ret;
}
@@ -509,24 +527,17 @@
if (a == null)
return null;
- Rectangle alloc = a.getBounds();
+ // Try to avoid allocation of Rectangle here.
+ Rectangle alloc = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
+
// Initialize the inside allocation rectangle. This is done inside
// a synchronized block in order to avoid multiple threads creating
// this instance simultanously.
- Rectangle inside;
- synchronized(this)
- {
- inside = insideAllocation;
- if (inside == null)
- {
- inside = new Rectangle();
- insideAllocation = inside;
- }
- }
- inside.x = alloc.x + left;
- inside.y = alloc.y + top;
- inside.width = alloc.width - left - right;
- inside.height = alloc.height - top - bottom;
+ Rectangle inside = insideAllocation;
+ inside.x = alloc.x + getLeftInset();
+ inside.y = alloc.y + getTopInset();
+ inside.width = alloc.width - getLeftInset() - getRightInset();
+ inside.height = alloc.height - getTopInset() - getBottomInset();
return inside;
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/DefaultCaret.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/DefaultCaret.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/DefaultCaret.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -1075,8 +1075,6 @@
handleHighlight();
appear();
-
- adjustVisibility(this);
}
}
@@ -1114,8 +1112,6 @@
clearHighlight();
appear();
-
- adjustVisibility(this);
}
}
@@ -1154,8 +1150,13 @@
// e.printStackTrace();
}
if (area != null)
+ {
+ adjustVisibility(area);
+ if (getMagicCaretPosition() == null)
+ setMagicCaretPosition(new Point(area.x, area.y));
damage(area);
}
+ }
repaint();
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/DefaultEditorKit.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/DefaultEditorKit.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/DefaultEditorKit.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -311,11 +311,12 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
int offs = t.getDocument().getLength();
Caret c = t.getCaret();
c.setDot(0);
c.moveDot(offs);
-
try
{
c.setMagicCaretPosition(t.modelToView(offs).getLocation());
@@ -326,6 +327,7 @@
}
}
}
+ }
static class SelectionBeginAction
extends TextAction
@@ -338,6 +340,8 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
Caret c = t.getCaret();
c.moveDot(0);
try
@@ -350,6 +354,7 @@
}
}
}
+ }
static class SelectionEndAction
extends TextAction
@@ -362,6 +367,8 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
int offs = t.getDocument().getLength();
Caret c = t.getCaret();
c.moveDot(offs);
@@ -375,6 +382,7 @@
}
}
}
+ }
static class SelectionBeginLineAction
extends TextAction
@@ -388,6 +396,8 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
Caret c = t.getCaret();
try
{
@@ -398,7 +408,7 @@
{
// Can't happen.
}
-
+ }
}
}
@@ -413,6 +423,8 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
Caret c = t.getCaret();
try
{
@@ -423,7 +435,7 @@
{
// Can't happen.
}
-
+ }
}
}
@@ -437,15 +449,15 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
Caret c = t.getCaret();
try
{
int offs1 = Utilities.getRowStart(t, c.getDot());
int offs2 = Utilities.getRowEnd(t, c.getDot());
-
c.setDot(offs2);
c.moveDot(offs1);
-
c.setMagicCaretPosition(t.modelToView(offs2).getLocation());
}
catch(BadLocationException ble)
@@ -454,6 +466,7 @@
}
}
}
+ }
static class SelectWordAction extends TextAction
{
@@ -465,9 +478,10 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
Caret c = t.getCaret();
int dot = c.getDot();
-
try
{
int wordStart = Utilities.getWordStart(t, dot);
@@ -505,7 +519,6 @@
// as well.
if (c.getDot() != dot)
c.setMagicCaretPosition(t.modelToView(c.getDot()).getLocation());
-
}
catch(BadLocationException ble)
{
@@ -513,6 +526,7 @@
}
}
}
+ }
static class SelectionDownAction
extends TextAction.VerticalMovementAction
@@ -714,10 +728,11 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
try
{
int offs = Utilities.getRowEnd(t, t.getCaretPosition());
-
if (offs > -1)
{
Caret c = t.getCaret();
@@ -731,6 +746,7 @@
}
}
}
+ }
static class BeginLineAction
extends TextAction
@@ -743,10 +759,11 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
try
{
int offs = Utilities.getRowStart(t, t.getCaretPosition());
-
if (offs > -1)
{
Caret c = t.getCaret();
@@ -760,6 +777,7 @@
}
}
}
+ }
static class BeginAction extends TextAction
{
@@ -772,6 +790,8 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
Caret c = t.getCaret();
c.setDot(0);
try
@@ -784,6 +804,7 @@
}
}
}
+ }
static class EndAction extends TextAction
{
@@ -796,6 +817,8 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
+ {
int offs = t.getDocument().getLength();
Caret c = t.getCaret();
c.setDot(offs);
@@ -809,6 +832,7 @@
}
}
}
+ }
/**
* Creates a beep on the PC speaker.
@@ -861,7 +885,9 @@
*/
public void actionPerformed(ActionEvent event)
{
- getTextComponent(event).copy();
+ JTextComponent target = getTextComponent(event);
+ if (target != null)
+ target.copy();
}
}
@@ -892,7 +918,9 @@
*/
public void actionPerformed(ActionEvent event)
{
- getTextComponent(event).cut();
+ JTextComponent target = getTextComponent(event);
+ if (target != null)
+ target.cut();
}
}
@@ -921,7 +949,9 @@
*/
public void actionPerformed(ActionEvent event)
{
- getTextComponent(event).paste();
+ JTextComponent target = getTextComponent(event);
+ if (target != null)
+ target.paste();
}
}
@@ -1003,6 +1033,7 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
t.replaceSelection("\n");
}
}
@@ -1058,6 +1089,7 @@
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
+ if (t != null)
t.replaceSelection("\t");
}
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/DefaultFormatter.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/DefaultFormatter.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/DefaultFormatter.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -216,7 +216,7 @@
*/
public DefaultFormatter()
{
- commitsOnValidEdit = true;
+ commitsOnValidEdit = false;
overwriteMode = true;
allowsInvalid = true;
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/DefaultStyledDocument.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/DefaultStyledDocument.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/DefaultStyledDocument.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -683,6 +683,58 @@
return ret;
}
+ /**
+ * Creates a document in response to a call to
+ * {@link DefaultStyledDocument#create(ElementSpec[])}.
+ *
+ * @param len the length of the inserted text
+ * @param data the specs for the elements
+ * @param ev the document event
+ */
+ void create(int len, ElementSpec[] data, DefaultDocumentEvent ev)
+ {
+ prepareEdit(offset, len);
+ Element el = root;
+ int index = el.getElementIndex(0);
+ while (! el.isLeaf())
+ {
+ Element child = el.getElement(index);
+ Edit edit = new Edit(el, index, false);
+ elementStack.push(edit);
+ el = child;
+ index = el.getElementIndex(0);
+ }
+ Edit ed = (Edit) elementStack.peek();
+ Element child = ed.e.getElement(ed.index);
+ ed.added.add(createLeafElement(ed.e, child.getAttributes(), getLength(),
+ child.getEndOffset()));
+ ed.removed.add(child);
+ while (elementStack.size() > 1)
+ pop();
+ int n = data.length;
+
+ // Reset root element's attributes.
+ AttributeSet newAtts = null;
+ if (n > 0 && data[0].getType() == ElementSpec.StartTagType)
+ newAtts = data[0].getAttributes();
+ if (newAtts == null)
+ newAtts = SimpleAttributeSet.EMPTY;
+ MutableAttributeSet mAtts = (MutableAttributeSet) root.getAttributes();
+ ev.addEdit(new AttributeUndoableEdit(root, newAtts, true));
+ mAtts.removeAttributes(mAtts);
+ mAtts.addAttributes(newAtts);
+
+ // Insert the specified elements.
+ for (int i = 1; i < n; i++)
+ insertElement(data[i]);
+
+ // Pop remaining stack.
+ while (elementStack.size() > 0)
+ pop();
+
+ finishEdit(ev);
+ }
+
private boolean canJoin(Element e0, Element e1)
{
boolean ret = false;
@@ -987,6 +1039,8 @@
ElementEdit ee = new ElementEdit(parent, index, removed, added);
ev.addEdit(ee);
}
+ edits.clear();
+ elementStack.clear();
}
/**
@@ -1069,16 +1123,15 @@
if (offset == 0 && fracturedParent != null
&& data[0].getType() == ElementSpec.EndTagType)
{
- for (int p = 0;
+ int p;
+ for (p = 0;
p < data.length && data[p].getType() == ElementSpec.EndTagType;
- p++)
- {
+ p++);
Edit edit = insertPath[insertPath.length - p - 1];
edit.index--;
edit.removed.add(0, edit.e.getElement(edit.index));
}
}
- }
private void pop()
{
@@ -2379,18 +2432,24 @@
if (length == 0)
return;
- UndoableEdit edit = content.insertString(offset,
+ Content c = getContent();
+ UndoableEdit edit = c.insertString(offset,
contentBuffer.toString());
// Create the DocumentEvent with the ElementEdit added
DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
length,
DocumentEvent.EventType.INSERT);
+
ev.addEdit(edit);
// Finally we must update the document structure and fire the insert
// update event.
buffer.insert(offset, length, data, ev);
+
+ super.insertUpdate(ev, null);
+
+ ev.end();
fireInsertUpdate(ev);
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
}
@@ -2410,14 +2469,16 @@
*/
protected void create(ElementSpec[] data)
{
- writeLock();
try
{
+
// Clear content if there is some.
int len = getLength();
if (len > 0)
remove(0, len);
+ writeLock();
+
// Now we insert the content.
StringBuilder b = new StringBuilder();
for (int i = 0; i < data.length; ++i)
@@ -2429,38 +2490,18 @@
Content content = getContent();
UndoableEdit cEdit = content.insertString(0, b.toString());
+ len = b.length();
DefaultDocumentEvent ev =
new DefaultDocumentEvent(0, b.length(),
DocumentEvent.EventType.INSERT);
ev.addEdit(cEdit);
- // We do a little trick here to get the new structure: We instantiate
- // a new ElementBuffer with a new root element, insert into that root
- // and then reparent the newly created elements to the old root
- // element.
- BranchElement createRoot =
- (BranchElement) createBranchElement(null, null);
- Element dummyLeaf = createLeafElement(createRoot, null, 0, 1);
- createRoot.replace(0, 0, new Element[]{ dummyLeaf });
- ElementBuffer createBuffer = new ElementBuffer(createRoot);
- createBuffer.insert(0, b.length(), data, new DefaultDocumentEvent(0, b.length(), DocumentEvent.EventType.INSERT));
- // Now the new root is the first child of the createRoot.
- Element newRoot = createRoot.getElement(0);
- BranchElement root = (BranchElement) getDefaultRootElement();
- Element[] added = new Element[newRoot.getElementCount()];
- for (int i = 0; i < added.length; ++i)
- {
- added[i] = newRoot.getElement(i);
- ((AbstractElement) added[i]).element_parent = root;
- }
- Element[] removed = new Element[root.getElementCount()];
- for (int i = 0; i < removed.length; ++i)
- removed[i] = root.getElement(i);
+ buffer.create(len, data, ev);
- // Replace the old elements in root with the new and update the event.
- root.replace(0, removed.length, added);
- ev.addEdit(new ElementEdit(root, 0, removed, added));
+ // For the bidi update.
+ super.insertUpdate(ev, null);
+ ev.end();
fireInsertUpdate(ev);
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/ElementIterator.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/ElementIterator.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/ElementIterator.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -37,6 +37,8 @@
package javax.swing.text;
+import java.util.Stack;
+
/**
* This class can be used to iterate over the {@link Element} tree of
* a {@link Document} or an {@link Element}. This iterator performs
@@ -46,30 +48,49 @@
*/
public class ElementIterator implements Cloneable
{
+ /**
+ * Uses to track the iteration on the stack.
+ */
+ private class ElementRef
+ {
+ /**
+ * The element.
+ */
+ Element element;
+
+ /**
+ * The child index. -1 means the element itself. >= 0 values mean the
+ * n-th child of the element.
+ */
+ int index;
+
+ /**
+ * Creates a new ElementRef.
+ *
+ * @param el the element
+ */
+ ElementRef(Element el)
+ {
+ element = el;
+ index = -1;
+ }
+ }
+
// The root element.
private Element root;
- // The current element.
- private Element currentElement;
- // The depth to which we have descended in the tree.
- private int currentDepth;
- // This is at least as big as the current depth, and at index N
- // contains the index of the child element we're currently
- // examining.
- private int[] state;
+ /**
+ * Holds ElementRefs.
+ */
+ private Stack stack;
- // The previous item.
- private Element previousItem;
-
/**
* Create a new ElementIterator to iterate over the given document.
* @param document the Document over which we iterate
*/
public ElementIterator(Document document)
{
- this.root = document.getDefaultRootElement();
- this.currentElement = root;
- this.state = new int[5];
+ root = document.getDefaultRootElement();
}
/**
@@ -79,8 +100,6 @@
public ElementIterator(Element root)
{
this.root = root;
- this.currentElement = root;
- this.state = new int[5];
}
/**
@@ -105,7 +124,24 @@
*/
public Element current()
{
- return currentElement;
+ Element current;
+ if (stack == null)
+ current = first();
+ else
+ {
+ current = null;
+ if (! stack.isEmpty())
+ {
+ ElementRef ref = (ElementRef) stack.peek();
+ Element el = ref.element;
+ int index = ref.index;
+ if (index == -1)
+ current = el;
+ else
+ current = el.getElement(index);
+ }
+ }
+ return current;
}
/**
@@ -113,7 +149,10 @@
*/
public int depth()
{
- return currentDepth;
+ int depth = 0;
+ if (stack != null)
+ depth = stack.size();
+ return depth;
}
/**
@@ -121,11 +160,15 @@
*/
public Element first()
{
- // Reset the iterator.
- currentElement = root;
- currentDepth = 0;
- previousItem = null;
- return root;
+ Element first = null;
+ if (root != null)
+ {
+ stack = new Stack();
+ if (root.getElementCount() > 0)
+ stack.push(new ElementRef(root));
+ first = root;
+ }
+ return first;
}
/**
@@ -134,39 +177,41 @@
*/
public Element next()
{
- previousItem = currentElement;
- if (currentElement == null)
- return null;
- if (! currentElement.isLeaf())
+ Element next;
+ if (stack == null)
+ next = first();
+ else
{
- ++currentDepth;
- if (currentDepth > state.length)
+ next = null;
+ if (! stack.isEmpty())
{
- int[] newState = new int[state.length * 2];
- System.arraycopy(state, 0, newState, 0, state.length);
- state = newState;
- }
- state[currentDepth] = 0;
- currentElement = currentElement.getElement(0);
- return currentElement;
+ ElementRef ref = (ElementRef) stack.peek();
+ Element el = ref.element;
+ int index = ref.index;
+ if (el.getElementCount() > index + 1)
+ {
+ Element child = el.getElement(index + 1);
+ if (child.isLeaf())
+ ref.index++;
+ else
+ stack.push(new ElementRef(child));
+ next = child;
+ next = child;
}
-
- while (currentDepth > 0)
+ else
{
- // At a leaf, or done with a non-leaf's children, so go up a
- // level.
- --currentDepth;
- currentElement = currentElement.getParentElement();
- ++state[currentDepth];
- if (state[currentDepth] < currentElement.getElementCount())
+ stack.pop();
+ if (! stack.isEmpty())
{
- currentElement = currentElement.getElement(state[currentDepth]);
- return currentElement;
+ ElementRef top = (ElementRef) stack.peek();
+ top.index++;
+ next = next();
}
}
-
- currentElement = null;
- return currentElement;
+ }
+ // else return null.
+ }
+ return next;
}
/**
@@ -174,8 +219,54 @@
*/
public Element previous()
{
- if (currentElement == null || currentElement == root)
- return null;
- return previousItem;
+ Element previous = null;
+ int stackSize;
+ if (stack != null && (stackSize = stack.size()) > 0)
+ {
+ ElementRef ref = (ElementRef) stack.peek();
+ Element el = ref.element;
+ int index = ref.index;
+ if (index > 0)
+ {
+ previous = deepestLeaf(el.getElement(--index));
+ }
+ else if (index == 0)
+ {
+ previous = el;
+ }
+ else if (index == -1)
+ {
+ ElementRef top = (ElementRef) stack.pop();
+ ElementRef item = (ElementRef) stack.peek();
+ stack.push(top);
+ index = item.index;
+ el = item.element;
+ previous = index == -1 ? el : deepestLeaf(el.getElement(index));
+ }
+ }
+ return previous;
}
+
+ /**
+ * Determines and returns the deepest leaf of the element <code>el</code>.
+ *
+ * @param el the base element
+ *
+ * @returnthe deepest leaf of the element <code>el</code>
+ */
+ private Element deepestLeaf(Element el)
+ {
+ Element leaf;
+ if (el.isLeaf())
+ leaf = el;
+ else
+ {
+ int count = el.getElementCount();
+ if (count == 0)
+ leaf = el;
+ else
+ leaf = deepestLeaf(el.getElement(count - 1));
+ }
+ return leaf;
+ }
}
Modified: trunk/core/src/classpath/javax/javax/swing/text/FieldView.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/FieldView.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/FieldView.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -45,8 +45,6 @@
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import javax.swing.BoundedRangeModel;
import javax.swing.JTextField;
@@ -225,7 +223,7 @@
public int getResizeWeight(int axis)
{
- return axis = axis == X_AXIS ? 1 : 0;
+ return axis == X_AXIS ? 1 : 0;
}
public Shape modelToView(int pos, Shape a, Position.Bias bias)
Modified: trunk/core/src/classpath/javax/javax/swing/text/FlowView.java
===================================================================
--- trunk/core/src/classpath/javax/javax/swing/text/FlowView.java 2006-12-09 18:44:58 UTC (rev 2881)
+++ trunk/core/src/classpath/javax/javax/swing/text/FlowView.java 2006-12-09 18:47:15 UTC (rev 2882)
@@ -38,6 +38,8 @@
package javax.swing.text;
+import java.awt.Component;
+import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
@@ -85,7 +87,17 @@
*/
public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- // The default implementation does nothing.
+ if (alloc == null)
+ {
+ fv.layoutChanged(X_AXIS);
+ fv.layoutChanged(Y_AXIS);
+ }
+ else
+ {
+ Component host = fv.getContainer();
+ if (host != null)
+ host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
+ }
}
/**
@@ -101,7 +113,17 @@
*/
public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- // The default implementation does nothing.
+ if (alloc == null)
+ {
+ fv.layoutChanged(X_AXIS);
+ fv.layoutChanged(Y_AXIS);
+ }
+ else
+ {
+ Component host = fv.getContainer();
+ if (host != null)
+ host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
+ }
}
/**
@@ -117,7 +139,17 @@
*/
public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- // The default implementation does nothing.
+ if (alloc == null)
+ {
+ fv.layoutChanged(X_AXIS);
+ fv.layoutChanged(Y_AXIS);
+ }
+ else
+ {
+ Component host = fv.getContainer();
+ if (host != null)
+ host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
+ }
}
/**
@@ -143,18 +175,35 @@
*/
public void layout(FlowView fv)
{
+ int start = fv.getStartOffset();
+ int end = fv.getEndOffset();
+
+ // Preserve the views from the logical view from beeing removed.
+ View lv = getLogicalView(fv);
+ int viewCount = lv.getViewCount();
+ for (int i = 0; i < viewCount; i++)
+ {
+ View v = lv.getView(i);
+ v.setParent(lv);
+ }
+
+ // Then remove all views from the flow view.
fv.removeAll();
- Element el = fv.getElement();
- int rowStart = el.getStartOffset();
- int end = el.getEndOffset();
- int rowIndex = 0;
- while (rowStart >= 0 && rowStart < end)
+ for (int rowIndex = 0; start < end; rowIndex++)
{
View row = fv.createRow();
fv.append(row);
- rowStart = layoutRow(fv, rowIndex, rowStart);
- rowIndex++;
+ int next = layoutRow(fv, rowIndex, start);
+ if (row.getViewCount() == 0)
+ {
+ row.append(createView(fv, start, Integer.MAX_VALUE, rowIndex));
+ next = row.getEndOffset();
+ }
+ if (start < next)
+ start = next;
+ else
+ assert false: "May not happen";
}
}
@@ -179,46 +228,69 @@
int axis = fv.getFlowAxis();
int span = fv.getFlowSpan(rowIndex);
int x = fv.getFlowStart(rowIndex);
- int offset = pos;
- View logicalView = getLogicalView(fv);
- // Special case when span == 0. We need to layout the row as if it had
- // a span of Integer.MAX_VALUE.
- if (span == 0)
- span = Integer.MAX_VALUE;
+ int end = fv.getEndOffset();
- Row: while (span > 0)
+ // Needed for adjusting indentation in adjustRow().
+ int preX = x;
+ int availableSpan = span;
+
+ TabExpander tabExp = fv instanceof TabExpander ? (TabExpander) fv : null;
+
+ boolean forcedBreak = false;
+ while (pos < end && span >= 0)
{
- if (logicalView.getViewIndex(offset, Position.Bias.Forward) == - 1)
+ View view = createView(fv, pos, span, rowIndex);
+ if (view == null
+ || (span == 0 && view.getPreferredSpan(axis) > 0))
break;
- View view = createView(fv, offset, span, rowIndex);
- if (view == null)
- break;
- int viewSpan = (int) view.getPreferredSpan(axis);
- int breakWeight = view.getBreakWeight(axis, x, span);
+ int viewSpan;
+ if (axis == X_AXIS && view instanceof TabableView)
+ viewSpan = (int) ((TabableView) view).getTabbedSpan(x, tabExp);
+ else
+ viewSpan = (int) view.getPreferredSpan(axis);
- row.append(view);
- offset += (view.getEndOffset() - view.getStartOffset());
- x += viewSpan;
- span -= viewSpan;
-
// Break if the line if the view does not fit in this row or the
// line just must be broken.
- if (span < 0 || breakWeight >= View.ForcedBreakWeight)
+ int breakWeight = view.getBreakWeight(axis, pos, span);
+ if (breakWeight >= ForcedBreakWeight)
{
- int flowStart = fv.getFlowStart(axis);
- int flowSpan = fv.getFlowSpan(axis);
- adjustRow(fv, rowIndex, flowSpan, flowStart);
int rowViewCount = row.getViewCount();
if (rowViewCount > 0)
- offset = row.getView(rowViewCount - 1).getEndOffset();
+ {
+ view = view.breakView(axis, pos, x, span);
+ if (view != null)
+ {
+ if (axis == X_AXIS && view instanceof TabableView)
+ viewSpan =
+ (int) ((TabableView) view).getTabbedSpan(x, tabExp);
else
- offset = - 1;
- break Row;
+ viewSpan = (int) view.getPreferredSpan(axis);
}
+ else
+ ...
[truncated message content] |