summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing
diff options
context:
space:
mode:
authormark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-10 21:46:48 +0000
committermark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-10 21:46:48 +0000
commitce57ab760f69de6db452def7ffbf5b114a2d8694 (patch)
treeea38c56431c5d4528fb54254c3f8e50f517bede3 /libjava/classpath/javax/swing
parent50996fe55769882de3f410896032c887f0ff0d04 (diff)
downloadgcc-ce57ab760f69de6db452def7ffbf5b114a2d8694.tar.gz
Imported GNU Classpath 0.90
* scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore. * gnu/classpath/jdwp/VMFrame.java (SIZE): New constant. * java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5. * java/lang/Math.java: New override file. * java/lang/Character.java: Merged from Classpath. (start, end): Now 'int's. (canonicalName): New field. (CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants. (UnicodeBlock): Added argument. (of): New overload. (forName): New method. Updated unicode blocks. (sets): Updated. * sources.am: Regenerated. * Makefile.in: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111942 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/javax/swing')
-rw-r--r--libjava/classpath/javax/swing/AbstractAction.java102
-rw-r--r--libjava/classpath/javax/swing/AbstractButton.java8
-rw-r--r--libjava/classpath/javax/swing/AbstractCellEditor.java29
-rw-r--r--libjava/classpath/javax/swing/AbstractListModel.java11
-rw-r--r--libjava/classpath/javax/swing/CellEditor.java42
-rw-r--r--libjava/classpath/javax/swing/CellRendererPane.java44
-rw-r--r--libjava/classpath/javax/swing/ComboBoxModel.java28
-rw-r--r--libjava/classpath/javax/swing/DefaultCellEditor.java350
-rw-r--r--libjava/classpath/javax/swing/DefaultListCellRenderer.java2
-rw-r--r--libjava/classpath/javax/swing/DefaultListSelectionModel.java9
-rw-r--r--libjava/classpath/javax/swing/ImageIcon.java4
-rw-r--r--libjava/classpath/javax/swing/JApplet.java2
-rw-r--r--libjava/classpath/javax/swing/JCheckBox.java2
-rw-r--r--libjava/classpath/javax/swing/JComponent.java332
-rw-r--r--libjava/classpath/javax/swing/JDialog.java7
-rw-r--r--libjava/classpath/javax/swing/JEditorPane.java55
-rw-r--r--libjava/classpath/javax/swing/JFileChooser.java12
-rw-r--r--libjava/classpath/javax/swing/JFrame.java11
-rw-r--r--libjava/classpath/javax/swing/JInternalFrame.java65
-rw-r--r--libjava/classpath/javax/swing/JLayeredPane.java492
-rw-r--r--libjava/classpath/javax/swing/JMenu.java2
-rw-r--r--libjava/classpath/javax/swing/JMenuBar.java12
-rw-r--r--libjava/classpath/javax/swing/JOptionPane.java4
-rw-r--r--libjava/classpath/javax/swing/JPanel.java2
-rw-r--r--libjava/classpath/javax/swing/JPopupMenu.java2
-rw-r--r--libjava/classpath/javax/swing/JProgressBar.java16
-rw-r--r--libjava/classpath/javax/swing/JRootPane.java58
-rw-r--r--libjava/classpath/javax/swing/JSpinner.java317
-rw-r--r--libjava/classpath/javax/swing/JSplitPane.java7
-rw-r--r--libjava/classpath/javax/swing/JTabbedPane.java81
-rw-r--r--libjava/classpath/javax/swing/JTable.java841
-rw-r--r--libjava/classpath/javax/swing/JTextField.java20
-rw-r--r--libjava/classpath/javax/swing/JTextPane.java8
-rw-r--r--libjava/classpath/javax/swing/JTree.java17
-rw-r--r--libjava/classpath/javax/swing/JViewport.java104
-rw-r--r--libjava/classpath/javax/swing/JWindow.java54
-rw-r--r--libjava/classpath/javax/swing/Popup.java2
-rw-r--r--libjava/classpath/javax/swing/PopupFactory.java19
-rw-r--r--libjava/classpath/javax/swing/RepaintManager.java392
-rw-r--r--libjava/classpath/javax/swing/ScrollPaneLayout.java26
-rw-r--r--libjava/classpath/javax/swing/SpinnerDateModel.java150
-rw-r--r--libjava/classpath/javax/swing/SpinnerNumberModel.java187
-rw-r--r--libjava/classpath/javax/swing/Spring.java136
-rw-r--r--libjava/classpath/javax/swing/SpringLayout.java29
-rw-r--r--libjava/classpath/javax/swing/SwingUtilities.java104
-rw-r--r--libjava/classpath/javax/swing/Timer.java7
-rw-r--r--libjava/classpath/javax/swing/ToolTipManager.java3
-rw-r--r--libjava/classpath/javax/swing/UIManager.java6
-rw-r--r--libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java18
-rw-r--r--libjava/classpath/javax/swing/ViewportLayout.java91
-rw-r--r--libjava/classpath/javax/swing/event/CaretEvent.java53
-rw-r--r--libjava/classpath/javax/swing/event/DocumentEvent.java24
-rw-r--r--libjava/classpath/javax/swing/event/EventListenerList.java4
-rw-r--r--libjava/classpath/javax/swing/event/ListSelectionEvent.java173
-rw-r--r--libjava/classpath/javax/swing/event/ListSelectionListener.java26
-rw-r--r--libjava/classpath/javax/swing/event/MenuDragMouseEvent.java117
-rw-r--r--libjava/classpath/javax/swing/event/MenuKeyEvent.java113
-rw-r--r--libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java278
-rw-r--r--libjava/classpath/javax/swing/event/TableColumnModelEvent.java104
-rw-r--r--libjava/classpath/javax/swing/event/TableModelListener.java29
-rw-r--r--libjava/classpath/javax/swing/event/TreeExpansionEvent.java72
-rw-r--r--libjava/classpath/javax/swing/event/TreeModelEvent.java245
-rw-r--r--libjava/classpath/javax/swing/event/TreeSelectionEvent.java45
-rw-r--r--libjava/classpath/javax/swing/event/UndoableEditEvent.java70
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicBorders.java36
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java1
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java5
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java16
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicHTML.java297
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java70
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java57
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicListUI.java40
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java141
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java3
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java323
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java1
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java6
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java42
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java206
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java31
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java108
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java7
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java351
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java160
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java250
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java297
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalBorders.java93
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java7
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java13
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java909
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java59
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java8
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalUtils.java5
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/ColorType.java130
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/Region.java474
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/SynthConstants.java85
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/SynthContext.java134
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java283
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java272
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/SynthPainter.java80
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/SynthStyle.java144
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/SynthStyleFactory.java64
-rw-r--r--libjava/classpath/javax/swing/plaf/synth/package.html47
-rw-r--r--libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java17
-rw-r--r--libjava/classpath/javax/swing/table/DefaultTableModel.java5
-rw-r--r--libjava/classpath/javax/swing/table/JTableHeader.java89
-rw-r--r--libjava/classpath/javax/swing/text/AbstractDocument.java167
-rw-r--r--libjava/classpath/javax/swing/text/AsyncBoxView.java1480
-rw-r--r--libjava/classpath/javax/swing/text/BoxView.java594
-rw-r--r--libjava/classpath/javax/swing/text/ComponentView.java3
-rw-r--r--libjava/classpath/javax/swing/text/CompositeView.java44
-rw-r--r--libjava/classpath/javax/swing/text/DefaultCaret.java123
-rw-r--r--libjava/classpath/javax/swing/text/DefaultEditorKit.java332
-rw-r--r--libjava/classpath/javax/swing/text/DefaultFormatter.java7
-rw-r--r--libjava/classpath/javax/swing/text/DefaultHighlighter.java140
-rw-r--r--libjava/classpath/javax/swing/text/DefaultStyledDocument.java2091
-rw-r--r--libjava/classpath/javax/swing/text/DefaultTextUI.java1
-rw-r--r--libjava/classpath/javax/swing/text/FlowView.java394
-rw-r--r--libjava/classpath/javax/swing/text/GapContent.java167
-rw-r--r--libjava/classpath/javax/swing/text/GlyphView.java126
-rw-r--r--libjava/classpath/javax/swing/text/IconView.java2
-rw-r--r--libjava/classpath/javax/swing/text/JTextComponent.java395
-rw-r--r--libjava/classpath/javax/swing/text/LabelView.java6
-rw-r--r--libjava/classpath/javax/swing/text/MutableAttributeSet.java64
-rw-r--r--libjava/classpath/javax/swing/text/NavigationFilter.java27
-rw-r--r--libjava/classpath/javax/swing/text/ParagraphView.java203
-rw-r--r--libjava/classpath/javax/swing/text/PasswordView.java44
-rw-r--r--libjava/classpath/javax/swing/text/PlainDocument.java55
-rw-r--r--libjava/classpath/javax/swing/text/PlainView.java110
-rw-r--r--libjava/classpath/javax/swing/text/Segment.java120
-rw-r--r--libjava/classpath/javax/swing/text/SimpleAttributeSet.java195
-rw-r--r--libjava/classpath/javax/swing/text/StringContent.java138
-rw-r--r--libjava/classpath/javax/swing/text/StyleConstants.java823
-rw-r--r--libjava/classpath/javax/swing/text/StyleContext.java25
-rw-r--r--libjava/classpath/javax/swing/text/TableView.java56
-rw-r--r--libjava/classpath/javax/swing/text/Utilities.java99
-rw-r--r--libjava/classpath/javax/swing/text/View.java136
-rw-r--r--libjava/classpath/javax/swing/text/WrappedPlainView.java3
-rw-r--r--libjava/classpath/javax/swing/text/html/FormView.java230
-rw-r--r--libjava/classpath/javax/swing/text/html/HTML.java79
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLDocument.java193
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLEditorKit.java43
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLTableView.java82
-rw-r--r--libjava/classpath/javax/swing/text/html/InlineView.java166
-rw-r--r--libjava/classpath/javax/swing/text/html/NullView.java102
-rw-r--r--libjava/classpath/javax/swing/text/html/ObjectView.java110
-rw-r--r--libjava/classpath/javax/swing/text/html/Option.java157
-rw-r--r--libjava/classpath/javax/swing/text/html/ParagraphView.java209
-rw-r--r--libjava/classpath/javax/swing/text/package.html4
-rw-r--r--libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java208
-rw-r--r--libjava/classpath/javax/swing/undo/StateEdit.java6
-rw-r--r--libjava/classpath/javax/swing/undo/StateEditable.java6
152 files changed, 15186 insertions, 5620 deletions
diff --git a/libjava/classpath/javax/swing/AbstractAction.java b/libjava/classpath/javax/swing/AbstractAction.java
index bd3167e1e93..4a2334570aa 100644
--- a/libjava/classpath/javax/swing/AbstractAction.java
+++ b/libjava/classpath/javax/swing/AbstractAction.java
@@ -1,5 +1,5 @@
/* AbstractAction.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing;
+import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -74,28 +75,30 @@ public abstract class AbstractAction
private transient HashMap store = new HashMap();
/**
- * Creates a new action with an empty string for the name. All other
- * properties are initialised to <code>null</code>
+ * Creates a new action with no properties set.
*/
public AbstractAction()
{
- this(null);
+ // Nothing to do.
}
/**
- * Creates a new action with the specified name. All other properties are
- * initialised to <code>null</code>.
+ * Creates a new action with the specified name. The name is stored as a
+ * property with the key {@link Action#NAME}, and no other properties are
+ * initialised.
*
* @param name the name (<code>null</code> permitted).
*/
public AbstractAction(String name)
{
- this(name, null);
+ putValue(NAME, name);
}
/**
- * Creates a new action with the specified name and icon. All other
- * properties are initialised to <code>null</code>.
+ * Creates a new action with the specified name and icon. The name is stored
+ * as a property with the key {@link Action#NAME}, the icon is stored as a
+ * property with the key {@link Action#SMALL_ICON}, and no other properties
+ * are initialised.
*
* @param name the name (<code>null</code> permitted).
* @param icon the icon (<code>null</code> permitted).
@@ -133,11 +136,12 @@ public abstract class AbstractAction
}
/**
- * clone
+ * Returns a clone of the action.
*
- * @return Object
+ * @return A clone of the action.
*
- * @exception CloneNotSupportedException TODO
+ * @exception CloneNotSupportedException if there is a problem cloning the
+ * action.
*/
protected Object clone() throws CloneNotSupportedException
{
@@ -153,6 +157,8 @@ public abstract class AbstractAction
*
* @return The value associated with the specified key, or
* <code>null</code> if the key is not found.
+ *
+ * @see #putValue(String, Object)
*/
public Object getValue(String key)
{
@@ -162,11 +168,17 @@ public abstract class AbstractAction
/**
* Sets the value associated with the specified key and sends a
* {@link java.beans.PropertyChangeEvent} to all registered listeners.
- * The standard keys are: {@link #NAME}, {@link #SHORT_DESCRIPTION},
- * {@link #LONG_DESCRIPTION}, {@link #SMALL_ICON},
- * {@link #ACTION_COMMAND_KEY}, {@link #ACCELERATOR_KEY} and
- * {@link #MNEMONIC_KEY}. Any existing value associated with the key will be
- * overwritten.
+ * The standard keys are:
+ * <ul>
+ * <li>{@link #NAME}</li>
+ * <li>{@link #SHORT_DESCRIPTION}</li>
+ * <li>{@link #LONG_DESCRIPTION}</li>
+ * <li>{@link #SMALL_ICON}</li>
+ * <li>{@link #ACTION_COMMAND_KEY}</li>
+ * <li>{@link #ACCELERATOR_KEY}</li>
+ * <li>{@link #MNEMONIC_KEY}</li>
+ * </ul>
+ * Any existing value associated with the key will be overwritten.
*
* @param key the key (not <code>null</code>).
* @param value the value (<code>null</code> permitted).
@@ -174,7 +186,7 @@ public abstract class AbstractAction
public void putValue(String key, Object value)
{
Object old = getValue(key);
- if (old == null || !old.equals(value))
+ if ((old == null && value != null) || (old != null && !old.equals(value)))
{
store.put(key, value);
firePropertyChange(key, old, value);
@@ -185,6 +197,8 @@ public abstract class AbstractAction
* Returns the flag that indicates whether or not the action is enabled.
*
* @return The flag.
+ *
+ * @see #setEnabled(boolean)
*/
public boolean isEnabled()
{
@@ -194,9 +208,12 @@ public abstract class AbstractAction
/**
* Sets the flag that indicates whether or not the action is enabled and, if
* the value of the flag changed from the previous setting, sends a
- * {@link java.beans.PropertyChangeEvent} to all registered listeners.
+ * {@link java.beans.PropertyChangeEvent} to all registered listeners (using
+ * the property name 'enabled').
*
* @param enabled the new flag value.
+ *
+ * @see #isEnabled()
*/
public void setEnabled(boolean enabled)
{
@@ -208,8 +225,11 @@ public abstract class AbstractAction
}
/**
- * getKeys
- * @returns Object[]
+ * Returns an array of the keys for the property values that have been
+ * defined via the {@link #putValue(String, Object)} method (or the class
+ * constructor).
+ *
+ * @return An array of keys.
*/
public Object[] getKeys()
{
@@ -217,12 +237,12 @@ public abstract class AbstractAction
}
/**
- * This method fires a PropertyChangeEvent given the propertyName
- * and the old and new values.
+ * Sends a {@link PropertyChangeEvent} for the named property to all
+ * registered listeners.
*
- * @param propertyName The property that changed.
- * @param oldValue The old value of the property.
- * @param newValue The new value of the property.
+ * @param propertyName the property name.
+ * @param oldValue the old value of the property.
+ * @param newValue the new value of the property.
*/
protected void firePropertyChange(String propertyName, Object oldValue,
Object newValue)
@@ -231,22 +251,27 @@ public abstract class AbstractAction
}
/**
- * This convenience method fires a PropertyChangeEvent given
- * the propertyName and the old and new values.
+ * Sends a {@link PropertyChangeEvent} for the named property to all
+ * registered listeners. This private method is called by the
+ * {@link #setEnabled(boolean)} method.
*
- * @param propertyName The property that changed.
- * @param oldValue The old value of the property.
- * @param newValue The new value of the property.
+ * @param propertyName the property name.
+ * @param oldValue the old value of the property.
+ * @param newValue the new value of the property.
*/
- private void firePropertyChange(String propertyName, boolean oldValue, boolean newValue)
+ private void firePropertyChange(String propertyName, boolean oldValue,
+ boolean newValue)
{
changeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
/**
- * addPropertyChangeListener
+ * Registers a listener to receive {@link PropertyChangeEvent} notifications
+ * from this action.
*
- * @param listener the listener to add
+ * @param listener the listener.
+ *
+ * @see #removePropertyChangeListener(PropertyChangeListener)
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
@@ -254,9 +279,12 @@ public abstract class AbstractAction
}
/**
- * removePropertyChangeListener
+ * Deregisters a listener so that it no longer receives
+ * {@link PropertyChangeEvent} notifications from this action.
*
- * @param listener the listener to remove
+ * @param listener the listener.
+ *
+ * @see #addPropertyChangeListener(PropertyChangeListener)
*/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
@@ -266,7 +294,7 @@ public abstract class AbstractAction
/**
* Returns all registered listeners.
*
- * @return array of listeners.
+ * @return An array of listeners.
*
* @since 1.4
*/
diff --git a/libjava/classpath/javax/swing/AbstractButton.java b/libjava/classpath/javax/swing/AbstractButton.java
index 376b3a056ae..3d289084e20 100644
--- a/libjava/classpath/javax/swing/AbstractButton.java
+++ b/libjava/classpath/javax/swing/AbstractButton.java
@@ -159,6 +159,14 @@ public abstract class AbstractButton extends JComponent
private static final long serialVersionUID = 1471056094226600578L;
/**
+ * The spec has no public/protected constructor for this class, so do we.
+ */
+ ButtonChangeListener()
+ {
+ // Nothing to do here.
+ }
+
+ /**
* Notified when the target of the listener changes its state.
*
* @param ev the ChangeEvent describing the change
diff --git a/libjava/classpath/javax/swing/AbstractCellEditor.java b/libjava/classpath/javax/swing/AbstractCellEditor.java
index 4ed15809a83..df0d3db12b5 100644
--- a/libjava/classpath/javax/swing/AbstractCellEditor.java
+++ b/libjava/classpath/javax/swing/AbstractCellEditor.java
@@ -1,5 +1,5 @@
/* AbstractCellEditor.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -69,10 +69,11 @@ public abstract class AbstractCellEditor
/**
* Creates a new instance of AbstractCellEditor.
*/
- public AbstractCellEditor() {
+ public AbstractCellEditor()
+ {
listenerList = new EventListenerList();
changeEvent = new ChangeEvent(this);
- } // AbstractCellEditor()
+ }
/**
* Returns <code>true</code> if the cell is editable using
@@ -84,9 +85,10 @@ public abstract class AbstractCellEditor
* @return <code>true</code> if the cell is editable using
* <code>event</code>, <code>false</code> if it's not
*/
- public boolean isCellEditable(EventObject event) {
+ public boolean isCellEditable(EventObject event)
+ {
return true;
- } // isCellEditable()
+ }
/**
* Returns <code>true</code> if the editing cell should be selected,
@@ -99,29 +101,32 @@ public abstract class AbstractCellEditor
* @return <code>true</code> if the editing cell should be selected,
* <code>false</code> otherwise
*/
- public boolean shouldSelectCell(EventObject event) {
+ public boolean shouldSelectCell(EventObject event)
+ {
return true;
- } // shouldSelectCell()
+ }
/**
* Stop editing the cell and accept any partial value that has been entered
* into the cell.
*
- * @returns <code>true</code> if editing has been stopped successfully,
+ * @return <code>true</code> if editing has been stopped successfully,
* <code>false</code>otherwise
*/
- public boolean stopCellEditing() {
+ public boolean stopCellEditing()
+ {
fireEditingStopped();
return true;
- } // stopCellEditing()
+ }
/**
* Stop editing the cell and do not accept any partial value that has
* been entered into the cell.
*/
- public void cancelCellEditing() {
+ public void cancelCellEditing()
+ {
fireEditingCanceled();
- } // cancelCellEditing()
+ }
/**
* Adds a CellEditorListener to the list of CellEditorListeners of this
diff --git a/libjava/classpath/javax/swing/AbstractListModel.java b/libjava/classpath/javax/swing/AbstractListModel.java
index 8973e529232..4b89689ddda 100644
--- a/libjava/classpath/javax/swing/AbstractListModel.java
+++ b/libjava/classpath/javax/swing/AbstractListModel.java
@@ -1,5 +1,5 @@
/* AbstractListModel.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -58,6 +58,9 @@ public abstract class AbstractListModel implements ListModel, Serializable
/** List of ListDataListeners called for each change to the list. */
protected EventListenerList listenerList;
+ /**
+ * Creates a new model instance - initialises the event listener list.
+ */
public AbstractListModel()
{
listenerList = new EventListenerList();
@@ -88,7 +91,7 @@ public abstract class AbstractListModel implements ListModel, Serializable
/**
* Call {@link ListDataListener#contentsChanged} on each element of the
* {@link #listenerList} which is a {@link ListDataListener}. The event
- * fired has type {@ListDataEvent.CONTENTS_CHANGED} and represents a
+ * fired has type {@link ListDataEvent#CONTENTS_CHANGED} and represents a
* change to the data elements in the range [startIndex, endIndex]
* inclusive.
*
@@ -110,7 +113,7 @@ public abstract class AbstractListModel implements ListModel, Serializable
/**
* Call {@link ListDataListener#intervalAdded} on each element of the
* {@link #listenerList} which is a {@link ListDataListener}. The event
- * fired has type {@ListDataEvent.INTERVAL_ADDED} and represents an
+ * fired has type {@link ListDataEvent#INTERVAL_ADDED} and represents an
* addition of the data elements in the range [startIndex, endIndex]
* inclusive.
*
@@ -132,7 +135,7 @@ public abstract class AbstractListModel implements ListModel, Serializable
/**
* Call {@link ListDataListener#intervalRemoved} on each element of the
* {@link #listenerList} which is a {@link ListDataListener}. The event
- * fired has type {@ListDataEvent.INTERVAL_REMOVED} and represents a
+ * fired has type {@link ListDataEvent#INTERVAL_REMOVED} and represents a
* removal of the data elements in the range [startIndex, endIndex]
* inclusive.
*
diff --git a/libjava/classpath/javax/swing/CellEditor.java b/libjava/classpath/javax/swing/CellEditor.java
index 3d229b26675..9eb083ab25d 100644
--- a/libjava/classpath/javax/swing/CellEditor.java
+++ b/libjava/classpath/javax/swing/CellEditor.java
@@ -1,5 +1,5 @@
/* CellEditor.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -41,6 +41,7 @@ package javax.swing;
import java.util.EventObject;
import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
/**
* Provides edit capabilities for components that display cells like
@@ -51,46 +52,57 @@ import javax.swing.event.CellEditorListener;
public interface CellEditor
{
/**
- * getCellEditorValue
- * @returns Object
+ * Returns the current value for the <code>CellEditor</code>.
+ *
+ * @return The value.
*/
Object getCellEditorValue();
/**
- * isCellEditable
- * @param event TODO
- * @returns boolean
+ * Returns <code>true</code> if the specified event makes the editor
+ * editable, and <code>false</code> otherwise.
+ *
+ * @param event the event.
+ *
+ * @return A boolean.
*/
boolean isCellEditable(EventObject event);
/**
* shouldSelectCell
* @param event TODO
- * @returns boolean
+ * @return boolean
*/
boolean shouldSelectCell(EventObject event);
/**
- * stopCellEditing
- * @returns boolean
+ * Signals to the <code>CellEditor</code> that it should stop editing,
+ * accepting the current cell value, and returns <code>true</code> if the
+ * editor actually stops editing, and <code>false</code> otherwise.
+ *
+ * @return A boolean.
*/
boolean stopCellEditing();
/**
- * cancelCellEditing
+ * Signals to the <code>CellEditor</code> that it should cancel editing.
*/
void cancelCellEditing();
/**
- * addCellEditorListener
- * @param listener TODO
+ * Registers a listener to receive {@link ChangeEvent} notifications from the
+ * <code>CellEditor</code>.
+ *
+ * @param listener the listener.
*/
void addCellEditorListener(CellEditorListener listener);
/**
- * removeCellEditorListener
- * @param listener TODO
+ * Deregisters a listener so that it no longer receives {@link ChangeEvent}
+ * notifications from the <code>CellEditor</code>.
+ *
+ * @param listener the listener.
*/
void removeCellEditorListener(CellEditorListener listener);
-} // CellEditor
+}
diff --git a/libjava/classpath/javax/swing/CellRendererPane.java b/libjava/classpath/javax/swing/CellRendererPane.java
index c59afd3188a..b3d6f6a7364 100644
--- a/libjava/classpath/javax/swing/CellRendererPane.java
+++ b/libjava/classpath/javax/swing/CellRendererPane.java
@@ -1,5 +1,5 @@
/* CellRendererPane.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -75,7 +75,7 @@ public class CellRendererPane extends Container implements Accessible
/**
* getAccessibleRole
- * @returns AccessibleRole
+ * @return AccessibleRole
*/
public AccessibleRole getAccessibleRole()
{
@@ -169,24 +169,32 @@ public class CellRendererPane extends Container implements Accessible
addImpl(c, null, 0);
Rectangle oldClip = graphics.getClipBounds();
- // translate to (x,y)
- graphics.translate(x, y);
- graphics.clipRect(0, 0, w, h);
- // set bounds of c
- c.setBounds(0, 0, w, h);
-
- // validate if necessary
- if (shouldValidate)
+ boolean translated = false;
+ try
{
- c.validate();
+ // translate to (x,y)
+ graphics.translate(x, y);
+ translated = true;
+ graphics.clipRect(0, 0, w, h);
+ // set bounds of c
+ c.setBounds(0, 0, w, h);
+
+ // validate if necessary
+ if (shouldValidate)
+ {
+ c.validate();
+ }
+
+ // paint component
+ c.paint(graphics);
+ }
+ finally
+ {
+ // untranslate g
+ if (translated)
+ graphics.translate(-x, -y);
+ graphics.setClip(oldClip);
}
-
- // paint component
- c.paint(graphics);
-
- // untranslate g
- graphics.translate(-x, -y);
- graphics.setClip(oldClip);
}
/**
diff --git a/libjava/classpath/javax/swing/ComboBoxModel.java b/libjava/classpath/javax/swing/ComboBoxModel.java
index 6968db49091..61052758758 100644
--- a/libjava/classpath/javax/swing/ComboBoxModel.java
+++ b/libjava/classpath/javax/swing/ComboBoxModel.java
@@ -1,5 +1,5 @@
/* ComboBoxModel.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,31 +37,33 @@ exception statement from your version. */
package javax.swing;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
/**
- * The data model for {@link JComboBox}. This model keeps
- * track of elements contained in the JComboBox as well as the current
- * combo box selection. Whenever selection in the JComboBox changes, the
- * ComboBoxModel should fire ListDataEvents to ComboBox's ListDataListeners.
+ * The data model for a {@link JComboBox}. This model keeps track of elements
+ * contained in the <code>JComboBox</code> as well as the current
+ * combo box selection. Whenever the selection in the <code>JComboBox</code>
+ * changes, the <code>ComboBoxModel</code> should fire a {@link ListDataEvent}
+ * to the model's {@link ListDataListener}s.
*
* @author Andrew Selkirk
*/
public interface ComboBoxModel extends ListModel
{
/**
- * This method sets the selected item in the combo box. Class
- * implementing this interface should fire ListDataEvents to
- * all registered ListDataListeners to indicated that the
- * selection has changed.
+ * Sets the selected item in the combo box. Classes implementing this
+ * interface should fire a {@link ListDataEvent} to all registered
+ * {@link ListDataListener}s to indicate that the selection has changed.
*
- * @param item item in the combo box that should be selected
+ * @param item the selected item (<code>null</code> permitted).
*/
void setSelectedItem(Object item);
/**
- * The method returns currently selected item in the combo box
+ * Returns the currently selected item in the combo box.
*
- * @returns item that is currently selected in the combo box.
+ * @return The selected item (possibly <code>null</code>).
*/
Object getSelectedItem();
-} // ComboBoxModel
+}
diff --git a/libjava/classpath/javax/swing/DefaultCellEditor.java b/libjava/classpath/javax/swing/DefaultCellEditor.java
index 39e48551efb..7f1c395ad03 100644
--- a/libjava/classpath/javax/swing/DefaultCellEditor.java
+++ b/libjava/classpath/javax/swing/DefaultCellEditor.java
@@ -1,5 +1,5 @@
/* DefaultCellEditor.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -59,8 +59,7 @@ import javax.swing.tree.TreeCellEditor;
* some standard object types.
*
* @author Andrew Selkirk
- *
- * @status mostly unimplemented
+ * @author Audrius Meskauskas
*/
public class DefaultCellEditor
extends AbstractCellEditor
@@ -69,17 +68,26 @@ public class DefaultCellEditor
private static final long serialVersionUID = 3564035141373880027L;
/**
- * Delegates a couple of method calls (such as {@link #isCellEditable}
- * to the component it contains and listens for events that indicate
- * that editing has stopped.
+ * This changeable module access the editor component in the component
+ * specific way. For instance, to set the value for JTextField, we need to
+ * call setText(String), and for JCheckBox we need to call
+ * setSelected(boolean). Each default editor has the component specific
+ * derivative of this class. These derivatives are private inner classes of
+ * the DefaultCellEditor.
+ *
+ * The editor delegate is also set for the editor component as the action
+ * listener. It listens for the events that indicate that editing has stopped.
*/
protected class EditorDelegate
implements ActionListener, ItemListener, Serializable
{
+ /**
+ * Use the serial version UID for interoperability.
+ */
private static final long serialVersionUID = -1420007406015481933L;
/**
- * value
+ * The object value (updated when getting and setting the value).
*/
protected Object value;
@@ -90,35 +98,38 @@ public class DefaultCellEditor
{
// Nothing to do here.
}
-
+
/**
- * setValue
+ * Set the value for the editor component. This method is normally
+ * overridden to set the value in the way, specific for the text
+ * component, check box or combo box.
*
- * @param value TODO
+ * @param aValue the value to set (String, Boolean or Number).
*/
- public void setValue(Object value)
+ public void setValue(Object aValue)
{
- // TODO: should be setting the value in the editorComp
- this.value = value;
+ value = aValue;
}
- /**
- * getCellEditorValue
- *
- * @returns Object
+ /**
+ * Get the value for the editor component. This method is normally
+ * overridden to obtain the value in the way, specific for the text
+ * component, check box or combo box.
+ *
+ * @return value the value of the component (String, Boolean or Number).
*/
public Object getCellEditorValue()
{
- // TODO: should be getting the updated value from the editorComp
return value;
- } // getCellEditorValue()
+ }
/**
- * isCellEditable
+ * The default method returns true for the {@link MouseEvent} and false
+ * for any other events.
*
- * @param event TODO
+ * @param event the event to check
*
- * @returns boolean
+ * @return true if the passed event is the mouse event and false otherwise.
*/
public boolean isCellEditable(EventObject event)
{
@@ -129,22 +140,27 @@ public class DefaultCellEditor
} // isCellEditable()
/**
- * shouldSelectCell
+ * Returns true to indicate that the editing cell can be selected.
+ *
+ * The default method returns true without action but may be overridden
+ * in derived classes for more specific behavior.
*
- * @param event TODO
+ * @param event unused in default method
*
- * @returns boolean
+ * @return true always
*/
public boolean shouldSelectCell(EventObject event)
{
// return true to indicate that the editing cell may be selected
return true;
- } // shouldSelectCell()
+ }
/**
- * stopCellEditing
+ * Finish the cell editing session. This method notifies the registered
+ * cell editor listeners (including the table) that the editing has been
+ * stopped.
*
- * @returns boolean
+ * @return boolean
*/
public boolean stopCellEditing()
{
@@ -153,7 +169,11 @@ public class DefaultCellEditor
} // stopCellEditing()
/**
- * cancelCellEditing
+ * Cancel the cell editing session. This method notifies the registered
+ * cell editor listeners (including the table) that the editing has been
+ * canceled.
+ *
+ * @returns boolean
*/
public void cancelCellEditing()
{
@@ -161,11 +181,13 @@ public class DefaultCellEditor
} // cancelCellEditing()
/**
- * startCellEditing
+ * Start editing session and returns true to indicate the editing has begun.
+ * The default method returns true without action but may be overridden
+ * in derived classes for more specific behavior.
*
- * @param event TODO
- *
- * @returns boolean
+ * @param event the event.
+ *
+ * @return true, always
*/
public boolean startCellEditing(EventObject event)
{
@@ -174,9 +196,11 @@ public class DefaultCellEditor
} // startCellEditing()
/**
- * actionPerformed
+ * This event is fired by the editor component (for instance, by pressing
+ * ENTER in the {@link JTextField}. The default method delegates call to
+ * the {@link #stopCellEditing}, finishing the editing session.
*
- * @param event TODO
+ * @param event unused in default method
*/
public void actionPerformed(ActionEvent event)
{
@@ -184,15 +208,20 @@ public class DefaultCellEditor
} // actionPerformed()
/**
- * itemStateChanged
+ * This event is fired by the editor component.The default method delegates
+ * call to the {@link #stopCellEditing}, finishing the editing session.
*
- * @param event TODO
+ * @param event unused in default method
*/
public void itemStateChanged(ItemEvent event)
{
stopCellEditing();
} // itemStateChanged()
+ /**
+ * Notify the registered listeners (including the table) that the editing
+ * has been completed.
+ */
void fireEditingStopped()
{
CellEditorListener[] listeners = getCellEditorListeners();
@@ -201,6 +230,10 @@ public class DefaultCellEditor
}
+ /**
+ * Notify the registered listeners (including the table) that the editing
+ * has been canceled.
+ */
void fireEditingCanceled()
{
CellEditorListener[] listeners = getCellEditorListeners();
@@ -208,59 +241,185 @@ public class DefaultCellEditor
listeners[index].editingCanceled(changeEvent);
}
} // EditorDelegate
+
+ /**
+ * Provides getter and setter methods to work with the text component.
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+ private class JTextFieldDelegate extends EditorDelegate
+ {
+ /**
+ * Use the serial version UID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Set the value for the editor component.
+ *
+ * @param aValue the value to set (toString() will be called).
+ */
+ public void setValue(Object aValue)
+ {
+ value = aValue;
+ JTextField f = (JTextField) editorComponent;
+ if (value == null)
+ f.setText("");
+ else
+ f.setText(value.toString());
+ }
+
+ /**
+ * Get the value for the editor component.
+ *
+ * @return value the value of the component (String)
+ */
+ public Object getCellEditorValue()
+ {
+ JTextField f = (JTextField) editorComponent;
+ return value = f.getText();
+ }
+ }
+
+ /**
+ * Provides getter and setter methods to work with the combo box.
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+ private class JComboBoxDelegate extends EditorDelegate
+ {
+ /**
+ * Use the serial version UID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Set the value for the editor component.
+ *
+ * @param aValue the value to set.
+ */
+ public void setValue(Object aValue)
+ {
+ value = aValue;
+ JComboBox c = (JComboBox) editorComponent;
+ if (value != null)
+ c.setSelectedItem(value);
+ }
- /**
- * editorComponent
+ /**
+ * Get the value for the editor component.
+ *
+ * @return value the value of the component (as String)
+ */
+ public Object getCellEditorValue()
+ {
+ JComboBox c = (JComboBox) editorComponent;
+ return value = c.getSelectedItem();
+ }
+ }
+
+ /**
+ * Provides getter and setter methods to work with the check box.
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+ private class JCheckBoxDelegate extends EditorDelegate
+ {
+ /**
+ * Use the serial version UID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Set the value for the editor component.
+ *
+ * @param value the value to set (must be Boolean).
+ */
+ public void setValue(Object value)
+ {
+ JCheckBox c = (JCheckBox) editorComponent;
+
+ if (value == null)
+ c.setSelected(false);
+ else
+ c.setSelected( ((Boolean) value).booleanValue());
+ }
+
+ /**
+ * Get the value for the editor component.
+ *
+ * @return value the value of the component (must be CharSequence)
+ */
+ public Object getCellEditorValue()
+ {
+ JCheckBox c = (JCheckBox) editorComponent;
+ value = c.isSelected() ? Boolean.TRUE : Boolean.FALSE;
+ return value;
+ }
+ }
+
+ /**
+ * The Swing JComponent, performing the editing session.
*/
protected JComponent editorComponent;
/**
- * delegate
+ * The editor delegate, responsible for listening the {@link #editorComponent}
+ * events and getting/setting its value.
*/
protected EditorDelegate delegate;
/**
- * clickCountToStart
+ * The number of the mouse clicks, required to start the editing session.
*/
protected int clickCountToStart;
/**
- * Constructor DefaultCellEditor
+ * Create the DefaultCellEditor that uses the text field as its editor
+ * component (appropriate for the text content)
*
- * @param textfield TODO
+ * @param textfield the text field as will be used as the editor component
*/
public DefaultCellEditor(JTextField textfield)
{
editorComponent = textfield;
- clickCountToStart = 3;
+ clickCountToStart = 2;
+ delegate = new JTextFieldDelegate();
+ textfield.addActionListener(delegate);
} // DefaultCellEditor()
/**
- * Constructor DefaultCellEditor
+ * Constructor DefaultCellEditor that uses the checkbox (appropriate
+ * for boolean values)
*
- * @param checkbox TODO
+ * @param checkbox the checkbox that will be used with this editor.
*/
public DefaultCellEditor(JCheckBox checkbox)
{
editorComponent = checkbox;
clickCountToStart = 1;
+ delegate = new JCheckBoxDelegate();
+ checkbox.addActionListener(delegate);
} // DefaultCellEditor()
/**
- * Constructor DefaultCellEditor
+ * Constructor DefaultCellEditor that uses the combo box.
*
- * @param combobox TODO
+ * @param combobox the combo box that will be used with this editor.
*/
public DefaultCellEditor(JComboBox combobox)
{
editorComponent = combobox;
clickCountToStart = 1;
+ delegate = new JComboBoxDelegate();
+ combobox.addActionListener(delegate);
} // DefaultCellEditor()
/**
- * getComponent
+ * Get the component that performs the editing sessions. It is the same
+ * component that was passed in constructor.
*
- * @returns Component
+ * @return the component, performing the editing sessions.
*/
public Component getComponent()
{
@@ -268,9 +427,9 @@ public class DefaultCellEditor
} // getComponent()
/**
- * getClickCountToStart
+ * Get the number of mouse clicks, required to start the editing session.
*
- * @returns int
+ * @return int the number of mouse clicks, required to start the session
*/
public int getClickCountToStart()
{
@@ -278,9 +437,9 @@ public class DefaultCellEditor
} // getClickCountToStart()
/**
- * setClickCountToStart
+ * Set the number of mouse clicks, required to start the editing session.
*
- * @param count TODO
+ * @param count the number of clicks, required to start the session
*/
public void setClickCountToStart(int count)
{
@@ -288,9 +447,10 @@ public class DefaultCellEditor
} // setClickCountToStart()
/**
- * getCellEditorValue
+ * Get the value, currently being displayed by the editor component. The
+ * call is forwarded to the {@link #delegate}.
*
- * @returns Object
+ * @return Object the value (class depends on the editor component)
*/
public Object getCellEditorValue()
{
@@ -298,11 +458,11 @@ public class DefaultCellEditor
} // getCellEditorValue()
/**
- * isCellEditable
+ * Forwards call to the {@link #delegate}.
*
- * @param event TODO
+ * @param event forwarded to the delegate.
*
- * @returns boolean
+ * @return boolean returned by delegate
*/
public boolean isCellEditable(EventObject event)
{
@@ -310,11 +470,11 @@ public class DefaultCellEditor
} // isCellEditable()
/**
- * shouldSelectCell
+ * Forwards call to the {@link #delegate}.
*
- * @param event TODO
+ * @param event forwarded to the delegate.
*
- * @returns boolean
+ * @return boolean returned by delegate
*/
public boolean shouldSelectCell(EventObject event)
{
@@ -322,9 +482,9 @@ public class DefaultCellEditor
} // shouldSelectCell()
/**
- * stopCellEditing
+ * Forwards call to the {@link #delegate}.
*
- * @returns boolean
+ * @return boolean returned by delegate
*/
public boolean stopCellEditing()
{
@@ -332,7 +492,7 @@ public class DefaultCellEditor
} // stopCellEditing()
/**
- * cancelCellEditing
+ * Forwards call to the {@link #delegate}.
*/
public void cancelCellEditing()
{
@@ -356,45 +516,30 @@ public class DefaultCellEditor
* @param leaf - true if the node is a leaf node
* @param row - the row index of the node being edited
*
- * @returns Component the component for editing
+ * @return Component the component for editing
*/
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean isSelected,
boolean expanded, boolean leaf,
int row)
{
- if (editorComponent instanceof JTextField)
- {
- ((JTextField)editorComponent).setText(value.toString());
- delegate = new EditorDelegate();
- ((JTextField)editorComponent).addActionListener(delegate);
- }
- else if (editorComponent instanceof JCheckBox)
- {
- ((JCheckBox)editorComponent).setText(value.toString());
- delegate = new EditorDelegate();
- ((JCheckBox)editorComponent).addActionListener(delegate);
- }
- else if (editorComponent instanceof JComboBox)
- {
- ((JComboBox)editorComponent).setSelectedItem(value.toString());
- delegate = new EditorDelegate();
- ((JComboBox)editorComponent).addActionListener(delegate);
- }
-
+ delegate.setValue(value);
return editorComponent;
} // getTreeCellEditorComponent()
/**
- * getTableCellEditorComponent
+ * Get the cell editor component that will perform the editing session. If
+ * returned once, the same component is also returned on the repetetive calls
+ * again (reused).
*
- * @param table TODO
- * @param value TODO
- * @param isSelected TODO
- * @param row TODO
- * @param column TODO
- *
- * @returns Component
+ * @param table the table where the editing is performed
+ * @param value the current value of the table. It is set as the initial
+ * component value.
+ * @param isSelected if true, the cell is currently selected
+ * @param row the row of the cell being edited
+ * @param column the column of the cell being edited
+ *
+ * @return Component the component that will perform the editing session
*/
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row,
@@ -402,24 +547,9 @@ public class DefaultCellEditor
{
// NOTE: as specified by Sun, we don't call new() everytime, we return
// editorComponent on each call to getTableCellEditorComponent or
- // getTreeCellEditorComponent. However, currently JTextFields have a
- // problem with getting rid of old text, so without calling new() there
- // are some strange results. If you edit more than one cell in the table
- // text from previously edited cells may unexpectedly show up in the
- // cell you are currently editing. This will be fixed automatically
- // when JTextField is fixed.
- if (editorComponent instanceof JTextField)
- {
- ((JTextField)editorComponent).setText(value.toString());
- delegate = new EditorDelegate();
- ((JTextField)editorComponent).addActionListener(delegate);
- }
- else
- {
- // TODO
- }
+ // getTreeCellEditorComponent.
+ delegate.setValue(value);
return editorComponent;
} // getTableCellEditorComponent()
-
}
diff --git a/libjava/classpath/javax/swing/DefaultListCellRenderer.java b/libjava/classpath/javax/swing/DefaultListCellRenderer.java
index 9a8e07071b5..598627fac35 100644
--- a/libjava/classpath/javax/swing/DefaultListCellRenderer.java
+++ b/libjava/classpath/javax/swing/DefaultListCellRenderer.java
@@ -93,7 +93,7 @@ public class DefaultListCellRenderer extends JLabel
int index, boolean isSelected,
boolean cellHasFocus)
{
- String s = value.toString();
+ String s = value != null ? value.toString() : "";
setText(s);
setOpaque(true);
setHorizontalAlignment(LEFT);
diff --git a/libjava/classpath/javax/swing/DefaultListSelectionModel.java b/libjava/classpath/javax/swing/DefaultListSelectionModel.java
index ce1dfdd79c5..7ec4e614c8f 100644
--- a/libjava/classpath/javax/swing/DefaultListSelectionModel.java
+++ b/libjava/classpath/javax/swing/DefaultListSelectionModel.java
@@ -447,6 +447,9 @@ public class DefaultListSelectionModel implements Cloneable,
*/
public void addSelectionInterval(int index0, int index1)
{
+ if (index0 == -1 || index1 == -1)
+ return;
+
int lo = Math.min(index0, index1);
int hi = Math.max(index0, index1);
oldSel = sel.clone();
@@ -508,6 +511,9 @@ public class DefaultListSelectionModel implements Cloneable,
public void removeSelectionInterval(int index0,
int index1)
{
+ if (index0 == -1 || index1 == -1)
+ return;
+
oldSel = sel.clone();
int lo = Math.min(index0, index1);
int hi = Math.max(index0, index1);
@@ -551,6 +557,9 @@ public class DefaultListSelectionModel implements Cloneable,
*/
public void setSelectionInterval(int index0, int index1)
{
+ if (index0 == -1 || index1 == -1)
+ return;
+
oldSel = sel.clone();
sel.clear();
if (selectionMode == SINGLE_SELECTION)
diff --git a/libjava/classpath/javax/swing/ImageIcon.java b/libjava/classpath/javax/swing/ImageIcon.java
index b6ed949d8dc..9e6265830a3 100644
--- a/libjava/classpath/javax/swing/ImageIcon.java
+++ b/libjava/classpath/javax/swing/ImageIcon.java
@@ -205,13 +205,13 @@ public class ImageIcon
private static final long serialVersionUID = 532615968316031794L;
/** A dummy Component that is used in the MediaTracker. */
- protected static Component component = new Component()
+ protected static final Component component = new Component()
{
// No need to implement this.
};
/** The MediaTracker used to monitor the loading of images. */
- protected static MediaTracker tracker = new MediaTracker(component);
+ protected static final MediaTracker tracker = new MediaTracker(component);
/** The ID that is used in the tracker. */
private static int id;
diff --git a/libjava/classpath/javax/swing/JApplet.java b/libjava/classpath/javax/swing/JApplet.java
index e90c451891e..68eb983dd01 100644
--- a/libjava/classpath/javax/swing/JApplet.java
+++ b/libjava/classpath/javax/swing/JApplet.java
@@ -66,7 +66,7 @@ public class JApplet extends Applet
/**
* Creates a new instance of <code>AccessibleJApplet</code>.
*/
- public AccessibleJApplet()
+ protected AccessibleJApplet()
{
super();
// Nothing to do here.
diff --git a/libjava/classpath/javax/swing/JCheckBox.java b/libjava/classpath/javax/swing/JCheckBox.java
index 74fda8f6dbe..26f9f6ca595 100644
--- a/libjava/classpath/javax/swing/JCheckBox.java
+++ b/libjava/classpath/javax/swing/JCheckBox.java
@@ -67,7 +67,7 @@ public class JCheckBox extends JToggleButton implements Accessible
/**
* Creates a new instance of <code>AccessibleJCheckBox</code>.
*/
- public AccessibleJCheckBox()
+ protected AccessibleJCheckBox()
{
// Nothing to do here.
}
diff --git a/libjava/classpath/javax/swing/JComponent.java b/libjava/classpath/javax/swing/JComponent.java
index 747eba54db4..ddd70860869 100644
--- a/libjava/classpath/javax/swing/JComponent.java
+++ b/libjava/classpath/javax/swing/JComponent.java
@@ -1,5 +1,5 @@
/* JComponent.java -- Every component in swing inherits from this class.
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -64,10 +64,10 @@ import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
-import java.awt.geom.Rectangle2D;
import java.awt.peer.LightweightPeer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.io.Serializable;
@@ -88,7 +88,6 @@ import javax.swing.border.TitledBorder;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.EventListenerList;
-import javax.swing.event.SwingPropertyChangeSupport;
import javax.swing.plaf.ComponentUI;
/**
@@ -165,11 +164,11 @@ public abstract class JComponent extends Container implements Serializable
/**
* Manages the property change listeners;
*/
- private SwingPropertyChangeSupport changeSupport;
+ private PropertyChangeSupport changeSupport;
protected AccessibleJComponent()
{
- changeSupport = new SwingPropertyChangeSupport(this);
+ changeSupport = new PropertyChangeSupport(this);
}
/**
@@ -528,14 +527,6 @@ public abstract class JComponent extends Container implements Serializable
protected EventListenerList listenerList = new EventListenerList();
/**
- * Support for {@link PropertyChangeEvent} events. This is constructed
- * lazily when the component gets its first {@link
- * PropertyChangeListener} subscription; until then it's an empty slot.
- */
- private SwingPropertyChangeSupport changeSupport;
-
-
- /**
* Storage for "client properties", which are key/value pairs associated
* with this component by a "client", such as a user application or a
* layout manager. This is lazily constructed when the component gets its
@@ -697,36 +688,6 @@ public abstract class JComponent extends Container implements Serializable
}
/**
- * Unregister a <code>PropertyChangeListener</code>.
- *
- * @param listener The listener to register
- *
- * @see #addPropertyChangeListener(PropertyChangeListener)
- * @see #changeSupport
- */
- public void removePropertyChangeListener(PropertyChangeListener listener)
- {
- if (changeSupport != null)
- changeSupport.removePropertyChangeListener(listener);
- }
-
- /**
- * Unregister a <code>PropertyChangeListener</code>.
- *
- * @param propertyName The property name to unregister the listener from
- * @param listener The listener to unregister
- *
- * @see #addPropertyChangeListener(String, PropertyChangeListener)
- * @see #changeSupport
- */
- public void removePropertyChangeListener(String propertyName,
- PropertyChangeListener listener)
- {
- if (changeSupport != null)
- changeSupport.removePropertyChangeListener(propertyName, listener);
- }
-
- /**
* Unregister a <code>VetoableChangeChangeListener</code>.
*
* @param listener The listener to unregister
@@ -751,24 +712,6 @@ public abstract class JComponent extends Container implements Serializable
}
/**
- * Register a <code>PropertyChangeListener</code>. This listener will
- * receive any PropertyChangeEvent, regardless of property name. To
- * listen to a specific property name, use {@link
- * #addPropertyChangeListener(String,PropertyChangeListener)} instead.
- *
- * @param listener The listener to register
- *
- * @see #removePropertyChangeListener(PropertyChangeListener)
- * @see #changeSupport
- */
- public void addPropertyChangeListener(PropertyChangeListener listener)
- {
- if (changeSupport == null)
- changeSupport = new SwingPropertyChangeSupport(this);
- changeSupport.addPropertyChangeListener(listener);
- }
-
- /**
* Register a <code>PropertyChangeListener</code> for a specific, named
* property. To listen to all property changes, regardless of name, use
* {@link #addPropertyChangeListener(PropertyChangeListener)} instead.
@@ -819,7 +762,10 @@ public abstract class JComponent extends Container implements Serializable
*/
public EventListener[] getListeners(Class listenerType)
{
- return listenerList.getListeners(listenerType);
+ if (listenerType == PropertyChangeListener.class)
+ return getPropertyChangeListeners();
+ else
+ return listenerList.getListeners(listenerType);
}
/**
@@ -845,134 +791,48 @@ public abstract class JComponent extends Container implements Serializable
}
/**
- * Return all <code>PropertyChangeListener</code> objects registered to listen
- * for a particular property.
- *
- * @param property The property to return the listeners of
- *
- * @return The set of <code>PropertyChangeListener</code> objects in
- * {@link #changeSupport} registered to listen on the specified property
- */
- public PropertyChangeListener[] getPropertyChangeListeners(String property)
- {
- return changeSupport == null ? new PropertyChangeListener[0]
- : changeSupport.getPropertyChangeListeners(property);
- }
-
- /**
* A variant of {@link #firePropertyChange(String,Object,Object)}
* for properties with <code>boolean</code> values.
+ *
+ * @specnote It seems that in JDK1.5 all property related methods have been
+ * moved to java.awt.Component, except this and 2 others. We call
+ * super here. I guess this will also be removed in one of the next
+ * releases.
*/
public void firePropertyChange(String propertyName, boolean oldValue,
boolean newValue)
{
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, Boolean.valueOf(oldValue),
- Boolean.valueOf(newValue));
- }
-
- /**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>byte</code> values.
- */
- public void firePropertyChange(String propertyName, byte oldValue,
- byte newValue)
- {
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, new Byte(oldValue),
- new Byte(newValue));
+ super.firePropertyChange(propertyName, oldValue, newValue);
}
/**
* A variant of {@link #firePropertyChange(String,Object,Object)}
* for properties with <code>char</code> values.
+ *
+ * @specnote It seems that in JDK1.5 all property related methods have been
+ * moved to java.awt.Component, except this and 2 others. We call
+ * super here. I guess this will also be removed in one of the next
+ * releases.
*/
public void firePropertyChange(String propertyName, char oldValue,
char newValue)
{
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, new Character(oldValue),
- new Character(newValue));
- }
-
- /**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>double</code> values.
- */
- public void firePropertyChange(String propertyName, double oldValue,
- double newValue)
- {
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, new Double(oldValue),
- new Double(newValue));
- }
-
- /**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>float</code> values.
- */
- public void firePropertyChange(String propertyName, float oldValue,
- float newValue)
- {
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, new Float(oldValue),
- new Float(newValue));
+ super.firePropertyChange(propertyName, oldValue, newValue);
}
/**
* A variant of {@link #firePropertyChange(String,Object,Object)}
* for properties with <code>int</code> values.
+ *
+ * @specnote It seems that in JDK1.5 all property related methods have been
+ * moved to java.awt.Component, except this and 2 others. We call
+ * super here. I guess this will also be removed in one of the next
+ * releases.
*/
public void firePropertyChange(String propertyName, int oldValue,
int newValue)
{
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, new Integer(oldValue),
- new Integer(newValue));
- }
-
- /**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>long</code> values.
- */
- public void firePropertyChange(String propertyName, long oldValue,
- long newValue)
- {
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, new Long(oldValue),
- new Long(newValue));
- }
-
- /**
- * Call {@link PropertyChangeListener#propertyChange} on all listeners
- * registered to listen to a given property. Any method which changes
- * the specified property of this component should call this method.
- *
- * @param propertyName The property which changed
- * @param oldValue The old value of the property
- * @param newValue The new value of the property
- *
- * @see #changeSupport
- * @see #addPropertyChangeListener(PropertyChangeListener)
- * @see #removePropertyChangeListener(PropertyChangeListener)
- */
- protected void firePropertyChange(String propertyName, Object oldValue,
- Object newValue)
- {
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, oldValue, newValue);
- }
-
- /**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>short</code> values.
- */
- public void firePropertyChange(String propertyName, short oldValue,
- short newValue)
- {
- if (changeSupport != null)
- changeSupport.firePropertyChange(propertyName, new Short(oldValue),
- new Short(newValue));
+ super.firePropertyChange(propertyName, oldValue, newValue);
}
/**
@@ -1518,9 +1378,8 @@ public abstract class JComponent extends Container implements Serializable
{
((JComponent) c).computeVisibleRect(rect);
rect.translate(-getX(), -getY());
- Rectangle2D.intersect(rect,
- new Rectangle(0, 0, getWidth(), getHeight()),
- rect);
+ rect = SwingUtilities.computeIntersection(0, 0, getWidth(),
+ getHeight(), rect);
}
else
rect.setRect(0, 0, getWidth(), getHeight());
@@ -1530,7 +1389,7 @@ public abstract class JComponent extends Container implements Serializable
* Return the component's visible rectangle in a new {@link Rectangle},
* rather than via a return slot.
*
- * @return The component's visible rectangle
+ * @return the component's visible rectangle
*
* @see #computeVisibleRect(Rectangle)
*/
@@ -1691,7 +1550,10 @@ public abstract class JComponent extends Container implements Serializable
// screen.
if (!isPaintingDoubleBuffered && isDoubleBuffered()
&& rm.isDoubleBufferingEnabled())
- paintDoubleBuffered(g);
+ {
+ Rectangle clip = g.getClipBounds();
+ paintDoubleBuffered(clip);
+ }
else
{
if (g.getClip() == null)
@@ -1755,11 +1617,10 @@ public abstract class JComponent extends Container implements Serializable
// optimizedDrawingEnabled (== it tiles its children).
if (! isOptimizedDrawingEnabled())
{
- Rectangle clip = g.getClipBounds();
for (int i = 0; i < children.length; i++)
{
Rectangle childBounds = children[i].getBounds();
- if (children[i].isOpaque()
+ if (children[i].isOpaque() && children[i].isVisible()
&& SwingUtilities.isRectangleContainingRectangle(childBounds,
g.getClipBounds()))
{
@@ -1892,33 +1753,29 @@ public abstract class JComponent extends Container implements Serializable
void paintImmediately2(Rectangle r)
{
RepaintManager rm = RepaintManager.currentManager(this);
- Graphics g = getGraphics();
- g.setClip(r.x, r.y, r.width, r.height);
if (rm.isDoubleBufferingEnabled() && isDoubleBuffered())
- paintDoubleBuffered(g);
+ paintDoubleBuffered(r);
else
- paintSimple(g);
- g.dispose();
+ paintSimple(r);
}
/**
* Performs double buffered repainting.
- *
- * @param g the graphics context to paint to
*/
- void paintDoubleBuffered(Graphics g)
+ private void paintDoubleBuffered(Rectangle r)
{
-
- Rectangle r = g.getClipBounds();
- if (r == null)
- r = new Rectangle(0, 0, getWidth(), getHeight());
RepaintManager rm = RepaintManager.currentManager(this);
// Paint on the offscreen buffer.
- Image buffer = rm.getOffscreenBuffer(this, getWidth(), getHeight());
+ Component root = SwingUtilities.getRoot(this);
+ Image buffer = rm.getOffscreenBuffer(this, root.getWidth(),
+ root.getHeight());
+ //Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root);
+ Point translation = SwingUtilities.convertPoint(this, 0, 0, root);
Graphics g2 = buffer.getGraphics();
- g2 = getComponentGraphics(g2);
+ g2.translate(translation.x, translation.y);
g2.setClip(r.x, r.y, r.width, r.height);
+ g2 = getComponentGraphics(g2);
isPaintingDoubleBuffered = true;
try
{
@@ -1929,20 +1786,27 @@ public abstract class JComponent extends Container implements Serializable
isPaintingDoubleBuffered = false;
g2.dispose();
}
-
+
// Paint the buffer contents on screen.
- g.drawImage(buffer, 0, 0, this);
+ rm.commitBuffer(root, new Rectangle(translation.x + r.x,
+ translation.y + r.y, r.width,
+ r.height));
}
/**
* Performs normal painting without double buffering.
*
- * @param g the graphics context to use
+ * @param r the area that should be repainted
*/
- void paintSimple(Graphics g)
+ void paintSimple(Rectangle r)
{
+ Graphics g = getGraphics();
Graphics g2 = getComponentGraphics(g);
+ g2.setClip(r);
paint(g2);
+ g2.dispose();
+ if (g != g2)
+ g.dispose();
}
/**
@@ -2339,12 +2203,8 @@ public abstract class JComponent extends Container implements Serializable
*/
public void repaint(long tm, int x, int y, int width, int height)
{
- Rectangle dirty = new Rectangle(x, y, width, height);
- Rectangle vis = getVisibleRect();
- dirty = dirty.intersection(vis);
- RepaintManager.currentManager(this).addDirtyRegion(this, dirty.x, dirty.y,
- dirty.width,
- dirty.height);
+ RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width,
+ height);
}
/**
@@ -2356,8 +2216,8 @@ public abstract class JComponent extends Container implements Serializable
*/
public void repaint(Rectangle r)
{
- repaint((long) 0, (int) r.getX(), (int) r.getY(), (int) r.getWidth(),
- (int) r.getHeight());
+ RepaintManager.currentManager(this).addDirtyRegion(this, r.x, r.y, r.width,
+ r.height);
}
/**
@@ -2879,7 +2739,7 @@ public abstract class JComponent extends Container implements Serializable
*
* @since 1.4
*/
- public boolean requestFocusInWindow(boolean temporary)
+ protected boolean requestFocusInWindow(boolean temporary)
{
return super.requestFocusInWindow(temporary);
}
@@ -3046,19 +2906,6 @@ public abstract class JComponent extends Container implements Serializable
}
/**
- * Return all <code>PropertyChangeListener</code> objects registered.
- *
- * @return The set of <code>PropertyChangeListener</code> objects
- */
- public PropertyChangeListener[] getPropertyChangeListeners()
- {
- if (changeSupport == null)
- return new PropertyChangeListener[0];
- else
- return changeSupport.getPropertyChangeListeners();
- }
-
- /**
* Prints this component to the given Graphics context. A call to this
* method results in calls to the methods {@link #printComponent},
* {@link #printBorder} and {@link #printChildren} in this order.
@@ -3098,7 +2945,7 @@ public abstract class JComponent extends Container implements Serializable
*
* @since 1.3
*/
- public void printComponent(Graphics g)
+ protected void printComponent(Graphics g)
{
paintComponent(g);
}
@@ -3112,7 +2959,7 @@ public abstract class JComponent extends Container implements Serializable
*
* @since 1.3
*/
- public void printChildren(Graphics g)
+ protected void printChildren(Graphics g)
{
paintChildren(g);
}
@@ -3126,7 +2973,7 @@ public abstract class JComponent extends Container implements Serializable
*
* @since 1.3
*/
- public void printBorder(Graphics g)
+ protected void printBorder(Graphics g)
{
paintBorder(g);
}
@@ -3245,62 +3092,25 @@ public abstract class JComponent extends Container implements Serializable
while (parent != null && !(parent instanceof Window))
{
Container newParent = parent.getParent();
- if (newParent == null)
+ if (newParent == null || newParent instanceof Window)
break;
// If the parent is optimizedDrawingEnabled, then its children are
// tiled and cannot have an overlapping child. Go directly to next
// parent.
- if (newParent instanceof JComponent
- && ((JComponent) newParent).isOptimizedDrawingEnabled())
+ if ((newParent instanceof JComponent
+ && ((JComponent) newParent).isOptimizedDrawingEnabled()))
+
{
parent = newParent;
continue;
}
-
- // First we must check if the new parent itself somehow clips the
- // target rectangle. This can happen in JViewports.
- Rectangle parRect = new Rectangle(0, 0, newParent.getWidth(),
- newParent.getHeight());
+ // If the parent is not optimizedDrawingEnabled, we must paint the
+ // parent.
Rectangle target = SwingUtilities.convertRectangle(found,
currentClip,
newParent);
- if (! target.intersection(parRect).equals(target))
- {
- found = newParent;
- currentClip = target;
- parent = newParent;
- continue;
- }
-
- // Otherwise we must check if one of the children of this parent
- // overlaps with the current component.
- Component[] children = newParent.getComponents();
- // This flag is used to skip components that are 'below' the component
- // in question.
- boolean skip = true;
- for (int i = children.length - 1; i >= 0; i--)
- {
- boolean nextSkip = skip;
- if (children[i] == parent)
- nextSkip = false;
- if (skip)
- continue;
- skip = nextSkip;
- Component c = children[i];
- Rectangle compBounds = c.getBounds();
- // If the component completely overlaps the clip in question, we
- // don't need to repaint. Return null.
- if (compBounds.contains(target))
- return null;
- if (compBounds.intersects(target))
- {
- // We found a parent whose children overlap with our current
- // component. Make this the current component.
- found = newParent;
- currentClip = target;
- break;
- }
- }
+ found = newParent;
+ currentClip = target;
parent = newParent;
}
return found;
diff --git a/libjava/classpath/javax/swing/JDialog.java b/libjava/classpath/javax/swing/JDialog.java
index b3f7c011f68..08dada2fd81 100644
--- a/libjava/classpath/javax/swing/JDialog.java
+++ b/libjava/classpath/javax/swing/JDialog.java
@@ -74,7 +74,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants,
/**
* Creates a new instance of <code>AccessibleJDialog</code>.
*/
- public AccessibleJDialog()
+ protected AccessibleJDialog()
{
super();
// Nothing to do here.
@@ -107,7 +107,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants,
*/
public JDialog()
{
- this(SwingUtilities.getOwnerFrame(), "", false, null);
+ this((Frame) SwingUtilities.getOwnerFrame(null), "", false, null);
}
/**
@@ -234,8 +234,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants,
public JDialog(Frame owner, String title, boolean modal,
GraphicsConfiguration gc)
{
- super((owner == null) ? SwingUtilities.getOwnerFrame() : owner,
- title, modal, gc);
+ super((Frame) SwingUtilities.getOwnerFrame(owner), title, modal, gc);
dialogInit();
}
diff --git a/libjava/classpath/javax/swing/JEditorPane.java b/libjava/classpath/javax/swing/JEditorPane.java
index 3560ffd57d4..73b775738de 100644
--- a/libjava/classpath/javax/swing/JEditorPane.java
+++ b/libjava/classpath/javax/swing/JEditorPane.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing;
+import java.awt.Container;
import java.awt.Dimension;
import java.io.IOException;
import java.io.InputStream;
@@ -682,27 +683,59 @@ public class JEditorPane extends JTextComponent
}
/**
- * Returns the preferred size for the JEditorPane.
+ * Returns the preferred size for the JEditorPane. This is implemented to
+ * return the super's preferred size, unless one of
+ * {@link #getScrollableTracksViewportHeight()} or
+ * {@link #getScrollableTracksViewportWidth()} returns <code>true</code>,
+ * in which case the preferred width and/or height is replaced by the UI's
+ * minimum size.
+ *
+ * @return the preferred size for the JEditorPane
*/
public Dimension getPreferredSize()
{
- return super.getPreferredSize();
+ Dimension pref = super.getPreferredSize();
+ if (getScrollableTracksViewportWidth())
+ pref.width = getUI().getMinimumSize(this).width;
+ if (getScrollableTracksViewportHeight())
+ pref.height = getUI().getMinimumSize(this).height;
+ return pref;
}
+ /**
+ * Returns <code>true</code> when a Viewport should force the height of
+ * this component to match the viewport height. This is implemented to return
+ * <code>true</code> when the parent is an instance of JViewport and
+ * the viewport height > the UI's minimum height.
+ *
+ * @return <code>true</code> when a Viewport should force the height of
+ * this component to match the viewport height
+ */
public boolean getScrollableTracksViewportHeight()
{
- /* Container parent = getParent();
- return (parent instanceof JViewport &&
- parent.isValid());*/
- return isValid();
+ // Tests show that this returns true when the parent is a JViewport
+ // and has a height > minimum UI height.
+ Container parent = getParent();
+ return parent instanceof JViewport
+ && parent.getHeight() > getUI().getMinimumSize(this).height;
}
+ /**
+ * Returns <code>true</code> when a Viewport should force the width of
+ * this component to match the viewport width. This is implemented to return
+ * <code>true</code> when the parent is an instance of JViewport and
+ * the viewport width > the UI's minimum width.
+ *
+ * @return <code>true</code> when a Viewport should force the width of
+ * this component to match the viewport width
+ */
public boolean getScrollableTracksViewportWidth()
{
- /*Container parent = getParent();
- return (parent instanceof JViewport &&
- parent.isValid());*/
- return isValid();
+ // Tests show that this returns true when the parent is a JViewport
+ // and has a width > minimum UI width.
+ Container parent = getParent();
+ return parent != null && parent instanceof JViewport
+ && parent.getWidth() > getUI().getMinimumSize(this).width;
}
public URL getPage()
@@ -893,7 +926,7 @@ public class JEditorPane extends JTextComponent
// Remove the current content.
Document doc = getDocument();
doc.remove(0, doc.getLength());
- if (t == null || t == "")
+ if (t == null || t.equals(""))
return;
// Let the EditorKit read the text into the Document.
diff --git a/libjava/classpath/javax/swing/JFileChooser.java b/libjava/classpath/javax/swing/JFileChooser.java
index 3a9d6a01f38..72bd2bb28f5 100644
--- a/libjava/classpath/javax/swing/JFileChooser.java
+++ b/libjava/classpath/javax/swing/JFileChooser.java
@@ -40,7 +40,6 @@ package javax.swing;
import java.awt.Component;
import java.awt.Frame;
import java.awt.HeadlessException;
-import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
@@ -658,8 +657,7 @@ public class JFileChooser extends JComponent implements Accessible
retval = ERROR_OPTION;
- Insets i = d.getInsets();
- d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height);
+ d.pack();
d.show();
return retval;
}
@@ -683,8 +681,7 @@ public class JFileChooser extends JComponent implements Accessible
retval = ERROR_OPTION;
- Insets i = d.getInsets();
- d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height);
+ d.pack();
d.show();
return retval;
}
@@ -710,8 +707,7 @@ public class JFileChooser extends JComponent implements Accessible
retval = ERROR_OPTION;
- Insets i = d.getInsets();
- d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height);
+ d.pack();
d.show();
return retval;
}
@@ -729,7 +725,7 @@ public class JFileChooser extends JComponent implements Accessible
{
Frame toUse = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent);
if (toUse == null)
- toUse = SwingUtilities.getOwnerFrame();
+ toUse = (Frame) SwingUtilities.getOwnerFrame(null);
JDialog dialog = new JDialog(toUse);
setSelectedFile(null);
diff --git a/libjava/classpath/javax/swing/JFrame.java b/libjava/classpath/javax/swing/JFrame.java
index 8d4dcb53b3c..d2512056085 100644
--- a/libjava/classpath/javax/swing/JFrame.java
+++ b/libjava/classpath/javax/swing/JFrame.java
@@ -76,7 +76,7 @@ public class JFrame extends Frame
/**
* Creates a new instance of <code>AccessibleJFrame</code>.
*/
- public AccessibleJFrame()
+ protected AccessibleJFrame()
{
super();
// Nothing to do here.
@@ -150,6 +150,15 @@ public class JFrame extends Frame
super.setLayout(new BorderLayout(1, 1));
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
getRootPane(); // will do set/create
+
+ // Setup the defaultLookAndFeelDecoration if requested.
+ if (isDefaultLookAndFeelDecorated()
+ && UIManager.getLookAndFeel().getSupportsWindowDecorations())
+ {
+ setUndecorated(true);
+ getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
+ }
+
// We're now done the init stage.
setRootPaneCheckingEnabled(true);
}
diff --git a/libjava/classpath/javax/swing/JInternalFrame.java b/libjava/classpath/javax/swing/JInternalFrame.java
index 948988c24a7..5bd6f781cd0 100644
--- a/libjava/classpath/javax/swing/JInternalFrame.java
+++ b/libjava/classpath/javax/swing/JInternalFrame.java
@@ -559,6 +559,8 @@ public class JInternalFrame extends JComponent implements Accessible,
this.iconable = iconifiable;
storedBounds = new Rectangle();
setRootPane(createRootPane());
+ // JInternalFrames are invisible by default.
+ setVisible(false);
updateUI();
setRootPaneCheckingEnabled(true); // Done the init stage, now adds go to content pane.
}
@@ -616,7 +618,7 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void dispose()
{
- hide();
+ setVisible(false);
JDesktopPane pane = getDesktopPane();
if (pane != null)
pane.setSelectedFrame(null);
@@ -647,11 +649,11 @@ public class JInternalFrame extends JComponent implements Accessible,
switch (getDefaultCloseOperation())
{
case HIDE_ON_CLOSE:
- hide();
- break;
+ setVisible(false);
+ break;
case DISPOSE_ON_CLOSE:
- dispose();
- break;
+ dispose();
+ break;
}
}
@@ -1257,13 +1259,14 @@ public class JInternalFrame extends JComponent implements Accessible,
{
if (b && ! isClosed())
{
- fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING);
- fireVetoableChange(IS_CLOSED_PROPERTY, false, true);
+ fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING);
+ fireVetoableChange(IS_CLOSED_PROPERTY, false, true);
- isClosed = b;
+ isClosed = b;
+ dispose();
- firePropertyChange(IS_CLOSED_PROPERTY, false, true);
- fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED);
+ firePropertyChange(IS_CLOSED_PROPERTY, false, true);
+ fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED);
}
}
@@ -1628,27 +1631,27 @@ public class JInternalFrame extends JComponent implements Accessible,
{
if (! isVisible())
{
- super.show();
-
- JDesktopPane pane = getDesktopPane();
- if (pane != null)
- pane.setSelectedFrame(this);
- else
- {
- try
- {
- setSelected(true);
- }
- catch (PropertyVetoException e)
- {
- // Do nothing. if they don't want to be selected.
- }
- }
- if (isFirstTimeVisible)
- {
- isFirstTimeVisible = false;
- fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED);
- }
+ super.show();
+
+ JDesktopPane pane = getDesktopPane();
+ if (pane != null)
+ pane.setSelectedFrame(this);
+ else
+ {
+ try
+ {
+ setSelected(true);
+ }
+ catch (PropertyVetoException e)
+ {
+ // Do nothing. if they don't want to be selected.
+ }
+ }
+ if (isFirstTimeVisible)
+ {
+ isFirstTimeVisible = false;
+ fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED);
+ }
}
}
diff --git a/libjava/classpath/javax/swing/JLayeredPane.java b/libjava/classpath/javax/swing/JLayeredPane.java
index dc8b10d2178..ffd803c8706 100644
--- a/libjava/classpath/javax/swing/JLayeredPane.java
+++ b/libjava/classpath/javax/swing/JLayeredPane.java
@@ -43,11 +43,7 @@ import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Rectangle;
-import java.awt.Shape;
import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeMap;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
@@ -119,6 +115,7 @@ import javax.accessibility.AccessibleRole;
* component indexing and position order</p>
*
* @author Graydon Hoare (graydon@redhat.com)
+ * @author Roman Kennke (kennke@aicas.com)
*/
public class JLayeredPane extends JComponent implements Accessible
{
@@ -131,7 +128,7 @@ public class JLayeredPane extends JComponent implements Accessible
/**
* Creates a new instance of <code>AccessibleJLayeredPane</code>.
*/
- public AccessibleJLayeredPane()
+ protected AccessibleJLayeredPane()
{
// Nothing to do here.
}
@@ -150,22 +147,18 @@ public class JLayeredPane extends JComponent implements Accessible
public static final String LAYER_PROPERTY = "layeredContainerLayer";
- public static Integer FRAME_CONTENT_LAYER = new Integer (-30000);
+ public static final Integer FRAME_CONTENT_LAYER = new Integer (-30000);
- public static Integer DEFAULT_LAYER = new Integer (0);
- public static Integer PALETTE_LAYER = new Integer (100);
- public static Integer MODAL_LAYER = new Integer (200);
- public static Integer POPUP_LAYER = new Integer (300);
- public static Integer DRAG_LAYER = new Integer (400);
+ public static final Integer DEFAULT_LAYER = new Integer (0);
+ public static final Integer PALETTE_LAYER = new Integer (100);
+ public static final Integer MODAL_LAYER = new Integer (200);
+ public static final Integer POPUP_LAYER = new Integer (300);
+ public static final Integer DRAG_LAYER = new Integer (400);
- TreeMap layers; // Layer Number (Integer) -> Layer Size (Integer)
- Hashtable componentToLayer; // Component -> Layer Number (Integer)
+ private Hashtable componentToLayer; // Component -> Layer Number (Integer)
- private transient Rectangle rectCache;
-
public JLayeredPane()
{
- layers = new TreeMap ();
componentToLayer = new Hashtable ();
setLayout(null);
}
@@ -173,47 +166,50 @@ public class JLayeredPane extends JComponent implements Accessible
/**
* Looks up the layer a child component is currently assigned to.
*
+ * If <code>c</code> is an instance of {@link JComponent}, then the layer
+ * is fetched from the client property with the key {@link #LAYER_PROPERTY}.
+ * Otherwise it is looked up in an internal hashtable that maps
+ * non-JComponent components to layers. If the components cannot be found
+ * in either way, the {@link #DEFAULT_LAYER} is returned.
+ *
* @param c the component to look up.
- * @return the layer the component is currently assigned to, in this container.
- * @throws IllegalArgumentException if the component is not a child of this container.
+ *
+ * @return the layer the component is currently assigned to; if the component
+ * is not in this layered pane, then 0 (DEFAULT_LAYER) is returned
*/
public int getLayer(Component c)
{
- Component myComp = c;
- while(! componentToLayer.containsKey(myComp))
+ Integer layerObj;
+ if (c instanceof JComponent)
{
- myComp = myComp.getParent();
- if (myComp == null)
- break;
+ JComponent jc = (JComponent) c;
+ layerObj = (Integer) jc.getClientProperty(LAYER_PROPERTY);
}
- if (myComp == null)
- throw new IllegalArgumentException
- ("component is not in this JLayeredPane");
- Integer layerObj = (Integer) componentToLayer.get(myComp);
+ else
+ layerObj = (Integer) componentToLayer.get(c);
+
+ if (layerObj == null)
+ layerObj = DEFAULT_LAYER;
+
return layerObj.intValue();
}
/**
- * Looks up the layer of <code>comp</code> in the component's nearest
- * JLayeredPane ancestor. If <code>comp</code> is not contained
- * in a JLayeredPane, the value 0 (default layer) is returned.
- *
+ * Looks up the layer in the client property with the key
+ * {@link #LAYER_PROPERTY} of <code>comp</code>. If no such property can be
+ * found, we return <code>0</code> ({@link #DEFAULT_LAYER}).
+ *
* @param comp the component for which the layer is looked up
*
- * @return the layer of <code>comp</code> in its nearest JLayeredPane
- * ancestor
+ * @return the layer of <code>comp</code> as stored in the corresponding
+ * client property, or <code>0</code> if there is no such property
*/
public static int getLayer(JComponent comp)
{
- JLayeredPane lp = (JLayeredPane) SwingUtilities.getAncestorOfClass
- (JLayeredPane.class, comp);
- if (lp == null)
- return 0;
- else
- // The cast here forces the call to the instance method getLayer()
- // instead of the static method (this would lead to infinite
- // recursion).
- return lp.getLayer((Component) comp);
+ Integer layerObj = (Integer) comp.getClientProperty(LAYER_PROPERTY);
+ if (layerObj == null)
+ layerObj = DEFAULT_LAYER;
+ return layerObj.intValue();
}
/**
@@ -236,105 +232,49 @@ public class JLayeredPane extends JComponent implements Accessible
}
/**
- * <p>Returns a pair of ints representing a half-open interval
- * <code>[top, bottom)</code>, which is the range of component indices
- * the provided layer number corresponds to.</p>
- *
- * <p>Note that "bottom" is <em>not</em> included in the interval of
- * component indices in this layer: a layer with 0 elements in it has
- * <code>ret[0] == ret[1]</code>.</p>
- *
- * @param layer the layer to look up.
- * @return the half-open range of indices this layer spans.
- * @throws IllegalArgumentException if layer does not refer to an active layer
- * in this container.
- */
- private int[] layerToRange (Integer layer)
- {
- int[] ret = new int[2];
- ret[1] = getComponents ().length;
- Iterator i = layers.entrySet ().iterator ();
- while (i.hasNext())
- {
- Map.Entry pair = (Map.Entry) i.next();
- Integer layerNum = (Integer) pair.getKey ();
- Integer layerSz = (Integer) pair.getValue ();
- int layerInt = layerNum.intValue();
- if (layerInt == layer.intValue())
- {
- ret[0] = ret[1] - layerSz.intValue ();
- break;
- }
- // In the following case there exists no layer with the specified
- // number, so we return an empty interval here with the index at which
- // such a layer would be inserted
- else if (layerInt > layer.intValue())
- {
- ret[1] = ret[0];
- break;
- }
- else
- {
- ret[1] -= layerSz.intValue ();
- }
- }
- return ret;
- }
-
- /**
- * Increments the recorded size of a given layer.
- *
- * @param layer the layer number to increment.
- * @see #incrLayer
- */
- private void incrLayer(Integer layer)
- {
- int sz = 1;
- if (layers.containsKey (layer))
- sz += ((Integer)(layers.get (layer))).intValue ();
- layers.put (layer, new Integer(sz));
- }
-
- /**
- * Decrements the recorded size of a given layer.
- *
- * @param layer the layer number to decrement.
- * @see #incrLayer
- */
- private void decrLayer(Integer layer)
- {
- int sz = 0;
- if (layers.containsKey (layer))
- sz = ((Integer)(layers.get (layer))).intValue () - 1;
- layers.put (layer, new Integer(sz));
- }
-
- /**
* Return the greatest layer number currently in use, in this container.
* This number may legally be positive <em>or</em> negative.
*
- * @return the least layer number.
+ * @return the highest layer number
+ *
* @see #lowestLayer()
*/
public int highestLayer()
{
- if (layers.size() == 0)
- return 0;
- return ((Integer)(layers.lastKey ())).intValue ();
+ Component[] components = getComponents();
+ int highest;
+ if (components.length == 0)
+ highest = 0;
+ else
+ {
+ highest = Integer.MIN_VALUE;
+ for (int i = 0; i < components.length; i++)
+ highest = Math.max(highest, getLayer(components[i]));
+ }
+ return highest;
}
/**
* Return the least layer number currently in use, in this container.
* This number may legally be positive <em>or</em> negative.
*
- * @return the least layer number.
+ * @return the least layer number
+ *
* @see #highestLayer()
*/
public int lowestLayer()
{
- if (layers.size() == 0)
- return 0;
- return ((Integer)(layers.firstKey ())).intValue ();
+ Component[] components = getComponents();
+ int lowest;
+ if (components.length == 0)
+ lowest = 0;
+ else
+ {
+ lowest = Integer.MAX_VALUE;
+ for (int i = 0; i < components.length; i++)
+ lowest = Math.max(lowest, getLayer(components[i]));
+ }
+ return lowest;
}
/**
@@ -343,9 +283,8 @@ public class JLayeredPane extends JComponent implements Accessible
* layer, so is usually the component which occludes the most other
* components in its layer.
*
- * @param c the component to move to the front of its layer.
- * @throws IllegalArgumentException if the component is not a child of
- * this container.
+ * @param c the component to move to the front of its layer
+ *
* @see #moveToBack
*/
public void moveToFront(Component c)
@@ -363,8 +302,7 @@ public class JLayeredPane extends JComponent implements Accessible
* other components in its layer.</p>
*
* @param c the component to move to the back of its layer.
- * @throws IllegalArgumentException if the component is not a child of
- * this container.
+ *
* @see #moveToFront
*/
public void moveToBack(Component c)
@@ -377,25 +315,30 @@ public class JLayeredPane extends JComponent implements Accessible
* from the "front" (position 0) to the "back" (position N-1), and drawn from
* the back towards the front.
*
- * @param c the component to get the position of.
- * @throws IllegalArgumentException if the component is not a child of
- * this container.
+ * @param c the component to get the position of
+ *
+ * @return the position of <code>c</code> within its layer or -1 if
+ * <code>c</code> is not a child of this layered pane
+ *
* @see #setPosition
*/
public int getPosition(Component c)
{
- int layer = getLayer (c);
- int[] range = layerToRange(new Integer(layer));
- int top = range[0];
- int bot = range[1];
- Component[] comps = getComponents ();
- for (int i = top; i < bot; ++i)
- {
- if (comps[i] == c)
- return i - top;
- }
- // should have found it
- throw new IllegalArgumentException ();
+ int pos = -1;
+ int index = getIndexOf(c);
+ Component[] components = getComponents();
+ int layer = getLayer(c);
+ if (index >= 0)
+ {
+ for (int i = index; i >= 0; --i)
+ {
+ if (layer == getLayer(components[i]))
+ pos++;
+ else
+ break;
+ }
+ }
+ return pos;
}
/**
@@ -403,47 +346,16 @@ public class JLayeredPane extends JComponent implements Accessible
* from the "front" (position 0) to the "back" (position N-1), and drawn from
* the back towards the front.
*
- * @param c the component to change the position of.
- * @param position the position to assign the component to.
- * @throws IllegalArgumentException if the component is not a child of
- * this container.
+ * @param c the component to change the position of
+ * @param position the position to assign the component to
+ *
* @see #getPosition
*/
public void setPosition(Component c, int position)
{
- int layer = getLayer (c);
- int[] range = layerToRange(new Integer(layer));
- if (range[0] == range[1])
- throw new IllegalArgumentException ();
-
- int top = range[0];
- int bot = range[1];
- if (position == -1)
- position = (bot - top) - 1;
- int targ = Math.min(top + position, bot-1);
- int curr = -1;
-
- Component[] comps = getComponents();
- for (int i = top; i < bot; ++i)
- {
- if (comps[i] == c)
- {
- curr = i;
- break;
- }
- }
- if (curr == -1)
- // should have found it
- throw new IllegalArgumentException();
-
- if (curr == 0)
- super.swapComponents(curr, targ);
- else
- while (curr > 0)
- super.swapComponents (curr, --curr);
-
- revalidate();
- repaint();
+ int layer = getLayer(c);
+ int index = insertIndexForLayer(layer, position);
+ setComponentZOrder(c, index);
}
/**
@@ -451,39 +363,44 @@ public class JLayeredPane extends JComponent implements Accessible
* container. Components are ordered front-to-back, with the "front"
* element (which draws last) at position 0 of the returned array.
*
- * @param layer the layer to return components from.
- * @return the components in the layer.
+ * @param layer the layer to return components from
+ *
+ * @return the components in the layer
*/
public Component[] getComponentsInLayer(int layer)
{
- int[] range = layerToRange (getObjectForLayer (layer));
- if (range[0] == range[1])
- return new Component[0];
- else
- {
- Component[] comps = getComponents ();
- int sz = range[1] - range[0];
- Component[] nc = new Component[sz];
- for (int i = 0; i < sz; ++i)
- nc[i] = comps[range[0] + i];
- return nc;
- }
+ Component[] inLayer = new Component[getComponentCountInLayer(layer)];
+ Component[] components = getComponents();
+ int j = 0;
+ for (int i = 0; i < components.length; ++i)
+ {
+ if (layer == getLayer(components[i]))
+ {
+ inLayer[j] = components[i];
+ j++;
+ }
+ }
+ return inLayer;
}
/**
* Return the number of components within a layer of this
* container.
*
- * @param layer the layer count components in.
- * @return the number of components in the layer.
+ * @param layer the layer count components in
+ *
+ * @return the number of components in the layer
*/
public int getComponentCountInLayer(int layer)
{
- int[] range = layerToRange (getObjectForLayer (layer));
- if (range[0] == range[1])
- return 0;
- else
- return (range[1] - range[0]);
+ Component[] components = getComponents();
+ int count = 0;
+ for (int i = components.length - 1; i >= 0; --i)
+ {
+ if (getLayer(components[i]) == layer)
+ count++;
+ }
+ return count;
}
/**
@@ -502,23 +419,14 @@ public class JLayeredPane extends JComponent implements Accessible
* drawing order of all children of the container.
*
* @param c the component to look up.
- * @return the external index of the component.
- * @throws IllegalArgumentException if the component is not a child of
- * this container.
+ *
+ * @return the external index of the component or <code>-1</code> if
+ * <code>c</code> is not a child of this layered pane
*/
public int getIndexOf(Component c)
{
- int layer = getLayer (c);
- int[] range = layerToRange(new Integer(layer));
- Component[] comps = getComponents();
- for (int i = range[0]; i < range[1]; ++i)
- {
- if (comps[i] == c)
- return i;
- }
- // should have found the component during iteration
- throw new IllegalArgumentException ();
- }
+ return getComponentZOrder(c);
+ }
/**
* Return an Integer object which holds the same int value as the
@@ -526,6 +434,7 @@ public class JLayeredPane extends JComponent implements Accessible
* identical Integer objects which we allocate.
*
* @param layer the layer number as an int.
+ *
* @return the layer number as an Integer, possibly shared.
*/
protected Integer getObjectForLayer(int layer)
@@ -564,25 +473,39 @@ public class JLayeredPane extends JComponent implements Accessible
*
* @param layer the layer in which to insert a component.
* @param position the position in the layer at which to insert a component.
+ *
* @return the index at which to insert the component.
*/
protected int insertIndexForLayer(int layer, int position)
{
+ // position < 0 means insert at greatest position within layer.
+ if (position < 0)
+ position = Integer.MAX_VALUE;
- Integer lobj = getObjectForLayer (layer);
- if (! layers.containsKey(lobj))
- layers.put (lobj, new Integer (0));
- int[] range = layerToRange (lobj);
- if (range[0] == range[1])
- return range[0];
-
- int top = range[0];
- int bot = range[1];
-
- if (position == -1 || position > (bot - top))
- return bot;
- else
- return top + position;
+ Component[] components = getComponents();
+ int index = 0;
+
+ // Try to find the start index of the specified layer.
+ int p = -1;
+ for (int i = 0; i < components.length; i++)
+ {
+ int l = getLayer(components[i]);
+ if (l > layer)
+ index++;
+ // If we are in the layer we look for, try to find the position.
+ else if (l == layer)
+ {
+ p++;
+ if (p < position)
+ index++;
+ else
+ break;
+ }
+ // No need to look further if the layer at i is smaller than layer.
+ else
+ break;
+ }
+ return index;
}
/**
@@ -594,12 +517,20 @@ public class JLayeredPane extends JComponent implements Accessible
public void remove(int index)
{
Component c = getComponent(index);
- int layer = getLayer(c);
- decrLayer(new Integer(layer));
- componentToLayer.remove(c);
+ if (! (c instanceof JComponent))
+ componentToLayer.remove(c);
super.remove(index);
- // FIXME: Figure out if this call is correct.
- revalidate();
+ }
+
+ /**
+ * Removes all components from this container.
+ *
+ * @since 1.5
+ */
+ public void removeAll()
+ {
+ componentToLayer.clear();
+ super.removeAll();
}
/**
@@ -615,7 +546,7 @@ public class JLayeredPane extends JComponent implements Accessible
*/
public void setLayer(Component c, int layer)
{
- componentToLayer.put (c, getObjectForLayer (layer));
+ setLayer(c, layer, -1);
}
/**
@@ -625,15 +556,20 @@ public class JLayeredPane extends JComponent implements Accessible
* @param layer the layer number to assign to the component.
* @param position the position number to assign to the component.
*/
- public void setLayer(Component c,
- int layer,
- int position)
+ public void setLayer(Component c, int layer, int position)
{
- remove(c);
- add(c, getObjectForLayer (layer));
- setPosition(c, position);
- revalidate();
- repaint();
+ Integer layerObj = getObjectForLayer(layer);
+ if (c instanceof JComponent)
+ {
+ JComponent jc = (JComponent) c;
+ jc.putClientProperty(LAYER_PROPERTY, layerObj);
+ }
+ else
+ componentToLayer.put (c, layerObj);
+
+ // Set position only of component is already added to this layered pane.
+ if (getIndexOf(c) != -1)
+ setPosition(c, position);
}
/**
@@ -642,26 +578,27 @@ public class JLayeredPane extends JComponent implements Accessible
* Integer}, specifying the layer to which the component will be added
* (at the bottom position).
*
- * @param comp the component to add.
- * @param layerConstraint an integer specifying the layer to add the component to.
- * @param index an ignored parameter, for compatibility.
+ * The argument <code>index</code> specifies the position within the layer
+ * at which the component should be added, where <code>0</code> is the top
+ * position greater values specify positions below that and <code>-1</code>
+ * specifies the bottom position.
+ *
+ * @param comp the component to add
+ * @param layerConstraint an integer specifying the layer to add the
+ * component to
+ * @param index the position within the layer
*/
protected void addImpl(Component comp, Object layerConstraint, int index)
{
- Integer layer;
+ int layer;
if (layerConstraint != null && layerConstraint instanceof Integer)
- layer = (Integer) layerConstraint;
- else if (componentToLayer.containsKey (comp))
- layer = (Integer) componentToLayer.remove (comp);
+ layer = ((Integer) layerConstraint).intValue();
else
- layer = DEFAULT_LAYER;
-
- int newIdx = insertIndexForLayer(layer.intValue (), index);
+ layer = getLayer(comp);
- componentToLayer.put (comp, layer);
- incrLayer (layer);
-
- super.addImpl(comp, null, newIdx);
+ int newIdx = insertIndexForLayer(layer, index);
+ setLayer(comp, layer);
+ super.addImpl(comp, layerConstraint, newIdx);
}
/**
@@ -672,7 +609,7 @@ public class JLayeredPane extends JComponent implements Accessible
*/
public static void putLayer(JComponent component, int layer)
{
- getLayeredPaneAbove(component).setLayer(component, layer);
+ component.putClientProperty(LAYER_PROPERTY, new Integer(layer));
}
/**
@@ -711,13 +648,42 @@ public class JLayeredPane extends JComponent implements Accessible
}
/**
- * Overridden to return <code>false</code>, since <code>JLayeredPane</code>
- * cannot guarantee that its children don't overlap.
+ * Returns <code>false</code> if components in this layered pane can overlap,
+ * otherwise <code>true</code>.
*
- * @return <code>false</code>
+ * @return <code>false</code> if components in this layered pane can overlap,
+ * otherwise <code>true</code>
*/
public boolean isOptimizedDrawingEnabled()
{
- return false;
+ int numChildren = getComponentCount();
+ boolean result = true;
+ for (int i = 0; i < numChildren; ++i)
+ {
+ Component c1 = getComponent(i);
+ if (! c1.isVisible())
+ continue;
+ Rectangle r1 = c1.getBounds();
+ if (r1.isEmpty())
+ continue;
+
+ for (int j = i + 1; j < numChildren; ++j)
+ {
+ Component c2 = getComponent(j);
+ if (! c2.isVisible())
+ continue;
+ Rectangle r2 = c2.getBounds();
+ if (r2.isEmpty())
+ continue;
+ if (r1.intersects(r2))
+ {
+ result = false;
+ break;
+ }
+ if (result == false)
+ break;
+ }
+ }
+ return result;
}
}
diff --git a/libjava/classpath/javax/swing/JMenu.java b/libjava/classpath/javax/swing/JMenu.java
index 369c44d40c6..a160dd44857 100644
--- a/libjava/classpath/javax/swing/JMenu.java
+++ b/libjava/classpath/javax/swing/JMenu.java
@@ -906,7 +906,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
/**
* This class listens to PropertyChangeEvents occuring in menu's action
*/
- protected class ActionChangedListener implements PropertyChangeListener
+ private class ActionChangedListener implements PropertyChangeListener
{
/** menu item associated with the action */
private JMenuItem menuItem;
diff --git a/libjava/classpath/javax/swing/JMenuBar.java b/libjava/classpath/javax/swing/JMenuBar.java
index f018daabf80..60726fb39bf 100644
--- a/libjava/classpath/javax/swing/JMenuBar.java
+++ b/libjava/classpath/javax/swing/JMenuBar.java
@@ -1,5 +1,5 @@
/* JMenuBar.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -51,6 +51,8 @@ import javax.accessibility.AccessibleSelection;
import javax.accessibility.AccessibleStateSet;
import javax.swing.plaf.MenuBarUI;
+import javax.swing.border.Border;
+
/**
* JMenuBar is a container for menu's. For a menu bar to be seen on the
* screen, at least one menu should be added to it. Just like adding
@@ -437,8 +439,12 @@ public class JMenuBar extends JComponent implements Accessible, MenuElement
protected void paintBorder(Graphics g)
{
if (borderPainted)
- getBorder().paintBorder(this, g, 0, 0, getSize(null).width,
- getSize(null).height);
+ {
+ Border border = getBorder();
+ if (border != null)
+ getBorder().paintBorder(this, g, 0, 0, getSize(null).width,
+ getSize(null).height);
+ }
}
/**
diff --git a/libjava/classpath/javax/swing/JOptionPane.java b/libjava/classpath/javax/swing/JOptionPane.java
index 057326cd209..705eca832fe 100644
--- a/libjava/classpath/javax/swing/JOptionPane.java
+++ b/libjava/classpath/javax/swing/JOptionPane.java
@@ -197,7 +197,7 @@ public class JOptionPane extends JComponent implements Accessible
public static final String WANTS_INPUT_PROPERTY = "wantsInput";
/** The value returned when the inputValue is uninitialized. */
- public static Object UNINITIALIZED_VALUE = "uninitializedValue";
+ public static final Object UNINITIALIZED_VALUE = "uninitializedValue";
/** The icon displayed in the dialog/internal frame. */
protected Icon icon;
@@ -236,7 +236,7 @@ public class JOptionPane extends JComponent implements Accessible
protected boolean wantsInput;
/** The common frame used when no parent is provided. */
- private static Frame privFrame = SwingUtilities.getOwnerFrame();
+ private static Frame privFrame = (Frame) SwingUtilities.getOwnerFrame(null);
/**
* Creates a new JOptionPane object using a message of "JOptionPane
diff --git a/libjava/classpath/javax/swing/JPanel.java b/libjava/classpath/javax/swing/JPanel.java
index c02a9cfad6f..815e452dc05 100644
--- a/libjava/classpath/javax/swing/JPanel.java
+++ b/libjava/classpath/javax/swing/JPanel.java
@@ -63,7 +63,7 @@ public class JPanel extends JComponent implements Accessible
/**
* Creates a new instance of <code>AccessibleJPanel</code>.
*/
- public AccessibleJPanel()
+ protected AccessibleJPanel()
{
// Nothing to do here.
}
diff --git a/libjava/classpath/javax/swing/JPopupMenu.java b/libjava/classpath/javax/swing/JPopupMenu.java
index 1f2282e2326..74f733e921e 100644
--- a/libjava/classpath/javax/swing/JPopupMenu.java
+++ b/libjava/classpath/javax/swing/JPopupMenu.java
@@ -866,7 +866,7 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement
/* This class resizes popup menu and repaints popup menu appropriately if one
of item's action has changed */
- protected class ActionChangeListener implements PropertyChangeListener
+ private class ActionChangeListener implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent evt)
{
diff --git a/libjava/classpath/javax/swing/JProgressBar.java b/libjava/classpath/javax/swing/JProgressBar.java
index abca3e7ae02..e7ee8004c09 100644
--- a/libjava/classpath/javax/swing/JProgressBar.java
+++ b/libjava/classpath/javax/swing/JProgressBar.java
@@ -1,5 +1,5 @@
/* JProgressBar.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -174,8 +174,8 @@ public class JProgressBar extends JComponent implements SwingConstants,
/** Whether the ProgressBar is determinate. */
private transient boolean indeterminate = false;
- /** The orientation of the ProgressBar */
- protected int orientation = HORIZONTAL;
+ /** The orientation of the ProgressBar. Always set by constructor. */
+ protected int orientation;
/** Whether borders should be painted. */
protected boolean paintBorder = true;
@@ -245,8 +245,9 @@ public class JProgressBar extends JComponent implements SwingConstants,
{
model = new DefaultBoundedRangeModel(minimum, 0, minimum, maximum);
if (orientation != HORIZONTAL && orientation != VERTICAL)
- throw new IllegalArgumentException(orientation + " is not a legal orientation");
- setOrientation(orientation);
+ throw new IllegalArgumentException(orientation
+ + " is not a legal orientation");
+ this.orientation = orientation;
changeListener = createChangeListener();
model.addChangeListener(changeListener);
updateUI();
@@ -316,11 +317,14 @@ public class JProgressBar extends JComponent implements SwingConstants,
* JProgressBar can be either horizontal or vertical.
*
* @param orientation The orientation of the JProgressBar.
+ * @throws IllegalArgumentException if <code>orientation</code> is not
+ * either {@link #HORIZONTAL} or {@link #VERTICAL}.
*/
public void setOrientation(int orientation)
{
if (orientation != VERTICAL && orientation != HORIZONTAL)
- throw new IllegalArgumentException("orientation must be one of VERTICAL or HORIZONTAL");
+ throw new IllegalArgumentException(orientation
+ + " is not a legal orientation");
if (this.orientation != orientation)
{
int oldOrientation = this.orientation;
diff --git a/libjava/classpath/javax/swing/JRootPane.java b/libjava/classpath/javax/swing/JRootPane.java
index dea4ee4b195..dec43956ca3 100644
--- a/libjava/classpath/javax/swing/JRootPane.java
+++ b/libjava/classpath/javax/swing/JRootPane.java
@@ -120,11 +120,6 @@ public class JRootPane extends JComponent implements Accessible
private Rectangle menuBarBounds;
/**
- * The cached preferred size.
- */
- private Dimension prefSize;
-
- /**
* Creates a new <code>RootLayout</code> object.
*/
protected RootLayout()
@@ -191,7 +186,6 @@ public class JRootPane extends JComponent implements Accessible
layeredPaneBounds = null;
contentPaneBounds = null;
menuBarBounds = null;
- prefSize = null;
}
}
@@ -251,7 +245,7 @@ public class JRootPane extends JComponent implements Accessible
layeredPane.setBounds(layeredPaneBounds);
if (menuBar != null)
menuBar.setBounds(menuBarBounds);
- contentPane.setBounds(contentPaneBounds);
+ getContentPane().setBounds(contentPaneBounds);
}
/**
@@ -287,29 +281,20 @@ public class JRootPane extends JComponent implements Accessible
*/
public Dimension preferredLayoutSize(Container c)
{
- // We must synchronize here, otherwise we cannot guarantee that the
- // prefSize is still non-null when returning.
- synchronized (this)
+ Dimension prefSize = new Dimension();
+ Insets i = getInsets();
+ prefSize = new Dimension(i.left + i.right, i.top + i.bottom);
+ Dimension contentPrefSize = getContentPane().getPreferredSize();
+ prefSize.width += contentPrefSize.width;
+ prefSize.height += contentPrefSize.height;
+ if (menuBar != null)
{
- if (prefSize == null)
- {
- Insets i = getInsets();
- prefSize = new Dimension(i.left + i.right, i.top + i.bottom);
- Dimension contentPrefSize = contentPane.getPreferredSize();
- prefSize.width += contentPrefSize.width;
- prefSize.height += contentPrefSize.height;
- if (menuBar != null)
- {
- Dimension menuBarSize = menuBar.getPreferredSize();
- if (menuBarSize.width > contentPrefSize.width)
- prefSize.width += menuBarSize.width - contentPrefSize.width;
- prefSize.height += menuBarSize.height;
- }
- }
- // Return a copy here so the cached value won't get trashed by some
- // other component.
- return new Dimension(prefSize);
- }
+ Dimension menuBarSize = menuBar.getPreferredSize();
+ if (menuBarSize.width > contentPrefSize.width)
+ prefSize.width += menuBarSize.width - contentPrefSize.width;
+ prefSize.height += menuBarSize.height;
+ }
+ return prefSize;
}
/**
@@ -541,6 +526,7 @@ public class JRootPane extends JComponent implements Accessible
getGlassPane();
getLayeredPane();
getContentPane();
+ setOpaque(true);
updateUI();
}
@@ -674,4 +660,18 @@ public class JRootPane extends JComponent implements Accessible
windowDecorationStyle = style;
firePropertyChange("windowDecorationStyle", oldStyle, style);
}
+
+ /**
+ * This returns <code>true</code> if the <code>glassPane</code> is not
+ * visible because then the root pane can guarantee to tile its children
+ * (the only other direct child is a JLayeredPane which must figure its
+ * <code>optimizeDrawingEnabled</code> state on its own).
+ *
+ * @return <code>true</code> if the <code>glassPane</code> is not
+ * visible
+ */
+ public boolean isOptimizedDrawingEnable()
+ {
+ return ! glassPane.isVisible();
+ }
}
diff --git a/libjava/classpath/javax/swing/JSpinner.java b/libjava/classpath/javax/swing/JSpinner.java
index af34d9cf67d..882d216e126 100644
--- a/libjava/classpath/javax/swing/JSpinner.java
+++ b/libjava/classpath/javax/swing/JSpinner.java
@@ -1,5 +1,5 @@
/* JSpinner.java --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -45,7 +45,9 @@ import java.awt.Insets;
import java.awt.LayoutManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.text.DateFormat;
import java.text.DecimalFormat;
+import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -53,10 +55,15 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.SpinnerUI;
import javax.swing.text.DateFormatter;
+import javax.swing.text.DefaultFormatterFactory;
+import javax.swing.text.NumberFormatter;
/**
- * A JSpinner is a component which typically contains a numeric value and a
- * way to manipulate the value.
+ * A <code>JSpinner</code> is a component that displays a single value from
+ * a sequence of values, and provides a convenient means for selecting the
+ * previous and next values in the sequence. Typically the spinner displays
+ * a numeric value, but it is possible to display dates or arbitrary items
+ * from a list.
*
* @author Ka-Hing Cheung
*
@@ -65,12 +72,15 @@ import javax.swing.text.DateFormatter;
public class JSpinner extends JComponent
{
/**
- * DOCUMENT ME!
+ * The base class for the editor used by the {@link JSpinner} component.
+ * The editor is in fact a panel containing a {@link JFormattedTextField}
+ * component.
*/
- public static class DefaultEditor extends JPanel implements ChangeListener,
- PropertyChangeListener,
- LayoutManager
+ public static class DefaultEditor
+ extends JPanel
+ implements ChangeListener, PropertyChangeListener, LayoutManager
{
+ /** The spinner that the editor is allocated to. */
private JSpinner spinner;
/** The JFormattedTextField that backs the editor. */
@@ -82,7 +92,8 @@ public class JSpinner extends JComponent
private static final long serialVersionUID = -5317788736173368172L;
/**
- * Creates a new <code>DefaultEditor</code> object.
+ * Creates a new <code>DefaultEditor</code> object. The editor is
+ * registered with the spinner as a {@link ChangeListener} here.
*
* @param spinner the <code>JSpinner</code> associated with this editor
*/
@@ -94,11 +105,15 @@ public class JSpinner extends JComponent
ftf = new JFormattedTextField();
add(ftf);
ftf.setValue(spinner.getValue());
+ ftf.addPropertyChangeListener(this);
spinner.addChangeListener(this);
}
/**
- * Returns the <code>JSpinner</code> object for this editor.
+ * Returns the <code>JSpinner</code> component that the editor is assigned
+ * to.
+ *
+ * @return The spinner that the editor is assigned to.
*/
public JSpinner getSpinner()
{
@@ -114,9 +129,10 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * Removes the editor from the {@link ChangeListener} list maintained by
+ * the specified <code>spinner</code>.
*
- * @param spinner DOCUMENT ME!
+ * @param spinner the spinner (<code>null</code> not permitted).
*/
public void dismiss(JSpinner spinner)
{
@@ -124,9 +140,10 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * Returns the text field used to display and edit the current value in
+ * the spinner.
*
- * @return DOCUMENT ME!
+ * @return The text field.
*/
public JFormattedTextField getTextField()
{
@@ -134,9 +151,10 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * Sets the bounds for the child components in this container. In this
+ * case, the text field is the only component to be laid out.
*
- * @param parent DOCUMENT ME!
+ * @param parent the parent container.
*/
public void layoutContainer(Container parent)
{
@@ -148,11 +166,13 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * Calculates the minimum size for this component. In this case, the
+ * text field is the only subcomponent, so the return value is the minimum
+ * size of the text field plus the insets of this component.
*
- * @param parent DOCUMENT ME!
+ * @param parent the parent container.
*
- * @return DOCUMENT ME!
+ * @return The minimum size.
*/
public Dimension minimumLayoutSize(Container parent)
{
@@ -163,11 +183,13 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * Calculates the preferred size for this component. In this case, the
+ * text field is the only subcomponent, so the return value is the
+ * preferred size of the text field plus the insets of this component.
*
- * @param parent DOCUMENT ME!
+ * @param parent the parent container.
*
- * @return DOCUMENT ME!
+ * @return The preferred size.
*/
public Dimension preferredLayoutSize(Container parent)
{
@@ -178,35 +200,51 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * Receives notification of property changes. If the text field's 'value'
+ * property changes, the spinner's model is updated accordingly.
*
- * @param event DOCUMENT ME!
+ * @param event the event.
*/
public void propertyChange(PropertyChangeEvent event)
{
- // TODO: Implement this properly.
+ if (event.getSource() == ftf)
+ {
+ if (event.getPropertyName().equals("value"))
+ spinner.getModel().setValue(event.getNewValue());
+ }
}
/**
- * DOCUMENT ME!
+ * Receives notification of changes in the state of the {@link JSpinner}
+ * that the editor belongs to - the content of the text field is updated
+ * accordingly.
*
- * @param event DOCUMENT ME!
+ * @param event the change event.
*/
public void stateChanged(ChangeEvent event)
{
- // TODO: Implement this properly.
+ ftf.setValue(spinner.getValue());
}
+ /**
+ * This method does nothing. It is required by the {@link LayoutManager}
+ * interface, but since this component has a single child, there is no
+ * need to use this method.
+ *
+ * @param child the child component to remove.
+ */
public void removeLayoutComponent(Component child)
{
// Nothing to do here.
}
/**
- * DOCUMENT ME!
- *
- * @param name DOCUMENT ME!
- * @param child DOCUMENT ME!
+ * This method does nothing. It is required by the {@link LayoutManager}
+ * interface, but since this component has a single child, there is no
+ * need to use this method.
+ *
+ * @param name the name.
+ * @param child the child component to add.
*/
public void addLayoutComponent(String name, Component child)
{
@@ -215,7 +253,11 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * A panel containing a {@link JFormattedTextField} that is configured for
+ * displaying and editing numbers. The panel is used as a subcomponent of
+ * a {@link JSpinner}.
+ *
+ * @see JSpinner#createEditor(SpinnerModel)
*/
public static class NumberEditor extends DefaultEditor
{
@@ -225,40 +267,72 @@ public class JSpinner extends JComponent
private static final long serialVersionUID = 3791956183098282942L;
/**
- * Creates a new NumberEditor object.
+ * Creates a new <code>NumberEditor</code> object for the specified
+ * <code>spinner</code>. The editor is registered with the spinner as a
+ * {@link ChangeListener}.
*
- * @param spinner DOCUMENT ME!
+ * @param spinner the component the editor will be used with.
*/
public NumberEditor(JSpinner spinner)
{
super(spinner);
+ NumberEditorFormatter nef = new NumberEditorFormatter();
+ nef.setMinimum(getModel().getMinimum());
+ nef.setMaximum(getModel().getMaximum());
+ ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
}
/**
- * Creates a new NumberEditor object.
+ * Creates a new <code>NumberEditor</code> object.
*
- * @param spinner DOCUMENT ME!
+ * @param spinner the spinner.
+ * @param decimalFormatPattern the number format pattern.
*/
public NumberEditor(JSpinner spinner, String decimalFormatPattern)
{
super(spinner);
+ NumberEditorFormatter nef
+ = new NumberEditorFormatter(decimalFormatPattern);
+ nef.setMinimum(getModel().getMinimum());
+ nef.setMaximum(getModel().getMaximum());
+ ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
}
/**
- * DOCUMENT ME!
+ * Returns the format used by the text field.
*
- * @return DOCUMENT ME!
+ * @return The format used by the text field.
*/
public DecimalFormat getFormat()
{
- return null;
+ NumberFormatter formatter = (NumberFormatter) ftf.getFormatter();
+ return (DecimalFormat) formatter.getFormat();
}
+ /**
+ * Returns the model used by the editor's {@link JSpinner} component,
+ * cast to a {@link SpinnerNumberModel}.
+ *
+ * @return The model.
+ */
public SpinnerNumberModel getModel()
{
return (SpinnerNumberModel) getSpinner().getModel();
}
}
+
+ static class NumberEditorFormatter
+ extends NumberFormatter
+ {
+ public NumberEditorFormatter()
+ {
+ super(NumberFormat.getInstance());
+ }
+ public NumberEditorFormatter(String decimalFormatPattern)
+ {
+ super(new DecimalFormat(decimalFormatPattern));
+ }
+ }
/**
* A <code>JSpinner</code> editor used for the {@link SpinnerListModel}.
@@ -279,6 +353,11 @@ public class JSpinner extends JComponent
super(spinner);
}
+ /**
+ * Returns the spinner's model cast as a {@link SpinnerListModel}.
+ *
+ * @return The spinner's model.
+ */
public SpinnerListModel getModel()
{
return (SpinnerListModel) getSpinner().getModel();
@@ -299,9 +378,6 @@ public class JSpinner extends JComponent
/** The serialVersionUID. */
private static final long serialVersionUID = -4279356973770397815L;
- /** The DateFormat instance used to format the date. */
- SimpleDateFormat dateFormat;
-
/**
* Creates a new instance of DateEditor for the specified
* <code>JSpinner</code>.
@@ -312,7 +388,10 @@ public class JSpinner extends JComponent
public DateEditor(JSpinner spinner)
{
super(spinner);
- init(new SimpleDateFormat());
+ DateEditorFormatter nef = new DateEditorFormatter();
+ nef.setMinimum(getModel().getStart());
+ nef.setMaximum(getModel().getEnd());
+ ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
}
/**
@@ -329,26 +408,10 @@ public class JSpinner extends JComponent
public DateEditor(JSpinner spinner, String dateFormatPattern)
{
super(spinner);
- init(new SimpleDateFormat(dateFormatPattern));
- }
-
- /**
- * Initializes the JFormattedTextField for this editor.
- *
- * @param format the date format to use in the formatted text field
- */
- private void init(SimpleDateFormat format)
- {
- dateFormat = format;
- getTextField().setFormatterFactory(
- new JFormattedTextField.AbstractFormatterFactory()
- {
- public JFormattedTextField.AbstractFormatter
- getFormatter(JFormattedTextField ftf)
- {
- return new DateFormatter(dateFormat);
- }
- });
+ DateEditorFormatter nef = new DateEditorFormatter(dateFormatPattern);
+ nef.setMinimum(getModel().getStart());
+ nef.setMaximum(getModel().getEnd());
+ ftf.setFormatterFactory(new DefaultFormatterFactory(nef));
}
/**
@@ -360,7 +423,8 @@ public class JSpinner extends JComponent
*/
public SimpleDateFormat getFormat()
{
- return dateFormat;
+ DateFormatter formatter = (DateFormatter) ftf.getFormatter();
+ return (SimpleDateFormat) formatter.getFormat();
}
/**
@@ -374,25 +438,59 @@ public class JSpinner extends JComponent
}
}
- private static final long serialVersionUID = 3412663575706551720L;
+ static class DateEditorFormatter
+ extends DateFormatter
+ {
+ public DateEditorFormatter()
+ {
+ super(DateFormat.getInstance());
+ }
+ public DateEditorFormatter(String dateFormatPattern)
+ {
+ super(new SimpleDateFormat(dateFormatPattern));
+ }
+ }
+
+ /**
+ * A listener that forwards {@link ChangeEvent} notifications from the model
+ * to the {@link JSpinner}'s listeners.
+ */
+ class ModelListener implements ChangeListener
+ {
+ /**
+ * Creates a new listener.
+ */
+ public ModelListener()
+ {
+ // nothing to do here
+ }
+
+ /**
+ * Receives notification from the model that its state has changed.
+ *
+ * @param event the event (ignored).
+ */
+ public void stateChanged(ChangeEvent event)
+ {
+ fireStateChanged();
+ }
+ }
- /** DOCUMENT ME! */
+ /**
+ * The model that defines the current value and permitted values for the
+ * spinner.
+ */
private SpinnerModel model;
- /** DOCUMENT ME! */
+ /** The current editor. */
private JComponent editor;
- /** DOCUMENT ME! */
- private ChangeListener listener = new ChangeListener()
- {
- public void stateChanged(ChangeEvent evt)
- {
- fireStateChanged();
- }
- };
+ private static final long serialVersionUID = 3412663575706551720L;
/**
- * Creates a JSpinner with <code>SpinnerNumberModel</code>
+ * Creates a new <code>JSpinner</code> with default instance of
+ * {@link SpinnerNumberModel} (that is, a model with value 0, step size 1,
+ * and no upper or lower limit).
*
* @see javax.swing.SpinnerNumberModel
*/
@@ -402,15 +500,19 @@ public class JSpinner extends JComponent
}
/**
- * Creates a JSpinner with the specific model and sets the default editor
+ * Creates a new <code>JSpinner with the specified model. The
+ * {@link #createEditor(SpinnerModel)} method is used to create an editor
+ * that is suitable for the model.
*
- * @param model DOCUMENT ME!
+ * @param model the model (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>model</code> is <code>null</code>.
*/
public JSpinner(SpinnerModel model)
{
this.model = model;
- model.addChangeListener(listener);
- setEditor(createEditor(model));
+ this.editor = createEditor(model);
+ model.addChangeListener(new ModelListener());
updateUI();
}
@@ -439,12 +541,13 @@ public class JSpinner extends JComponent
}
/**
- * Changes the current editor to the new editor. This methods should remove
- * the old listeners (if any) and adds the new listeners (if any).
+ * Changes the current editor to the new editor. The old editor is
+ * removed from the spinner's {@link ChangeEvent} list.
*
- * @param editor the new editor
+ * @param editor the new editor (<code>null</code> not permitted.
*
- * @throws IllegalArgumentException DOCUMENT ME!
+ * @throws IllegalArgumentException if <code>editor</code> is
+ * <code>null</code>.
*
* @see #getEditor
*/
@@ -453,21 +556,22 @@ public class JSpinner extends JComponent
if (editor == null)
throw new IllegalArgumentException("editor may not be null");
- if (this.editor instanceof DefaultEditor)
- ((DefaultEditor) editor).dismiss(this);
- else if (this.editor instanceof ChangeListener)
- removeChangeListener((ChangeListener) this.editor);
-
- if (editor instanceof ChangeListener)
- addChangeListener((ChangeListener) editor);
-
+ JComponent oldEditor = this.editor;
+ if (oldEditor instanceof DefaultEditor)
+ ((DefaultEditor) oldEditor).dismiss(this);
+ else if (oldEditor instanceof ChangeListener)
+ removeChangeListener((ChangeListener) oldEditor);
+
this.editor = editor;
+ firePropertyChange("editor", oldEditor, editor);
}
/**
- * Gets the underly model.
+ * Returns the model used by the {@link JSpinner} component.
*
- * @return the underly model
+ * @return The model.
+ *
+ * @see #setModel(SpinnerModel)
*/
public SpinnerModel getModel()
{
@@ -492,9 +596,7 @@ public class JSpinner extends JComponent
SpinnerModel oldModel = model;
model = newModel;
firePropertyChange("model", oldModel, newModel);
-
- if (editor == null)
- setEditor(createEditor(model));
+ setEditor(createEditor(model));
}
/**
@@ -545,9 +647,9 @@ public class JSpinner extends JComponent
}
/**
- * DOCUMENT ME!
+ * Sets the value in the model.
*
- * @param value DOCUMENT ME!
+ * @param value the new value.
*/
public void setValue(Object value)
{
@@ -555,10 +657,10 @@ public class JSpinner extends JComponent
}
/**
- * This method returns a name to identify which look and feel class will be
+ * Returns the ID that identifies which look and feel class will be
* the UI delegate for this spinner.
*
- * @return The UIClass identifier. "SpinnerUI"
+ * @return <code>"SpinnerUI"</code>.
*/
public String getUIClassID()
{
@@ -575,7 +677,7 @@ public class JSpinner extends JComponent
}
/**
- * This method sets the spinner's UI delegate.
+ * Sets the UI delegate for the component.
*
* @param ui The spinner's UI delegate.
*/
@@ -628,14 +730,11 @@ public class JSpinner extends JComponent
}
/**
- * Creates an editor for this <code>JSpinner</code>. Really, it should be a
- * <code>JSpinner.DefaultEditor</code>, but since that should be
- * implemented by a JFormattedTextField, and one is not written, I am just
- * using a dummy one backed by a JLabel.
+ * Creates an editor that is appropriate for the specified <code>model</code>.
*
- * @param model DOCUMENT ME!
+ * @param model the model.
*
- * @return the default editor
+ * @return The editor.
*/
protected JComponent createEditor(SpinnerModel model)
{
@@ -643,6 +742,8 @@ public class JSpinner extends JComponent
return new DateEditor(this);
else if (model instanceof SpinnerNumberModel)
return new NumberEditor(this);
+ else if (model instanceof SpinnerListModel)
+ return new ListEditor(this);
else
return new DefaultEditor(this);
}
diff --git a/libjava/classpath/javax/swing/JSplitPane.java b/libjava/classpath/javax/swing/JSplitPane.java
index 70feefab26e..dc75dfe3184 100644
--- a/libjava/classpath/javax/swing/JSplitPane.java
+++ b/libjava/classpath/javax/swing/JSplitPane.java
@@ -343,10 +343,13 @@ public class JSplitPane extends JComponent implements Accessible
throw new
IllegalArgumentException("Constraints is not a known identifier.");
+ // If no dividerLocation has been set, then we need to trigger an
+ // initial layout.
+ if (getDividerLocation() != -1)
+ resetToPreferredSizes();
+
super.addImpl(comp, constraints, index);
}
- invalidate();
- layout();
}
/**
diff --git a/libjava/classpath/javax/swing/JTabbedPane.java b/libjava/classpath/javax/swing/JTabbedPane.java
index 8a7d4c07fa7..3c91a5ea397 100644
--- a/libjava/classpath/javax/swing/JTabbedPane.java
+++ b/libjava/classpath/javax/swing/JTabbedPane.java
@@ -44,12 +44,14 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.io.Serializable;
+import java.util.Locale;
import java.util.Vector;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.accessibility.AccessibleSelection;
+import javax.accessibility.AccessibleStateSet;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.TabbedPaneUI;
@@ -136,7 +138,12 @@ public class JTabbedPane extends JComponent implements Serializable,
*/
public Accessible getAccessibleChild(int i)
{
- return null;
+ // Testing shows that the reference implementation returns instances
+ // of page here.
+ Accessible child = null;
+ if (i >= 0 && i < tabs.size())
+ child = (Page) tabs.get(i);
+ return child;
}
/**
@@ -273,6 +280,8 @@ public class JTabbedPane extends JComponent implements Serializable,
* A private class that holds all the information for each tab.
*/
private class Page
+ extends AccessibleContext
+ implements Accessible
{
/** The tooltip string. */
private String tip;
@@ -553,6 +562,74 @@ public class JTabbedPane extends JComponent implements Serializable,
underlinedChar = index;
}
+
+ /**
+ * Returns the accessible context, which is this object itself.
+ *
+ * @return the accessible context, which is this object itself
+ */
+ public AccessibleContext getAccessibleContext()
+ {
+ return this;
+ }
+
+ /**
+ * Returns the accessible role of this tab, which is always
+ * {@link AccessibleRole#PAGE_TAB}.
+ *
+ * @return the accessible role of this tab
+ */
+ public AccessibleRole getAccessibleRole()
+ {
+ return AccessibleRole.PAGE_TAB;
+ }
+
+ public AccessibleStateSet getAccessibleStateSet()
+ {
+ // FIXME: Implement this properly.
+ return null;
+ }
+
+ public int getAccessibleIndexInParent()
+ {
+ // FIXME: Implement this properly.
+ return 0;
+ }
+
+ /**
+ * Returns the number of accessible children, which is always one (the
+ * component of this tab).
+ *
+ * @return the number of accessible children
+ */
+ public int getAccessibleChildrenCount()
+ {
+ return 1;
+ }
+
+ /**
+ * Returns the accessible child of this tab, which is the component
+ * displayed by the tab.
+ *
+ * @return the accessible child of this tab
+ */
+ public Accessible getAccessibleChild(int i)
+ {
+ // A quick test shows that this method always returns the component
+ // displayed by the tab, regardless of the index.
+ return (Accessible) component;
+ }
+
+ /**
+ * Returns the locale of this accessible object.
+ *
+ * @return the locale of this accessible object
+ */
+ public Locale getLocale()
+ {
+ // TODO: Is this ok?
+ return Locale.getDefault();
+ }
}
private static final long serialVersionUID = 1614381073220130939L;
@@ -1088,7 +1165,7 @@ public class JTabbedPane extends JComponent implements Serializable,
*/
public void remove(int index)
{
- remove(getComponentAt(index));
+ super.remove(index);
removeTabAt(index);
}
diff --git a/libjava/classpath/javax/swing/JTable.java b/libjava/classpath/javax/swing/JTable.java
index 0875306a012..fbf74934a0a 100644
--- a/libjava/classpath/javax/swing/JTable.java
+++ b/libjava/classpath/javax/swing/JTable.java
@@ -1,5 +1,5 @@
/* JTable.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -46,8 +46,6 @@ import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Point;
import java.awt.Rectangle;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -86,8 +84,16 @@ import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
-import javax.swing.text.Caret;
+/**
+ * The table component, displaying information, organized in rows and columns.
+ * The table can be placed in the scroll bar and have the optional header
+ * that is always visible. Cell values may be editable after double clicking
+ * on the cell. Cell columns may have various data types, that are
+ * displayed and edited by the different renderers and editors. It is possible
+ * to set different column width. The columns are also resizeable by
+ * dragging the column boundary in the header.
+ */
public class JTable
extends JComponent
implements TableModelListener, Scrollable, TableColumnModelListener,
@@ -588,7 +594,7 @@ public class JTable
return lastColumn;
}
}
-
+
/**
* Creates a new <code>AccessibleJTable</code>.
*
@@ -979,9 +985,9 @@ public class JTable
class TableColumnPropertyChangeHandler implements PropertyChangeListener
{
/**
- * Receives notification that a property of the observed TableColumns
- * has changed.
- *
+ * Receives notification that a property of the observed TableColumns has
+ * changed.
+ *
* @param ev the property change event
*/
public void propertyChange(PropertyChangeEvent ev)
@@ -989,13 +995,15 @@ public class JTable
if (ev.getPropertyName().equals("preferredWidth"))
{
JTableHeader header = getTableHeader();
- if (header != null)
- {
- TableColumn col = (TableColumn) ev.getSource();
- header.setResizingColumn(col);
- doLayout();
- header.setResizingColumn(null);
- }
+ if (header != null)
+ // Do nothing if the table is in the resizing mode.
+ if (header.getResizingColumn() == null)
+ {
+ TableColumn col = (TableColumn) ev.getSource();
+ header.setResizingColumn(col);
+ doLayout();
+ header.setResizingColumn(null);
+ }
}
}
}
@@ -1006,11 +1014,30 @@ public class JTable
private class BooleanCellRenderer
extends DefaultTableCellRenderer
{
-
/**
* The CheckBox that is used for rendering.
*/
- private JCheckBox checkBox = new JCheckBox();
+ private final JCheckBox checkBox = new JCheckBox();
+
+ /**
+ * The check box must have the text field background and be centered.
+ */
+ private BooleanCellRenderer()
+ {
+ // Render the checkbox identically as the text field.
+ JTextField f = new JTextField();
+ checkBox.setForeground(f.getForeground());
+ checkBox.setBackground(f.getBackground());
+ checkBox.setHorizontalAlignment(SwingConstants.CENTER);
+ }
+
+ /**
+ * Get the check box.
+ */
+ JCheckBox getCheckBox()
+ {
+ return checkBox;
+ }
/**
* Returns the component that is used for rendering the value.
@@ -1029,8 +1056,14 @@ public class JTable
boolean hasFocus, int row,
int column)
{
- Boolean boolValue = (Boolean) value;
- checkBox.setSelected(boolValue.booleanValue());
+ // Null is rendered as false.
+ if (value == null)
+ checkBox.setSelected(false);
+ else
+ {
+ Boolean boolValue = (Boolean) value;
+ checkBox.setSelected(boolValue.booleanValue());
+ }
return checkBox;
}
}
@@ -1200,12 +1233,52 @@ public class JTable
{
Icon iconValue = (Icon) value;
setIcon(iconValue);
+ setText("");
}
return this;
}
}
+
+ /**
+ * The JTable text component (used in editing) always has the table
+ * as its parent. The scrollRectToVisible must be adjusted taking the
+ * relative component position.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+ private class TableTextField extends JTextField
+ {
+ /**
+ * Create the text field without the border.
+ */
+ TableTextField()
+ {
+ setBorder(null);
+ }
+
+ /**
+ * Scroll the table, making the given rectangle of this component
+ * visible. Mind the component position with relate to the table.
+ * With not this method overridden, the scroll pane scrolls to the
+ * top left cornec (untranslated position of the caret) after the first
+ * keystroke.
+ */
+ public void scrollRectToVisible(Rectangle r)
+ {
+ // In private class we known that the rectangle data will not be
+ // reused and we need not to clone it.
+ r.translate(getX(), getY());
+ super.scrollRectToVisible(r);
+ }
+ }
+
private static final long serialVersionUID = 3876025080382781659L;
+
+ /**
+ * This table, for referring identically name methods from inner classes.
+ */
+ final JTable this_table = this;
/**
@@ -1343,7 +1416,7 @@ public class JTable
protected boolean rowSelectionAllowed;
/**
- * @deprecated Use {@link #rowSelectionAllowed}, {@link
+ * Obsolete. Use {@link #rowSelectionAllowed}, {@link
* #getColumnSelectionAllowed}, or the combined methods {@link
* #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}.
*/
@@ -1477,27 +1550,6 @@ public class JTable
protected JTableHeader tableHeader;
/**
- * The row of the cell being edited.
- */
- int rowBeingEdited = -1;
-
- /**
- * The column of the cell being edited.
- */
- int columnBeingEdited = -1;
-
- /**
- * The action listener for the editor's Timer.
- */
- Timer editorTimer = new EditorUpdateTimer();
-
- /**
- * Stores the old value of a cell before it was edited, in case
- * editing is cancelled
- */
- Object oldCellValue;
-
- /**
* The property handler for this table's columns.
*/
TableColumnPropertyChangeHandler tableColumnPropertyChangeHandler =
@@ -1510,6 +1562,11 @@ public class JTable
private boolean surrendersFocusOnKeystroke = false;
/**
+ * A Rectangle object to be reused in {@link #getCellRect}.
+ */
+ private Rectangle rectCache = new Rectangle();
+
+ /**
* Creates a new <code>JTable</code> instance.
*/
public JTable ()
@@ -1518,7 +1575,8 @@ public class JTable
}
/**
- * Creates a new <code>JTable</code> instance.
+ * Creates a new <code>JTable</code> instance with the given number
+ * of rows and columns.
*
* @param numRows an <code>int</code> value
* @param numColumns an <code>int</code> value
@@ -1529,10 +1587,12 @@ public class JTable
}
/**
- * Creates a new <code>JTable</code> instance.
+ * Creates a new <code>JTable</code> instance, storing the given data
+ * array and heaving the given column names. To see the column names,
+ * you must place the JTable into the {@link JScrollPane}.
*
- * @param data an <code>Object[][]</code> value
- * @param columnNames an <code>Object[]</code> value
+ * @param data an <code>Object[][]</code> the table data
+ * @param columnNames an <code>Object[]</code> the column headers
*/
public JTable(Object[][] data, Object[] columnNames)
{
@@ -1540,20 +1600,31 @@ public class JTable
}
/**
- * Creates a new <code>JTable</code> instance.
- *
- * @param dm a <code>TableModel</code> value
+ * Creates a new <code>JTable</code> instance, using the given data model
+ * object that provides information about the table content. The table model
+ * object is asked for the table size, other features and also receives
+ * notifications in the case when the table has been edited by the user.
+ *
+ * @param model
+ * the table model.
*/
- public JTable (TableModel dm)
+ public JTable (TableModel model)
{
- this(dm, null, null);
+ this(model, null, null);
}
/**
- * Creates a new <code>JTable</code> instance.
- *
- * @param dm a <code>TableModel</code> value
- * @param cm a <code>TableColumnModel</code> value
+ * Creates a new <code>JTable</code> instance, using the given model object
+ * that provides information about the table content. The table data model
+ * object is asked for the table size, other features and also receives
+ * notifications in the case when the table has been edited by the user. The
+ * table column model provides more detailed control on the table column
+ * related features.
+ *
+ * @param dm
+ * the table data mode
+ * @param cm
+ * the table column model
*/
public JTable (TableModel dm, TableColumnModel cm)
{
@@ -1561,11 +1632,13 @@ public class JTable
}
/**
- * Creates a new <code>JTable</code> instance.
+ * Creates a new <code>JTable</code> instance, providing data model,
+ * column model and list selection model. The list selection model
+ * manages the selections.
*
- * @param dm a <code>TableModel</code> value
- * @param cm a <code>TableColumnModel</code> value
- * @param sm a <code>ListSelectionModel</code> value
+ * @param dm data model (manages table data)
+ * @param cm column model (manages table columns)
+ * @param sm list selection model (manages table selections)
*/
public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm)
{
@@ -1593,8 +1666,23 @@ public class JTable
columnModel.getSelectionModel().setAnchorSelectionIndex(0);
columnModel.getSelectionModel().setLeadSelectionIndex(0);
updateUI();
- }
-
+ }
+
+ /**
+ * Creates a new <code>JTable</code> instance that uses data and column
+ * names, stored in {@link Vector}s.
+ *
+ * @param data the table data
+ * @param columnNames the table column names.
+ */
+ public JTable(Vector data, Vector columnNames)
+ {
+ this(new DefaultTableModel(data, columnNames));
+ }
+
+ /**
+ * Initialize local variables to default values.
+ */
protected void initializeLocalVars()
{
setTableHeader(createDefaultTableHeader());
@@ -1623,63 +1711,18 @@ public class JTable
this.editingRow = -1;
setIntercellSpacing(new Dimension(1,1));
}
-
- /**
- * Creates a new <code>JTable</code> instance.
- *
- * @param data a <code>Vector</code> value
- * @param columnNames a <code>Vector</code> value
- */
- public JTable(Vector data, Vector columnNames)
- {
- this(new DefaultTableModel(data, columnNames));
- }
-
+
/**
- * The timer that updates the editor component.
+ * Add the new table column. The table column class allows to specify column
+ * features more precisely, setting the preferred width, column data type
+ * (column class) and table headers.
+ *
+ * There is no need the add columns to the table if the default column
+ * handling is sufficient.
+ *
+ * @param column
+ * the new column to add.
*/
- private class EditorUpdateTimer
- extends Timer
- implements ActionListener
- {
- /**
- * Creates a new EditorUpdateTimer object with a default delay of 0.5 seconds.
- */
- public EditorUpdateTimer()
- {
- super(500, null);
- addActionListener(this);
- }
-
- /**
- * Lets the caret blink and repaints the table.
- */
- public void actionPerformed(ActionEvent ev)
- {
- Caret c = ((JTextField)JTable.this.editorComp).getCaret();
- if (c != null)
- c.setVisible(!c.isVisible());
- JTable.this.repaint();
- }
-
- /**
- * Updates the blink delay according to the current caret.
- */
- public void update()
- {
- stop();
- Caret c = ((JTextField)JTable.this.editorComp).getCaret();
- if (c != null)
- {
- setDelay(c.getBlinkRate());
- if (((JTextField)JTable.this.editorComp).isEditable())
- start();
- else
- c.setVisible(false);
- }
- }
- }
-
public void addColumn(TableColumn column)
{
if (column.getHeaderValue() == null)
@@ -1691,12 +1734,24 @@ public class JTable
columnModel.addColumn(column);
column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
}
-
+
+ /**
+ * Create the default editors for this table. The default method creates
+ * the editor for Booleans.
+ *
+ * Other fields are edited as strings at the moment.
+ */
protected void createDefaultEditors()
{
- //FIXME: Create the editor object.
+ JCheckBox box = new BooleanCellRenderer().getCheckBox();
+ setDefaultEditor(Boolean.class, new DefaultCellEditor(box));
}
-
+
+ /**
+ * Create the default renderers for this table. The default method creates
+ * renderers for Boolean, Number, Double, Date, Icon and ImageIcon.
+ *
+ */
protected void createDefaultRenderers()
{
setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
@@ -1705,6 +1760,7 @@ public class JTable
setDefaultRenderer(Double.class, new FloatCellRenderer());
setDefaultRenderer(Date.class, new DateCellRenderer());
setDefaultRenderer(Icon.class, new IconCellRenderer());
+ setDefaultRenderer(ImageIcon.class, new IconCellRenderer());
}
/**
@@ -1714,112 +1770,148 @@ public class JTable
{
return new JScrollPane(table);
}
-
+
+ /**
+ * Create the default table column model that is used if the user-defined
+ * column model is not provided. The default method creates
+ * {@link DefaultTableColumnModel}.
+ *
+ * @return the created table column model.
+ */
protected TableColumnModel createDefaultColumnModel()
{
return new DefaultTableColumnModel();
}
+ /**
+ * Create the default table data model that is used if the user-defined
+ * data model is not provided. The default method creates
+ * {@link DefaultTableModel}.
+ *
+ * @return the created table data model.
+ */
protected TableModel createDefaultDataModel()
{
return new DefaultTableModel();
}
+ /**
+ * Create the default table selection model that is used if the user-defined
+ * selection model is not provided. The default method creates
+ * {@link DefaultListSelectionModel}.
+ *
+ * @return the created table data model.
+ */
protected ListSelectionModel createDefaultSelectionModel()
{
return new DefaultListSelectionModel();
}
-
+
+ /**
+ * Create the default table header, if the user - defined table header is not
+ * provided.
+ *
+ * @return the default table header.
+ */
protected JTableHeader createDefaultTableHeader()
{
return new JTableHeader(columnModel);
}
-
- // listener support
-
+
+ /**
+ * Invoked when the column is added. Revalidates and repains the table.
+ */
public void columnAdded (TableColumnModelEvent event)
{
revalidate();
repaint();
}
+ /**
+ * Invoked when the column margin is changed.
+ * Revalidates and repains the table.
+ */
public void columnMarginChanged (ChangeEvent event)
{
revalidate();
repaint();
}
+ /**
+ * Invoked when the column is moved. Revalidates and repains the table.
+ */
public void columnMoved (TableColumnModelEvent event)
{
revalidate();
repaint();
}
+ /**
+ * Invoked when the column is removed. Revalidates and repains the table.
+ */
public void columnRemoved (TableColumnModelEvent event)
{
revalidate();
repaint();
}
+ /**
+ * Invoked when the the column selection changes.
+ */
public void columnSelectionChanged (ListSelectionEvent event)
{
repaint();
}
-
+
+ /**
+ * Invoked when the editing is cancelled.
+ */
public void editingCanceled (ChangeEvent event)
{
- if (rowBeingEdited > -1 && columnBeingEdited > -1)
+ if (editorComp!=null)
{
- if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof JTextField)
- {
- remove ((Component)getValueAt(rowBeingEdited, columnBeingEdited));
- setValueAt(oldCellValue, rowBeingEdited, columnBeingEdited);
- }
- rowBeingEdited = -1;
- columnBeingEdited = -1;
+ remove(editorComp);
+ repaint(editorComp.getBounds());
+ editorComp = null;
}
- editorTimer.stop();
- editorComp = null;
- cellEditor = null;
- requestFocusInWindow(false);
- repaint();
}
-
+
+ /**
+ * Finish the current editing session and update the table with the
+ * new value by calling {@link #setValueAt}.
+ *
+ * @param event the change event
+ */
public void editingStopped (ChangeEvent event)
{
- if (rowBeingEdited > -1 && columnBeingEdited > -1)
+ if (editorComp!=null)
{
- if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof JTextField)
- {
- remove((Component)getValueAt(rowBeingEdited, columnBeingEdited));
- setValueAt(((JTextField)editorComp).getText(),
- rowBeingEdited, columnBeingEdited);
- }
- rowBeingEdited = -1;
- columnBeingEdited = -1;
+ remove(editorComp);
+ setValueAt(cellEditor.getCellEditorValue(), editingRow, editingColumn);
+ repaint(editorComp.getBounds());
+ editorComp = null;
}
- editorTimer.stop();
- editorComp = null;
- cellEditor = null;
- requestFocusInWindow(false);
- repaint();
+ requestFocusInWindow();
}
+ /**
+ * Invoked when the table changes.
+ * <code>null</code> means everything changed.
+ */
public void tableChanged (TableModelEvent event)
{
// update the column model from the table model if the structure has
// changed and the flag autoCreateColumnsFromModel is set
- if ((event.getFirstRow() ==TableModelEvent.HEADER_ROW)
- && autoCreateColumnsFromModel)
-
+ if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW))
+ && autoCreateColumnsFromModel)
createDefaultColumnsFromModel();
// If the structure changes, we need to revalidate, since that might
// affect the size parameters of the JTable. Otherwise we only need
// to perform a repaint to update the view.
- if (event.getType() == TableModelEvent.INSERT)
+ if (event == null || event.getType() == TableModelEvent.INSERT)
revalidate();
- else if (event.getType() == TableModelEvent.DELETE)
+ if (event == null || event.getType() == TableModelEvent.DELETE)
{
if (dataModel.getRowCount() == 0)
clearSelection();
@@ -1828,6 +1920,9 @@ public class JTable
repaint();
}
+ /**
+ * Invoked when another table row is selected.
+ */
public void valueChanged (ListSelectionEvent event)
{
repaint();
@@ -1863,29 +1958,30 @@ public class JTable
}
/**
- * Returns index of the row that contains specified point or
- * -1 if this table doesn't contain this point.
- *
- * @param point point to identify the row
- * @return index of the row that contains specified point or
- * -1 if this table doesn't contain this point.
+ * Returns index of the row that contains specified point or -1 if this table
+ * doesn't contain this point.
+ *
+ * @param point
+ * point to identify the row
+ * @return index of the row that contains specified point or -1 if this table
+ * doesn't contain this point.
*/
public int rowAtPoint(Point point)
{
if (point != null)
{
int nrows = getRowCount();
- int height = getRowHeight();
+ int height = getRowHeight() + getRowMargin();
int y = point.y;
- for (int i = 0; i < nrows; ++i)
- {
- if (0 <= y && y < height)
- return i;
- y -= height;
- }
+ int r = y / height;
+ if (r < 0 || r >= nrows)
+ return -1;
+ else
+ return r;
}
- return -1;
+ else
+ return -1;
}
/**
@@ -1908,6 +2004,9 @@ public class JTable
int column,
boolean includeSpacing)
{
+ // moveToCellBeingEdited expects the cached value and clones it.
+ // If the caching would be removed later, uplate moveToCellBeingEdited
+ // as well.
int height = getRowHeight(row);
int width = columnModel.getColumn(column).getWidth();
int x_gap = columnModel.getColumnMargin();
@@ -1923,9 +2022,10 @@ public class JTable
x += columnModel.getColumn(i).getWidth();
if (includeSpacing)
- return new Rectangle(x, y, width, height);
+ rectCache.setBounds(x, y, width, height +y_gap);
else
- return new Rectangle(x, y, width - x_gap, height - y_gap);
+ rectCache.setBounds(x, y, width - x_gap, height);
+ return rectCache;
}
public void clearSelection()
@@ -2008,44 +2108,88 @@ public class JTable
}
+ /**
+ * Get the cell editor, suitable for editing the given cell. The default
+ * method requests the editor from the column model. If the column model does
+ * not provide the editor, the call is forwarded to the
+ * {@link #getDefaultEditor(Class)} with the parameter, obtained from
+ * {@link TableModel#getColumnClass(int)}.
+ *
+ * @param row the cell row
+ * @param column the cell column
+ * @return the editor to edit that cell
+ */
public TableCellEditor getCellEditor(int row, int column)
{
TableCellEditor editor = columnModel.getColumn(column).getCellEditor();
if (editor == null)
- editor = getDefaultEditor(dataModel.getColumnClass(column));
-
+ {
+ int mcolumn = convertColumnIndexToModel(column);
+ editor = getDefaultEditor(dataModel.getColumnClass(mcolumn));
+ }
+
return editor;
}
-
+
+ /**
+ * Get the default editor for editing values of the given type
+ * (String, Boolean and so on).
+ *
+ * @param columnClass the class of the value that will be edited.
+ *
+ * @return the editor, suitable for editing this data type
+ */
public TableCellEditor getDefaultEditor(Class columnClass)
{
if (defaultEditorsByColumnClass.containsKey(columnClass))
return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass);
else
{
- // FIXME: We have at least an editor for Object.class in our defaults.
- TableCellEditor r = new DefaultCellEditor(new JTextField());
+ JTextField t = new TableTextField();
+ TableCellEditor r = new DefaultCellEditor(t);
defaultEditorsByColumnClass.put(columnClass, r);
return r;
}
}
-
+
+ /**
+ * Get the cell renderer for rendering the given cell.
+ *
+ * @param row the cell row
+ * @param column the cell column
+ * @return the cell renderer to render that cell.
+ */
public TableCellRenderer getCellRenderer(int row, int column)
{
- TableCellRenderer renderer =
- columnModel.getColumn(column).getCellRenderer();
+ TableCellRenderer renderer = columnModel.getColumn(column).getCellRenderer();
if (renderer == null)
- renderer = getDefaultRenderer(getColumnClass(column));
-
+ {
+ int mcolumn = convertColumnIndexToModel(column);
+ renderer = getDefaultRenderer(dataModel.getColumnClass(mcolumn));
+ }
return renderer;
}
-
+
+ /**
+ * Set default renderer for rendering the given data type.
+ *
+ * @param columnClass the data type (String, Boolean and so on) that must be
+ * rendered.
+ * @param rend the renderer that will rend this data type
+ */
public void setDefaultRenderer(Class columnClass, TableCellRenderer rend)
{
defaultRenderersByColumnClass.put(columnClass, rend);
}
-
+
+ /**
+ * Get the default renderer for rendering the given data type.
+ *
+ * @param columnClass the data that must be rendered
+ *
+ * @return the appropriate defauld renderer for rendering that data type.
+ */
public TableCellRenderer getDefaultRenderer(Class columnClass)
{
if (defaultRenderersByColumnClass.containsKey(columnClass))
@@ -2057,7 +2201,19 @@ public class JTable
return r;
}
}
-
+
+ /**
+ * Convert the table model index into the table column number.
+ * The model number need not match the real column position. The columns
+ * may be rearranged by the user with mouse at any time by dragging the
+ * column headers.
+ *
+ * @param vc the column number (0=first).
+ *
+ * @return the table column model index of this column.
+ *
+ * @see TableColumn#getModelIndex()
+ */
public int convertColumnIndexToModel(int vc)
{
if (vc < 0)
@@ -2065,7 +2221,19 @@ public class JTable
else
return columnModel.getColumn(vc).getModelIndex();
}
-
+
+ /**
+ * Convert the table column number to the table column model index.
+ * The model number need not match the real column position. The columns
+ * may be rearranged by the user with mouse at any time by dragging the
+ * column headers.
+ *
+ * @param mc the table column index (0=first).
+ *
+ * @return the table column number in the model
+ *
+ * @see TableColumn#getModelIndex()
+ */
public int convertColumnIndexToView(int mc)
{
if (mc < 0)
@@ -2078,7 +2246,16 @@ public class JTable
}
return -1;
}
-
+
+ /**
+ * Prepare the renderer for rendering the given cell.
+ *
+ * @param renderer the renderer being prepared
+ * @param row the row of the cell being rendered
+ * @param column the column of the cell being rendered
+ *
+ * @return the component which .paint() method will paint the cell.
+ */
public Component prepareRenderer(TableCellRenderer renderer,
int row,
int column)
@@ -2640,8 +2817,13 @@ public class JTable
if (dataModel != null && columnModel != null)
{
int ncols = getColumnCount();
+ TableColumn column;
for (int i = 0; i < ncols; ++i)
- columnModel.getColumn(i).setHeaderValue(dataModel.getColumnName(i));
+ {
+ column = columnModel.getColumn(i);
+ if (column.getHeaderValue()==null)
+ column.setHeaderValue(dataModel.getColumnName(i));
+ }
}
// according to Sun's spec we also have to set the tableHeader's
@@ -2899,10 +3081,36 @@ public class JTable
for (int i = 0; i < cols.length; i++)
{
if (cols[i] != null)
- cols[i].setWidth(cols[i].getWidth() + average);
+ cols[i].setWidth(cols[i].getPreferredWidth() + average);
}
}
-
+
+ /**
+ * This distributes the superfluous width in a table, setting the width of the
+ * column being resized strictly to its preferred width.
+ */
+ private void distributeSpillResizing(TableColumn[] cols, int spill,
+ TableColumn resizeIt)
+ {
+ int average = 0;
+ if (cols.length != 1)
+ average = spill / (cols.length-1);
+ for (int i = 0; i < cols.length; i++)
+ {
+ if (cols[i] != null && !cols[i].equals(resizeIt))
+ cols[i].setWidth(cols[i].getPreferredWidth() + average);
+ }
+ resizeIt.setWidth(resizeIt.getPreferredWidth());
+ }
+
+ /**
+ * Set the widths of all columns, taking they preferred widths into
+ * consideration. The excess space, if any, will be distrubuted between
+ * all columns. This method also handles special cases when one of the
+ * collumns is currently being resized.
+ *
+ * @see TableColumn#setPreferredWidth(int)
+ */
public void doLayout()
{
TableColumn resizingColumn = null;
@@ -2911,7 +3119,6 @@ public class JTable
if (ncols < 1)
return;
- int[] pref = new int[ncols];
int prefSum = 0;
int rCol = -1;
@@ -2921,8 +3128,7 @@ public class JTable
for (int i = 0; i < ncols; ++i)
{
TableColumn col = columnModel.getColumn(i);
- int p = col.getWidth();
- pref[i] = p;
+ int p = col.getPreferredWidth();
prefSum += p;
if (resizingColumn == col)
rCol = i;
@@ -2951,14 +3157,38 @@ public class JTable
cols = new TableColumn[ncols];
for (int i = 0; i < ncols; ++i)
cols[i] = columnModel.getColumn(i);
- distributeSpill(cols, spill);
+ distributeSpillResizing(cols, spill, resizingColumn);
break;
case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
- cols = new TableColumn[ncols];
- for (int i = rCol; i < ncols; ++i)
- cols[i] = columnModel.getColumn(i);
- distributeSpill(cols, spill);
+
+ // Subtract the width of the non-resized columns from the spill.
+ int w = 0;
+ int wp = 0;
+ TableColumn column;
+ for (int i = 0; i < rCol; i++)
+ {
+ column = columnModel.getColumn(i);
+ w += column.getWidth();
+ wp+= column.getPreferredWidth();
+ }
+
+ // The number of columns right from the column being resized.
+ int n = ncols-rCol-1;
+ if (n>0)
+ {
+ // If there are any columns on the right sied to resize.
+ spill = (getWidth()-w) - (prefSum-wp);
+ int average = spill / n;
+
+ // For all columns right from the column being resized:
+ for (int i = rCol+1; i < ncols; i++)
+ {
+ column = columnModel.getColumn(i);
+ column.setWidth(column.getPreferredWidth() + average);
+ }
+ }
+ resizingColumn.setWidth(resizingColumn.getPreferredWidth());
break;
case AUTO_RESIZE_OFF:
@@ -2974,6 +3204,16 @@ public class JTable
cols[i] = columnModel.getColumn(i);
distributeSpill(cols, spill);
}
+
+ if (editorComp!=null)
+ moveToCellBeingEdited(editorComp);
+
+ // Repaint fixes the invalid view after the first keystroke if the cell
+ // editing is started immediately after the program start or cell
+ // resizing.
+ repaint();
+ if (tableHeader!=null)
+ tableHeader.repaint();
}
/**
@@ -2983,7 +3223,7 @@ public class JTable
{
doLayout();
}
-
+
/**
* Obsolete since JDK 1.4. Please use <code>doLayout()</code>.
*/
@@ -3023,48 +3263,109 @@ public class JTable
revalidate();
repaint();
}
-
+
+ /**
+ * Get the class (datatype) of the column. The cells are rendered and edited
+ * differently, depending from they data type.
+ *
+ * @param column the column (not the model index).
+ *
+ * @return the class, defining data type of that column (String.class for
+ * String, Boolean.class for boolean and so on).
+ */
public Class getColumnClass(int column)
{
- return getModel().getColumnClass(column);
+ return getModel().getColumnClass(convertColumnIndexToModel(column));
}
+ /**
+ * Get the name of the column. If the column has the column identifier set,
+ * the return value is the result of the .toString() method call on that
+ * identifier. If the identifier is not explicitly set, the returned value
+ * is calculated by
+ * {@link javax.swing.table.AbstractTableModel#getColumnName(int)}.
+ *
+ * @param column the column
+ *
+ * @return the name of that column.
+ */
public String getColumnName(int column)
{
int modelColumn = columnModel.getColumn(column).getModelIndex();
return dataModel.getColumnName(modelColumn);
}
-
+
+ /**
+ * Get the column, currently being edited
+ *
+ * @return the column, currently being edited.
+ */
public int getEditingColumn()
{
return editingColumn;
}
-
+
+ /**
+ * Set the column, currently being edited
+ *
+ * @param column the column, currently being edited.
+ */
public void setEditingColumn(int column)
{
editingColumn = column;
}
+ /**
+ * Get the row currently being edited.
+ *
+ * @return the row, currently being edited.
+ */
public int getEditingRow()
{
return editingRow;
}
-
- public void setEditingRow(int column)
+
+ /**
+ * Set the row currently being edited.
+ *
+ * @param row the row, that will be edited
+ */
+ public void setEditingRow(int row)
{
- editingRow = column;
+ editingRow = row;
}
+ /**
+ * Get the editor component that is currently editing one of the cells
+ *
+ * @return the editor component or null, if none of the cells is being
+ * edited.
+ */
public Component getEditorComponent()
{
return editorComp;
}
+ /**
+ * Check if one of the table cells is currently being edited.
+ *
+ * @return true if there is a cell being edited.
+ */
public boolean isEditing()
{
return editorComp != null;
}
-
+
+ /**
+ * Set the default editor for the given column class (column data type).
+ * By default, String is handled by text field and Boolean is handled by
+ * the check box.
+ *
+ * @param columnClass the column data type
+ * @param editor the editor that will edit this data type
+ *
+ * @see TableModel#getColumnClass(int)
+ */
public void setDefaultEditor(Class columnClass, TableCellEditor editor)
{
if (editor != null)
@@ -3072,7 +3373,7 @@ public class JTable
else
defaultEditorsByColumnClass.remove(columnClass);
}
-
+
public void addColumnSelectionInterval(int index0, int index1)
{
if ((index0 < 0 || index0 > (getColumnCount()-1)
@@ -3127,21 +3428,49 @@ public class JTable
getSelectionModel().removeSelectionInterval(index0, index1);
}
+ /**
+ * Checks if the given column is selected.
+ *
+ * @param column the column
+ *
+ * @return true if the column is selected (as reported by the selection
+ * model, associated with the column model), false otherwise.
+ */
public boolean isColumnSelected(int column)
{
return getColumnModel().getSelectionModel().isSelectedIndex(column);
}
-
+
+ /**
+ * Checks if the given row is selected.
+ *
+ * @param row the row
+ *
+ * @return true if the row is selected (as reported by the selection model),
+ * false otherwise.
+ */
public boolean isRowSelected(int row)
{
return getSelectionModel().isSelectedIndex(row);
}
-
+
+ /**
+ * Checks if the given cell is selected. The cell is selected if both
+ * the cell row and the cell column are selected.
+ *
+ * @param row the cell row
+ * @param column the cell column
+ *
+ * @return true if the cell is selected, false otherwise
+ */
public boolean isCellSelected(int row, int column)
{
return isRowSelected(row) && isColumnSelected(column);
}
+ /**
+ * Select all table.
+ */
public void selectAll()
{
// rowLead and colLead store the current lead selection indices
@@ -3156,22 +3485,51 @@ public class JTable
addColumnSelectionInterval(colLead,colLead);
addRowSelectionInterval(rowLead, rowLead);
}
-
+
+ /**
+ * Get the cell value at the given position.
+ *
+ * @param row the row to get the value
+ * @param column the actual column number (not the model index)
+ * to get the value.
+ *
+ * @return the cell value, as returned by model.
+ */
public Object getValueAt(int row, int column)
{
return dataModel.getValueAt(row, convertColumnIndexToModel(column));
}
-
+
+ /**
+ * Set value for the cell at the given position. If the cell is not
+ * editable, this method returns without action. The modified cell is
+ * repainted.
+ *
+ * @param value the value to set
+ * @param row the row of the cell being modified
+ * @param column the column of the cell being modified
+ */
public void setValueAt(Object value, int row, int column)
{
if (!isCellEditable(row, column))
return;
-
- if (value instanceof Component)
- add((Component)value);
dataModel.setValueAt(value, row, convertColumnIndexToModel(column));
+
+ repaint(getCellRect(row, column, true));
}
-
+
+ /**
+ * Get table column with the given identified.
+ *
+ * @param identifier the column identifier
+ *
+ * @return the table column with this identifier
+ *
+ * @throws IllegalArgumentException if <code>identifier</code> is
+ * <code>null</code> or there is no column with that identifier.
+ *
+ * @see TableColumn#setIdentifier(Object)
+ */
public TableColumn getColumn(Object identifier)
{
return columnModel.getColumn(columnModel.getColumnIndex(identifier));
@@ -3184,7 +3542,7 @@ public class JTable
* @param row the row index.
* @param column the column index.
*
- * @return A boolean.
+ * @return true if the cell is editable, false otherwise.
*/
public boolean isCellEditable(int row, int column)
{
@@ -3273,19 +3631,50 @@ public class JTable
*/
public boolean editCellAt (int row, int column)
{
- oldCellValue = getValueAt(row, column);
+ // Complete the previous editing session, if still active.
+ if (isEditing())
+ editingStopped(new ChangeEvent("editingStopped"));
+
+ editingRow = row;
+ editingColumn = column;
+
setCellEditor(getCellEditor(row, column));
editorComp = prepareEditor(cellEditor, row, column);
- cellEditor.addCellEditorListener(this);
- rowBeingEdited = row;
- columnBeingEdited = column;
- setValueAt(editorComp, row, column);
- ((JTextField)editorComp).requestFocusInWindow(false);
- editorTimer.start();
+
+ // Remove the previous editor components, if present. Only one
+ // editor component at time is allowed in the table.
+ removeAll();
+ add(editorComp);
+ moveToCellBeingEdited(editorComp);
+ scrollRectToVisible(editorComp.getBounds());
+ editorComp.requestFocusInWindow();
return true;
}
/**
+ * Move the given component under the cell being edited.
+ * The table must be in the editing mode.
+ *
+ * @param component the component to move.
+ */
+ private void moveToCellBeingEdited(Component component)
+ {
+ Rectangle r = getCellRect(editingRow, editingColumn, true);
+ // Place the text field so that it would not touch the table
+ // border.
+
+ // TODO Figure out while 5 and which constant should here be.
+ int xOffset = 5;
+ r.x+=xOffset;
+ r.y++;
+ r.width -=xOffset;
+ r.height --;
+
+ // Clone rectangle as getCellRect returns the cached value.
+ component.setBounds(new Rectangle(r));
+ }
+
+ /**
* Programmatically starts editing the specified cell.
*
* @param row the row of the cell to edit.
@@ -3343,7 +3732,7 @@ public class JTable
// TODO: Implement functionality of this property (in UI impl).
surrendersFocusOnKeystroke = value;
}
-
+
/**
* Returns whether cell editors of this table should receive keyboard focus
* when the editor is activated by a keystroke. The default setting is
diff --git a/libjava/classpath/javax/swing/JTextField.java b/libjava/classpath/javax/swing/JTextField.java
index c4903106131..01c5c06a350 100644
--- a/libjava/classpath/javax/swing/JTextField.java
+++ b/libjava/classpath/javax/swing/JTextField.java
@@ -41,6 +41,7 @@ package javax.swing;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
+import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
@@ -352,7 +353,10 @@ public class JTextField extends JTextComponent
Dimension size = super.getPreferredSize();
if (columns != 0)
- size.width = columns * getColumnWidth();
+ {
+ Insets i = getInsets();
+ size.width = columns * getColumnWidth() + i.left + i.right;
+ }
return size;
}
@@ -526,4 +530,18 @@ public class JTextField extends JTextComponent
// javax.swing.text.FieldView.
return horizontalVisibility;
}
+
+ /**
+ * Returns <code>true</code>, unless this is embedded in a
+ * <code>JViewport</code> in which case the viewport takes responsibility of
+ * validating.
+ *
+ * @return <code>true</code>, unless this is embedded in a
+ * <code>JViewport</code> in which case the viewport takes
+ * responsibility of validating
+ */
+ public boolean isValidateRoot()
+ {
+ return ! (getParent() instanceof JViewport);
+ }
}
diff --git a/libjava/classpath/javax/swing/JTextPane.java b/libjava/classpath/javax/swing/JTextPane.java
index 7c95d7682c5..c0a5f80cfc8 100644
--- a/libjava/classpath/javax/swing/JTextPane.java
+++ b/libjava/classpath/javax/swing/JTextPane.java
@@ -327,9 +327,11 @@ public class JTextPane
if (start == dot && end == dot)
// There is no selection, update insertAttributes instead
{
- MutableAttributeSet inputAttributes =
- getStyledEditorKit().getInputAttributes();
- inputAttributes.addAttributes(attribute);
+ MutableAttributeSet inputAttributes =
+ getStyledEditorKit().getInputAttributes();
+ if (replace)
+ inputAttributes.removeAttributes(inputAttributes);
+ inputAttributes.addAttributes(attribute);
}
else
getStyledDocument().setCharacterAttributes(start, end - start, attribute,
diff --git a/libjava/classpath/javax/swing/JTree.java b/libjava/classpath/javax/swing/JTree.java
index cfcb2291b2c..7876eeb6aaa 100644
--- a/libjava/classpath/javax/swing/JTree.java
+++ b/libjava/classpath/javax/swing/JTree.java
@@ -1482,6 +1482,9 @@ public class JTree extends JComponent implements Scrollable, Accessible
setModel(model);
setSelectionModel(new EmptySelectionModel());
selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+
+ // The root node appears expanded by default.
+ nodeStates.put(new TreePath(model.getRoot()), EXPANDED);
}
/**
@@ -2497,8 +2500,9 @@ public class JTree extends JComponent implements Scrollable, Accessible
{
TreeUI ui = getUI();
- if (ui != null)
- return ui.stopEditing(this);
+ if (isEditing())
+ if (ui != null)
+ return ui.stopEditing(this);
return false;
}
@@ -2506,9 +2510,10 @@ public class JTree extends JComponent implements Scrollable, Accessible
public void cancelEditing()
{
TreeUI ui = getUI();
-
- if (ui != null)
- ui.cancelEditing(this);
+
+ if (isEditing())
+ if (ui != null)
+ ui.cancelEditing(this);
}
public void startEditingAtPath(TreePath path)
@@ -2738,7 +2743,7 @@ public class JTree extends JComponent implements Scrollable, Accessible
*
* @return a String representation of this JTree
*/
- public String paramString()
+ protected String paramString()
{
// TODO: this is completely legal, but it would possibly be nice
// to return some more content, like the tree structure, some properties
diff --git a/libjava/classpath/javax/swing/JViewport.java b/libjava/classpath/javax/swing/JViewport.java
index debb5742e2c..2b5d1cd5a2f 100644
--- a/libjava/classpath/javax/swing/JViewport.java
+++ b/libjava/classpath/javax/swing/JViewport.java
@@ -48,6 +48,7 @@ import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.Shape;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.Serializable;
@@ -113,7 +114,7 @@ public class JViewport extends JComponent implements Accessible
/**
* Creates a new instance of <code>AccessibleJViewport</code>.
*/
- public AccessibleJViewport()
+ protected AccessibleJViewport()
{
// Nothing to do here.
}
@@ -252,6 +253,13 @@ public class JViewport extends JComponent implements Accessible
boolean sizeChanged = true;
/**
+ * Indicates if this JViewport is the paint root or not. If it is not, then
+ * we may not assume that the offscreen buffer still has the right content
+ * because parent components may have cleared the background already.
+ */
+ private boolean isPaintRoot = false;
+
+ /**
* Initializes the default setting for the scrollMode property.
*/
static
@@ -635,11 +643,19 @@ public class JViewport extends JComponent implements Accessible
*/
public void repaint(long tm, int x, int y, int w, int h)
{
- Component parent = getParent();
- if (parent != null)
- {
- parent.repaint(tm, x + getX(), y + getY(), w, h);
- }
+// Component parent = getParent();
+// if (parent != null)
+// parent.repaint(tm, x + getX(), y + getY(), w, h);
+// else
+// super.repaint(tm, x, y, w, h);
+
+ // The specs suggest to implement something like the above. This however
+ // breaks blit painting, because the parent (most likely a JScrollPane)
+ // clears the background of the offscreen area of the JViewport, thus
+ // destroying the pieces that we want to clip. So we simply call super here
+ // instead.
+ super.repaint(tm, x, y, w, h);
+
}
protected void addImpl(Component comp, Object constraints, int index)
@@ -710,9 +726,11 @@ public class JViewport extends JComponent implements Accessible
protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo,
Dimension blitSize, Rectangle blitPaint)
{
- if ((dx != 0 && dy != 0) || damaged)
+ if ((dx != 0 && dy != 0) || (dy == 0 && dy == 0) || damaged)
// We cannot blit if the viewport is scrolled in both directions at
- // once.
+ // once. Also, we do not want to blit if the viewport is not scrolled at
+ // all, because that probably means the view component repaints itself
+ // and the buffer needs updating.
return false;
Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds());
@@ -791,6 +809,8 @@ public class JViewport extends JComponent implements Accessible
Point pos = getViewPosition();
Component view = getView();
+ Shape oldClip = g.getClip();
+ g.clipRect(0, 0, getWidth(), getHeight());
boolean translated = false;
try
{
@@ -802,6 +822,7 @@ public class JViewport extends JComponent implements Accessible
{
if (translated)
g.translate (pos.x, pos.y);
+ g.setClip(oldClip);
}
}
@@ -854,6 +875,11 @@ public class JViewport extends JComponent implements Accessible
// everything.
else
{
+ // If the image has not been scrolled at all, only the changed
+ // clip must be updated in the buffer.
+ if (dx==0 && dy==0)
+ g2.setClip(g.getClip());
+
paintSimple(g2);
}
g2.dispose();
@@ -877,23 +903,49 @@ public class JViewport extends JComponent implements Accessible
*/
void paintBlit(Graphics g)
{
- // We cannot perform blitted painting as it is described in Sun's API docs.
- // There it is suggested that this painting method should blit directly
- // on the parent window's surface. This is not possible because when using
- // Swing's double buffering (at least our implementation), it would
- // immediatly be painted when the buffer is painted on the screen. For this
- // to work we would need a kind of hole in the buffer image. And honestly
- // I find this method not very elegant.
- // The alternative, blitting directly on the buffer image, is also not
- // possible because the buffer image gets cleared everytime when an opaque
- // parent component is drawn on it.
-
- // What we do instead is falling back to the backing store approach which
- // is in fact a mixed blitting/backing store approach where the blitting
- // is performed on the backing store image and this is then drawn to the
- // graphics context. This is very robust and works independent of the
- // painting mechanism that is used by Swing. And it should have comparable
- // performance characteristics as the blitting method.
- paintBackingStore(g);
+ // First we move the part that remains visible after scrolling, then
+ // we only need to paint the bit that becomes newly visible.
+ Point viewPosition = getViewPosition();
+ int dx = viewPosition.x - lastPaintPosition.x;
+ int dy = viewPosition.y - lastPaintPosition.y;
+ boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
+ cachedBlitSize, cachedBlitPaint);
+ if (canBlit && isPaintRoot)
+ {
+ // Copy the part that remains visible during scrolling.
+ g.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
+ cachedBlitSize.width, cachedBlitSize.height,
+ cachedBlitTo.x - cachedBlitFrom.x,
+ cachedBlitTo.y - cachedBlitFrom.y);
+ // Now paint the part that becomes newly visible.
+ Shape oldClip = g.getClip();
+ g.clipRect(cachedBlitPaint.x, cachedBlitPaint.y,
+ cachedBlitPaint.width, cachedBlitPaint.height);
+ try
+ {
+ paintSimple(g);
+ }
+ finally
+ {
+ g.setClip(oldClip);
+ }
+ }
+ // If blitting is not possible for some reason, fall back to repainting
+ // everything.
+ else
+ paintSimple(g);
+ lastPaintPosition.setLocation(getViewPosition());
+ }
+
+ /**
+ * Overridden from JComponent to set the {@link #isPaintRoot} flag.
+ *
+ * @param r the rectangle to paint
+ */
+ void paintImmediately2(Rectangle r)
+ {
+ isPaintRoot = true;
+ super.paintImmediately2(r);
+ isPaintRoot = false;
}
}
diff --git a/libjava/classpath/javax/swing/JWindow.java b/libjava/classpath/javax/swing/JWindow.java
index cc0ac7fd95a..19d830ed1f7 100644
--- a/libjava/classpath/javax/swing/JWindow.java
+++ b/libjava/classpath/javax/swing/JWindow.java
@@ -68,7 +68,7 @@ public class JWindow extends Window implements Accessible, RootPaneContainer
/**
* Creates a new instance of <code>AccessibleJWindow</code>.
*/
- public AccessibleJWindow()
+ protected AccessibleJWindow()
{
super();
// Nothing to do here.
@@ -86,33 +86,73 @@ public class JWindow extends Window implements Accessible, RootPaneContainer
protected AccessibleContext accessibleContext;
+ /**
+ * Creates a new <code>JWindow</code> that has a shared invisible owner frame
+ * as its parent.
+ */
public JWindow()
{
- super(SwingUtilities.getOwnerFrame());
+ super(SwingUtilities.getOwnerFrame(null));
windowInit();
}
+ /**
+ * Creates a new <code>JWindow</code> that uses the specified graphics
+ * environment. This can be used to open a window on a different screen for
+ * example.
+ *
+ * @param gc the graphics environment to use
+ */
public JWindow(GraphicsConfiguration gc)
{
- super(SwingUtilities.getOwnerFrame(), gc);
+ super(SwingUtilities.getOwnerFrame(null), gc);
windowInit();
}
-
+
+ /**
+ * Creates a new <code>JWindow</code> that has the specified
+ * <code>owner</code> frame. If <code>owner</code> is <code>null</code>, then
+ * an invisible shared owner frame is installed as owner frame.
+ *
+ * @param owner the owner frame of this window; if <code>null</code> a shared
+ * invisible owner frame is used
+ */
public JWindow(Frame owner)
{
- super(owner);
+ super(SwingUtilities.getOwnerFrame(owner));
windowInit();
}
+ /**
+ * Creates a new <code>JWindow</code> that has the specified
+ * <code>owner</code> window. If <code>owner</code> is <code>null</code>,
+ * then an invisible shared owner frame is installed as owner frame.
+ *
+ * @param owner the owner window of this window; if <code>null</code> a
+ * shared invisible owner frame is used
+ */
public JWindow(Window owner)
{
- super(owner);
+ super(SwingUtilities.getOwnerFrame(owner));
windowInit();
}
+ /**
+ * Creates a new <code>JWindow</code> for the given graphics configuration
+ * and that has the specified <code>owner</code> window. If
+ * <code>owner</code> is <code>null</code>, then an invisible shared owner
+ * frame is installed as owner frame.
+ *
+ * The <code>gc</code> parameter can be used to open the window on a
+ * different screen for example.
+ *
+ * @param owner the owner window of this window; if <code>null</code> a
+ * shared invisible owner frame is used
+ * @param gc the graphics configuration to use
+ */
public JWindow(Window owner, GraphicsConfiguration gc)
{
- super(owner, gc);
+ super(SwingUtilities.getOwnerFrame(owner), gc);
windowInit();
}
diff --git a/libjava/classpath/javax/swing/Popup.java b/libjava/classpath/javax/swing/Popup.java
index 203ee3c9b0c..c3de69e05ab 100644
--- a/libjava/classpath/javax/swing/Popup.java
+++ b/libjava/classpath/javax/swing/Popup.java
@@ -161,7 +161,7 @@ public class Popup
super(owner, contents, x, y);
this.contents = contents;
- window = new JWindow();
+ window = new JWindow(SwingUtilities.getWindowAncestor(owner));
window.getContentPane().add(contents);
window.setLocation(x, y);
window.setFocusableWindowState(false);
diff --git a/libjava/classpath/javax/swing/PopupFactory.java b/libjava/classpath/javax/swing/PopupFactory.java
index 7bb2529cd54..b326205999c 100644
--- a/libjava/classpath/javax/swing/PopupFactory.java
+++ b/libjava/classpath/javax/swing/PopupFactory.java
@@ -152,13 +152,18 @@ public class PopupFactory
// If we have a root pane and the contents fits within the root pane and
// lightweight popups are enabled, than we can use a lightweight popup.
JRootPane root = SwingUtilities.getRootPane(owner);
- Point rootLoc = root.getLocationOnScreen();
- Dimension contentsSize = contents.getSize();
- Dimension rootSize = root.getSize();
- if (x >= rootLoc.x && y > rootLoc.y
- && (x - rootLoc.x) + contentsSize.width < rootSize.width
- && (y - rootLoc.y) + contentsSize.height < rootSize.height)
- popup = new Popup.LightweightPopup(owner, contents, x, y);
+ if (root != null)
+ {
+ Point rootLoc = root.getLocationOnScreen();
+ Dimension contentsSize = contents.getSize();
+ Dimension rootSize = root.getSize();
+ if (x >= rootLoc.x && y > rootLoc.y
+ && (x - rootLoc.x) + contentsSize.width < rootSize.width
+ && (y - rootLoc.y) + contentsSize.height < rootSize.height)
+ popup = new Popup.LightweightPopup(owner, contents, x, y);
+ else
+ popup = new Popup.JWindowPopup(owner, contents, x, y);
+ }
else
popup = new Popup.JWindowPopup(owner, contents, x, y);
return popup;
diff --git a/libjava/classpath/javax/swing/RepaintManager.java b/libjava/classpath/javax/swing/RepaintManager.java
index 0be81053dc5..ed0500992c5 100644
--- a/libjava/classpath/javax/swing/RepaintManager.java
+++ b/libjava/classpath/javax/swing/RepaintManager.java
@@ -40,14 +40,18 @@ package javax.swing;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
+import java.awt.Window;
import java.awt.image.VolatileImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
import java.util.WeakHashMap;
/**
@@ -62,6 +66,7 @@ import java.util.WeakHashMap;
* href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this
* document</a> for more details.</p>
*
+ * @author Roman Kennke (kennke@aicas.com)
* @author Graydon Hoare (graydon@redhat.com)
*/
public class RepaintManager
@@ -69,8 +74,13 @@ public class RepaintManager
/**
* The current repaint managers, indexed by their ThreadGroups.
*/
- static WeakHashMap currentRepaintManagers;
-
+ private static WeakHashMap currentRepaintManagers;
+
+ /**
+ * A rectangle object to be reused in damaged regions calculation.
+ */
+ private static Rectangle rectCache = new Rectangle();
+
/**
* <p>A helper class which is placed into the system event queue at
* various times in order to facilitate repainting and layout. There is
@@ -84,7 +94,7 @@ public class RepaintManager
* swing paint thread, which revalidates all invalid components and
* repaints any damage in the swing scene.</p>
*/
- protected class RepaintWorker
+ private class RepaintWorker
implements Runnable
{
@@ -107,12 +117,18 @@ public class RepaintManager
public void run()
{
- ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
- RepaintManager rm =
- (RepaintManager) currentRepaintManagers.get(threadGroup);
- setLive(false);
- rm.validateInvalidComponents();
- rm.paintDirtyRegions();
+ try
+ {
+ ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
+ RepaintManager rm =
+ (RepaintManager) currentRepaintManagers.get(threadGroup);
+ rm.validateInvalidComponents();
+ rm.paintDirtyRegions();
+ }
+ finally
+ {
+ setLive(false);
+ }
}
}
@@ -135,41 +151,23 @@ public class RepaintManager
* @param o1 the first component
* @param o2 the second component
*
- * @return a negative integer, if <code>o1</code> is higher in the
- * hierarchy than <code>o2</code>, zero, if both are at the same
- * level and a positive integer, if <code>o1</code> is deeper in
- * the hierarchy than <code>o2</code>
+ * @return a negative integer, if <code>o1</code> is bigger in than
+ * <code>o2</code>, zero, if both are at the same size and a
+ * positive integer, if <code>o1</code> is smaller than
+ * <code>o2</code>
*/
public int compare(Object o1, Object o2)
{
if (o1 instanceof JComponent && o2 instanceof JComponent)
{
JComponent c1 = (JComponent) o1;
+ Rectangle d1 = (Rectangle) dirtyComponents.get(c1);
JComponent c2 = (JComponent) o2;
- return getDepth(c1) - getDepth(c2);
- }
- else
- throw new ClassCastException("This comparator can only be used with "
- + "JComponents");
- }
-
- /**
- * Computes the depth for a given JComponent.
- *
- * @param c the component to compute the depth for
- *
- * @return the depth of the component
- */
- private int getDepth(JComponent c)
- {
- Component comp = c;
- int depth = 0;
- while (comp != null)
- {
- comp = comp.getParent();
- depth++;
+ Rectangle d2 = (Rectangle) dirtyComponents.get(c2);
+ return d2.width * d2.height - d1.width * d1.height;
}
- return depth;
+ throw new ClassCastException("This comparator can only be used with "
+ + "JComponents");
}
}
@@ -179,6 +177,9 @@ public class RepaintManager
* to exactly one rectangle. When more regions are marked as dirty on a
* component, they are union'ed with the existing rectangle.
*
+ * This is package private to avoid a synthetic accessor method in inner
+ * class.
+ *
* @see #addDirtyRegion
* @see #getDirtyRegion
* @see #isCompletelyDirty
@@ -187,18 +188,10 @@ public class RepaintManager
*/
HashMap dirtyComponents;
- HashMap workDirtyComponents;
-
- /**
- * Stores the order in which the components get repainted.
- */
- ArrayList repaintOrder;
- ArrayList workRepaintOrder;
-
/**
* The comparator used for ordered inserting into the repaintOrder list.
*/
- Comparator comparator;
+ private transient Comparator comparator;
/**
* A single, shared instance of the helper class. Any methods which mark
@@ -209,7 +202,7 @@ public class RepaintManager
* @see #addDirtyRegion
* @see #addInvalidComponent
*/
- RepaintWorker repaintWorker;
+ private RepaintWorker repaintWorker;
/**
* The set of components which need revalidation, in the "layout" sense.
@@ -221,8 +214,7 @@ public class RepaintManager
* @see #removeInvalidComponent
* @see #validateInvalidComponents
*/
- ArrayList invalidComponents;
- ArrayList workInvalidComponents;
+ private ArrayList invalidComponents;
/**
* Whether or not double buffering is enabled on this repaint
@@ -232,17 +224,27 @@ public class RepaintManager
* @see #isDoubleBufferingEnabled
* @see #setDoubleBufferingEnabled
*/
- boolean doubleBufferingEnabled;
+ private boolean doubleBufferingEnabled;
- /**
- * The current offscreen buffer. This is reused for all requests for
- * offscreen drawing buffers. It grows as necessary, up to {@link
- * #doubleBufferMaximumSize}, but there is only one shared instance.
- *
- * @see #getOffscreenBuffer
- * @see #doubleBufferMaximumSize
+ /**
+ * The offscreen buffers. This map holds one offscreen buffer per
+ * Window/Applet and releases them as soon as the Window/Applet gets garbage
+ * collected.
*/
- Image doubleBuffer;
+ private WeakHashMap offscreenBuffers;
+
+ /**
+ * Indicates if the RepaintManager is currently repainting an area.
+ */
+ private boolean repaintUnderway;
+
+ /**
+ * This holds buffer commit requests when the RepaintManager is working.
+ * This maps Component objects (the top level components) to Rectangle
+ * objects (the area of the corresponding buffer that must be blitted on
+ * the component).
+ */
+ private HashMap commitRequests;
/**
* The maximum width and height to allocate as a double buffer. Requests
@@ -252,7 +254,7 @@ public class RepaintManager
* @see #getDoubleBufferMaximumSize
* @see #setDoubleBufferMaximumSize
*/
- Dimension doubleBufferMaximumSize;
+ private Dimension doubleBufferMaximumSize;
/**
@@ -261,14 +263,13 @@ public class RepaintManager
public RepaintManager()
{
dirtyComponents = new HashMap();
- workDirtyComponents = new HashMap();
- repaintOrder = new ArrayList();
- workRepaintOrder = new ArrayList();
invalidComponents = new ArrayList();
- workInvalidComponents = new ArrayList();
repaintWorker = new RepaintWorker();
doubleBufferMaximumSize = new Dimension(2000,2000);
doubleBufferingEnabled = true;
+ offscreenBuffers = new WeakHashMap();
+ repaintUnderway = false;
+ commitRequests = new HashMap();
}
/**
@@ -346,9 +347,9 @@ public class RepaintManager
*
* @see #removeInvalidComponent
*/
- public synchronized void addInvalidComponent(JComponent component)
+ public void addInvalidComponent(JComponent component)
{
- Component ancestor = component.getParent();
+ Component ancestor = component;
while (ancestor != null
&& (! (ancestor instanceof JComponent)
@@ -363,8 +364,11 @@ public class RepaintManager
if (invalidComponents.contains(component))
return;
- invalidComponents.add(component);
-
+ synchronized (invalidComponents)
+ {
+ invalidComponents.add(component);
+ }
+
if (! repaintWorker.isLive())
{
repaintWorker.setLive(true);
@@ -379,9 +383,12 @@ public class RepaintManager
*
* @see #addInvalidComponent
*/
- public synchronized void removeInvalidComponent(JComponent component)
+ public void removeInvalidComponent(JComponent component)
{
- invalidComponents.remove(component);
+ synchronized (invalidComponents)
+ {
+ invalidComponents.remove(component);
+ }
}
/**
@@ -402,41 +409,40 @@ public class RepaintManager
* @see #markCompletelyClean
* @see #markCompletelyDirty
*/
- public synchronized void addDirtyRegion(JComponent component, int x, int y,
- int w, int h)
+ public void addDirtyRegion(JComponent component, int x, int y,
+ int w, int h)
{
- if (w == 0 || h == 0 || !component.isShowing())
+ if (w <= 0 || h <= 0 || !component.isShowing())
return;
- Rectangle r = new Rectangle(x, y, w, h);
- if (dirtyComponents.containsKey(component))
- r = r.union((Rectangle)dirtyComponents.get(component));
- else
- insertInRepaintOrder(component);
- dirtyComponents.put(component, r);
- if (! repaintWorker.isLive())
+
+ component.computeVisibleRect(rectCache);
+ SwingUtilities.computeIntersection(x, y, w, h, rectCache);
+
+ if (! rectCache.isEmpty())
{
- repaintWorker.setLive(true);
- SwingUtilities.invokeLater(repaintWorker);
+ if (dirtyComponents.containsKey(component))
+ {
+ SwingUtilities.computeUnion(rectCache.x, rectCache.y,
+ rectCache.width, rectCache.height,
+ (Rectangle) dirtyComponents.get(component));
+ }
+ else
+ {
+ synchronized (dirtyComponents)
+ {
+ dirtyComponents.put(component, rectCache.getBounds());
+ }
+ }
+
+ if (! repaintWorker.isLive())
+ {
+ repaintWorker.setLive(true);
+ SwingUtilities.invokeLater(repaintWorker);
+ }
}
}
/**
- * Inserts a component into the repaintOrder list in an ordered fashion,
- * using a binary search.
- *
- * @param c the component to be inserted
- */
- private void insertInRepaintOrder(JComponent c)
- {
- if (comparator == null)
- comparator = new ComponentComparator();
- int insertIndex = Collections.binarySearch(repaintOrder, c, comparator);
- if (insertIndex < 0)
- insertIndex = -(insertIndex + 1);
- repaintOrder.add(insertIndex, c);
- }
-
- /**
* Get the dirty region associated with a component, or <code>null</code>
* if the component has no dirty region.
*
@@ -489,7 +495,7 @@ public class RepaintManager
*/
public void markCompletelyClean(JComponent component)
{
- synchronized (this)
+ synchronized (dirtyComponents)
{
dirtyComponents.remove(component);
}
@@ -523,63 +529,58 @@ public class RepaintManager
*/
public void validateInvalidComponents()
{
- // In order to keep the blocking of application threads minimal, we switch
- // the invalidComponents field with the workInvalidComponents field and
- // work with the workInvalidComponents field.
- synchronized(this)
- {
- ArrayList swap = invalidComponents;
- invalidComponents = workInvalidComponents;
- workInvalidComponents = swap;
- }
- for (Iterator i = workInvalidComponents.iterator(); i.hasNext(); )
+ // We don't use an iterator here because that would fail when there are
+ // components invalidated during the validation of others, which happens
+ // quite frequently. Instead we synchronize the access a little more.
+ while (invalidComponents.size() > 0)
{
- Component comp = (Component) i.next();
- // Find validate root.
- while ((!(comp instanceof JComponent)
- || !((JComponent) comp).isValidateRoot())
- && comp.getParent() != null)
- comp = comp.getParent();
-
- // Validate the validate root.
+ Component comp;
+ synchronized (invalidComponents)
+ {
+ comp = (Component) invalidComponents.remove(0);
+ }
+ // Validate the validate component.
if (! (comp.isVisible() && comp.isShowing()))
continue;
comp.validate();
}
- workInvalidComponents.clear();
}
/**
* Repaint all regions of all components which have been marked dirty in
* the {@link #dirtyComponents} table.
*/
- public synchronized void paintDirtyRegions()
+ public void paintDirtyRegions()
{
- // In order to keep the blocking of application threads minimal, we switch
- // the dirtyComponents field with the workdirtyComponents field and the
- // repaintOrder field with the workRepaintOrder field and work with the
- // work* fields.
- synchronized(this)
- {
- ArrayList swap = workRepaintOrder;
- workRepaintOrder = repaintOrder;
- repaintOrder = swap;
- HashMap swap2 = workDirtyComponents;
- workDirtyComponents = dirtyComponents;
- dirtyComponents = swap2;
- }
- for (Iterator i = workRepaintOrder.iterator(); i.hasNext();)
+ // Short cicuit if there is nothing to paint.
+ if (dirtyComponents.size() == 0)
+ return;
+
+ synchronized (dirtyComponents)
{
- JComponent comp = (JComponent) i.next();
- // If a component is marked completely clean in the meantime, then skip
- // it.
- Rectangle damaged = (Rectangle) workDirtyComponents.get(comp);
- if (damaged == null || damaged.isEmpty())
- continue;
- comp.paintImmediately(damaged);
+ // We sort the components by their size here. This way we have a good
+ // chance that painting the bigger components also paints the smaller
+ // components and we don't need to paint them twice.
+ ArrayList repaintOrder = new ArrayList(dirtyComponents.size());
+ repaintOrder.addAll(dirtyComponents.keySet());
+ if (comparator == null)
+ comparator = new ComponentComparator();
+ Collections.sort(repaintOrder, comparator);
+ repaintUnderway = true;
+ for (Iterator i = repaintOrder.iterator(); i.hasNext();)
+ {
+ JComponent comp = (JComponent) i.next();
+ // If a component is marked completely clean in the meantime, then skip
+ // it.
+ Rectangle damaged = (Rectangle) dirtyComponents.get(comp);
+ if (damaged == null || damaged.isEmpty())
+ continue;
+ comp.paintImmediately(damaged);
+ dirtyComponents.remove(comp);
+ }
+ repaintUnderway = false;
+ commitRemainingBuffers();
}
- workRepaintOrder.clear();
- workDirtyComponents.clear();
}
/**
@@ -592,21 +593,114 @@ public class RepaintManager
* @param proposedHeight The proposed height of the offscreen buffer
*
* @return A shared offscreen buffer for painting
- *
- * @see #doubleBuffer
*/
public Image getOffscreenBuffer(Component component, int proposedWidth,
int proposedHeight)
{
- if (doubleBuffer == null
- || (((doubleBuffer.getWidth(null) < proposedWidth)
- || (doubleBuffer.getHeight(null) < proposedHeight))
- && (proposedWidth < doubleBufferMaximumSize.width)
- && (proposedHeight < doubleBufferMaximumSize.height)))
+ Component root = SwingUtilities.getRoot(component);
+ Image buffer = (Image) offscreenBuffers.get(root);
+ if (buffer == null
+ || buffer.getWidth(null) < proposedWidth
+ || buffer.getHeight(null) < proposedHeight)
+ {
+ int width = Math.max(proposedWidth, root.getWidth());
+ width = Math.min(doubleBufferMaximumSize.width, width);
+ int height = Math.max(proposedHeight, root.getHeight());
+ height = Math.min(doubleBufferMaximumSize.height, height);
+ buffer = component.createImage(width, height);
+ offscreenBuffers.put(root, buffer);
+ }
+ return buffer;
+ }
+
+ /**
+ * Blits the back buffer of the specified root component to the screen. If
+ * the RepaintManager is currently working on a paint request, the commit
+ * requests are queued up and committed at once when the paint request is
+ * done (by {@link #commitRemainingBuffers}). This is package private because
+ * it must get called by JComponent.
+ *
+ * @param root the component, either a Window or an Applet instance
+ * @param area the area to paint on screen
+ */
+ void commitBuffer(Component root, Rectangle area)
+ {
+ // We synchronize on dirtyComponents here because that is what
+ // paintDirtyRegions also synchronizes on while painting.
+ synchronized (dirtyComponents)
+ {
+ // If the RepaintManager is not currently painting, then directly
+ // blit the requested buffer on the screen.
+ if (! repaintUnderway)
+ {
+ Graphics g = root.getGraphics();
+ Image buffer = (Image) offscreenBuffers.get(root);
+ Rectangle clip = g.getClipBounds();
+ if (clip != null)
+ area = SwingUtilities.computeIntersection(clip.x, clip.y,
+ clip.width, clip.height,
+ area);
+ int dx1 = area.x;
+ int dy1 = area.y;
+ int dx2 = area.x + area.width;
+ int dy2 = area.y + area.height;
+ // Make sure we have a sane clip at this point.
+ g.clipRect(area.x, area.y, area.width, area.height);
+
+ // Make sure the coordinates are inside the buffer, everything else
+ // might lead to problems.
+ // TODO: This code should not really be necessary, however, in fact
+ // we have two issues here:
+ // 1. We shouldn't get repaint requests in areas outside the buffer
+ // region in the first place. This still happens for example
+ // when a component is inside a JViewport, and the component has
+ // a size that would reach beyond the window size.
+ // 2. Graphics.drawImage() should not behave strange when trying
+ // to draw regions outside the image.
+ int bufferWidth = buffer.getWidth(root);
+ int bufferHeight = buffer.getHeight(root);
+ dx1 = Math.min(bufferWidth, dx1);
+ dy1 = Math.min(bufferHeight, dy1);
+ dx2 = Math.min(bufferWidth, dx2);
+ dy2 = Math.min(bufferHeight, dy2);
+ g.drawImage(buffer, dx1, dy1, dx2, dy2,
+ dx1, dy1, dx2, dy2, root);
+ g.dispose();
+ }
+ // Otherwise queue this request up, until all the RepaintManager work
+ // is done.
+ else
+ {
+ if (commitRequests.containsKey(root))
+ SwingUtilities.computeUnion(area.x, area.y, area.width,
+ area.height,
+ (Rectangle) commitRequests.get(root));
+ else
+ commitRequests.put(root, area);
+ }
+ }
+ }
+
+ /**
+ * Commits the queued up back buffers to screen all at once.
+ */
+ private void commitRemainingBuffers()
+ {
+ // We synchronize on dirtyComponents here because that is what
+ // paintDirtyRegions also synchronizes on while painting.
+ synchronized (dirtyComponents)
{
- doubleBuffer = component.createImage(proposedWidth, proposedHeight);
+ Set entrySet = commitRequests.entrySet();
+ Iterator i = entrySet.iterator();
+ while (i.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ Component root = (Component) entry.getKey();
+ Rectangle area = (Rectangle) entry.getValue();
+ commitBuffer(root, area);
+ i.remove();
+ }
}
- return doubleBuffer;
}
/**
diff --git a/libjava/classpath/javax/swing/ScrollPaneLayout.java b/libjava/classpath/javax/swing/ScrollPaneLayout.java
index edf1f1f4292..b00b5c4e7ae 100644
--- a/libjava/classpath/javax/swing/ScrollPaneLayout.java
+++ b/libjava/classpath/javax/swing/ScrollPaneLayout.java
@@ -285,20 +285,20 @@ public class ScrollPaneLayout
// Sun's implementation simply throws a ClassCastException if
// parent is no JScrollPane, so do we.
JScrollPane sc = (JScrollPane) parent;
- Dimension viewportSize = viewport.getMinimumSize();
- int width = viewportSize.width;
- int height = viewportSize.height;
- if (hsb != null && hsb.isVisible())
- height += hsb.getMinimumSize().height;
- if (vsb != null && vsb.isVisible())
- width += vsb.getMinimumSize().width;
- if (rowHead != null && rowHead.isVisible())
- width += rowHead.getMinimumSize().width;
- if (colHead != null && colHead.isVisible())
- height += colHead.getMinimumSize().height;
Insets i = sc.getInsets();
- return new Dimension(width + i.left + i.right,
- height + i.top + i.bottom);
+ Dimension viewportMinSize = sc.getViewport().getMinimumSize();
+
+ int width = i.left + i.right + viewportMinSize.width;
+ if (sc.getVerticalScrollBarPolicy()
+ != JScrollPane.VERTICAL_SCROLLBAR_NEVER)
+ width += sc.getVerticalScrollBar().getMinimumSize().width;
+
+ int height = i.top + i.bottom + viewportMinSize.height;
+ if (sc.getHorizontalScrollBarPolicy()
+ != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
+ height += sc.getHorizontalScrollBar().getMinimumSize().height;
+
+ return new Dimension(width, height);
}
/**
diff --git a/libjava/classpath/javax/swing/SpinnerDateModel.java b/libjava/classpath/javax/swing/SpinnerDateModel.java
index c0de7d55c8e..e0ccab776fb 100644
--- a/libjava/classpath/javax/swing/SpinnerDateModel.java
+++ b/libjava/classpath/javax/swing/SpinnerDateModel.java
@@ -1,5 +1,5 @@
/* SpinnerDateModel.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,21 +42,37 @@ import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
+import javax.swing.event.ChangeEvent;
+
/**
- * SpinnerDateModel
- *
- * Implements a SpinnerModel for dates, rotating a calendar field such as
- * month, year, day, week, hour, minute.
+ * A date model used by the {@link JSpinner} component. This implements a
+ * spinner model for dates, rotating a calendar field such as month, year,
+ * day, week, hour, minute.
*
* @author Sven de Marothy
- * @version 0.1 (first implementation)
+ * @since 1.4
*/
public class SpinnerDateModel extends AbstractSpinnerModel
implements Serializable
{
+ /** The current date. */
private Calendar date;
+
+ /**
+ * The start or earliest permitted date (<code>null</code> for no
+ * minimum).
+ */
private Comparable start;
+
+ /**
+ * The end or latest permitted date (<code>null</code> for no
+ * maximum).
+ */
private Comparable end;
+
+ /**
+ * The calendar field used to calculate the previous or next date.
+ */
private int calendarField;
/**
@@ -66,8 +82,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel
private static final long serialVersionUID = -4802518107105940612L;
/**
- * Constructs a SpinnerDateModel using the current date,
- * no start or end limit, and Calendar.DAY_OF_MONTH as the calendar field.
+ * Constructs a <code>SpinnerDateModel</code> using the current date,
+ * no start or end limit, and {@link Calendar#DAY_OF_MONTH} as the calendar
+ * field.
*/
public SpinnerDateModel()
{
@@ -87,6 +104,12 @@ public class SpinnerDateModel extends AbstractSpinnerModel
public SpinnerDateModel(Date value, Comparable start, Comparable end,
int calendarField)
{
+ if (value == null)
+ throw new IllegalArgumentException("Null 'value' argument.");
+ if (start != null && value.compareTo(start) < 0)
+ throw new IllegalArgumentException("Require value on or after start.");
+ if (end != null && value.compareTo(end) > 0)
+ throw new IllegalArgumentException("Require value on or before end.");
date = Calendar.getInstance();
date.setTime(value);
this.start = start;
@@ -95,7 +118,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel
}
/**
- * Returns the value of the Calendar field to spin.
+ * Returns the {@link Calendar} field used to calculate the previous and
+ * next dates in the sequence.
+ *
+ * @return The date field code.
*/
public int getCalendarField()
{
@@ -103,8 +129,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel
}
/**
- * Returns the current date in the sequence.
- * @return a <code>Date</code> object.
+ * Returns the current date.
+ *
+ * @return The current date.
*/
public Date getDate()
{
@@ -112,8 +139,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel
}
/**
- * Returns the starting limit of the SpinnerModel.
- * @return a Date object, or <code>null</code> if there is no limit.
+ * Returns the start date, or <code>null</code> if there is no minimum date.
+ *
+ * @return The start date.
*/
public Comparable getStart()
{
@@ -121,8 +149,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel
}
/**
- * Returns the end limit of the SpinnerModel.
- * @return a Date object, or <code>null</code> if there is no limit.
+ * Returns the end date, or <code>null</code> if there is no maximum date.
+ *
+ * @return The end date.
*/
public Comparable getEnd()
{
@@ -130,9 +159,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel
}
/**
- * Returns the current date in the sequence,
- * this method returns the same as <code>getDate()</code>.
- * @return a <code>Date</code> object.
+ * Returns the current date in the sequence (this method returns the same as
+ * {@link #getDate()}.
+ *
+ * @return The current date.
*/
public Object getValue()
{
@@ -141,8 +171,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel
/**
* Returns the next date in the sequence, or <code>null</code> if the
- * next date is equal to or past the end limit.
- * @return a Date object, or <code>null</code>.
+ * next date is after the end date. The current date is not changed.
+ *
+ * @return The next date, or <code>null</code> if the current value is
+ * the latest date represented by the model.
*/
public Object getNextValue()
{
@@ -152,14 +184,17 @@ public class SpinnerDateModel extends AbstractSpinnerModel
Date nextDate = nextCal.getTime();
if (end != null)
if (end.compareTo(nextDate) < 0)
- return null;
+ return null;
return nextDate;
}
/**
* Returns the previous date in the sequence, or <code>null</code> if the
- * next date is equal to or past the end limit.
- * @return a Date object, or <code>null</code>.
+ * previous date is prior to the start date. The current date is not
+ * changed.
+ *
+ * @return The previous date, or <code>null</code> if the current value is
+ * the earliest date represented by the model.
*/
public Object getPreviousValue()
{
@@ -167,16 +202,21 @@ public class SpinnerDateModel extends AbstractSpinnerModel
prevCal.setTime(date.getTime());
prevCal.roll(calendarField, false);
Date prevDate = prevCal.getTime();
- if (end != null)
- if (end.compareTo(prevDate) > 0)
- return null;
+ if (start != null)
+ if (start.compareTo(prevDate) > 0)
+ return null;
return prevDate;
}
/**
- * Sets the date field to change. It must be a valid Calendar field,
- * excluding Calendar.ZONE_OFFSET and Calendar.DST_OFFSET.
- * @param calendarField - the calendar field to set.
+ * Sets the date field to change when calculating the next and previous
+ * values. It must be a valid {@link Calendar} field, excluding
+ * {@link Calendar#ZONE_OFFSET} and {@link Calendar#DST_OFFSET}.
+ *
+ * @param calendarField the calendar field to set.
+ *
+ * @throws IllegalArgumentException if <code>calendarField</code> is not
+ * a valid code.
*/
public void setCalendarField(int calendarField)
{
@@ -187,51 +227,67 @@ public class SpinnerDateModel extends AbstractSpinnerModel
if (this.calendarField != calendarField)
{
- this.calendarField = calendarField;
- fireStateChanged();
+ this.calendarField = calendarField;
+ fireStateChanged();
}
}
/**
- * Sets the starting date limit for the sequence.
- *
- * @param start - a Date object of the limit date,
- * or <code>null</code> for no limit.
+ * Sets the start date and, if the new date is different to the old date,
+ * sends a {@link ChangeEvent} to all registered listeners. A
+ * <code>null</code> date is interpreted as "no start date". No check
+ * is made to ensure that the new start date is on or before the current
+ * date - the caller is responsible for ensuring that this relationship
+ * holds.
+ *
+ * @param start the new start date (<code>null</code> permitted).
*/
public void setStart(Comparable start)
{
if (this.start != start)
{
- this.start = start;
- fireStateChanged();
+ this.start = start;
+ fireStateChanged();
}
}
/**
- * Sets the end date limit for the sequence.
- *
- * @param end - a Date object of the limit date,
- * or <code>null</code> for no limit.
+ * Sets the end date and, if the new date is different to the old date,
+ * sends a {@link ChangeEvent} to all registered listeners. A
+ * <code>null</code> date is interpreted as "no end date". No check
+ * is made to ensure that the new end date is on or after the current date -
+ * the caller is responsible for ensuring that this relationship holds.
+ *
+ * @param end the new end date (<code>null</code> permitted).
*/
public void setEnd(Comparable end)
{
if (this.end != end)
{
- this.end = end;
- fireStateChanged();
+ this.end = end;
+ fireStateChanged();
}
}
/**
- * Sets the current date in the sequence.
+ * Sets the current date and, if the new value is different to the old
+ * value, sends a {@link ChangeEvent} to all registered listeners.
*
- * @param value - a Date object.
+ * @param value the new date (<code>null</code> not permitted, must be an
+ * instance of <code>Date</code>).
+ *
+ * @throws IllegalArgumentException if <code>value</code> is not an instance
+ * of <code>Date</code>.
*/
public void setValue(Object value)
{
if (! (value instanceof Date) || value == null)
throw new IllegalArgumentException("Value not a date.");
- date.setTime((Date) value);
- fireStateChanged();
+
+ if (!date.getTime().equals(value))
+ {
+ date.setTime((Date) value);
+ fireStateChanged();
+ }
}
}
diff --git a/libjava/classpath/javax/swing/SpinnerNumberModel.java b/libjava/classpath/javax/swing/SpinnerNumberModel.java
index 2274c9ec038..389c536e47f 100644
--- a/libjava/classpath/javax/swing/SpinnerNumberModel.java
+++ b/libjava/classpath/javax/swing/SpinnerNumberModel.java
@@ -1,5 +1,5 @@
/* SpinnerNumberModel.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,11 +39,13 @@ package javax.swing;
import java.io.Serializable;
+import javax.swing.event.ChangeEvent;
+
/**
- * SpinnerNumberModel
+ * A model used by the {@link JSpinner} component.
*
* @author Ka-Hing Cheung
- * @version 1.0
+ * @since 1.4
*/
public class SpinnerNumberModel extends AbstractSpinnerModel
implements Serializable
@@ -53,16 +55,16 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
*/
private static final long serialVersionUID = 7279176385485777821L;
- /** DOCUMENT ME! */
+ /** The current value. */
private Number value;
- /** DOCUMENT ME! */
+ /** The minimum value (or <code>null</code>). */
private Comparable minimum;
- /** DOCUMENT ME! */
+ /** The maximum value (or <code>null</code>). */
private Comparable maximum;
- /** DOCUMENT ME! */
+ /** The step size. */
private Number stepSize;
/**
@@ -75,14 +77,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
}
/**
- * Creates a <code>SpinnerNumberModel</code> with double precision
+ * Creates a <code>SpinnerNumberModel</code> with double precision.
*
* @param value the initial value
* @param minimum the minimum value
* @param maximum the maximum value
* @param stepSize the step size
- * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum does not
- * hold
+ * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum does
+ * not hold.
*/
public SpinnerNumberModel(double value, double minimum, double maximum,
double stepSize)
@@ -92,14 +94,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
}
/**
- * Creates a <code>SpinnerNumberModel</code> with integer precision
+ * Creates a <code>SpinnerNumberModel</code> with integer precision.
*
* @param value the initial value
* @param minimum the minimum value
* @param maximum the maximum value
* @param stepSize the step size
- * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum does not
- * hold
+ * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum does
+ * not hold.
*/
public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize)
{
@@ -108,16 +110,19 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
}
/**
- * Creates a <code>SpinnerNumberModel</code> with <code>Number</code>s and
- * <code>Comparable</code>s.
+ * Creates a <code>SpinnerNumberModel</code> with the given attributes.
*
- * @param value the initial value
- * @param minimum the minimum value, if null there's no minimum
- * @param maximum the maximum value, if null there's no maximum
- * @param stepSize the step size
+ * @param value the initial value.
+ * @param minimum the minimum value (<code>null</code> permitted).
+ * @param maximum the maximum value (<code>null</code> permitted).
+ * @param stepSize the step size.
*
* @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum
* does not hold
+ * @throws IllegalArgumentException if <code>value</code> is
+ * <code>null</code>.
+ * @throws IllegalArgumentException if <code>stepSize</code> is
+ * <code>null</code>.
*/
public SpinnerNumberModel(Number value, Comparable minimum,
Comparable maximum, Number stepSize)
@@ -128,33 +133,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
throw new IllegalArgumentException("value may not be null");
if (minimum != null)
{
- if (minimum.compareTo(value) > 0)
- throw new IllegalArgumentException("minimum is not <= value");
+ if (minimum.compareTo(value) > 0)
+ throw new IllegalArgumentException("minimum is not <= value");
}
- else
- minimum = new Comparable()
- {
- public int compareTo(Object obj)
- {
- return -1;
- }
- };
-
-
if (maximum != null)
{
- if (maximum.compareTo(value) < 0)
- throw new IllegalArgumentException("maximum is not >= value");
+ if (maximum.compareTo(value) < 0)
+ throw new IllegalArgumentException("maximum is not >= value");
}
- else
- maximum = new Comparable()
- {
- public int compareTo(Object obj)
- {
- return 1;
- }
- };
-
this.value = value;
this.stepSize = stepSize;
@@ -163,26 +149,31 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
}
/**
- * Sets the new value and fire a change event
+ * Sets the current value and, if the new value is different to the old
+ * value, sends a {@link ChangeEvent} to all registered listeners.
*
- * @param value the new value
+ * @param value the new value (<code>null</code> not permitted, must be an
+ * instance of <code>Number</code>).
*
- * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum
- * does not hold
+ * @throws IllegalArgumentException if <code>value</code> is not an instance
+ * of <code>Number</code>.
*/
public void setValue(Object value)
{
if (! (value instanceof Number))
throw new IllegalArgumentException("value must be a Number");
- this.value = (Number) value;
- fireStateChanged();
+ if (!this.value.equals(value))
+ {
+ this.value = (Number) value;
+ fireStateChanged();
+ }
}
/**
- * Gets the current value
+ * Returns the current value.
*
- * @return the current value
+ * @return The current value.
*/
public Object getValue()
{
@@ -190,10 +181,12 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
}
/**
- * Gets the next value without changing the current value, or null if the
- * current value is maximum.
+ * Returns the next value, or <code>null</code> if adding the step size to
+ * the current value results in a value greater than the maximum value.
+ * The current value is not changed.
*
- * @return the next value
+ * @return The next value, or <code>null</code> if the current value is the
+ * maximum value represented by this model.
*/
public Object getNextValue()
{
@@ -211,15 +204,21 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
num = new Short((short) (value.shortValue() + stepSize.shortValue()));
else
num = new Byte((byte) (value.byteValue() + stepSize.byteValue()));
-
- return maximum.compareTo(num) >= 0 ? num : null;
+
+ // check upper bound if set
+ if ((maximum != null) && maximum.compareTo(num) < 0)
+ num = null;
+
+ return num;
}
/**
- * Gets the previous value without changing the current value, or null if
- * the current value is minimum.
+ * Returns the previous value, or <code>null</code> if subtracting the
+ * step size from the current value results in a value less than the minimum
+ * value. The current value is not changed.
*
- * @return the previous value
+ * @return The previous value, or <code>null</code> if the current value
+ * is the minimum value represented by this model.
*/
public Object getPreviousValue()
{
@@ -237,62 +236,110 @@ public class SpinnerNumberModel extends AbstractSpinnerModel
num = new Short((short) (value.shortValue() - stepSize.shortValue()));
else
num = new Byte((byte) (value.byteValue() - stepSize.byteValue()));
+
+ // check lower bound if set
+ if ((minimum != null) && minimum.compareTo(num) > 0)
+ num = null;
- return minimum.compareTo(num) <= 0 ? num : null;
+ return num;
}
/**
- * DOCUMENT ME!
+ * Returns the current value.
*
- * @return DOCUMENT ME!
+ * @return The current value.
*/
public Number getNumber()
{
return value;
}
+ /**
+ * Returns the minimum value, or <code>null</code> if there is no minimum.
+ *
+ * @return The minimum value.
+ */
public Comparable getMinimum()
{
return minimum;
}
+ /**
+ * Sets the minimum value and, if the new value is different to the old
+ * value, sends a {@link ChangeEvent} to all registered listeners. A
+ * <code>null</code> value is interpreted as "no minimum value". No check
+ * is made to ensure that the new minimum is less than or equal to the
+ * current value, the caller is responsible for ensuring that this
+ * relationship holds.
+ *
+ * @param newMinimum the new minimum value (<code>null</code> permitted).
+ */
public void setMinimum(Comparable newMinimum)
{
- if (minimum != newMinimum)
+ if (minimum != null ? !minimum.equals(newMinimum) : newMinimum != null)
{
- minimum = newMinimum;
- fireStateChanged();
+ minimum = newMinimum;
+ fireStateChanged();
}
}
+ /**
+ * Returns the maximum value, or <code>null</code> if there is no maximum.
+ *
+ * @return The maximum value.
+ */
public Comparable getMaximum()
{
return maximum;
}
+ /**
+ * Sets the maximum value and, if the new value is different to the old
+ * value, sends a {@link ChangeEvent} to all registered listeners. A
+ * <code>null</code> value is interpreted as "no maximum value". No check
+ * is made to ensure that the new maximum is greater than or equal to the
+ * current value, the caller is responsible for ensuring that this
+ * relationship holds.
+ *
+ * @param newMaximum the new maximum (<code>null</code> permitted).
+ */
public void setMaximum(Comparable newMaximum)
{
- if (maximum != newMaximum)
+ if (maximum != null ? !maximum.equals(newMaximum) : newMaximum != null)
{
- maximum = newMaximum;
- fireStateChanged();
+ maximum = newMaximum;
+ fireStateChanged();
}
}
+ /**
+ * Returns the step size.
+ *
+ * @return The step size.
+ */
public Number getStepSize()
{
return stepSize;
}
+ /**
+ * Sets the step size and, if the new step size is different to the old
+ * step size, sends a {@link ChangeEvent} to all registered listeners.
+ *
+ * @param newStepSize the new step size (<code>null</code> not permitted).
+ *
+ * @throws IllegalArgumentException if <code>newStepSize</code> is
+ * <code>null</code>.
+ */
public void setStepSize(Number newStepSize)
{
if (newStepSize == null)
throw new IllegalArgumentException();
- if (stepSize != newStepSize)
+ if (!stepSize.equals(newStepSize))
{
- stepSize = newStepSize;
- fireStateChanged();
+ stepSize = newStepSize;
+ fireStateChanged();
}
}
}
diff --git a/libjava/classpath/javax/swing/Spring.java b/libjava/classpath/javax/swing/Spring.java
index 8f7105d496d..b9890c7147f 100644
--- a/libjava/classpath/javax/swing/Spring.java
+++ b/libjava/classpath/javax/swing/Spring.java
@@ -37,6 +37,9 @@ exception statement from your version. */
package javax.swing;
+import java.awt.Component;
+import java.awt.Dimension;
+
/**
* Calculates the space between component edges, that are layed out by
* {@link SpringLayout}.
@@ -168,6 +171,139 @@ public abstract class Spring
}
/**
+ * Return a new Spring which computes its values by scaling
+ * the values of another spring by a constant factor. If the
+ * factor is negative, the minimum and maximum values of
+ * the argument spring will be interchanged.
+ * @param spring the spring to track
+ * @param factor the factor by which to scale
+ * @return a new multiplicative Spring
+ * @since 1.5
+ */
+ public static Spring scale(final Spring spring, final float factor)
+ {
+ if (spring == null)
+ throw new NullPointerException("spring argument is null");
+ return new Spring()
+ {
+ public int getMaximumValue()
+ {
+ return (int) ((factor < 0 ? spring.getMinimumValue()
+ : spring.getMaximumValue())
+ * factor);
+ }
+
+ public int getMinimumValue()
+ {
+ return (int) ((factor < 0 ? spring.getMaximumValue()
+ : spring.getMinimumValue())
+ * factor);
+ }
+
+ public int getPreferredValue()
+ {
+ return (int) (spring.getPreferredValue() * factor);
+ }
+
+ public int getValue()
+ {
+ return (int) (spring.getValue() * factor);
+ }
+
+ public void setValue(int value)
+ {
+ spring.setValue((int) (value / factor));
+ }
+ };
+ }
+
+ /**
+ * Return a new Spring which takes its values from the specified
+ * Component. In particular, the maximum value is taken from
+ * the maximumSize, the minimum value is taken from the minimumSize,
+ * the preferred value is taken from the preferredSize, and the
+ * value is taken from the component's current size. These values
+ * change as the component changes size.
+ * @param component the component
+ * @return a new Spring which tracks the component's width
+ * @since 1.5
+ */
+ public static Spring width(final Component component)
+ {
+ return new Spring()
+ {
+ public int getMaximumValue()
+ {
+ return component.getMaximumSize().width;
+ }
+
+ public int getMinimumValue()
+ {
+ return component.getMinimumSize().width;
+ }
+
+ public int getPreferredValue()
+ {
+ return component.getPreferredSize().width;
+ }
+
+ public int getValue()
+ {
+ return component.getSize().width;
+ }
+
+ public void setValue(int value)
+ {
+ Dimension d = component.getSize();
+ component.setSize(value, d.height);
+ }
+ };
+ }
+
+ /**
+ * Return a new Spring which takes its values from the specified
+ * Component. In particular, the maximum value is taken from
+ * the maximumSize, the minimum value is taken from the minimumSize,
+ * the preferred value is taken from the preferredSize, and the
+ * value is taken from the component's current size. These values
+ * change as the component changes size.
+ * @param component the component
+ * @return a new Spring which tracks the component's height
+ * @since 1.5
+ */
+ public static Spring height(final Component component)
+ {
+ return new Spring()
+ {
+ public int getMaximumValue()
+ {
+ return component.getMaximumSize().height;
+ }
+
+ public int getMinimumValue()
+ {
+ return component.getMinimumSize().height;
+ }
+
+ public int getPreferredValue()
+ {
+ return component.getPreferredSize().height;
+ }
+
+ public int getValue()
+ {
+ return component.getSize().height;
+ }
+
+ public void setValue(int value)
+ {
+ Dimension d = component.getSize();
+ component.setSize(d.width, value);
+ }
+ };
+ }
+
+ /**
* A simple Spring, that holds constant values for min, pref and max.
*
* @author Roman Kennke (roman@ontographics.com)
diff --git a/libjava/classpath/javax/swing/SpringLayout.java b/libjava/classpath/javax/swing/SpringLayout.java
index 592cc0e02a9..8d46a736a58 100644
--- a/libjava/classpath/javax/swing/SpringLayout.java
+++ b/libjava/classpath/javax/swing/SpringLayout.java
@@ -1,5 +1,5 @@
/* SpringLayout.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -150,6 +150,25 @@ public class SpringLayout implements LayoutManager2
}
/**
+ * Create a new Constraints object which tracks the indicated
+ * component. The x and y positions for this Constraints object
+ * are constant Springs created with the component's location at
+ * the time this constructor is called. The width and height
+ * of this Constraints are Springs created using
+ * {@link Spring#width(Component)} and {@link Spring#height(Component)},
+ * respectively.
+ * @param component the component to track
+ * @since 1.5
+ */
+ public Constraints(Component component)
+ {
+ this(Spring.constant(component.getX()),
+ Spring.constant(component.getY()),
+ Spring.width(component),
+ Spring.height(component));
+ }
+
+ /**
* Returns the constraint for the edge with the <code>edgeName</code>.
* This is expected to be one of
* {@link #EAST}, {@link #WEST}, {@link #NORTH} or {@link #SOUTH}.
@@ -343,8 +362,8 @@ public class SpringLayout implements LayoutManager2
/**
* Adds a layout component and a constraint object to this layout.
- * This method is usually only called by a {@java.awt.Container}s add
- * Method.
+ * This method is usually only called by a {@link java.awt.Container}s add
+ * method.
*
* @param component the component to be added.
* @param constraint the constraint to be set.
@@ -357,8 +376,8 @@ public class SpringLayout implements LayoutManager2
/**
* Adds a layout component and a constraint object to this layout.
- * This method is usually only called by a {@java.awt.Container}s add
- * Method. This method does nothing, since SpringLayout does not manage
+ * This method is usually only called by a {@link java.awt.Container}s add
+ * method. This method does nothing, since SpringLayout does not manage
* String-indexed components.
*
* @param name the name.
diff --git a/libjava/classpath/javax/swing/SwingUtilities.java b/libjava/classpath/javax/swing/SwingUtilities.java
index 2d859b7448e..6762ccd804a 100644
--- a/libjava/classpath/javax/swing/SwingUtilities.java
+++ b/libjava/classpath/javax/swing/SwingUtilities.java
@@ -83,31 +83,6 @@ public class SwingUtilities
{
// Do nothing.
}
-
- /**
- * Calculates the portion of the base rectangle which is inside the
- * insets.
- *
- * @param base The rectangle to apply the insets to
- * @param insets The insets to apply to the base rectangle
- * @param ret A rectangle to use for storing the return value, or
- * <code>null</code>
- *
- * @return The calculated area inside the base rectangle and its insets,
- * either stored in ret or a new Rectangle if ret is <code>null</code>
- *
- * @see #calculateInnerArea
- */
- public static Rectangle calculateInsetArea(Rectangle base, Insets insets,
- Rectangle ret)
- {
- if (ret == null)
- ret = new Rectangle();
- ret.setBounds(base.x + insets.left, base.y + insets.top,
- base.width - (insets.left + insets.right),
- base.height - (insets.top + insets.bottom));
- return ret;
- }
/**
* Calculates the portion of the component's bounds which is inside the
@@ -122,13 +97,18 @@ public class SwingUtilities
*
* @return The calculated area inside the component and its border
* insets
- *
- * @see #calculateInsetArea
*/
public static Rectangle calculateInnerArea(JComponent c, Rectangle r)
{
Rectangle b = getLocalBounds(c);
- return calculateInsetArea(b, c.getInsets(), r);
+ if (r == null)
+ r = new Rectangle();
+ Insets i = c.getInsets();
+ r.x = b.x + i.left;
+ r.width = b.width - i.left - i.right;
+ r.y = b.y + i.top;
+ r.height = b.height - i.top - i.bottom;
+ return r;
}
/**
@@ -1021,11 +1001,16 @@ public class SwingUtilities
*
* @return The common Frame
*/
- static Frame getOwnerFrame()
+ static Window getOwnerFrame(Window owner)
{
- if (ownerFrame == null)
- ownerFrame = new OwnerFrame();
- return ownerFrame;
+ Window result = owner;
+ if (result == null)
+ {
+ if (ownerFrame == null)
+ ownerFrame = new OwnerFrame();
+ result = ownerFrame;
+ }
+ return result;
}
/**
@@ -1262,26 +1247,31 @@ public class SwingUtilities
}
/**
- * Calculates the intersection of two rectangles.
+ * Calculates the intersection of two rectangles. The result is stored
+ * in <code>rect</code>. This is basically the same
+ * like {@link Rectangle#intersection(Rectangle)}, only that it does not
+ * create new Rectangle instances. The tradeoff is that you loose any data in
+ * <code>rect</code>.
*
* @param x upper-left x coodinate of first rectangle
* @param y upper-left y coodinate of first rectangle
* @param w width of first rectangle
* @param h height of first rectangle
* @param rect a Rectangle object of the second rectangle
- * @throws NullPointerException if rect is null.
+ *
+ * @throws NullPointerException if rect is null
*
* @return a rectangle corresponding to the intersection of the
- * two rectangles. A zero rectangle is returned if the rectangles
- * do not overlap.
+ * two rectangles. An empty rectangle is returned if the rectangles
+ * do not overlap
*/
public static Rectangle computeIntersection(int x, int y, int w, int h,
Rectangle rect)
{
- int x2 = (int) rect.getX();
- int y2 = (int) rect.getY();
- int w2 = (int) rect.getWidth();
- int h2 = (int) rect.getHeight();
+ int x2 = (int) rect.x;
+ int y2 = (int) rect.y;
+ int w2 = (int) rect.width;
+ int h2 = (int) rect.height;
int dx = (x > x2) ? x : x2;
int dy = (y > y2) ? y : y2;
@@ -1289,9 +1279,11 @@ public class SwingUtilities
int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
if (dw >= 0 && dh >= 0)
- return new Rectangle(dx, dy, dw, dh);
+ rect.setBounds(dx, dy, dw, dh);
+ else
+ rect.setBounds(0, 0, 0, 0);
- return new Rectangle(0, 0, 0, 0);
+ return rect;
}
/**
@@ -1308,26 +1300,31 @@ public class SwingUtilities
}
/**
- * Calculates the union of two rectangles.
+ * Calculates the union of two rectangles. The result is stored in
+ * <code>rect</code>. This is basically the same as
+ * {@link Rectangle#union(Rectangle)} except that it avoids creation of new
+ * Rectangle objects. The tradeoff is that you loose any data in
+ * <code>rect</code>.
*
* @param x upper-left x coodinate of first rectangle
* @param y upper-left y coodinate of first rectangle
* @param w width of first rectangle
* @param h height of first rectangle
* @param rect a Rectangle object of the second rectangle
- * @throws NullPointerException if rect is null.
+ *
+ * @throws NullPointerException if rect is null
*
* @return a rectangle corresponding to the union of the
- * two rectangles. A rectangle encompassing both is returned if the
- * rectangles do not overlap.
+ * two rectangles; a rectangle encompassing both is returned if the
+ * rectangles do not overlap
*/
public static Rectangle computeUnion(int x, int y, int w, int h,
Rectangle rect)
{
- int x2 = (int) rect.getX();
- int y2 = (int) rect.getY();
- int w2 = (int) rect.getWidth();
- int h2 = (int) rect.getHeight();
+ int x2 = (int) rect.x;
+ int y2 = (int) rect.y;
+ int w2 = (int) rect.width;
+ int h2 = (int) rect.height;
int dx = (x < x2) ? x : x2;
int dy = (y < y2) ? y : y2;
@@ -1335,9 +1332,10 @@ public class SwingUtilities
int dh = (y + h > y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
if (dw >= 0 && dh >= 0)
- return new Rectangle(dx, dy, dw, dh);
-
- return new Rectangle(0, 0, 0, 0);
+ rect.setBounds(dx, dy, dw, dh);
+ else
+ rect.setBounds(0, 0, 0, 0);
+ return rect;
}
/**
diff --git a/libjava/classpath/javax/swing/Timer.java b/libjava/classpath/javax/swing/Timer.java
index cf91c23e8ec..231b71d73bb 100644
--- a/libjava/classpath/javax/swing/Timer.java
+++ b/libjava/classpath/javax/swing/Timer.java
@@ -68,11 +68,11 @@ public class Timer
public void run()
{
if (logTimers)
- System.out.println("javax.swing.Timer -> queueEvent()");
+ System.out.println("javax.swing.Timer -> queueEvent()");
queueEvent();
if (!repeats)
- task = null;
+ task = null;
}
}
@@ -141,8 +141,9 @@ public class Timer
/**
* The task that calls queueEvent(). When null this Timer is stopped.
+ * This is package private to avoid synthetic accessor method.
*/
- private Task task;
+ Task task;
/**
* This object manages a "queue" of virtual actionEvents, maintained as a
diff --git a/libjava/classpath/javax/swing/ToolTipManager.java b/libjava/classpath/javax/swing/ToolTipManager.java
index 289149fb603..c7de4db8330 100644
--- a/libjava/classpath/javax/swing/ToolTipManager.java
+++ b/libjava/classpath/javax/swing/ToolTipManager.java
@@ -40,9 +40,6 @@ package javax.swing;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.LayoutManager;
-import java.awt.Panel;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
diff --git a/libjava/classpath/javax/swing/UIManager.java b/libjava/classpath/javax/swing/UIManager.java
index fbf1c7c79cb..bf8739daca2 100644
--- a/libjava/classpath/javax/swing/UIManager.java
+++ b/libjava/classpath/javax/swing/UIManager.java
@@ -43,11 +43,11 @@ import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.Locale;
import javax.swing.border.Border;
-import javax.swing.event.SwingPropertyChangeSupport;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalLookAndFeel;
@@ -138,8 +138,8 @@ public class UIManager implements Serializable
static UIDefaults userUIDefaults;
/** Property change listener mechanism. */
- static SwingPropertyChangeSupport listeners
- = new SwingPropertyChangeSupport(UIManager.class);
+ static PropertyChangeSupport listeners
+ = new PropertyChangeSupport(UIManager.class);
static
{
diff --git a/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java b/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java
index f99c0ac19f7..b65119a00bc 100644
--- a/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java
+++ b/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java
@@ -1,5 +1,5 @@
/* UnsupportedLookAndFeelException.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,11 +37,21 @@ exception statement from your version. */
package javax.swing;
-
+/**
+ * Thrown by the {@link UIManager#setLookAndFeel(LookAndFeel)} method when the
+ * specified look and feel is not supported on the current platform.
+ *
+ * @see LookAndFeel#isSupportedLookAndFeel()
+ */
public class UnsupportedLookAndFeelException extends Exception
{
- public UnsupportedLookAndFeelException(String a)
+ /**
+ * Creates a new exception instance with the specified message.
+ *
+ * @param s the exception message.
+ */
+ public UnsupportedLookAndFeelException(String s)
{
- super(a);
+ super(s);
}
}
diff --git a/libjava/classpath/javax/swing/ViewportLayout.java b/libjava/classpath/javax/swing/ViewportLayout.java
index 79fd26c56df..674de959f6e 100644
--- a/libjava/classpath/javax/swing/ViewportLayout.java
+++ b/libjava/classpath/javax/swing/ViewportLayout.java
@@ -1,5 +1,5 @@
/* ViewportLayout.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -46,9 +46,16 @@ import java.awt.Rectangle;
import java.io.Serializable;
/**
- * ViewportLayout
- * @author Andrew Selkirk
- * @author Graydon Hoare
+ * The default layout for {@link JViewport}. The viewport makes its view the
+ * same size as itself, but not smaller than its minimum size.
+ *
+ * If the port extends extends into space <em>past</em> the edge of the view,
+ * this layout manager moves the port up or to the left, in view space, by the
+ * amount of empty space (keep the lower and right edges lined up).
+ *
+ * @author Andrew Selkirk
+ * @author Graydon Hoare
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
*/
public class ViewportLayout implements LayoutManager, Serializable
{
@@ -58,17 +65,31 @@ public class ViewportLayout implements LayoutManager, Serializable
{
// Nothing to do here.
}
-
+
+ /**
+ * The method is not used with this manager.
+ */
public void addLayoutComponent(String name, Component c)
{
// Nothing to do here.
}
+ /**
+ * The method is not used with this manager.
+ */
public void removeLayoutComponent(Component c)
{
// Nothing to do here.
}
-
+
+ /**
+ * Get the preferred layout size. If the view implements
+ * {@link Scrollable}, this method returns
+ * {@link Scrollable#getPreferredScrollableViewportSize}.
+ * Otherwise, it returns {@link Component#getPreferredSize()}.
+ *
+ * @return the preferred layout size, as described about.
+ */
public Dimension preferredLayoutSize(Container parent)
{
JViewport vp = (JViewport)parent;
@@ -83,14 +104,19 @@ public class ViewportLayout implements LayoutManager, Serializable
return new Dimension();
}
+ /**
+ * Get the minimum layout size. Normally this method returns the value,
+ * returned by the view method {@link Component#getMinimumSize()}.
+ *
+ * If the view is not set, the zero size is returned.
+ *
+ * @param parent the viewport
+ * @return the minimum layout size.
+ */
public Dimension minimumLayoutSize(Container parent)
{
- JViewport vp = (JViewport)parent;
- Component view = vp.getView();
- if (view != null)
- return view.getMinimumSize();
- else
- return new Dimension();
+ // These values have been determined by the Mauve test for this method.
+ return new Dimension(4, 4);
}
/**
@@ -101,15 +127,13 @@ public class ViewportLayout implements LayoutManager, Serializable
*
* <ol>
*
- * <li>If the port is larger than the view's minimum size, put the port
- * at view position <code>(0,0)</code> and make the view's size equal to
- * the port's.</li>
- *
* <li>If the port is smaller than the view, leave the view at its
- * minimum size. also, do not move the port, <em>unless</em> the port
+ * current size. Also, do not move the port, <em>unless</em> the port
* extends into space <em>past</em> the edge of the view. If so, move the
* port up or to the left, in view space, by the amount of empty space
* (keep the lower and right edges lined up)</li>
+ * <li>In {@link JViewport#setViewSize(Dimension)}, the view size is never
+ * set smaller that its minimum size.</li>
*
* </ol>
*
@@ -118,7 +142,6 @@ public class ViewportLayout implements LayoutManager, Serializable
* @see JViewport#getViewPosition
* @see JViewport#setViewPosition
*/
-
public void layoutContainer(Container parent)
{
// The way to interpret this function is basically to ignore the names
@@ -141,23 +164,22 @@ public class ViewportLayout implements LayoutManager, Serializable
Rectangle portBounds = port.getViewRect();
Dimension viewPref = view.getPreferredSize();
Dimension viewMinimum = view.getMinimumSize();
+
Point portLowerRight = new Point(portBounds.x + portBounds.width,
portBounds.y + portBounds.height);
+ int overextension;
// vertical implementation of the above rules
if ((! (view instanceof Scrollable) && viewPref.height < portBounds.height
|| (view instanceof Scrollable
&& ((Scrollable) view).getScrollableTracksViewportHeight())))
viewPref.height = portBounds.height;
-
- if (portBounds.height >= viewMinimum.height)
- portBounds.y = 0;
- else
- {
- int overextension = portLowerRight.y - viewPref.height;
- if (overextension > 0)
- portBounds.y -= overextension;
- }
+
+ // If the view is larger than the port, and port is partly outside
+ // the view, it is moved fully into the view area.
+ overextension = portLowerRight.y - viewPref.height;
+ if (overextension > 0)
+ portBounds.y -= overextension;
// horizontal implementation of the above rules
if ((! (view instanceof Scrollable) && viewPref.width < portBounds.width
@@ -165,16 +187,13 @@ public class ViewportLayout implements LayoutManager, Serializable
&& ((Scrollable) view).getScrollableTracksViewportWidth())))
viewPref.width = portBounds.width;
- if (portBounds.width >= viewMinimum.width)
- portBounds.x = 0;
- else
- {
- int overextension = portLowerRight.x - viewPref.width;
- if (overextension > 0)
- portBounds.x -= overextension;
- }
+ // If the view is larger than the port, and port is partly outside
+ // the view, it is moved fully into the view area.
+ overextension = portLowerRight.x - viewPref.width;
+ if (overextension > 0)
+ portBounds.x -= overextension;
- port.setViewPosition(portBounds.getLocation());
port.setViewSize(viewPref);
+ port.setViewPosition(portBounds.getLocation());
}
}
diff --git a/libjava/classpath/javax/swing/event/CaretEvent.java b/libjava/classpath/javax/swing/event/CaretEvent.java
index c4870a8008f..7de05a81b74 100644
--- a/libjava/classpath/javax/swing/event/CaretEvent.java
+++ b/libjava/classpath/javax/swing/event/CaretEvent.java
@@ -1,5 +1,5 @@
/* CaretEvent.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,43 +37,34 @@ exception statement from your version. */
package javax.swing.event;
-// Imports
import java.util.EventObject;
/**
* CaretEvent
* @author Andrew Selkirk
*/
-public abstract class CaretEvent extends EventObject {
+public abstract class CaretEvent extends EventObject
+{
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * CaretEvent constructor
- * @param source Source object
- */
- public CaretEvent(Object source) {
- super(source);
- } // CaretEvent()
+ /**
+ * CaretEvent constructor
+ * @param source Source object
+ */
+ public CaretEvent(Object source)
+ {
+ super(source);
+ }
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Get caret location
- * @returns the dot
- */
- public abstract int getDot();
+ /**
+ * Get caret location
+ * @return the dot
+ */
+ public abstract int getDot();
- /**
- * Get mark
- * @returns the mark
- */
- public abstract int getMark();
+ /**
+ * Get mark
+ * @return the mark
+ */
+ public abstract int getMark();
-
-} // CaretEvent
+}
diff --git a/libjava/classpath/javax/swing/event/DocumentEvent.java b/libjava/classpath/javax/swing/event/DocumentEvent.java
index 6cd8e61fee4..82230492520 100644
--- a/libjava/classpath/javax/swing/event/DocumentEvent.java
+++ b/libjava/classpath/javax/swing/event/DocumentEvent.java
@@ -1,5 +1,5 @@
/* DocumentEvent.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -54,25 +54,25 @@ public interface DocumentEvent
{
/**
* getIndex
- * @returns int
+ * @return int
*/
int getIndex();
/**
* getElement
- * @returns Element
+ * @return Element
*/
Element getElement();
/**
* getChildrenRemoved
- * @returns Element[]
+ * @return Element[]
*/
Element[] getChildrenRemoved();
/**
* getChildrenAdded
- * @returns Element[]
+ * @return Element[]
*/
Element[] getChildrenAdded();
@@ -81,7 +81,7 @@ public interface DocumentEvent
/**
* EventType
*/
- class EventType
+ final class EventType
{
/**
* INSERT
@@ -114,7 +114,7 @@ public interface DocumentEvent
/**
* toString
- * @returns String
+ * @return String
*/
public String toString()
{
@@ -124,32 +124,32 @@ public interface DocumentEvent
/**
* getType
- * @returns EventType
+ * @return EventType
*/
EventType getType();
/**
* getOffset
- * @returns int
+ * @return int
*/
int getOffset();
/**
* getLength
- * @returns int
+ * @return int
*/
int getLength();
/**
* getDocument
- * @returns Document
+ * @return Document
*/
Document getDocument();
/**
* getChange
* @param element TODO
- * @returns ElementChange
+ * @return ElementChange
*/
ElementChange getChange(Element element);
diff --git a/libjava/classpath/javax/swing/event/EventListenerList.java b/libjava/classpath/javax/swing/event/EventListenerList.java
index 147d68ef184..a7fbec44d36 100644
--- a/libjava/classpath/javax/swing/event/EventListenerList.java
+++ b/libjava/classpath/javax/swing/event/EventListenerList.java
@@ -188,7 +188,7 @@ public class EventListenerList
/**
* Get a list of listenerType/listener pairs
- * @returns Listener list
+ * @return Listener list
*/
public Object[] getListenerList()
{
@@ -214,7 +214,7 @@ public class EventListenerList
* @throws NullPointerException if <code>c</code> is
* <code>null</code>.
*
- * @returns an array of <code>c</code> whose elements are the
+ * @return an array of <code>c</code> whose elements are the
* currently subscribed listeners of the specified type. If there
* are no such listeners, an empty array is returned.
*
diff --git a/libjava/classpath/javax/swing/event/ListSelectionEvent.java b/libjava/classpath/javax/swing/event/ListSelectionEvent.java
index e5e4c33bad9..d79cbfa507f 100644
--- a/libjava/classpath/javax/swing/event/ListSelectionEvent.java
+++ b/libjava/classpath/javax/swing/event/ListSelectionEvent.java
@@ -1,5 +1,5 @@
/* ListSelectionEvent.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,90 +37,99 @@ exception statement from your version. */
package javax.swing.event;
-// Imports
import java.util.EventObject;
+import javax.swing.ListSelectionModel;
+
/**
- * ListSelectionEvent
+ * An event that indicates a change to a list selection, including the source
+ * of the change (a {@link ListSelectionModel}) and the range of items in the
+ * list that have potentially changed their selection status.
+ *
* @author Andrew Selkirk
* @author Ronald Veldema
*/
-public class ListSelectionEvent extends EventObject {
-
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * firstIndex
- */
- private int firstIndex = 0;
-
- /**
- * lastIndex
- */
- private int lastIndex = 0;
-
- /**
- * isAdjusting
- */
- private boolean isAdjusting = false;
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor ListSelectionEvent
- * @param source Source
- * @param firstIndex First index
- * @param lastIndex Last index
- * @param isAdjusting Is Adjusting?
- */
- public ListSelectionEvent(Object source, int firstIndex,
- int lastIndex, boolean isAdjusting) {
- super(source);
- this.firstIndex = firstIndex;
- this.lastIndex = lastIndex;
- this.isAdjusting = isAdjusting;
- } // ListSelectionEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * getFirstIndex
- * @returns firstIndex
- */
- public int getFirstIndex() {
- return firstIndex;
- } // getFirstIndex()
-
- /**
- * getLastIndex
- * @returns lastIndex
- */
- public int getLastIndex() {
- return lastIndex;
- } // getLastIndex()
-
- /**
- * getValueIsAdjusting
- * @returns isAdjusting
- */
- public boolean getValueIsAdjusting() {
- return isAdjusting;
- } // getValueIsAdjusting()
-
- /**
- * String representation
- * @returns String representation
- */
- public String toString() {
- return null; // TODO
- } // toString()
-
-
-} // ListSelectionEvent
+public class ListSelectionEvent extends EventObject
+{
+
+ /**
+ * The index of the first list item in the range of items that has
+ * potentially had its selection status modified.
+ */
+ private int firstIndex = 0;
+
+ /**
+ * The index of the last list item in the range of items that has
+ * potentially had its selection status modified.
+ */
+ private int lastIndex = 0;
+
+ /** A flag that indicates that this event is one in a series of events. */
+ private boolean isAdjusting = false;
+
+ /**
+ * Creates a new <code>ListSelectionEvent</code>.
+ *
+ * @param source the event source (<code>null</code> not permitted).
+ * @param firstIndex the first index.
+ * @param lastIndex the last index.
+ * @param isAdjusting a flag indicating that this event is one in a series
+ * of events updating a selection.
+ *
+ * @throws IllegalArgumentException if <code>source</code> is
+ * <code>null</code>.
+ */
+ public ListSelectionEvent(Object source, int firstIndex,
+ int lastIndex, boolean isAdjusting)
+ {
+ super(source);
+ this.firstIndex = firstIndex;
+ this.lastIndex = lastIndex;
+ this.isAdjusting = isAdjusting;
+ }
+
+ /**
+ * Returns the first index.
+ *
+ * @return The first index.
+ */
+ public int getFirstIndex()
+ {
+ return firstIndex;
+ }
+
+ /**
+ * Returns the last index.
+ *
+ * @return The last index.
+ */
+ public int getLastIndex()
+ {
+ return lastIndex;
+ }
+
+ /**
+ * Returns the flag that indicates that this event is one in a series of
+ * events updating a selection.
+ *
+ * @return A boolean.
+ */
+ public boolean getValueIsAdjusting()
+ {
+ return isAdjusting;
+ }
+
+ /**
+ * Returns a string representation of the event, typically used for debugging
+ * purposes.
+ *
+ * @return A string representation of the event.
+ */
+ public String toString()
+ {
+ return this.getClass().toString() + "[ source=" + source.toString()
+ + " firstIndex= " + firstIndex + " lastIndex= " + lastIndex
+ + " isAdjusting= " + isAdjusting + " ]";
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/event/ListSelectionListener.java b/libjava/classpath/javax/swing/event/ListSelectionListener.java
index 4ebf5830432..a21dc7365bc 100644
--- a/libjava/classpath/javax/swing/event/ListSelectionListener.java
+++ b/libjava/classpath/javax/swing/event/ListSelectionListener.java
@@ -1,5 +1,5 @@
/* ListSelectionListener.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,21 +37,25 @@ exception statement from your version. */
package javax.swing.event;
-// Imports
import java.util.EventListener;
+import javax.swing.ListSelectionModel;
+
/**
- * ListSelectionListener public interface
+ * A listener that receives {@link ListSelectionEvent} notifications,
+ * typically from a {@link ListSelectionModel} when it is modified.
+ *
* @author Andrew Selkirk
* @author Ronald Veldema
*/
-public interface ListSelectionListener extends EventListener {
-
- /**
- * Value changed
- * @param event List Selection Event
- */
- void valueChanged(ListSelectionEvent event);
+public interface ListSelectionListener extends EventListener
+{
+ /**
+ * Receives notification of a {@link ListSelectionEvent}.
+ *
+ * @param event the event.
+ */
+ void valueChanged(ListSelectionEvent event);
-} // ListSelectionListener
+} \ No newline at end of file
diff --git a/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java b/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java
index 99761670629..6be11bcca71 100644
--- a/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java
+++ b/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java
@@ -1,5 +1,5 @@
/* MenuDragMouseEvent.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -48,68 +48,57 @@ import javax.swing.MenuSelectionManager;
* MenuDragMouseEvent
* @author Andrew Selkirk
*/
-public class MenuDragMouseEvent extends MouseEvent {
+public class MenuDragMouseEvent extends MouseEvent
+{
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * path
- */
- private MenuElement[] path = null;
+ /**
+ * path
+ */
+ private MenuElement[] path = null;
- /**
- * manager
- */
- private MenuSelectionManager manager = null;
-
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor MenuDragMouseEvent
- * @param source Source
- * @param id MouseEvent type
- * @param when Time
- * @param modifiers Key modifiers
- * @param x Horizontal position
- * @param y Vertical position
- * @param clickCount Click count
- * @param popupTrigger Popup trigger?
- * @param path Path
- * @param manager MenuSelectionManager
- */
- public MenuDragMouseEvent(Component source, int id, long when, int modifiers,
- int x, int y, int clickCount, boolean popupTrigger,
- MenuElement[] path, MenuSelectionManager manager) {
- super(source, id, when, modifiers, x, y, clickCount, popupTrigger);
- this.path = path;
- this.manager = manager;
- } // MenuDragMouseEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Get path
- * @returns path
- */
- public MenuElement[] getPath() {
- return path;
- } // getPath()
-
- /**
- * Get menu selection manager
- * @returns manager
- */
- public MenuSelectionManager getMenuSelectionManager() {
- return manager;
- } // getMenuSelectionManager()
-
-
-} // MenuDragMouseEvent
+ /**
+ * manager
+ */
+ private MenuSelectionManager manager = null;
+
+ /**
+ * Constructor MenuDragMouseEvent
+ * @param source Source
+ * @param id MouseEvent type
+ * @param when Time
+ * @param modifiers Key modifiers
+ * @param x Horizontal position
+ * @param y Vertical position
+ * @param clickCount Click count
+ * @param popupTrigger Popup trigger?
+ * @param path Path
+ * @param manager MenuSelectionManager
+ */
+ public MenuDragMouseEvent(Component source, int id, long when, int modifiers,
+ int x, int y, int clickCount, boolean popupTrigger,
+ MenuElement[] path, MenuSelectionManager manager)
+ {
+ super(source, id, when, modifiers, x, y, clickCount, popupTrigger);
+ this.path = path;
+ this.manager = manager;
+ }
+
+ /**
+ * Get path
+ * @return path
+ */
+ public MenuElement[] getPath()
+ {
+ return path;
+ }
+
+ /**
+ * Get menu selection manager
+ * @return manager
+ */
+ public MenuSelectionManager getMenuSelectionManager()
+ {
+ return manager;
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/event/MenuKeyEvent.java b/libjava/classpath/javax/swing/event/MenuKeyEvent.java
index 511cb2254cd..3335850bced 100644
--- a/libjava/classpath/javax/swing/event/MenuKeyEvent.java
+++ b/libjava/classpath/javax/swing/event/MenuKeyEvent.java
@@ -1,5 +1,5 @@
/* MenuKeyEvent.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -48,66 +48,55 @@ import javax.swing.MenuSelectionManager;
* MenuKeyEvent
* @author Andrew Selkirk
*/
-public class MenuKeyEvent extends KeyEvent {
+public class MenuKeyEvent extends KeyEvent
+{
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * path
- */
- private MenuElement[] path = null;
+ /**
+ * path
+ */
+ private MenuElement[] path = null;
- /**
- * manager
- */
- private MenuSelectionManager manager = null;
-
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor MenuKeyEvent
- * @param source Source
- * @param id KeyEvent ID
- * @param when Time
- * @param modifiers Modifier keys
- * @param keyCode Key code
- * @param keyChar Key char
- * @param path Path
- * @param manager MenuSelectionManager
- */
- public MenuKeyEvent(Component source, int id, long when, int modifiers,
- int keyCode, char keyChar, MenuElement[] path,
- MenuSelectionManager manager) {
- super(source, id, when, modifiers, keyCode, keyChar);
- this.path = path;
- this.manager = manager;
- } // MenuKeyEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * getPath
- * @returns path
- */
- public MenuElement[] getPath() {
- return path;
- } // getPath()
-
- /**
- * getMenuSelectionManager
- * @returns MenuSelectionManager
- */
- public MenuSelectionManager getMenuSelectionManager() {
- return manager;
- } // getMenuSelectionManager()
-
-
-} // MenuKeyEvent
+ /**
+ * manager
+ */
+ private MenuSelectionManager manager = null;
+
+ /**
+ * Constructor MenuKeyEvent
+ * @param source Source
+ * @param id KeyEvent ID
+ * @param when Time
+ * @param modifiers Modifier keys
+ * @param keyCode Key code
+ * @param keyChar Key char
+ * @param path Path
+ * @param manager MenuSelectionManager
+ */
+ public MenuKeyEvent(Component source, int id, long when, int modifiers,
+ int keyCode, char keyChar, MenuElement[] path,
+ MenuSelectionManager manager)
+ {
+ super(source, id, when, modifiers, keyCode, keyChar);
+ this.path = path;
+ this.manager = manager;
+ }
+
+ /**
+ * getPath
+ * @return path
+ */
+ public MenuElement[] getPath()
+ {
+ return path;
+ }
+
+ /**
+ * getMenuSelectionManager
+ * @return MenuSelectionManager
+ */
+ public MenuSelectionManager getMenuSelectionManager()
+ {
+ return manager;
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java b/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java
index 7e8ff0dc2e9..7fb8aa67d7a 100644
--- a/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java
+++ b/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java
@@ -1,5 +1,5 @@
/* SwingPropertyChangeSupport.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,48 +39,24 @@ package javax.swing.event;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
-import java.beans.PropertyChangeListenerProxy;
import java.beans.PropertyChangeSupport;
-import java.util.ArrayList;
-import java.util.EventListener;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
/**
* Provides a mechanism for registering {@link PropertyChangeListener}s and
* forwarding {@link PropertyChangeEvent}s to those listeners.
- *
+ *
+ * As of JDK1.5 this class is no longer in use. Use
+ * {@link PropertyChangeSupport} instead.
+ *
* @author Andrew Selkirk
*/
public final class SwingPropertyChangeSupport
- extends PropertyChangeSupport
+ extends PropertyChangeSupport
{
private static final long serialVersionUID = 7162625831330845068L;
/**
- * Storage for the listeners that are not linked to a specific property.
- */
- private transient EventListenerList listeners;
-
- /**
- * Storage for the listeners that are linked (by name) to a specific property.
- * The hash table maps <code>String</code> objects (the property names) to
- * {@link EventListenerList} instances (which record the listener(s) for the
- * given property).
- */
- private Hashtable propertyListeners;
-
- /**
- * The object that is used as the default source for the
- * {@link PropertyChangeEvent}s generated by this class.
- */
- private Object source;
-
- /**
* Creates a new instance.
*
* @param source the source (<code>null</code> not permitted).
@@ -90,247 +66,5 @@ public final class SwingPropertyChangeSupport
public SwingPropertyChangeSupport(Object source)
{
super(source);
- this.source = source;
- this.listeners = new EventListenerList();
- this.propertyListeners = new Hashtable();
}
-
- /**
- * Registers <code>listener</code> to receive notification of any future
- * {@link PropertyChangeEvent}s generated by this instance.
- *
- * @param listener the listener (<code>null</code> is ignored).
- *
- * @see #removePropertyChangeListener(PropertyChangeListener)
- */
- public synchronized void addPropertyChangeListener(PropertyChangeListener
- listener)
- {
- listeners.add(PropertyChangeListener.class, listener);
- }
-
- /**
- * Registers <code>listener</code> to receive notification of any future
- * {@link PropertyChangeEvent}s generated by this instance for the named
- * property.
- *
- * @param propertyName the property name.
- * @param listener the listener.
- *
- * @see #removePropertyChangeListener(String, PropertyChangeListener)
- */
- public synchronized void addPropertyChangeListener(String propertyName,
- PropertyChangeListener listener)
- {
- EventListenerList list;
- list = (EventListenerList) propertyListeners.get(propertyName);
- if (list == null)
- {
- list = new EventListenerList();
- propertyListeners.put(propertyName, list);
- }
- list.add(PropertyChangeListener.class, listener);
- }
-
- /**
- * Removes <code>listener</code> from the list of registered listeners, so
- * that it will no longer receive notification of property change events.
- *
- * @param listener the listener to remove.
- */
- public synchronized void removePropertyChangeListener(PropertyChangeListener
- listener)
- {
- listeners.remove(PropertyChangeListener.class, listener);
- }
-
- /**
- * Removes <code>listener</code> from the list of registered listeners for
- * the named property, so that it will no longer receive notification of
- * property change events.
- *
- * @param propertyName the property name.
- * @param listener the listener to remove.
- */
- public synchronized void removePropertyChangeListener(String propertyName,
- PropertyChangeListener listener)
- {
- EventListenerList list;
- list = (EventListenerList) propertyListeners.get(propertyName);
- if (list == null)
- return;
- list.remove(PropertyChangeListener.class, listener);
- if (list.getListenerCount() == 0)
- {
- propertyListeners.remove(propertyName);
- }
- }
-
- /**
- * Returns an array of the {@link PropertyChangeListener}s registered with
- * this <code>SwingPropertyChangeSupport</code> instance.
- *
- * @return The array of listeners.
- *
- * @since 1.4
- */
- public synchronized PropertyChangeListener[] getPropertyChangeListeners()
- {
- // fetch the named listeners first so we know how many there are
- List namedListeners = new ArrayList();
- Set namedListenerEntries = propertyListeners.entrySet();
- Iterator iterator = namedListenerEntries.iterator();
- while (iterator.hasNext())
- {
- Map.Entry e = (Map.Entry) iterator.next();
- String propertyName = (String) e.getKey();
- EventListenerList ell = (EventListenerList) e.getValue();
- if (ell != null)
- {
- Object[] list = ell.getListenerList();
- for (int i = 0; i < list.length; i += 2)
- {
- namedListeners.add(new PropertyChangeListenerProxy(propertyName,
- (PropertyChangeListener) list[i + 1]));
- }
- }
- }
-
- // create an array that can hold everything
- int size = listeners.getListenerCount() + namedListeners.size();
- PropertyChangeListener[] result = new PropertyChangeListener[size];
-
- // copy in the general listeners
- Object[] list = listeners.getListenerList();
- int index = 0;
- for (int i = 0; i < list.length; i += 2)
- result[index++] = (PropertyChangeListener) list[i + 1];
-
- // ...and the named listeners
- Iterator iterator2 = namedListeners.iterator();
- while (iterator2.hasNext())
- result[index++] = (PropertyChangeListenerProxy) iterator2.next();
-
- return result;
- }
-
- /**
- * Returns an array of all listeners that are registered to receive
- * notification of changes to the named property. This includes the general
- * listeners as well as those registered specifically for the named
- * property.
- *
- * @param propertyName the property name.
- *
- * @return An array of all listeners for the named property.
- */
- public synchronized PropertyChangeListener[] getPropertyChangeListeners(
- String propertyName)
- {
- EventListenerList list
- = (EventListenerList) propertyListeners.get(propertyName);
- if (list == null)
- return getPropertyChangeListeners();
- int size = listeners.getListenerCount() + list.getListenerCount();
- PropertyChangeListener[] result = new PropertyChangeListener[size];
-
- // copy in the general listeners
- int index = 0;
- for (int i = 0; i < listeners.listenerList.length; i += 2)
- {
- result[index++]
- = (PropertyChangeListener) listeners.listenerList[i + 1];
- }
-
- // copy in the specific listeners
- Object[] specificListeners = list.getListenerList();
- for (int i = 0; i < specificListeners.length; i += 2)
- {
- result[index++] = (PropertyChangeListener) specificListeners[i + 1];
- }
- return result;
- }
-
- /**
- * Creates a new {@link PropertyChangeEvent} using the given arguments (and
- * the default <code>source</code> for this
- * <code>SwingPropertyChangeSupport</code> instance) and forwards it to all
- * registered listeners via the
- * {@link PropertyChangeListener#propertyChange(PropertyChangeEvent)} method.
- * <p>
- * Note that if <code>oldValue</code> and <code>newValue</code> are non-null
- * and equal, no listeners will be notified.
- *
- * @param propertyName the property name.
- * @param oldValue the old value
- * @param newValue the new value.
- */
- public void firePropertyChange(String propertyName, Object oldValue,
- Object newValue)
- {
- PropertyChangeEvent event;
- event = new PropertyChangeEvent(source, propertyName, oldValue, newValue);
- firePropertyChange(event);
- }
-
- /**
- * Forwards <code>event</code> to registered listeners.
- * <p>
- * Note that if the event's <code>getOldValue()</code> and
- * <code>getNewValue()</code> methods return non-null and equal values, no
- * listeners will be notified.
- *
- * @param event the event.
- */
- public void firePropertyChange(PropertyChangeEvent event)
- {
- EventListenerList list;
- EventListener[] listenerList;
- int index;
- PropertyChangeListener listener;
-
- // if the old and new values are non-null and equal, don't notify listeners
- if (event.getOldValue() != null && event.getNewValue() != null &&
- event.getOldValue().equals(event.getNewValue()))
- return;
-
- // Process Main Listener List
- listenerList = listeners.getListeners(PropertyChangeListener.class);
- for (index = 0; index < listenerList.length; index++)
- {
- listener = (PropertyChangeListener) listenerList[index];
- listener.propertyChange(event);
- }
-
- // Process Property Listener List
- list = (EventListenerList) propertyListeners.get(event.getPropertyName());
- if (list != null)
- {
- listenerList = list.getListeners(PropertyChangeListener.class);
- for (index = 0; index < listenerList.length; index++)
- {
- listener = (PropertyChangeListener) listenerList[index];
- listener.propertyChange(event);
- }
- }
-
- }
-
- /**
- * Tell whether the specified property is being listened on or not. This
- * will only return <code>true</code> if there are listeners on all
- * properties or if there is a listener specifically on this property.
- *
- * @param propertyName the property that may be listened on
- * @return whether the property is being listened on
- * @throws NullPointerException if propertyName is null
- */
- public synchronized boolean hasListeners(String propertyName)
- {
- if (listeners.getListenerCount() > 0)
- return true;
- else
- return (propertyListeners.get(propertyName) != null);
- }
-
}
diff --git a/libjava/classpath/javax/swing/event/TableColumnModelEvent.java b/libjava/classpath/javax/swing/event/TableColumnModelEvent.java
index 2ca4148aadb..cff49130e35 100644
--- a/libjava/classpath/javax/swing/event/TableColumnModelEvent.java
+++ b/libjava/classpath/javax/swing/event/TableColumnModelEvent.java
@@ -1,5 +1,5 @@
/* TableColumnModelEvent.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -46,60 +46,48 @@ import javax.swing.table.TableColumnModel;
* TableColumnModelEvent
* @author Andrew Selkirk
*/
-public class TableColumnModelEvent extends EventObject {
-
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * fromIndex
- */
- protected int fromIndex = 0;
-
- /**
- * toIndex
- */
- protected int toIndex = 0;
-
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor TableColumnModelEvent
- * @param source Source TableColumnModel
- * @param from From index
- * @param to To index
- */
- public TableColumnModelEvent(TableColumnModel source,
- int from, int to) {
- super(source);
- fromIndex = from;
- toIndex = to;
- } // TableColumnModelEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * getFromIndex.
- * @returns From index
- */
- public int getFromIndex() {
- return fromIndex;
- } // getFromIndex()
-
- /**
- * getToIndex.
- * @returns To index
- */
- public int getToIndex() {
- return toIndex;
- } // getToIndex()
-
-
-} // TableColumnModelEvent
+public class TableColumnModelEvent extends EventObject
+{
+
+ /**
+ * fromIndex
+ */
+ protected int fromIndex = 0;
+
+ /**
+ * toIndex
+ */
+ protected int toIndex = 0;
+
+ /**
+ * Constructor TableColumnModelEvent
+ * @param source Source TableColumnModel
+ * @param from From index
+ * @param to To index
+ */
+ public TableColumnModelEvent(TableColumnModel source, int from, int to)
+ {
+ super(source);
+ fromIndex = from;
+ toIndex = to;
+ }
+
+ /**
+ * getFromIndex.
+ * @return From index
+ */
+ public int getFromIndex()
+ {
+ return fromIndex;
+ }
+
+ /**
+ * getToIndex.
+ * @return To index
+ */
+ public int getToIndex()
+ {
+ return toIndex;
+ }
+
+} \ No newline at end of file
diff --git a/libjava/classpath/javax/swing/event/TableModelListener.java b/libjava/classpath/javax/swing/event/TableModelListener.java
index c8d6e8f8dbc..21e5ea0474e 100644
--- a/libjava/classpath/javax/swing/event/TableModelListener.java
+++ b/libjava/classpath/javax/swing/event/TableModelListener.java
@@ -1,5 +1,5 @@
/* TableModelListener.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,16 +40,21 @@ package javax.swing.event;
import java.util.EventListener;
/**
- * TableModelListener public interface
+ * A <code>TableModelListener</code> can register with a
+ * {@link javax.swing.table.TableModel} and receive notification of updates to
+ * the model.
+ *
* @author Andrew Selkirk
*/
-public interface TableModelListener extends EventListener {
-
- /**
- * Table changed
- * @param event Table Model Event
- */
- void tableChanged(TableModelEvent event);
-
-
-} // TableModelListener
+public interface TableModelListener extends EventListener
+{
+
+ /**
+ * Called to notify the listener that the
+ * {@link javax.swing.table.TableModel} has been updated.
+ *
+ * @param event contains details of the update.
+ */
+ void tableChanged(TableModelEvent event);
+
+}
diff --git a/libjava/classpath/javax/swing/event/TreeExpansionEvent.java b/libjava/classpath/javax/swing/event/TreeExpansionEvent.java
index c4b33134694..5820b339172 100644
--- a/libjava/classpath/javax/swing/event/TreeExpansionEvent.java
+++ b/libjava/classpath/javax/swing/event/TreeExpansionEvent.java
@@ -1,5 +1,5 @@
/* TreeExpansionEvent.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -46,44 +46,32 @@ import javax.swing.tree.TreePath;
* TreeExpansionEvent
* @author Andrew Selkirk
*/
-public class TreeExpansionEvent extends EventObject {
-
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * path
- */
- protected TreePath path = null;
-
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor TreeExpansionEvent
- * @param source Source object
- * @param path Path
- */
- public TreeExpansionEvent(Object source, TreePath path) {
- super(source);
- this.path = path;
- } // TreeExpansionEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * getPath
- * @returns Tree path
- */
- public TreePath getPath() {
- return path;
- } // getPath()
-
-
-} // TreeExpansionEvent
+public class TreeExpansionEvent extends EventObject
+{
+
+ /**
+ * path
+ */
+ protected TreePath path = null;
+
+ /**
+ * Constructor TreeExpansionEvent
+ * @param source Source object
+ * @param path Path
+ */
+ public TreeExpansionEvent(Object source, TreePath path)
+ {
+ super(source);
+ this.path = path;
+ }
+
+ /**
+ * getPath
+ * @return Tree path
+ */
+ public TreePath getPath()
+ {
+ return path;
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/event/TreeModelEvent.java b/libjava/classpath/javax/swing/event/TreeModelEvent.java
index 8fa28a7eadb..2d562a5c4a8 100644
--- a/libjava/classpath/javax/swing/event/TreeModelEvent.java
+++ b/libjava/classpath/javax/swing/event/TreeModelEvent.java
@@ -1,5 +1,5 @@
/* TreeModelEvent.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -46,128 +46,123 @@ import javax.swing.tree.TreePath;
* TreeModelEvent
* @author Andrew Selkirk
*/
-public class TreeModelEvent extends EventObject {
-
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * childIndices
- */
- protected int[] childIndices = null;
-
- /**
- * children
- */
- protected Object[] children = null;
-
- /**
- * path
- */
- protected TreePath path = null;
-
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
+public class TreeModelEvent extends EventObject
+{
+
+ /**
+ * childIndices
+ */
+ protected int[] childIndices = null;
+
+ /**
+ * children
+ */
+ protected Object[] children = null;
+
+ /**
+ * path
+ */
+ protected TreePath path = null;
- /**
- * Constructor TreeModelEvent
- * @param source Source object
- * @param path
- */
- public TreeModelEvent(Object source, Object[] path) {
- super(source);
- this.path = new TreePath(path);
- } // TreeModelEvent()
-
- /**
- * Constructor TreeModelEvent
- * @param source Source object
- * @param path path
- * @param childIndices Child indices
- * @param children Children
- */
- public TreeModelEvent(Object source, Object[] path,
- int[] childIndices, Object[] children) {
- super(source);
- this.path = new TreePath(path);
- this.childIndices = childIndices;
- this.children = children;
- } // TreeModelEvent()
-
- /**
- * Constructor TreeModelEvent
- * @param source Source object
- * @param path Path
- */
- public TreeModelEvent(Object source, TreePath path) {
- super(source);
- this.path = path;
- } // TreeModelEvent()
-
- /**
- * Constructor TreeModelEvent
- * @param source Source object
- * @param path Path
- * @param childIndices Child indices
- * @param children Children
- */
- public TreeModelEvent(Object source, TreePath path,
- int[] childIndices, Object[] children) {
- super(source);
- this.path = path;
- this.childIndices = childIndices;
- this.children = children;
- } // TreeModelEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * getChildIndices
- * @returns child indices
- */
- public int[] getChildIndices() {
- return childIndices;
- } // getChildIndices()
-
- /**
- * getChildren
- * @returns children
- */
- public Object[] getChildren() {
- return children;
- } // getChildren()
-
- /**
- * getPath
- * @returns path
- */
- public Object[] getPath() {
- return path.getPath();
- } // getPath()
-
- /**
- * getTreePath
- * @returns TreePath
- */
- public TreePath getTreePath() {
- return path;
- } // getTreePath()
-
- /**
- * String representation
- * @returns String representation
- */
- public String toString() {
- return getClass() + " [Source: " + getSource() + ", TreePath: " + getTreePath() +
- ", Child Indicies: " + getChildIndices() + ", Children: " + getChildren() +
- ", Path: " + getPath() +"]";
- } // toString()
-
-
-} // TreeModelEvent
+ /**
+ * Constructor TreeModelEvent
+ * @param source Source object
+ * @param path
+ */
+ public TreeModelEvent(Object source, Object[] path)
+ {
+ super(source);
+ this.path = new TreePath(path);
+ }
+
+ /**
+ * Constructor TreeModelEvent
+ * @param source Source object
+ * @param path path
+ * @param childIndices Child indices
+ * @param children Children
+ */
+ public TreeModelEvent(Object source, Object[] path,
+ int[] childIndices, Object[] children)
+ {
+ super(source);
+ this.path = new TreePath(path);
+ this.childIndices = childIndices;
+ this.children = children;
+ }
+
+ /**
+ * Constructor TreeModelEvent
+ * @param source Source object
+ * @param path Path
+ */
+ public TreeModelEvent(Object source, TreePath path)
+ {
+ super(source);
+ this.path = path;
+ }
+
+ /**
+ * Constructor TreeModelEvent
+ * @param source Source object
+ * @param path Path
+ * @param childIndices Child indices
+ * @param children Children
+ */
+ public TreeModelEvent(Object source, TreePath path,
+ int[] childIndices, Object[] children)
+ {
+ super(source);
+ this.path = path;
+ this.childIndices = childIndices;
+ this.children = children;
+ }
+
+ /**
+ * getChildIndices
+ * @return child indices
+ */
+ public int[] getChildIndices()
+ {
+ return childIndices;
+ }
+
+ /**
+ * getChildren
+ * @return children
+ */
+ public Object[] getChildren()
+ {
+ return children;
+ }
+
+ /**
+ * getPath
+ * @return path
+ */
+ public Object[] getPath()
+ {
+ return path.getPath();
+ }
+
+ /**
+ * getTreePath
+ * @return TreePath
+ */
+ public TreePath getTreePath()
+ {
+ return path;
+ }
+
+ /**
+ * String representation
+ * @return String representation
+ */
+ public String toString()
+ {
+ return getClass() + " [Source: " + getSource() + ", TreePath: "
+ + getTreePath() + ", Child Indicies: " + getChildIndices()
+ + ", Children: " + getChildren() + ", Path: " + getPath() +"]";
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/event/TreeSelectionEvent.java b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java
index 9b87667a387..1930677af9f 100644
--- a/libjava/classpath/javax/swing/event/TreeSelectionEvent.java
+++ b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java
@@ -1,5 +1,5 @@
/* TreeSelectionEvent.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -49,10 +49,6 @@ import javax.swing.tree.TreePath;
*/
public class TreeSelectionEvent extends EventObject {
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
/**
* paths
*/
@@ -73,11 +69,6 @@ public class TreeSelectionEvent extends EventObject {
*/
protected TreePath newLeadSelectionPath;
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
/**
* Constructor TreeSelectionEvent
* @param source TODO
@@ -95,7 +86,7 @@ public class TreeSelectionEvent extends EventObject {
this.areNew = areNew;
this.oldLeadSelectionPath = oldLeadSelectionPath;
this.newLeadSelectionPath = newLeadSelectionPath;
- } // TreeSelectionEvent()
+ }
/**
* Constructor TreeSelectionEvent
@@ -114,29 +105,24 @@ public class TreeSelectionEvent extends EventObject {
this.areNew = new boolean[]{isNew};
this.oldLeadSelectionPath = oldLeadSelectionPath;
this.newLeadSelectionPath = newLeadSelectionPath;
- } // TreeSelectionEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
+ }
/**
- * @returns the first path element
+ * @return the first path element
*/
public TreePath getPath()
{
return paths[0];
- } // getPath()
+ }
/**
*
- * @returns the paths with selection changed
+ * @return the paths with selection changed
*/
public TreePath[] getPaths()
{
return (TreePath[]) paths.clone();
- } // getPaths()
+ }
/**
* @return true if the first path is added to the selection, false otherwise
@@ -144,7 +130,7 @@ public class TreeSelectionEvent extends EventObject {
public boolean isAddedPath()
{
return areNew[0];
- } // isAddedPath()
+ }
/**
* @param path the path to check
@@ -157,7 +143,7 @@ public class TreeSelectionEvent extends EventObject {
return areNew[i];
return false;
- } // isAddedPath()
+ }
/**
* @param index the index'th path
@@ -166,7 +152,7 @@ public class TreeSelectionEvent extends EventObject {
public boolean isAddedPath(int index)
{
return areNew[index];
- } // isAddedPath()
+ }
/**
* @return the previous lead selection path
@@ -174,15 +160,15 @@ public class TreeSelectionEvent extends EventObject {
public TreePath getOldLeadSelectionPath()
{
return oldLeadSelectionPath;
- } // getOldLeadSelectionPath()
+ }
/**
- * @returns the current lead selection path
+ * @return the current lead selection path
*/
public TreePath getNewLeadSelectionPath()
{
return newLeadSelectionPath;
- } // getNewLeadSelectionPath()
+ }
/**
* @param source the new event source
@@ -193,7 +179,6 @@ public class TreeSelectionEvent extends EventObject {
return new TreeSelectionEvent (source, paths, areNew,
oldLeadSelectionPath,
newLeadSelectionPath);
- } // cloneWithSource()
-
+ }
-} // TreeSelectionEvent
+}
diff --git a/libjava/classpath/javax/swing/event/UndoableEditEvent.java b/libjava/classpath/javax/swing/event/UndoableEditEvent.java
index 147c2e5b1c5..b59ceadc9c2 100644
--- a/libjava/classpath/javax/swing/event/UndoableEditEvent.java
+++ b/libjava/classpath/javax/swing/event/UndoableEditEvent.java
@@ -1,5 +1,5 @@
/* UndoableEditEvent.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -47,46 +47,34 @@ import javax.swing.undo.UndoableEdit;
* @author Andrew Selkirk
* @author Ronald Veldema
*/
-public class UndoableEditEvent extends EventObject {
+public class UndoableEditEvent extends EventObject
+{
private static final long serialVersionUID = 4418044561759134484L;
- //-------------------------------------------------------------
- // Variables --------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * edit
- */
- private UndoableEdit edit;
-
-
- //-------------------------------------------------------------
- // Initialization ---------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * Constructor UndoableEditEvent
- * @param source TODO
- * @param edit TODO
- */
- public UndoableEditEvent(Object source, UndoableEdit edit) {
- super(source);
- this.edit = edit;
- } // UndoableEditEvent()
-
-
- //-------------------------------------------------------------
- // Methods ----------------------------------------------------
- //-------------------------------------------------------------
-
- /**
- * getEdit
- * @returns UndoableEdit
- */
- public UndoableEdit getEdit() {
- return edit;
- } // getEdit()
-
-
-} // UndoableEditEvent
+ /**
+ * edit
+ */
+ private UndoableEdit edit;
+
+ /**
+ * Constructor UndoableEditEvent
+ * @param source TODO
+ * @param edit TODO
+ */
+ public UndoableEditEvent(Object source, UndoableEdit edit)
+ {
+ super(source);
+ this.edit = edit;
+ }
+
+ /**
+ * getEdit
+ * @return UndoableEdit
+ */
+ public UndoableEdit getEdit()
+ {
+ return edit;
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java
index 5d4ce18932b..5e2cf2e48ca 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java
@@ -299,9 +299,7 @@ public class BasicBorders
public static Border getSplitPaneDividerBorder()
{
/* See comment in methods above for why this border is not shared. */
- return new SplitPaneDividerBorder(
- UIManager.getColor("SplitPane.highlight"),
- UIManager.getColor("SplitPane.darkShadow"));
+ return new SplitPaneDividerBorder();
}
@@ -1518,34 +1516,15 @@ public class BasicBorders
implements Border, UIResource, Serializable
{
/**
- * The highlight color, which is drawn on the left or top edge
- * depending on the orientation of the JSplitPanel.
- */
- protected Color highlight;
-
-
- /**
- * The highlight color, which is drawn on the right or bottom edge
- * depending on the orientation of the JSplitPanel.
- */
- protected Color shadow;
-
-
- /**
* Constructs a new border for drawing the divider of a JSplitPane
* in the Basic look and feel. The outer parts of the JSplitPane have
* their own border class, <code>SplitPaneBorder</code>.
- *
- * @param shadow the shadow color.
- * @param highlight the highlight color.
*/
- public SplitPaneDividerBorder(Color highlight, Color shadow)
+ public SplitPaneDividerBorder()
{
- this.highlight = (highlight != null) ? highlight : Color.white;
- this.shadow = (shadow != null) ? shadow : Color.black;
+ // Nothing to do here.
}
-
/**
* Paints the border around the divider of a <code>JSplitPane</code>.
*
@@ -1564,6 +1543,8 @@ public class BasicBorders
public void paintBorder(Component c, Graphics g,
int x, int y, int width, int height)
{
+ Color highlight = UIManager.getColor("SplitPane.highlight");
+ Color shadow = UIManager.getColor("SplitPane.shadow");
Color oldColor, dcol;
int x2, y2;
JSplitPane sp;
@@ -1624,17 +1605,15 @@ public class BasicBorders
return new Insets(1, 1, 1, 1);
}
-
/**
* Determines whether this border fills every pixel in its area
* when painting.
*
- * @return <code>true</code> if both highlight and shadow
- * color are fully opaque.
+ * @return <code>true</code>
*/
public boolean isBorderOpaque()
{
- return (highlight.getAlpha() == 255) && (shadow.getAlpha() == 255);
+ return true;
}
@@ -1785,4 +1764,5 @@ public class BasicBorders
return insets;
}
}
+
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java
index 95e0dc98257..e45970ed02c 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java
@@ -45,7 +45,6 @@ import javax.swing.JMenuItem;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.UIDefaults;
-import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java
index 5a872ae6368..f37cbd7b838 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java
@@ -141,10 +141,9 @@ public class BasicColorChooserUI extends ColorChooserUI
protected PropertyChangeListener propertyChangeListener;
/**
- * The JColorChooser.
- * This is package-private to avoid an accessor method.
+ * The JColorChooser this is installed on.
*/
- JColorChooser chooser;
+ protected JColorChooser chooser;
/** The JTabbedPane that is used. */
JTabbedPane pane;
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java
index 08dab7f9f36..798101d0d85 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java
@@ -69,6 +69,7 @@ import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
+import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
@@ -193,8 +194,23 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
if (selectedIndex > comboBox.getMaximumRowCount())
scrollbar.setValue(getPopupHeightForRowCount(selectedIndex));
+ // We put the autoclose-registration inside an InvocationEvent, so that
+ // the same event that triggered this show() call won't hide the popup
+ // immediately.
+ SwingUtilities.invokeLater
+ (new Runnable()
+ {
+ public void run()
+ {
+ // Register this popup to be autoclosed when user clicks outside the
+ // popup.
+ BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel();
+ laf.registerForAutoClose(BasicComboPopup.this);
+ }});
+
// location specified is relative to comboBox
super.show(comboBox, 0, cbBounds.height);
+
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java b/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java
index b9891e14401..98c9cb277f4 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java
@@ -38,12 +38,21 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import java.awt.Container;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
import java.io.IOException;
import java.io.StringReader;
import javax.swing.JComponent;
+import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
import javax.swing.text.Element;
+import javax.swing.text.Position;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTMLDocument;
@@ -59,6 +68,287 @@ public class BasicHTML
{
/**
+ * This class serves as the root view for HTML rendering components.
+ * Its purpose and implementation is similar to the BasicTextUI.RootView
+ * class, only that is implements some stuff differently due to the nature
+ * of not beeing inside a JTextComponent.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private static class HTMLRootView extends View
+ {
+ /**
+ * The real root view.
+ */
+ private View view;
+
+ /**
+ * The component on which to render the view.
+ */
+ private JComponent component;
+
+ /**
+ * The EditorKit.
+ */
+ private EditorKit editorKit;
+
+ /**
+ * The document to use.
+ */
+ private Document document;
+
+ /**
+ * Creates a new RootView.
+ */
+ public HTMLRootView(JComponent c, View view, EditorKit kit, Document doc)
+ {
+ super(null);
+ component = c;
+ editorKit = kit;
+ document = doc;
+ setView(view);
+ }
+
+ /**
+ * Returns the ViewFactory for this RootView. If the current EditorKit
+ * provides a ViewFactory, this is used. Otherwise the TextUI itself
+ * is returned as a ViewFactory.
+ *
+ * @return the ViewFactory for this RootView
+ */
+ public ViewFactory getViewFactory()
+ {
+ return editorKit.getViewFactory();
+ }
+
+ /**
+ * Indicates that the preferences of one of the child view has changed.
+ * This calls revalidate on the text component.
+ *
+ * @param v the child view which's preference has changed
+ * @param width <code>true</code> if the width preference has changed
+ * @param height <code>true</code> if the height preference has changed
+ */
+ public void preferenceChanged(View v, boolean width, boolean height)
+ {
+ component.revalidate();
+ }
+
+ /**
+ * Sets the real root view.
+ *
+ * @param v the root view to set
+ */
+ public void setView(View v)
+ {
+ if (view != null)
+ view.setParent(null);
+
+ if (v != null)
+ v.setParent(this);
+
+ view = v;
+ }
+
+ /**
+ * Returns the real root view, regardless of the index.
+ *
+ * @param index not used here
+ *
+ * @return the real root view, regardless of the index.
+ */
+ public View getView(int index)
+ {
+ return view;
+ }
+
+ /**
+ * Returns <code>1</code> since the RootView always contains one
+ * child, that is the real root of the View hierarchy.
+ *
+ * @return <code>1</code> since the RootView always contains one
+ * child, that is the real root of the View hierarchy
+ */
+ public int getViewCount()
+ {
+ int count = 0;
+ if (view != null)
+ count = 1;
+ return count;
+ }
+
+ /**
+ * Returns the <code>Container</code> that contains this view. This
+ * normally will be the text component that is managed by this TextUI.
+ *
+ * @return the <code>Container</code> that contains this view
+ */
+ public Container getContainer()
+ {
+ return component;
+ }
+
+ /**
+ * Returns the preferred span along the specified <code>axis</code>.
+ * This is delegated to the real root view.
+ *
+ * @param axis the axis for which the preferred span is queried
+ *
+ * @return the preferred span along the axis
+ */
+ public float getPreferredSpan(int axis)
+ {
+ if (view != null)
+ return view.getPreferredSpan(axis);
+
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * Paints the view. This is delegated to the real root view.
+ *
+ * @param g the <code>Graphics</code> context to paint to
+ * @param s the allocation for the View
+ */
+ public void paint(Graphics g, Shape s)
+ {
+ if (view != null)
+ {
+ Rectangle b = s.getBounds();
+ view.setSize(b.width, b.height);
+ view.paint(g, s);
+ }
+ }
+
+
+ /**
+ * Maps a position in the document into the coordinate space of the View.
+ * The output rectangle usually reflects the font height but has a width
+ * of zero.
+ *
+ * This is delegated to the real root view.
+ *
+ * @param position the position of the character in the model
+ * @param a the area that is occupied by the view
+ * @param bias either {@link Position.Bias#Forward} or
+ * {@link Position.Bias#Backward} depending on the preferred
+ * direction bias. If <code>null</code> this defaults to
+ * <code>Position.Bias.Forward</code>
+ *
+ * @return a rectangle that gives the location of the document position
+ * inside the view coordinate space
+ *
+ * @throws BadLocationException if <code>pos</code> is invalid
+ * @throws IllegalArgumentException if b is not one of the above listed
+ * valid values
+ */
+ public Shape modelToView(int position, Shape a, Position.Bias bias)
+ throws BadLocationException
+ {
+ return view.modelToView(position, a, bias);
+ }
+
+ /**
+ * Maps coordinates from the <code>View</code>'s space into a position
+ * in the document model.
+ *
+ * @param x the x coordinate in the view space
+ * @param y the y coordinate in the view space
+ * @param a the allocation of this <code>View</code>
+ * @param b the bias to use
+ *
+ * @return the position in the document that corresponds to the screen
+ * coordinates <code>x, y</code>
+ */
+ public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
+ {
+ return view.viewToModel(x, y, a, b);
+ }
+
+ /**
+ * Notification about text insertions. These are forwarded to the
+ * real root view.
+ *
+ * @param ev the DocumentEvent describing the change
+ * @param shape the current allocation of the view's display
+ * @param vf the ViewFactory to use for creating new Views
+ */
+ public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+ {
+ view.insertUpdate(ev, shape, vf);
+ }
+
+ /**
+ * Notification about text removals. These are forwarded to the
+ * real root view.
+ *
+ * @param ev the DocumentEvent describing the change
+ * @param shape the current allocation of the view's display
+ * @param vf the ViewFactory to use for creating new Views
+ */
+ public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+ {
+ view.removeUpdate(ev, shape, vf);
+ }
+
+ /**
+ * Notification about text changes. These are forwarded to the
+ * real root view.
+ *
+ * @param ev the DocumentEvent describing the change
+ * @param shape the current allocation of the view's display
+ * @param vf the ViewFactory to use for creating new Views
+ */
+ public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+ {
+ view.changedUpdate(ev, shape, vf);
+ }
+
+ /**
+ * Returns the document position that is (visually) nearest to the given
+ * document position <code>pos</code> in the given direction <code>d</code>.
+ *
+ * @param pos the document position
+ * @param b the bias for <code>pos</code>
+ * @param a the allocation for the view
+ * @param d the direction, must be either {@link SwingConstants#NORTH},
+ * {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+ * {@link SwingConstants#EAST}
+ * @param biasRet an array of {@link Position.Bias} that can hold at least
+ * one element, which is filled with the bias of the return position
+ * on method exit
+ *
+ * @return the document position that is (visually) nearest to the given
+ * document position <code>pos</code> in the given direction
+ * <code>d</code>
+ *
+ * @throws BadLocationException if <code>pos</code> is not a valid offset in
+ * the document model
+ */
+ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
+ int d, Position.Bias[] biasRet)
+ throws BadLocationException
+ {
+ return view.getNextVisualPositionFrom(pos, b, a, d, biasRet);
+ }
+
+ public int getStartOffset()
+ {
+ return 0;
+ }
+
+ public int getEndOffset()
+ {
+ return getDocument().getLength();
+ }
+
+ public Document getDocument()
+ {
+ return document;
+ }
+ }
+
+ /**
* The key that is used to store a HTML view in a JComponent's client
* properties.
*/
@@ -116,7 +406,8 @@ public class BasicHTML
ViewFactory vf = kit.getViewFactory();
Element root = doc.getDefaultRootElement();
View view = vf.create(root);
- return view;
+ HTMLRootView rootView = new HTMLRootView(c, view, kit, doc);
+ return rootView;
}
/**
@@ -132,13 +423,13 @@ public class BasicHTML
{
// We consider a string to be HTML if it contains both the '<' and '>'
// character at least once.
- return s.contains("<") && s.contains(">");
+ return (s != null) && s.contains("<") && s.contains(">");
}
/**
* Stores a HTML renderer in <code>c</code>'s client property if
* <code>text</code> is HTML, otherwise it clears the corresponding client
- * property. This is useful for {@link java.swing.plaf.ComponentUI}
+ * property. This is useful for {@link javax.swing.plaf.ComponentUI}
* implementations that are shared between it's components.
*
* @param c the component to update the renderer for
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
index f9653bd2edd..f6cbeec8879 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
@@ -54,8 +54,6 @@ import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
-import java.beans.PropertyVetoException;
-import java.beans.VetoableChangeListener;
import javax.swing.DefaultDesktopManager;
import javax.swing.DesktopManager;
@@ -94,7 +92,7 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
public void internalFrameActivated(InternalFrameEvent e)
{
- // FIXME: Implement.
+ frame.getGlassPane().setVisible(false);
}
/**
@@ -124,7 +122,7 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
public void internalFrameDeactivated(InternalFrameEvent e)
{
- // FIXME: Implement.
+ frame.getGlassPane().setVisible(true);
}
/**
@@ -464,8 +462,6 @@ public class BasicInternalFrameUI extends InternalFrameUI
dims.width -= insets.left + insets.right;
dims.height -= insets.top + insets.bottom;
- frame.getRootPane().getGlassPane().setBounds(0, 0, dims.width,
- dims.height);
int nh = 0;
int sh = 0;
int ew = 0;
@@ -526,18 +522,6 @@ public class BasicInternalFrameUI extends InternalFrameUI
}
/**
- * This method returns the maximum layout size.
- *
- * @param c
- * The Container to find a maximum layout size for.
- * @return The maximum dimensions for the JInternalFrame.
- */
- public Dimension maximumLayoutSize(Container c)
- {
- return preferredLayoutSize(c);
- }
-
- /**
* Th8is method returns the preferred layout size.
*
* @param c
@@ -891,40 +875,12 @@ public class BasicInternalFrameUI extends InternalFrameUI
* This helper class listens for PropertyChangeEvents from the
* JInternalFrame.
*/
- public class InternalFramePropertyChangeListener implements
- PropertyChangeListener, VetoableChangeListener
+ public class InternalFramePropertyChangeListener
+ implements PropertyChangeListener
{
/**
* This method is called when one of the JInternalFrame's properties change.
- * This method is to allow JInternalFrame to veto an attempt to close the
- * internal frame. This allows JInternalFrame to honour its
- * defaultCloseOperation if that is DO_NOTHING_ON_CLOSE.
- */
- public void vetoableChange(PropertyChangeEvent e)
- throws PropertyVetoException
- {
- if (e.getPropertyName().equals(JInternalFrame.IS_CLOSED_PROPERTY))
- {
- if (frame.getDefaultCloseOperation() == JInternalFrame.HIDE_ON_CLOSE)
- {
- frame.setVisible(false);
- frame.getDesktopPane().repaint();
- throw new PropertyVetoException(
- "close operation is HIDE_ON_CLOSE\n",
- e);
- }
- else if (frame.getDefaultCloseOperation() == JInternalFrame.DISPOSE_ON_CLOSE)
- closeFrame(frame);
- else
- throw new PropertyVetoException(
- "close operation is DO_NOTHING_ON_CLOSE\n",
- e);
- }
- }
-
- /**
- * This method is called when one of the JInternalFrame's properties change.
*
* @param evt
* The PropertyChangeEvent.
@@ -1091,13 +1047,6 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
protected PropertyChangeListener propertyChangeListener;
- /**
- * The VetoableChangeListener. Listens to PropertyChangeEvents
- * from the JInternalFrame and allows the JInternalFrame to
- * veto attempts to close it.
- */
- private VetoableChangeListener internalFrameVetoableChangeListener;
-
/** The InternalFrameListener that listens to the JInternalFrame. */
private transient BasicInternalFrameListener internalFrameListener;
@@ -1165,14 +1114,15 @@ public class BasicInternalFrameUI extends InternalFrameUI
{
frame = (JInternalFrame) c;
- ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false);
- frame.getRootPane().getGlassPane().setVisible(true);
-
installDefaults();
installListeners();
installComponents();
installKeyboardActions();
+ ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false);
+ if (! frame.isSelected())
+ frame.getRootPane().getGlassPane().setVisible(true);
+
frame.setOpaque(true);
frame.invalidate();
}
@@ -1205,8 +1155,6 @@ public class BasicInternalFrameUI extends InternalFrameUI
frame.setLayout(internalFrameLayout);
LookAndFeel.installBorder(frame, "InternalFrame.border");
frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon"));
- // InternalFrames are invisible by default.
- frame.setVisible(false);
}
/**
@@ -1238,13 +1186,11 @@ public class BasicInternalFrameUI extends InternalFrameUI
borderListener = createBorderListener(frame);
componentListener = createComponentListener();
propertyChangeListener = createPropertyChangeListener();
- internalFrameVetoableChangeListener = new InternalFramePropertyChangeListener();
frame.addMouseListener(borderListener);
frame.addMouseMotionListener(borderListener);
frame.addInternalFrameListener(internalFrameListener);
frame.addPropertyChangeListener(propertyChangeListener);
- frame.addVetoableChangeListener(internalFrameVetoableChangeListener);
frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher);
frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher);
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
index fd4cff56895..d0964f4733e 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
@@ -53,6 +53,7 @@ import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.LabelUI;
+import javax.swing.text.View;
/**
* This is the Basic Look and Feel class for the JLabel. One BasicLabelUI
@@ -64,11 +65,22 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
protected static BasicLabelUI labelUI;
/**
+ * These fields hold the rectangles for the whole label,
+ * the icon and the text.
+ */
+ private Rectangle vr;
+ private Rectangle ir;
+ private Rectangle tr;
+
+ /**
* Creates a new BasicLabelUI object.
*/
public BasicLabelUI()
{
super();
+ vr = new Rectangle();
+ ir = new Rectangle();
+ tr = new Rectangle();
}
/**
@@ -99,13 +111,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
public Dimension getPreferredSize(JComponent c)
{
JLabel lab = (JLabel) c;
- Rectangle vr = new Rectangle();
- Rectangle ir = new Rectangle();
- Rectangle tr = new Rectangle();
Insets insets = lab.getInsets();
FontMetrics fm = lab.getFontMetrics(lab.getFont());
layoutCL(lab, fm, lab.getText(), lab.getIcon(), vr, ir, tr);
- Rectangle cr = tr.union(ir);
+ Rectangle cr = SwingUtilities.computeUnion(tr.x, tr.y, tr.width, tr.height,
+ ir);
return new Dimension(insets.left + cr.width + insets.right, insets.top
+ cr.height + insets.bottom);
@@ -148,11 +158,6 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
public void paint(Graphics g, JComponent c)
{
JLabel b = (JLabel) c;
-
- Rectangle tr = new Rectangle();
- Rectangle ir = new Rectangle();
- Rectangle vr = new Rectangle();
-
FontMetrics fm = g.getFontMetrics();
vr = SwingUtilities.calculateInnerArea(c, vr);
@@ -168,13 +173,21 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
if (icon != null)
icon.paintIcon(b, g, ir.x, ir.y);
- if (text != null && !text.equals(""))
- {
- if (b.isEnabled())
- paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent());
- else
- paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent());
- }
+ Object htmlRenderer = b.getClientProperty(BasicHTML.propertyKey);
+ if (htmlRenderer == null)
+ {
+ if (text != null && !text.equals(""))
+ {
+ if (b.isEnabled())
+ paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent());
+ else
+ paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent());
+ }
+ }
+ else
+ {
+ ((View) htmlRenderer).paint(g, tr);
+ }
}
/**
@@ -312,7 +325,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
*/
protected void installComponents(JLabel c)
{
- //FIXME: fix javadoc + implement.
+ BasicHTML.updateRenderer(c, c.getText());
}
/**
@@ -322,7 +335,8 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
*/
protected void uninstallComponents(JLabel c)
{
- //FIXME: fix javadoc + implement.
+ c.putClientProperty(BasicHTML.propertyKey, null);
+ c.putClientProperty(BasicHTML.documentBaseKey, null);
}
/**
@@ -402,6 +416,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
*/
public void propertyChange(PropertyChangeEvent e)
{
- // What to do here?
+ if (e.getPropertyName().equals("text"))
+ {
+ String text = (String) e.getNewValue();
+ JLabel l = (JLabel) e.getSource();
+ BasicHTML.updateRenderer(l, text);
+ }
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
index 00d157a62c4..19dfe21f889 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
@@ -64,6 +64,7 @@ import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
@@ -135,6 +136,7 @@ public class BasicListUI extends ListUI
*/
public void contentsChanged(ListDataEvent e)
{
+ updateLayoutStateNeeded |= modelChanged;
list.revalidate();
}
@@ -145,6 +147,7 @@ public class BasicListUI extends ListUI
*/
public void intervalAdded(ListDataEvent e)
{
+ updateLayoutStateNeeded |= modelChanged;
list.revalidate();
}
@@ -155,6 +158,7 @@ public class BasicListUI extends ListUI
*/
public void intervalRemoved(ListDataEvent e)
{
+ updateLayoutStateNeeded |= modelChanged;
list.revalidate();
}
}
@@ -541,17 +545,21 @@ public class BasicListUI extends ListUI
*/
public void propertyChange(PropertyChangeEvent e)
{
- if (e.getSource() == BasicListUI.this.list)
+ if (e.getPropertyName().equals("model"))
{
if (e.getOldValue() != null && e.getOldValue() instanceof ListModel)
- ((ListModel) e.getOldValue()).removeListDataListener(BasicListUI.this.listDataListener);
-
+ {
+ ListModel oldModel = (ListModel) e.getOldValue();
+ oldModel.removeListDataListener(listDataListener);
+ }
if (e.getNewValue() != null && e.getNewValue() instanceof ListModel)
- ((ListModel) e.getNewValue()).addListDataListener(BasicListUI.this.listDataListener);
+ {
+ ListModel newModel = (ListModel) e.getNewValue();
+ newModel.addListDataListener(BasicListUI.this.listDataListener);
+ }
+
+ updateLayoutStateNeeded |= modelChanged;
}
- // Update the updateLayoutStateNeeded flag.
- if (e.getPropertyName().equals("model"))
- updateLayoutStateNeeded |= modelChanged;
else if (e.getPropertyName().equals("selectionModel"))
updateLayoutStateNeeded |= selectionModelChanged;
else if (e.getPropertyName().equals("font"))
@@ -720,14 +728,20 @@ public class BasicListUI extends ListUI
int minIndex = Math.min(index1, index2);
int maxIndex = Math.max(index1, index2);
Point loc = indexToLocation(list, minIndex);
- Rectangle bounds = new Rectangle(loc.x, loc.y, cellWidth,
+
+ // When the layoutOrientation is VERTICAL, then the width == the list
+ // width. Otherwise the cellWidth field is used.
+ int width = cellWidth;
+ if (l.getLayoutOrientation() == JList.VERTICAL)
+ width = l.getWidth();
+
+ Rectangle bounds = new Rectangle(loc.x, loc.y, width,
getCellHeight(minIndex));
for (int i = minIndex + 1; i <= maxIndex; i++)
{
Point hiLoc = indexToLocation(list, i);
- Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, cellWidth,
- getCellHeight(i));
- bounds = bounds.union(hibounds);
+ bounds = SwingUtilities.computeUnion(hiLoc.x, hiLoc.y, width,
+ getCellHeight(i), bounds);
}
return bounds;
@@ -883,8 +897,6 @@ public class BasicListUI extends ListUI
Dimension dim = flyweight.getPreferredSize();
cellWidth = Math.max(cellWidth, dim.width);
}
- if (list.getLayoutOrientation() == JList.VERTICAL)
- cellWidth = Math.max(cellWidth, list.getSize().width);
}
}
@@ -894,7 +906,7 @@ public class BasicListUI extends ListUI
*/
protected void maybeUpdateLayoutState()
{
- if (updateLayoutStateNeeded != 0 || !list.isValid())
+ if (updateLayoutStateNeeded != 0)
{
updateLayoutState();
updateLayoutStateNeeded = 0;
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
index f5217be1ff6..3451224beeb 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
@@ -38,15 +38,24 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import java.awt.AWTEvent;
import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Enumeration;
+import java.util.Iterator;
import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.WeakHashMap;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
@@ -57,8 +66,11 @@ import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
+import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
+import javax.swing.MenuSelectionManager;
+import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
@@ -77,6 +89,96 @@ import javax.swing.plaf.InsetsUIResource;
public abstract class BasicLookAndFeel extends LookAndFeel
implements Serializable
{
+
+ /**
+ * Helps closing menu popups when the user clicks outside of any menu area.
+ * This is implemented as an AWTEventListener that listens on the event
+ * queue directly, grabs all mouse events from there and finds out of they
+ * are targetted at a menu/submenu/menubar or not. If not,
+ * the MenuSelectionManager is messaged to close the currently opened menus,
+ * if any.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private class PopupHelper implements AWTEventListener
+ {
+
+ /**
+ * Registered popups for autoclose.
+ */
+ private WeakHashMap autoClosePopups = new WeakHashMap();
+
+ /**
+ * Receives an event from the event queue.
+ *
+ * @param event
+ */
+ public void eventDispatched(AWTEvent event)
+ {
+ if (event instanceof MouseEvent)
+ {
+ MouseEvent mouseEvent = (MouseEvent) event;
+ if (mouseEvent.getID() == MouseEvent.MOUSE_PRESSED)
+ mousePressed(mouseEvent);
+ }
+ }
+
+ /**
+ * Handles mouse pressed events from the event queue.
+ *
+ * @param ev the mouse pressed event
+ */
+ private void mousePressed(MouseEvent ev)
+ {
+ // Autoclose all menus managed by the MenuSelectionManager.
+ MenuSelectionManager m = MenuSelectionManager.defaultManager();
+ Component target = ev.getComponent();
+ if (target instanceof Container)
+ target = ((Container) target).findComponentAt(ev.getPoint());
+ if (! m.isComponentPartOfCurrentMenu(target))
+ m.clearSelectedPath();
+
+ // Handle other registered popup instances, like ComboBox popups.
+ autoClosePopups(ev, target);
+ }
+
+ /**
+ * Registers Popup and its content to be autoclosed when a mouseclick
+ * occurs outside of the popup.
+ *
+ * @param popup the popup to be autoclosed when clicked outside
+ */
+ void registerForAutoClose(JPopupMenu popup)
+ {
+ autoClosePopups.put(popup, null);
+ }
+
+ /**
+ * Automatically closes all popups that are not 'hit' by the mouse event.
+ *
+ * @param ev the mouse event
+ * @param target the target of the mouse event
+ */
+ private void autoClosePopups(MouseEvent ev, Component target)
+ {
+ if (autoClosePopups.size() != 0)
+ {
+ Set popups = autoClosePopups.keySet();
+ Iterator i = popups.iterator();
+ while (i.hasNext())
+ {
+ JPopupMenu popup = (JPopupMenu) i.next();
+ if (!(target == popup
+ || SwingUtilities.isDescendingFrom(target, popup)))
+ {
+ popup.setVisible(false);
+ i.remove();
+ }
+ }
+ }
+ }
+ }
+
/**
* An action that can play an audio file.
*
@@ -137,6 +239,11 @@ public abstract class BasicLookAndFeel extends LookAndFeel
static final long serialVersionUID = -6096995660290287879L;
+ /**
+ * Helps closing menu popups when user clicks outside of the menu area.
+ */
+ private transient PopupHelper popupHelper;
+
private ActionMap audioActionMap;
/**
@@ -1023,6 +1130,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"SplitPane.dividerSize", new Integer(7),
"SplitPane.highlight", new ColorUIResource(highLight),
"SplitPane.shadow", new ColorUIResource(shadow),
+ "SplitPaneDivider.border", BasicBorders.getSplitPaneDividerBorder(),
+ "SplitPaneDivider.draggingColor", new ColorUIResource(Color.DARK_GRAY),
"TabbedPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
"ctrl PAGE_DOWN","navigatePageDown",
"ctrl PAGE_UP", "navigatePageUp",
@@ -1520,4 +1629,36 @@ public abstract class BasicLookAndFeel extends LookAndFeel
}
}
+ /**
+ * Initializes the Look and Feel.
+ */
+ public void initialize()
+ {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ popupHelper = new PopupHelper();
+ toolkit.addAWTEventListener(popupHelper, AWTEvent.MOUSE_EVENT_MASK);
+ }
+
+ /**
+ * Uninitializes the Look and Feel.
+ */
+ public void uninitialize()
+ {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ toolkit.removeAWTEventListener(popupHelper);
+ popupHelper = null;
+ }
+
+ /**
+ * Registers a JPopupMenu for autoclosing when a mouseclick occurs outside
+ * of the JPopupMenu. This must be called when the popup gets opened. The
+ * popup is unregistered from autoclosing as soon as it either got closed
+ * by this helper, or when it has been garbage collected.
+ *
+ * @param popup the popup menu to autoclose
+ */
+ void registerForAutoClose(JPopupMenu popup)
+ {
+ popupHelper.registerForAutoClose(popup);
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
index 63f0ce2068b..9166c49ee83 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
@@ -610,8 +610,7 @@ public class BasicMenuItemUI extends MenuItemUI
Font f = m.getFont();
g.setFont(f);
FontMetrics fm = g.getFontMetrics(f);
- SwingUtilities.calculateInnerArea(m, br);
- SwingUtilities.calculateInsetArea(br, m.getInsets(), vr);
+ SwingUtilities.calculateInnerArea(m, vr);
paintBackground(g, m, background);
/*
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
index e15a17bab28..6ecd06b3988 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
@@ -37,28 +37,20 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import java.awt.AWTEvent;
import java.awt.Component;
-import java.awt.Container;
-import java.awt.Cursor;
import java.awt.Dimension;
-import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
-import javax.swing.JLayeredPane;
-import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.LookAndFeel;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
-import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
-import javax.swing.event.MouseInputListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.ComponentUI;
@@ -73,9 +65,6 @@ public class BasicPopupMenuUI extends PopupMenuUI
/* popupMenu for which this UI delegate is for*/
protected JPopupMenu popupMenu;
- /* MouseInputListener listens to mouse events. Package private for inner classes. */
- static transient MouseInputListener mouseInputListener;
-
/* PopupMenuListener listens to popup menu events fired by JPopupMenu*/
private transient PopupMenuListener popupMenuListener;
@@ -270,30 +259,9 @@ public class BasicPopupMenuUI extends PopupMenuUI
// remove listener that listens to component events fired
// by the top - level window that this popup belongs to.
Component invoker = popupMenu.getInvoker();
-
- RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities
- .getRoot(invoker);
+ Component rootContainer = SwingUtilities.getRoot(invoker);
if (rootContainer != null)
- {
- ((Container) rootContainer).removeComponentListener(topWindowListener);
-
- // If this popup menu is the last popup menu visible on the screen,
- // then
- // stop interrupting mouse events in the glass pane before hiding this
- // last popup menu.
- boolean topLevelMenu = (popupMenu.getInvoker() instanceof JMenu)
- && ((JMenu) popupMenu.getInvoker()).isTopLevelMenu();
-
- if (topLevelMenu || !(popupMenu.getInvoker() instanceof MenuElement))
- {
- // set glass pane not to interrupt mouse events and remove
- // mouseInputListener
- Container glassPane = (Container) rootContainer.getGlassPane();
- glassPane.setVisible(false);
- glassPane.removeMouseListener(mouseInputListener);
- mouseInputListener = null;
- }
- }
+ rootContainer.removeComponentListener(topWindowListener);
}
/**
@@ -307,20 +275,8 @@ public class BasicPopupMenuUI extends PopupMenuUI
// ComponentEvents fired by it. We need to cancel this popup menu
// if topWindow to which this popup belongs was resized or moved.
Component invoker = popupMenu.getInvoker();
- RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities
- .getRoot(invoker);
- ((Container) rootContainer).addComponentListener(topWindowListener);
-
- // Set the glass pane to interrupt all mouse events originating in root
- // container
- if (mouseInputListener == null)
- {
- Container glassPane = (Container) rootContainer.getGlassPane();
- glassPane.setVisible(true);
- mouseInputListener = new MouseInputHandler(rootContainer);
- glassPane.addMouseListener(mouseInputListener);
- glassPane.addMouseMotionListener(mouseInputListener);
- }
+ Component rootContainer = SwingUtilities.getRoot(invoker);
+ rootContainer.addComponentListener(topWindowListener);
// if this popup menu is a free floating popup menu,
// then by default its first element should be always selected when
@@ -399,275 +355,4 @@ public class BasicPopupMenuUI extends PopupMenuUI
}
}
- /**
- * MouseInputHandler listens to all mouse events originated in the root
- * container. This class is responsible for closing menu hierarchy when the
- * user presses mouse over any component that do not belong to the current
- * menu hierarchy. This is acomplished by interrupting all mouse event in
- * the glass pane and checking if other component was pressed while menu
- * was open, before redestributing events further to intended components
- */
- private class MouseInputHandler implements MouseInputListener
- {
- private JLayeredPane layeredPane;
- private Container glassPane;
- private Cursor nativeCursor;
- private transient Component mouseEventTarget;
- private transient Component pressedComponent;
- private transient Component lastComponentEntered;
- private transient Component tempComponent;
- private transient int pressCount;
-
- /**
- * Creates a new MouseInputHandler object.
- *
- * @param c the top most root container
- */
- public MouseInputHandler(RootPaneContainer c)
- {
- layeredPane = c.getLayeredPane();
- glassPane = (Container) c.getGlassPane();
- }
-
- /**
- * Handles mouse clicked event
- *
- * @param e Mouse event
- */
- public void mouseClicked(MouseEvent e)
- {
- handleEvent(e);
- }
-
- /**
- * Handles mouseDragged event
- *
- * @param e MouseEvent
- */
- public void mouseDragged(MouseEvent e)
- {
- handleEvent(e);
- }
-
- /**
- * Handles mouseEntered event
- *
- * @param e MouseEvent
- */
- public void mouseEntered(MouseEvent e)
- {
- handleEvent(e);
- }
-
- /**
- * Handles mouseExited event
- *
- * @param e MouseEvent
- */
- public void mouseExited(MouseEvent e)
- {
- handleEvent(e);
- }
-
- /**
- * Handles mouse moved event
- *
- * @param e MouseEvent
- */
- public void mouseMoved(MouseEvent e)
- {
- handleEvent(e);
- }
-
- /**
- * Handles mouse pressed event
- *
- * @param e MouseEvent
- */
- public void mousePressed(MouseEvent e)
- {
- handleEvent(e);
- }
-
- /**
- * Handles mouse released event
- *
- * @param e MouseEvent
- */
- public void mouseReleased(MouseEvent e)
- {
- handleEvent(e);
- }
-
- /*
- * This method determines component that was intended to received mouse
- * event, before it was interrupted within the glass pane. This method
- * also redispatches mouse entered and mouse exited events to the
- * appropriate components. This code is slightly modified code from
- * Container.LightweightDispatcher class, which is private inside
- * Container class and cannot be used here.
- */
- public void acquireComponentForMouseEvent(MouseEvent me)
- {
- int x = me.getX();
- int y = me.getY();
-
- // Find the candidate which should receive this event.
- Component parent = layeredPane;
- Component candidate = null;
- Point p = me.getPoint();
- while ((candidate == null) && (parent != null))
- {
- p = SwingUtilities.convertPoint(glassPane, p.x, p.y, parent);
- candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
-
- if (candidate == null)
- {
- p = SwingUtilities.convertPoint(parent, p.x, p.y,
- parent.getParent());
- parent = parent.getParent();
- }
- }
-
- // If the only candidate we found was the native container itself,
- // don't dispatch any event at all. We only care about the lightweight
- // children here.
- if (candidate == layeredPane)
- candidate = null;
-
- // If our candidate is new, inform the old target we're leaving.
- if ((lastComponentEntered != null) && lastComponentEntered.isShowing()
- && (lastComponentEntered != candidate))
- {
- // Old candidate could have been removed from
- // the layeredPane so we check first.
- if (SwingUtilities.isDescendingFrom(lastComponentEntered, layeredPane))
- {
- Point tp = SwingUtilities.convertPoint(layeredPane, x, y,
- lastComponentEntered);
- MouseEvent exited = new MouseEvent(lastComponentEntered,
- MouseEvent.MOUSE_EXITED,
- me.getWhen(),
- me.getModifiersEx(), tp.x,
- tp.y, me.getClickCount(),
- me.isPopupTrigger(),
- me.getButton());
-
- tempComponent = lastComponentEntered;
- lastComponentEntered = null;
- tempComponent.dispatchEvent(exited);
- }
-
- lastComponentEntered = null;
- }
-
- // If we have a candidate, maybe enter it.
- if (candidate != null)
- {
- mouseEventTarget = candidate;
-
- if (candidate.isLightweight() && candidate.isShowing()
- && (candidate != layeredPane)
- && (candidate != lastComponentEntered))
- {
- lastComponentEntered = mouseEventTarget;
-
- Point cp = SwingUtilities.convertPoint(layeredPane, x, y,
- lastComponentEntered);
- MouseEvent entered = new MouseEvent(lastComponentEntered,
- MouseEvent.MOUSE_ENTERED,
- me.getWhen(),
- me.getModifiersEx(), cp.x,
- cp.y, me.getClickCount(),
- me.isPopupTrigger(),
- me.getButton());
- lastComponentEntered.dispatchEvent(entered);
- }
- }
-
- if ((me.getID() == MouseEvent.MOUSE_RELEASED)
- || ((me.getID() == MouseEvent.MOUSE_PRESSED) && (pressCount > 0))
- || (me.getID() == MouseEvent.MOUSE_DRAGGED))
- {
- // If any of the following events occur while a button is held down,
- // they should be dispatched to the same component to which the
- // original MOUSE_PRESSED event was dispatched:
- // - MOUSE_RELEASED
- // - MOUSE_PRESSED: another button pressed while the first is held down
- // - MOUSE_DRAGGED
- if (SwingUtilities.isDescendingFrom(pressedComponent, layeredPane))
- mouseEventTarget = pressedComponent;
- else if (me.getID() == MouseEvent.MOUSE_CLICKED)
- {
- // Don't dispatch CLICKED events whose target is not the same as the
- // target for the original PRESSED event.
- if (candidate != pressedComponent)
- mouseEventTarget = null;
- else if (pressCount == 0)
- pressedComponent = null;
- }
- }
- }
-
- /*
- * This method handles mouse events interrupted by glassPane. It
- * redispatches the mouse events appropriately to the intended components.
- * The code in this method is also taken from
- * Container.LightweightDispatcher class. The code is slightly modified
- * to handle the case when mouse is released over non-menu component. In
- * this case this method closes current menu hierarchy before
- * redispatching the event further.
- */
- public void handleEvent(AWTEvent e)
- {
- if (e instanceof MouseEvent)
- {
- MouseEvent me = (MouseEvent) e;
-
- acquireComponentForMouseEvent(me);
-
- // Avoid dispatching ENTERED and EXITED events twice.
- if (mouseEventTarget != null && mouseEventTarget.isShowing()
- && (e.getID() != MouseEvent.MOUSE_ENTERED)
- && (e.getID() != MouseEvent.MOUSE_EXITED))
- {
- MouseEvent newEvt = SwingUtilities.convertMouseEvent(glassPane,
- me,
- mouseEventTarget);
-
- mouseEventTarget.dispatchEvent(newEvt);
-
- // If mouse was clicked over the component that is not part
- // of menu hierarchy,then must close the menu hierarchy */
- if (e.getID() == MouseEvent.MOUSE_RELEASED)
- {
- boolean partOfMenuHierarchy = false;
- MenuSelectionManager manager = MenuSelectionManager
- .defaultManager();
-
- partOfMenuHierarchy = manager.isComponentPartOfCurrentMenu(mouseEventTarget);
-
- if (! partOfMenuHierarchy)
- manager.clearSelectedPath();
- }
-
- switch (e.getID())
- {
- case MouseEvent.MOUSE_PRESSED:
- if (pressCount++ == 0)
- pressedComponent = mouseEventTarget;
- break;
- case MouseEvent.MOUSE_RELEASED:
- // Clear our memory of the original PRESSED event, only if
- // we're not expecting a CLICKED event after this. If
- // there is a CLICKED event after this, it will do clean up.
- if ((--pressCount == 0)
- && (mouseEventTarget != pressedComponent))
- pressedComponent = null;
- break;
- }
- }
- }
- }
- }
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java
index 8af5ff7f95c..f8f62e15651 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java
@@ -45,7 +45,6 @@ import javax.swing.JMenuItem;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.UIDefaults;
-import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java
index 2a698e8a162..28e3b67c1a5 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java
@@ -1,4 +1,4 @@
-/* BasicPanelUI.java --
+/* BasicRootPaneUI.java --
Copyright (C) 2002, 2004 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -43,7 +43,6 @@ import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import javax.swing.JRootPane;
-import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.RootPaneUI;
@@ -75,8 +74,7 @@ public class BasicRootPaneUI extends RootPaneUI
*/
protected void installDefaults(JRootPane rp)
{
- // Is this ok?
- rp.setBackground(UIManager.getColor("control"));
+ // TODO: What to do here, if anything? (might be a hook method)
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
index a2f5b82dbec..c8713c934dd 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
@@ -653,19 +653,17 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
{
- width += incrButton.getPreferredSize().getWidth();
- width += decrButton.getPreferredSize().getWidth();
-
- width += (scrollbar.getMaximum() - scrollbar.getMinimum());
- height = UIManager.getInt("ScrollBar.width");
+ width += incrButton.getPreferredSize().getWidth();
+ width += decrButton.getPreferredSize().getWidth();
+ width += 16;
+ height = UIManager.getInt("ScrollBar.width");
}
else
{
- height += incrButton.getPreferredSize().getHeight();
- height += decrButton.getPreferredSize().getHeight();
-
- height += (scrollbar.getMaximum() - scrollbar.getMinimum());
- width = UIManager.getInt("ScrollBar.width");
+ height += incrButton.getPreferredSize().getHeight();
+ height += decrButton.getPreferredSize().getHeight();
+ height += 16;
+ width = UIManager.getInt("ScrollBar.width");
}
Insets insets = scrollbar.getInsets();
@@ -721,18 +719,6 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
*/
protected void installComponents()
{
- if (incrButton != null)
- scrollbar.add(incrButton);
- if (decrButton != null)
- scrollbar.add(decrButton);
- }
-
- /**
- * This method installs the defaults for the scrollbar specified by the
- * Basic Look and Feel.
- */
- protected void installDefaults()
- {
int orientation = scrollbar.getOrientation();
switch (orientation)
{
@@ -746,6 +732,18 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
break;
}
+ if (incrButton != null)
+ scrollbar.add(incrButton);
+ if (decrButton != null)
+ scrollbar.add(decrButton);
+ }
+
+ /**
+ * This method installs the defaults for the scrollbar specified by the
+ * Basic Look and Feel.
+ */
+ protected void installDefaults()
+ {
LookAndFeel.installColors(scrollbar, "ScrollBar.background",
"ScrollBar.foreground");
LookAndFeel.installBorder(scrollbar, "ScrollBar.border");
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java
index 3b7399eafaa..6f7a41a1d96 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java
@@ -1,5 +1,5 @@
-/* SpinnerUI.java --
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+/* BasicSpinnerUI.java --
+ Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -41,6 +41,7 @@ package javax.swing.plaf.basic;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
+import java.awt.Font;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
@@ -59,22 +60,21 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.SpinnerUI;
/**
- * DOCUMENT ME!
+ * A UI delegate for the {@link JSpinner} component.
*
* @author Ka-Hing Cheung
*
- * @see javax.swing.JSpinner
* @since 1.4
*/
public class BasicSpinnerUI extends SpinnerUI
{
/**
- * Creates a new <code>ComponentUI</code> for the specified
+ * Creates a new <code>BasicSpinnerUI</code> for the specified
* <code>JComponent</code>
*
- * @param c DOCUMENT ME!
+ * @param c the component (ignored).
*
- * @return a ComponentUI
+ * @return A new instance of {@link BasicSpinnerUI}.
*/
public static ComponentUI createUI(JComponent c)
{
@@ -144,14 +144,15 @@ public class BasicSpinnerUI extends SpinnerUI
{
return new PropertyChangeListener()
{
- public void propertyChange(PropertyChangeEvent evt)
- {
- // FIXME: Add check for enabled property change. Need to
- // disable the buttons.
- if ("editor".equals(evt.getPropertyName()))
- BasicSpinnerUI.this.replaceEditor((JComponent) evt.getOldValue(),
- (JComponent) evt.getNewValue());
- }
+ public void propertyChange(PropertyChangeEvent event)
+ {
+ // FIXME: Add check for enabled property change. Need to
+ // disable the buttons.
+ if ("editor".equals(event.getPropertyName()))
+ BasicSpinnerUI.this.replaceEditor((JComponent) event.getOldValue(),
+ (JComponent) event.getNewValue());
+ // FIXME: Handle 'font' property change
+ }
};
}
@@ -169,6 +170,12 @@ public class BasicSpinnerUI extends SpinnerUI
LookAndFeel.installColorsAndFont(spinner, "Spinner.background",
"Spinner.foreground", "Spinner.font");
LookAndFeel.installBorder(spinner, "Spinner.border");
+ JComponent e = spinner.getEditor();
+ if (e instanceof JSpinner.DefaultEditor)
+ {
+ JSpinner.DefaultEditor de = (JSpinner.DefaultEditor) e;
+ de.getTextField().setBorder(null);
+ }
spinner.setLayout(createLayout());
spinner.setOpaque(true);
}
@@ -352,7 +359,8 @@ public class BasicSpinnerUI extends SpinnerUI
private PropertyChangeListener listener = createPropertyChangeListener();
/**
- * DOCUMENT ME!
+ * A layout manager for the {@link JSpinner} component. The spinner has
+ * three subcomponents: an editor, a 'next' button and a 'previous' button.
*/
private class DefaultLayoutManager implements LayoutManager
{
@@ -365,58 +373,52 @@ public class BasicSpinnerUI extends SpinnerUI
{
synchronized (parent.getTreeLock())
{
- Insets i = parent.getInsets();
- boolean l2r = parent.getComponentOrientation().isLeftToRight();
- /*
- -------------- --------------
- | | n | | n | |
- | e | - | or | - | e |
- | | p | | p | |
- -------------- --------------
- */
- Dimension e = minSize(editor);
- Dimension n = minSize(next);
- Dimension p = minSize(previous);
- Dimension s = spinner.getPreferredSize();
-
- int x = l2r ? i.left : i.right;
- int y = i.top;
- int w = Math.max(p.width, n.width);
- int h = Math.max(p.height, n.height);
- h = Math.max(h, e.height / 2);
- int e_width = s.width - w;
-
- if (l2r)
- {
- setBounds(editor, x, y + (s.height - e.height) / 2, e_width,
- e.height);
- x += e_width;
-
- setBounds(next, x, y, w, h);
- y += h;
-
- setBounds(previous, x, y, w, h);
- }
- else
- {
- setBounds(next, x, y + (s.height - e.height) / 2, w, h);
- y += h;
-
- setBounds(previous, x, y, w, h);
- x += w;
- y -= h;
-
- setBounds(editor, x, y, e_width, e.height);
- }
+ Insets i = parent.getInsets();
+ boolean l2r = parent.getComponentOrientation().isLeftToRight();
+ /*
+ -------------- --------------
+ | | n | | n | |
+ | e | - | or | - | e |
+ | | p | | p | |
+ -------------- --------------
+ */
+ Dimension e = prefSize(editor);
+ Dimension n = prefSize(next);
+ Dimension p = prefSize(previous);
+ Dimension s = spinner.getPreferredSize();
+
+ int x = l2r ? i.left : i.right;
+ int y = i.top;
+ int w = Math.max(p.width, n.width);
+ int h = e.height / 2;
+ int e_width = s.width - w - i.left - i.right;
+
+ if (l2r)
+ {
+ setBounds(editor, x, y, e_width, 2 * h);
+ x += e_width;
+ setBounds(next, x, y, w, h);
+ y += h;
+ setBounds(previous, x, y, w, h);
+ }
+ else
+ {
+ setBounds(next, x, y + (s.height - e.height) / 2, w, h);
+ y += h;
+ setBounds(previous, x, y + (s.height - e.height) / 2, w, h);
+ x += w;
+ y -= h;
+ setBounds(editor, x, y, e_width, e.height);
+ }
}
}
/**
- * DOCUMENT ME!
+ * Calculates the minimum layout size.
*
- * @param parent DOCUMENT ME!
+ * @param parent the parent.
*
- * @return DOCUMENT ME!
+ * @return The minimum layout size.
*/
public Dimension minimumLayoutSize(Container parent)
{
@@ -424,36 +426,32 @@ public class BasicSpinnerUI extends SpinnerUI
if (editor != null)
{
- Dimension tmp = editor.getMinimumSize();
- d.width += tmp.width;
- d.height = tmp.height;
+ Dimension tmp = editor.getMinimumSize();
+ d.width += tmp.width;
+ d.height = tmp.height;
}
int nextWidth = 0;
int previousWidth = 0;
- int otherHeight = 0;
if (next != null)
{
- Dimension tmp = next.getMinimumSize();
- nextWidth = tmp.width;
- otherHeight += tmp.height;
+ Dimension tmp = next.getMinimumSize();
+ nextWidth = tmp.width;
}
if (previous != null)
{
- Dimension tmp = previous.getMinimumSize();
- previousWidth = tmp.width;
- otherHeight += tmp.height;
+ Dimension tmp = previous.getMinimumSize();
+ previousWidth = tmp.width;
}
- d.height = Math.max(d.height, otherHeight);
d.width += Math.max(nextWidth, previousWidth);
return d;
}
/**
- * DOCUMENT ME!
+ * Returns the preferred layout size of the container.
*
* @param parent DOCUMENT ME!
*
@@ -465,31 +463,29 @@ public class BasicSpinnerUI extends SpinnerUI
if (editor != null)
{
- Dimension tmp = editor.getPreferredSize();
- d.width += Math.max(tmp.width, 40);
- d.height = tmp.height;
+ Dimension tmp = editor.getPreferredSize();
+ d.width += Math.max(tmp.width, 40);
+ d.height = tmp.height;
}
int nextWidth = 0;
int previousWidth = 0;
- int otherHeight = 0;
if (next != null)
{
- Dimension tmp = next.getPreferredSize();
- nextWidth = tmp.width;
- otherHeight += tmp.height;
+ Dimension tmp = next.getPreferredSize();
+ nextWidth = tmp.width;
}
if (previous != null)
{
- Dimension tmp = previous.getPreferredSize();
- previousWidth = tmp.width;
- otherHeight += tmp.height;
+ Dimension tmp = previous.getPreferredSize();
+ previousWidth = tmp.width;
}
- d.height = Math.max(d.height, otherHeight);
d.width += Math.max(nextWidth, previousWidth);
-
+ Insets insets = parent.getInsets();
+ d.width = d.width + insets.left + insets.right;
+ d.height = d.height + insets.top + insets.bottom;
return d;
}
@@ -501,11 +497,11 @@ public class BasicSpinnerUI extends SpinnerUI
public void removeLayoutComponent(Component child)
{
if (child == editor)
- editor = null;
+ editor = null;
else if (child == next)
- next = null;
+ next = null;
else if (previous == child)
- previous = null;
+ previous = null;
}
/**
@@ -517,11 +513,11 @@ public class BasicSpinnerUI extends SpinnerUI
public void addLayoutComponent(String name, Component child)
{
if ("Editor".equals(name))
- editor = child;
+ editor = child;
else if ("Next".equals(name))
- next = child;
+ next = child;
else if ("Previous".equals(name))
- previous = child;
+ previous = child;
}
/**
@@ -531,36 +527,36 @@ public class BasicSpinnerUI extends SpinnerUI
*
* @return DOCUMENT ME!
*/
- private Dimension minSize(Component c)
+ private Dimension prefSize(Component c)
{
if (c == null)
- return new Dimension();
+ return new Dimension();
else
- return c.getMinimumSize();
+ return c.getPreferredSize();
}
/**
- * DOCUMENT ME!
+ * Sets the bounds for the specified component.
*
- * @param c DOCUMENT ME!
- * @param x DOCUMENT ME!
- * @param y DOCUMENT ME!
- * @param w DOCUMENT ME!
- * @param h DOCUMENT ME!
+ * @param c the component.
+ * @param x the x-coordinate for the top-left of the component bounds.
+ * @param y the y-coordinate for the top-left of the component bounds.
+ * @param w the width of the bounds.
+ * @param h the height of the bounds.
*/
private void setBounds(Component c, int x, int y, int w, int h)
{
if (c != null)
- c.setBounds(x, y, w, h);
+ c.setBounds(x, y, w, h);
}
- /** DOCUMENT ME! */
+ /** The editor component. */
private Component editor;
- /** DOCUMENT ME! */
+ /** The next button. */
private Component next;
- /** DOCUMENT ME! */
+ /** The previous button. */
private Component previous;
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java
index ff17ff084c2..06d32984efb 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java
@@ -38,7 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
@@ -161,31 +160,6 @@ public class BasicSplitPaneDivider extends Container
*/
transient int currentDividerLocation = 1;
- /** DOCUMENT ME! */
- private transient Border tmpBorder = new Border()
- {
- public Insets getBorderInsets(Component c)
- {
- return new Insets(2, 2, 2, 2);
- }
-
- public boolean isBorderOpaque()
- {
- return false;
- }
-
- public void paintBorder(Component c, Graphics g, int x, int y,
- int width, int height)
- {
- Color saved = g.getColor();
- g.setColor(Color.BLACK);
-
- g.drawRect(x + 2, y + 2, width - 4, height - 4);
-
- g.setColor(saved);
- }
- };
-
/**
* Constructs a new divider.
*
@@ -196,7 +170,6 @@ public class BasicSplitPaneDivider extends Container
setLayout(new DividerLayout());
setBasicSplitPaneUI(ui);
setDividerSize(splitPane.getDividerSize());
- setBorder(tmpBorder);
}
/**
@@ -212,8 +185,6 @@ public class BasicSplitPaneDivider extends Container
if (splitPane != null)
{
splitPane.removePropertyChangeListener(this);
- splitPane.removeMouseListener(mouseHandler);
- splitPane.removeMouseMotionListener(mouseHandler);
removeMouseListener(mouseHandler);
removeMouseMotionListener(mouseHandler);
splitPane = null;
@@ -227,8 +198,6 @@ public class BasicSplitPaneDivider extends Container
if (splitPane != null)
{
splitPane.addPropertyChangeListener(this);
- splitPane.addMouseListener(mouseHandler);
- splitPane.addMouseMotionListener(mouseHandler);
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider();
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java
index cf31e8b5df1..8a7c9d2a290 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java
@@ -62,6 +62,7 @@ import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.SplitPaneUI;
+import javax.swing.plaf.UIResource;
/**
* This is the Basic Look and Feel implementation of the SplitPaneUI class.
@@ -253,20 +254,21 @@ public class BasicSplitPaneUI extends SplitPaneUI
JSplitPane split = (JSplitPane) container;
distributeExtraSpace();
Insets insets = split.getInsets();
- int width = getInitialLocation(insets);
Dimension dims = split.getSize();
- for (int i = 0; i < components.length; i += 2)
- {
- if (components[i] == null)
- continue;
- setComponentToSize(components[i], sizes[i], width, insets, dims);
- width += sizes[i];
- }
- if (components[1] != null)
- {
- setComponentToSize(components[1], sizes[1], width, insets, dims);
- width += sizes[1];
- }
+ int loc = getInitialLocation(insets);
+ int available = getAvailableSize(dims, insets);
+ sizes[0] = getDividerLocation(split) - loc;
+ sizes[1] = available - sizes[0] - sizes[2];
+ // The size of the divider won't change.
+
+ // Layout component#1.
+ setComponentToSize(components[0], sizes[0], loc, insets, dims);
+ // Layout divider.
+ loc += sizes[0];
+ setComponentToSize(components[2], sizes[2], loc, insets, dims);
+ // Layout component#2.
+ loc += sizes[2];
+ setComponentToSize(components[1], sizes[1], loc, insets, dims);
}
}
@@ -388,6 +390,8 @@ public class BasicSplitPaneUI extends SplitPaneUI
{
for (int i = 0; i < components.length; i++)
resetSizeAt(i);
+ setDividerLocation(splitPane,
+ getInitialLocation(splitPane.getInsets()) + sizes[0]);
}
/**
@@ -451,21 +455,7 @@ public class BasicSplitPaneUI extends SplitPaneUI
*/
void distributeExtraSpace()
{
- int availSize = getAvailableSize(splitPane.getSize(),
- splitPane.getInsets());
- int[] newSizes = new int[3];
- double weight = splitPane.getResizeWeight();
-
- int oldLen = sizes[0] + sizes[1];
-
- // dividers don't change size.
- availSize -= sizes[2] + oldLen;
-
- int rightAlloc = (int) (availSize * (1 - weight));
- int leftAlloc = availSize - rightAlloc;
-
- sizes[0] += leftAlloc;
- sizes[1] += rightAlloc;
+ // FIXME: This needs to be reimplemented correctly.
}
/**
@@ -835,8 +825,6 @@ public class BasicSplitPaneUI extends SplitPaneUI
if (prop <= 1 && prop >= 0)
splitPane.setDividerLocation(prop);
}
- layoutManager.layoutContainer(splitPane);
- splitPane.repaint();
// Don't have to deal with continuous_layout - only
// necessary in dragging modes (and it's checked
// every time you drag there)
@@ -933,6 +921,8 @@ public class BasicSplitPaneUI extends SplitPaneUI
/** The JSplitPane that this UI draws. */
protected JSplitPane splitPane;
+ private int dividerLocation;
+
/**
* Creates a new BasicSplitPaneUI object.
*/
@@ -992,6 +982,7 @@ public class BasicSplitPaneUI extends SplitPaneUI
"SplitPane.foreground");
LookAndFeel.installBorder(splitPane, "SplitPane.border");
divider = createDefaultDivider();
+ divider.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
resetLayoutManager();
nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider();
splitPane.add(divider, JSplitPane.DIVIDER);
@@ -1012,8 +1003,10 @@ public class BasicSplitPaneUI extends SplitPaneUI
divider = null;
nonContinuousLayoutDivider = null;
- splitPane.setBackground(null);
- splitPane.setBorder(null);
+ if (splitPane.getBackground() instanceof UIResource)
+ splitPane.setBackground(null);
+ if (splitPane.getBorder() instanceof UIResource)
+ splitPane.setBorder(null);
}
/**
@@ -1219,7 +1212,8 @@ public class BasicSplitPaneUI extends SplitPaneUI
if (nonContinuousLayoutDivider == null)
{
nonContinuousLayoutDivider = new Canvas();
- nonContinuousLayoutDivider.setBackground(Color.DARK_GRAY);
+ Color c = UIManager.getColor("SplitPaneDivider.draggingColor");
+ nonContinuousLayoutDivider.setBackground(c);
}
return nonContinuousLayoutDivider;
}
@@ -1298,44 +1292,7 @@ public class BasicSplitPaneUI extends SplitPaneUI
*/
public void setDividerLocation(JSplitPane jc, int location)
{
- location = validLocation(location);
- Container p = jc.getParent();
- Component right = jc.getRightComponent();
- Dimension rightPrefSize = right == null ? new Dimension(0, 0)
- : right.getPreferredSize();
- Dimension size = jc.getSize();
- // check if the size has been set for the splitpane
- if (size.width == 0 && size.height == 0)
- size = jc.getPreferredSize();
-
- if (getOrientation() == 0 && location > size.height)
- {
- location = size.height;
- while (p != null)
- {
- p.setSize(p.getWidth(), p.getHeight() + rightPrefSize.height);
- p = p.getParent();
- }
- }
- else if (location > size.width)
- {
- location = size.width;
- while (p != null)
- {
- p.setSize(p.getWidth() + rightPrefSize.width, p.getHeight());
- p = p.getParent();
- }
- }
-
- setLastDragLocation(getDividerLocation(splitPane));
- splitPane.setLastDividerLocation(getDividerLocation(splitPane));
- int[] tmpSizes = layoutManager.getSizes();
- tmpSizes[0] = location
- - layoutManager.getInitialLocation(splitPane.getInsets());
- tmpSizes[1] = layoutManager.getAvailableSize(splitPane.getSize(),
- splitPane.getInsets())
- - tmpSizes[0];
- layoutManager.setSizes(tmpSizes);
+ dividerLocation = location;
splitPane.revalidate();
splitPane.repaint();
}
@@ -1349,8 +1306,7 @@ public class BasicSplitPaneUI extends SplitPaneUI
*/
public int getDividerLocation(JSplitPane jc)
{
- return layoutManager.sizes[0]
- + layoutManager.getInitialLocation(splitPane.getInsets());
+ return dividerLocation;
}
/**
@@ -1365,7 +1321,7 @@ public class BasicSplitPaneUI extends SplitPaneUI
{
int value = layoutManager.getInitialLocation(jc.getInsets());
if (layoutManager.components[0] != null)
- value -= layoutManager.minimumSizeOfComponent(0);
+ value += layoutManager.minimumSizeOfComponent(0);
return value;
}
@@ -1501,8 +1457,6 @@ public class BasicSplitPaneUI extends SplitPaneUI
nonContinuousLayoutDivider.setVisible(true);
nonContinuousLayoutDivider.setBounds(divider.getBounds());
}
- splitPane.revalidate();
- splitPane.repaint();
}
/**
@@ -1544,11 +1498,9 @@ public class BasicSplitPaneUI extends SplitPaneUI
nonContinuousLayoutDivider.setVisible(false);
draggingHW = false;
location = validLocation(location);
- dragDividerTo(location);
splitPane.setDividerLocation(location);
splitPane.setLastDividerLocation(beginDragDividerLocation);
beginDragDividerLocation = -1;
- splitPane.repaint();
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
index a8f52cef617..5b1e1ff0f60 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
@@ -451,6 +451,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
}
}
runCount = runs;
+ if (runCount > tabRuns.length)
+ expandTabRunsArray();
tabRuns[0] = 0;
normalizeTabRuns(tabPlacement, tabCount, start, max);
@@ -1025,6 +1027,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
}
}
runCount = runs;
+ if (runCount > tabRuns.length)
+ expandTabRunsArray();
padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
}
@@ -1733,9 +1737,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int tabCount = tabPane.getTabCount();
int currRun = 1;
- if (tabCount > runCount)
- runCount = tabCount;
-
if (tabCount < 1)
return;
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java
index 9c8a5ef9598..1e8e39f38c2 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java
@@ -39,14 +39,18 @@ exception statement from your version. */
package javax.swing.plaf.basic;
import java.awt.Component;
+import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.LookAndFeel;
+import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.MouseInputListener;
@@ -57,62 +61,346 @@ import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
+/**
+ * Basic pluggable look and feel interface for JTableHeader.
+ */
public class BasicTableHeaderUI extends TableHeaderUI
{
-
+ /**
+ * The width of the space (in both direction) around the column boundary,
+ * where mouse cursor changes shape into "resize"
+ */
+ static int COLUMN_BOUNDARY_TOLERANCE = 3;
+
public static ComponentUI createUI(JComponent h)
{
return new BasicTableHeaderUI();
}
-
+
+ /**
+ * The table header that is using this interface.
+ */
protected JTableHeader header;
+
+ /**
+ * The mouse input listener, responsible for mouse manipulations with
+ * the table header.
+ */
protected MouseInputListener mouseInputListener;
+
+ /**
+ * Paint the header cell.
+ */
protected CellRendererPane rendererPane;
+
+ /**
+ * The header cell border.
+ */
protected Border cellBorder;
-
- public class MouseInputHandler implements MouseInputListener
+
+ /**
+ * If not null, one of the columns is currently being dragged.
+ */
+ Rectangle draggingHeaderRect;
+
+ /**
+ * Handles column movement and rearrangement by mouse. The same instance works
+ * both as mouse listener and the mouse motion listner.
+ */
+ public class MouseInputHandler
+ implements MouseInputListener
{
+ /**
+ * If true, the cursor is being already shown in the alternative "resize"
+ * shape.
+ */
+ boolean showingResizeCursor;
+
+ /**
+ * The position, from where the cursor is dragged during resizing. Double
+ * purpose field (absolute value during resizing and relative offset during
+ * column dragging).
+ */
+ int draggingFrom = - 1;
+
+ /**
+ * The number of the column being dragged.
+ */
+ int draggingColumnNumber;
+
+ /**
+ * The previous preferred width of the column.
+ */
+ int prevPrefWidth = - 1;
+
+ /**
+ * The timer to coalesce column resizing events.
+ */
+ Timer timer;
+
+ /**
+ * Returns without action, part of the MouseInputListener interface.
+ */
public void mouseClicked(MouseEvent e)
{
- // TODO: Implement this properly.
+ // Nothing to do.
}
+ /**
+ * If being in the resizing mode, handle resizing.
+ */
public void mouseDragged(MouseEvent e)
{
- // TODO: Implement this properly.
+ TableColumn resizeIt = header.getResizingColumn();
+ if (resizeIt != null && header.getResizingAllowed())
+ {
+ // The timer is intialised on demand.
+ if (timer == null)
+ {
+ // The purpose of timer is to coalesce events. If the queue
+ // is free, the repaint event is fired immediately.
+ timer = new Timer(1, new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ header.getTable().doLayout();
+ }
+ });
+ timer.setRepeats(false);
+ timer.setCoalesce(true);
+ }
+ resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom);
+ timer.restart();
+ }
+ else if (draggingHeaderRect != null && header.getReorderingAllowed())
+ {
+ draggingHeaderRect.x = e.getX() + draggingFrom;
+ header.repaint();
+ }
}
+ /**
+ * Returns without action, part of the MouseInputListener interface.
+ */
public void mouseEntered(MouseEvent e)
{
- // TODO: Implement this properly.
+ // Nothing to do.
}
+ /**
+ * Reset drag information of the column resizing.
+ */
public void mouseExited(MouseEvent e)
{
- // TODO: Implement this properly.
+ if (header.getResizingColumn() != null && header.getResizingAllowed())
+ endResizing();
+ if (header.getDraggedColumn() != null && header.getReorderingAllowed())
+ endDragging(null);
}
+ /**
+ * Change the mouse cursor if the mouse if above the column boundary.
+ */
public void mouseMoved(MouseEvent e)
{
- // TODO: Implement this properly.
+ // When dragging, the functionality is handled by the mouseDragged.
+ if (e.getButton() == 0 && header.getResizingAllowed())
+ {
+ TableColumnModel model = header.getColumnModel();
+ int n = model.getColumnCount();
+ if (n < 2)
+ // It must be at least two columns to have at least one boundary.
+ // Otherwise, nothing to do.
+ return;
+
+ boolean onBoundary = false;
+
+ int x = e.getX();
+ int a = x - COLUMN_BOUNDARY_TOLERANCE;
+ int b = x + COLUMN_BOUNDARY_TOLERANCE;
+
+ int p = 0;
+
+ Scan: for (int i = 0; i < n - 1; i++)
+ {
+ p += model.getColumn(i).getWidth();
+
+ if (p >= a && p <= b)
+ {
+ TableColumn column = model.getColumn(i);
+ onBoundary = true;
+
+ draggingFrom = x;
+ prevPrefWidth = column.getWidth();
+ header.setResizingColumn(column);
+ break Scan;
+ }
+ }
+
+ if (onBoundary != showingResizeCursor)
+ {
+ // Change the cursor shape, if needed.
+ if (onBoundary)
+ {
+
+ if (p < x)
+ header.setCursor(Cursor.getPredefinedCursor
+ (Cursor.W_RESIZE_CURSOR));
+ else
+ header.setCursor(Cursor.getPredefinedCursor
+ (Cursor.E_RESIZE_CURSOR));
+ }
+ else
+ {
+ header.setCursor(Cursor.getDefaultCursor());
+ header.setResizingColumn(null);
+ }
+
+ showingResizeCursor = onBoundary;
+ }
+ }
}
+ /**
+ * Starts the dragging/resizing procedure.
+ */
public void mousePressed(MouseEvent e)
{
- // TODO: Implement this properly.
+ if (header.getResizingAllowed())
+ {
+ TableColumn resizingColumn = header.getResizingColumn();
+ if (resizingColumn != null)
+ {
+ resizingColumn.setPreferredWidth(resizingColumn.getWidth());
+ return;
+ }
+ }
+
+ if (header.getReorderingAllowed())
+ {
+ TableColumnModel model = header.getColumnModel();
+ int n = model.getColumnCount();
+ if (n < 2)
+ // It must be at least two columns to change the column location.
+ return;
+
+ boolean onBoundary = false;
+
+ int x = e.getX();
+ int p = 0;
+ int col = - 1;
+
+ Scan: for (int i = 0; i < n; i++)
+ {
+ p += model.getColumn(i).getWidth();
+ if (p > x)
+ {
+ col = i;
+ break Scan;
+ }
+ }
+ if (col < 0)
+ return;
+
+ TableColumn dragIt = model.getColumn(col);
+ header.setDraggedColumn(dragIt);
+
+ draggingFrom = (p - dragIt.getWidth()) - x;
+ draggingHeaderRect = new Rectangle(header.getHeaderRect(col));
+ draggingColumnNumber = col;
+ }
}
+ /**
+ * Set all column preferred width to the current width to prevend abrupt
+ * width changes during the next resize.
+ */
public void mouseReleased(MouseEvent e)
{
- // TODO: Implement this properly.
+ if (header.getResizingColumn() != null && header.getResizingAllowed())
+ endResizing();
+ if (header.getDraggedColumn() != null && header.getReorderingAllowed())
+ endDragging(e);
+ }
+
+ /**
+ * Stop resizing session.
+ */
+ void endResizing()
+ {
+ TableColumnModel model = header.getColumnModel();
+ int n = model.getColumnCount();
+ if (n > 2)
+ {
+ TableColumn c;
+ for (int i = 0; i < n; i++)
+ {
+ c = model.getColumn(i);
+ c.setPreferredWidth(c.getWidth());
+ }
+ }
+ header.setResizingColumn(null);
+ showingResizeCursor = false;
+ if (timer != null)
+ timer.stop();
+ header.setCursor(Cursor.getDefaultCursor());
}
- }
+ /**
+ * Stop the dragging session.
+ *
+ * @param e the "mouse release" mouse event, needed to determing the final
+ * location for the dragged column.
+ */
+ void endDragging(MouseEvent e)
+ {
+ header.setDraggedColumn(null);
+
+ // Return if the mouse have left the header area while pressed.
+ if (e == null)
+ {
+ header.repaint(draggingHeaderRect);
+ draggingHeaderRect = null;
+ return;
+ }
+ else
+ draggingHeaderRect = null;
+
+ TableColumnModel model = header.getColumnModel();
+
+ // Find where have we dragged the column.
+ int x = e.getX();
+ int p = 0;
+ int col = - 1;
+ int n = model.getColumnCount();
+
+ Scan: for (int i = 0; i < n; i++)
+ {
+ p += model.getColumn(i).getWidth();
+ if (p > x)
+ {
+ col = i;
+ break Scan;
+ }
+ }
+ if (col >= 0)
+ header.getTable().moveColumn(draggingColumnNumber, col);
+ }
+ }
+
+ /**
+ * Create and return the mouse input listener.
+ *
+ * @return the mouse listener ({@link MouseInputHandler}, if not overridden.
+ */
protected MouseInputListener createMouseInputListener()
{
return new MouseInputHandler();
}
-
+
+ /**
+ * Construct a new BasicTableHeaderUI, create mouse listeners.
+ */
public BasicTableHeaderUI()
{
mouseInputListener = createMouseInputListener();
@@ -131,9 +419,15 @@ public class BasicTableHeaderUI extends TableHeaderUI
// TODO: Implement this properly.
}
+ /**
+ * Add the mouse listener and the mouse motion listener to the table
+ * header. The listeners support table column resizing and rearrangement
+ * by mouse.
+ */
protected void installListeners()
{
header.addMouseListener(mouseInputListener);
+ header.addMouseMotionListener(mouseInputListener);
}
public void installUI(JComponent c)
@@ -156,10 +450,14 @@ public class BasicTableHeaderUI extends TableHeaderUI
{
// TODO: Implement this properly.
}
-
+
+ /**
+ * Remove the previously installed listeners.
+ */
protected void uninstallListeners()
{
header.removeMouseListener(mouseInputListener);
+ header.removeMouseMotionListener(mouseInputListener);
}
public void uninstallUI(JComponent c)
@@ -168,7 +466,10 @@ public class BasicTableHeaderUI extends TableHeaderUI
uninstallKeyboardActions();
uninstallDefaults();
}
-
+
+ /**
+ * Repaint the table header.
+ */
public void paint(Graphics gfx, JComponent c)
{
TableColumnModel cmod = header.getColumnModel();
@@ -206,10 +507,26 @@ public class BasicTableHeaderUI extends TableHeaderUI
bounds.width, bounds.height);
}
}
-
+
+ // This displays a running rectangle that is much simplier than the total
+ // animation, as it is seen in Sun's application.
+ // TODO animate the collumn dragging like in Sun's jre.
+ if (draggingHeaderRect!=null)
+ {
+ gfx.setColor(header.getForeground());
+ gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y+2,
+ draggingHeaderRect.width-1, draggingHeaderRect.height-6);
+ }
}
- public Dimension getPreferredSize(JComponent c)
+ /**
+ * Get the preferred header size.
+ *
+ * @param ignored unused
+ *
+ * @return the preferred size of the associated header.
+ */
+ public Dimension getPreferredSize(JComponent ignored)
{
TableColumnModel cmod = header.getColumnModel();
TableCellRenderer defaultRend = header.getDefaultRenderer();
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
index 18b69120d11..8360a9ec771 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
@@ -58,11 +58,11 @@ import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.CellRendererPane;
+import javax.swing.DefaultCellEditor;
import javax.swing.DefaultListSelectionModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JTable;
-import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.LookAndFeel;
@@ -74,8 +74,8 @@ import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TableUI;
+import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
-import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
@@ -193,10 +193,31 @@ public class BasicTableUI extends TableUI
colModel.setSelectionInterval(lo_col, hi_col);
}
}
-
- public void mouseClicked(MouseEvent e)
+
+ /**
+ * For the double click, start the cell editor.
+ */
+ public void mouseClicked(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ Point p = e.getPoint();
+ int row = table.rowAtPoint(p);
+ int col = table.columnAtPoint(p);
+ if (table.isCellEditable(row, col))
+ {
+ // If the cell editor is the default editor, we request the
+ // number of the required clicks from it. Otherwise,
+ // require two clicks (double click).
+ TableCellEditor editor = table.getCellEditor(row, col);
+ if (editor instanceof DefaultCellEditor)
+ {
+ DefaultCellEditor ce = (DefaultCellEditor) editor;
+ if (e.getClickCount() < ce.getClickCountToStart())
+ return;
+ }
+ else if (e.getClickCount() < 2)
+ return;
+ table.editCellAt(row, col);
+ }
}
public void mouseDragged(MouseEvent e)
@@ -354,7 +375,8 @@ public class BasicTableUI extends TableUI
maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth();
if (maxTotalColumnWidth == 0 || table.getRowCount() == 0)
return null;
- return new Dimension(maxTotalColumnWidth, table.getRowCount()*table.getRowHeight());
+ return new Dimension(maxTotalColumnWidth, table.getRowCount()*
+ (table.getRowHeight()+table.getRowMargin()));
}
/**
@@ -380,7 +402,7 @@ public class BasicTableUI extends TableUI
public Dimension getPreferredSize(JComponent comp)
{
int width = table.getColumnModel().getTotalColumnWidth();
- int height = table.getRowCount() * table.getRowHeight();
+ int height = table.getRowCount() * (table.getRowHeight()+table.getRowMargin());
return new Dimension(width, height);
}
@@ -854,6 +876,10 @@ public class BasicTableUI extends TableUI
rowModel.setAnchorSelectionIndex(rowLead);
colModel.setAnchorSelectionIndex(colLead);
}
+ else if (command.equals("stopEditing"))
+ {
+ table.editingStopped(new ChangeEvent(command));
+ }
else
{
// If we're here that means we bound this TableAction class
@@ -1185,30 +1211,17 @@ public class BasicTableUI extends TableUI
* system beginning at <code>(0,0)</code> in the upper left corner of the
* table
* @param rend A cell renderer to paint with
- * @param data The data to provide to the cell renderer
- * @param rowLead The lead selection for the rows of the table.
- * @param colLead The lead selection for the columns of the table.
*/
void paintCell(Graphics g, int row, int col, Rectangle bounds,
- TableCellRenderer rend, TableModel data,
- int rowLead, int colLead)
+ TableCellRenderer rend)
{
Component comp = table.prepareRenderer(rend, row, col);
rendererPane.paintComponent(g, comp, table, bounds);
-
- // FIXME: this is manual painting of the Caret, why doesn't the
- // JTextField take care of this itself?
- if (comp instanceof JTextField)
- {
- Rectangle oldClip = g.getClipBounds();
- g.translate(bounds.x, bounds.y);
- g.clipRect(0, 0, bounds.width, bounds.height);
- ((JTextField)comp).getCaret().paint(g);
- g.translate(-bounds.x, -bounds.y);
- g.setClip(oldClip);
- }
}
+ /**
+ * Paint the associated table.
+ */
public void paint(Graphics gfx, JComponent ignored)
{
int ncols = table.getColumnCount();
@@ -1217,59 +1230,72 @@ public class BasicTableUI extends TableUI
return;
Rectangle clip = gfx.getClipBounds();
- TableColumnModel cols = table.getColumnModel();
-
- int height = table.getRowHeight();
- int x0 = 0, y0 = 0;
- int x = x0;
- int y = y0;
-
- Dimension gap = table.getIntercellSpacing();
- int ymax = clip.y + clip.height;
- int xmax = clip.x + clip.width;
+ // Determine the range of cells that are within the clip bounds.
+ Point p1 = new Point(clip.x, clip.y);
+ int c0 = table.columnAtPoint(p1);
+ if (c0 == -1)
+ c0 = 0;
+ int r0 = table.rowAtPoint(p1);
+ if (r0 == -1)
+ r0 = 0;
+ Point p2 = new Point(clip.x + clip.width, clip.y + clip.height);
+ int cn = table.columnAtPoint(p2);
+ if (cn == -1)
+ cn = table.getColumnCount() - 1;
+ int rn = table.rowAtPoint(p2);
+ if (rn == -1)
+ rn = table.getRowCount() - 1;
+
+ TableColumnModel cmodel = table.getColumnModel();
+ int [] widths = new int[cn+1];
+ for (int i = c0; i <=cn ; i++)
+ {
+ widths[i] = cmodel.getColumn(i).getWidth();
+ }
+
+ Rectangle bounds = table.getCellRect(r0, c0, false);
+ bounds.height = table.getRowHeight()+table.getRowMargin();
+
+ // The left boundary of the area being repainted.
+ int left = bounds.x;
+
+ // The top boundary of the area being repainted.
+ int top = bounds.y;
+
+ // The bottom boundary of the area being repainted.
+ int bottom;
+
+ // The cell height.
+ int height = bounds.height;
+
// paint the cell contents
- for (int c = 0; c < ncols && x < xmax; ++c)
+ Color grid = table.getGridColor();
+ for (int r = r0; r <= rn; ++r)
{
- y = y0;
- TableColumn col = cols.getColumn(c);
- int width = col.getWidth();
- int halfGapWidth = gap.width / 2;
- int halfGapHeight = gap.height / 2;
- for (int r = 0; r < nrows && y < ymax; ++r)
+ for (int c = c0; c <= cn; ++c)
{
- Rectangle bounds = new Rectangle(x + halfGapWidth,
- y + halfGapHeight + 1,
- width - gap.width + 1,
- height - gap.height);
- if (bounds.intersects(clip))
- {
- paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c),
- table.getModel(),
- table.getSelectionModel().getLeadSelectionIndex(),
- table.getColumnModel().getSelectionModel().getLeadSelectionIndex());
- }
- y += height;
+ bounds.width = widths[c];
+ paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c));
+ bounds.x += widths[c];
}
- x += width;
+ bounds.y += height;
+ bounds.x = left;
}
-
- // tighten up the x and y max bounds
- ymax = y;
- xmax = x;
-
- Color grid = table.getGridColor();
+
+ bottom = bounds.y;
// paint vertical grid lines
if (grid != null && table.getShowVerticalLines())
{
- x = x0;
Color save = gfx.getColor();
gfx.setColor(grid);
- for (int c = 0; c < ncols && x < xmax; ++c)
+ int x = left;
+
+ for (int c = c0; c <= cn; ++c)
{
- x += cols.getColumn(c).getWidth();
- gfx.drawLine(x, y0, x, ymax);
+ gfx.drawLine(x, top, x, bottom);
+ x += widths[c];
}
gfx.setColor(save);
}
@@ -1277,13 +1303,13 @@ public class BasicTableUI extends TableUI
// paint horizontal grid lines
if (grid != null && table.getShowHorizontalLines())
{
- y = y0;
Color save = gfx.getColor();
gfx.setColor(grid);
- for (int r = 0; r < nrows && y < ymax; ++r)
+ int y = top;
+ for (int r = r0; r <= rn; ++r)
{
+ gfx.drawLine(left, y, p2.x, y);
y += height;
- gfx.drawLine(x0, y, xmax, y);
}
gfx.setColor(save);
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
index fc388948419..beb1a6dfeac 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
@@ -1,5 +1,5 @@
/* BasicTextUI.java --
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -46,15 +46,11 @@ import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
-import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
-import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
@@ -70,6 +66,7 @@ import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TextUI;
import javax.swing.plaf.UIResource;
+import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.DefaultCaret;
@@ -82,6 +79,7 @@ import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.Position;
+import javax.swing.text.Utilities;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
@@ -161,11 +159,11 @@ public abstract class BasicTextUI extends TextUI
* Indicates that the preferences of one of the child view has changed.
* This calls revalidate on the text component.
*
- * @param view the child view which's preference has changed
+ * @param v the child view which's preference has changed
* @param width <code>true</code> if the width preference has changed
* @param height <code>true</code> if the height preference has changed
*/
- public void preferenceChanged(View view, boolean width, boolean height)
+ public void preferenceChanged(View v, boolean width, boolean height)
{
textComponent.revalidate();
}
@@ -181,7 +179,7 @@ public abstract class BasicTextUI extends TextUI
view.setParent(null);
if (v != null)
- v.setParent(null);
+ v.setParent(this);
view = v;
}
@@ -207,10 +205,10 @@ public abstract class BasicTextUI extends TextUI
*/
public int getViewCount()
{
+ int count = 0;
if (view != null)
- return 1;
- else
- return 0;
+ count = 1;
+ return count;
}
/**
@@ -249,7 +247,11 @@ public abstract class BasicTextUI extends TextUI
public void paint(Graphics g, Shape s)
{
if (view != null)
- view.paint(g, s);
+ {
+ Rectangle b = s.getBounds();
+ view.setSize(b.width, b.height);
+ view.paint(g, s);
+ }
}
@@ -277,7 +279,7 @@ public abstract class BasicTextUI extends TextUI
public Shape modelToView(int position, Shape a, Position.Bias bias)
throws BadLocationException
{
- return ((View) view).modelToView(position, a, bias);
+ return view.modelToView(position, a, bias);
}
/**
@@ -363,12 +365,44 @@ public abstract class BasicTextUI extends TextUI
{
return view.getNextVisualPositionFrom(pos, b, a, d, biasRet);
}
+
+ /**
+ * Returns the startOffset of this view, which is always the beginning
+ * of the document.
+ *
+ * @return the startOffset of this view
+ */
+ public int getStartOffset()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the endOffset of this view, which is always the end
+ * of the document.
+ *
+ * @return the endOffset of this view
+ */
+ public int getEndOffset()
+ {
+ return getDocument().getLength();
+ }
+
+ /**
+ * Returns the document associated with this view.
+ *
+ * @return the document associated with this view
+ */
+ public Document getDocument()
+ {
+ return textComponent.getDocument();
+ }
}
/**
* Receives notifications when properties of the text component change.
*/
- class PropertyChangeHandler implements PropertyChangeListener
+ private class PropertyChangeHandler implements PropertyChangeListener
{
/**
* Notifies when a property of the text component changes.
@@ -448,7 +482,7 @@ public abstract class BasicTextUI extends TextUI
/**
* Receives notification when the model changes.
*/
- PropertyChangeHandler updateHandler = new PropertyChangeHandler();
+ private PropertyChangeHandler updateHandler = new PropertyChangeHandler();
/** The DocumentEvent handler. */
DocumentHandler documentHandler = new DocumentHandler();
@@ -515,20 +549,19 @@ public abstract class BasicTextUI extends TextUI
c.setOpaque(true);
textComponent = (JTextComponent) c;
-
Document doc = textComponent.getDocument();
if (doc == null)
{
- doc = getEditorKit(textComponent).createDefaultDocument();
- textComponent.setDocument(doc);
+ doc = getEditorKit(textComponent).createDefaultDocument();
+ textComponent.setDocument(doc);
}
-
- textComponent.addPropertyChangeListener(updateHandler);
- modelChanged();
-
installDefaults();
installListeners();
installKeyboardActions();
+
+ // We need to trigger this so that the view hierarchy gets initialized.
+ modelChanged();
+
}
/**
@@ -584,6 +617,7 @@ public abstract class BasicTextUI extends TextUI
protected void installListeners()
{
textComponent.addFocusListener(focuslistener);
+ textComponent.addPropertyChangeListener(updateHandler);
installDocumentListeners();
}
@@ -621,6 +655,11 @@ public abstract class BasicTextUI extends TextUI
*/
protected Keymap createKeymap()
{
+ // FIXME: It seems to me that this method implementation is wrong. It seems
+ // to fetch the focusInputMap and transform it to the KeyBinding/Keymap
+ // implemenation. I would think that it should be done the other way,
+ // fetching the keybindings (from prefix + ".bindings") and transform
+ // it to the newer InputMap/ActionMap implementation.
JTextComponent.KeyBinding[] bindings = null;
String prefix = getPropertyPrefix();
InputMapUIResource m = (InputMapUIResource) UIManager.get(prefix + ".focusInputMap");
@@ -637,10 +676,7 @@ public abstract class BasicTextUI extends TextUI
}
}
if (bindings == null)
- {
- bindings = new JTextComponent.KeyBinding[0];
- UIManager.put(prefix + ".focusInputMap", bindings);
- }
+ bindings = new JTextComponent.KeyBinding[0];
Keymap km = JTextComponent.addKeymap(getKeymapName(),
JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP));
@@ -726,8 +762,6 @@ public abstract class BasicTextUI extends TextUI
super.uninstallUI(component);
rootView.setView(null);
- textComponent.removePropertyChangeListener(updateHandler);
-
uninstallDefaults();
uninstallListeners();
uninstallKeyboardActions();
@@ -750,6 +784,7 @@ public abstract class BasicTextUI extends TextUI
*/
protected void uninstallListeners()
{
+ textComponent.removePropertyChangeListener(updateHandler);
textComponent.removeFocusListener(focuslistener);
textComponent.getDocument().removeDocumentListener(documentHandler);
}
@@ -786,7 +821,9 @@ public abstract class BasicTextUI extends TextUI
float w = v.getPreferredSpan(View.X_AXIS);
float h = v.getPreferredSpan(View.Y_AXIS);
- return new Dimension((int) w, (int) h);
+ Insets i = c.getInsets();
+ return new Dimension((int) w + i.left + i.right,
+ (int) h + i.top + i.bottom);
}
/**
@@ -817,18 +854,49 @@ public abstract class BasicTextUI extends TextUI
}
/**
- * Paints the text component.
+ * Paints the text component. This acquires a read lock on the model and then
+ * calls {@link #paintSafely(Graphics)} in order to actually perform the
+ * painting.
*
* @param g the <code>Graphics</code> context to paint to
* @param c not used here
*/
public final void paint(Graphics g, JComponent c)
{
- paintSafely(g);
+ try
+ {
+ Document doc = textComponent.getDocument();
+ if (doc instanceof AbstractDocument)
+ {
+ AbstractDocument aDoc = (AbstractDocument) doc;
+ aDoc.readLock();
+ }
+
+ paintSafely(g);
+ }
+ finally
+ {
+ Document doc = textComponent.getDocument();
+ if (doc instanceof AbstractDocument)
+ {
+ AbstractDocument aDoc = (AbstractDocument) doc;
+ aDoc.readUnlock();
+ }
+ }
}
/**
- * Actually performs the painting.
+ * This paints the text component while beeing sure that the model is not
+ * modified while painting.
+ *
+ * The following is performed in this order:
+ * <ol>
+ * <li>If the text component is opaque, the background is painted by
+ * calling {@link #paintBackground(Graphics)}.</li>
+ * <li>If there is a highlighter, the highlighter is painted.</li>
+ * <li>The view hierarchy is painted.</li>
+ * <li>The Caret is painter.</li>
+ * </ol>
*
* @param g the <code>Graphics</code> context to paint to
*/
@@ -840,9 +908,19 @@ public abstract class BasicTextUI extends TextUI
if (textComponent.isOpaque())
paintBackground(g);
- if (highlighter != null
- && textComponent.getSelectionStart() != textComponent.getSelectionEnd())
- highlighter.paint(g);
+ // Try painting with the highlighter without checking whether there
+ // is a selection because a highlighter can be used to do more than
+ // marking selected text.
+ if (highlighter != null)
+ {
+ // Handle restoring of the color here to prevent
+ // drawing problems when the Highlighter implementor
+ // forgets to restore it.
+ Color oldColor = g.getColor();
+ highlighter.paint(g);
+ g.setColor(oldColor);
+ }
+
rootView.paint(g, getVisibleEditorRect());
@@ -857,10 +935,23 @@ public abstract class BasicTextUI extends TextUI
*/
protected void paintBackground(Graphics g)
{
- // This method does nothing. All the background filling is done by the
- // ComponentUI update method. However, the method is called by paint
- // to provide a way for subclasses to draw something different (e.g.
- // background images etc) on the background.
+ Color old = g.getColor();
+ g.setColor(textComponent.getBackground());
+ g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight());
+ g.setColor(old);
+ }
+
+ /**
+ * Overridden for better control over background painting. This now simply
+ * calls {@link #paint} and this delegates the background painting to
+ * {@link #paintBackground}.
+ *
+ * @param g the graphics to use
+ * @param c the component to be painted
+ */
+ public void update(Graphics g, JComponent c)
+ {
+ paint(g, c);
}
/**
@@ -895,7 +986,84 @@ public abstract class BasicTextUI extends TextUI
public void damageRange(JTextComponent t, int p0, int p1,
Position.Bias firstBias, Position.Bias secondBias)
{
- // TODO: Implement me.
+ try
+ {
+ // Limit p0 and p1 to sane values to prevent unfriendly
+ // BadLocationExceptions. This makes it possible for the highlighter
+ // to send us illegal values which can happen when a large number
+ // of selected characters are removed (eg. by pressing delete
+ // or backspace).
+ // The reference implementation does not throw an exception, too.
+ p0 = Math.min(p0, t.getDocument().getLength());
+ p1 = Math.min(p1, t.getDocument().getLength());
+
+ Rectangle l1 = modelToView(t, p0, firstBias);
+ Rectangle l2 = modelToView(t, p1, secondBias);
+ if (l1.y == l2.y)
+ t.repaint(l1.union(l2));
+ else
+ {
+ // The two rectangles lie on different lines and we need a
+ // different algorithm to calculate the damaged area:
+ // 1. The line of p0 is damaged from the position of p0
+ // to the right border.
+ // 2. All lines between the ones where p0 and p1 lie on
+ // are completely damaged. Use the allocation area to find
+ // out the bounds.
+ // 3. The final line is damaged from the left bound to the
+ // position of p1.
+ Insets insets = t.getInsets();
+
+ // Damage first line until the end.
+ l1.width = insets.right + t.getWidth() - l1.x;
+ t.repaint(l1);
+
+ // Note: Utilities.getPositionBelow() may return the offset
+ // that was put in. In that case there is no next line and
+ // we should stop searching for one.
+
+ int posBelow = Utilities.getPositionBelow(t, p0, l1.x);
+ if (posBelow < p1 && posBelow != -1 && posBelow != p0)
+ {
+ // Take the rectangle of the offset we just found and grow it
+ // to the maximum width. Retain y because this is our start
+ // height.
+ Rectangle grow = modelToView(t, posBelow);
+ grow.x = insets.left;
+ grow.width = t.getWidth() + insets.right;
+
+ // Find further lines which have to be damaged completely.
+ int nextPosBelow = posBelow;
+ while (nextPosBelow < p1 && nextPosBelow != -1 && posBelow != nextPosBelow)
+ {
+ posBelow = nextPosBelow;
+ nextPosBelow = Utilities.getPositionBelow(t, posBelow, l1.x);
+ }
+ // Now posBelow is an offset on the last line which has to be damaged
+ // completely. (newPosBelow is on the same line as p1)
+
+ // Retrieve the rectangle of posBelow and use its y and height
+ // value to calculate the final height of the multiple line
+ // spanning rectangle.
+ Rectangle end = modelToView(t, posBelow);
+ grow.height = end.y + end.height - grow.y;
+
+ // Mark that area as damage.
+ t.repaint(grow);
+ }
+
+ // Damage last line from its beginning to the position of p1.
+ l2.width += l2.x;
+ l2.x = insets.left;
+ t.repaint(l2);
+ }
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError err = new AssertionError("Unexpected bad location");
+ err.initCause(ex);
+ throw err;
+ }
}
/**
@@ -1061,7 +1229,6 @@ public abstract class BasicTextUI extends TextUI
*/
protected Rectangle getVisibleEditorRect()
{
- JTextComponent textComponent = getComponent();
int width = textComponent.getWidth();
int height = textComponent.getHeight();
@@ -1082,7 +1249,6 @@ public abstract class BasicTextUI extends TextUI
protected final void setView(View view)
{
rootView.setView(view);
- view.setParent(rootView);
textComponent.revalidate();
textComponent.repaint();
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
index f2ebcfca9ac..1c6e6c5e502 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
@@ -45,6 +45,7 @@ import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
+import java.awt.Label;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
@@ -114,9 +115,18 @@ import javax.swing.tree.TreeSelectionModel;
* @see javax.swing.JTree
* @author Lillian Angel (langel@redhat.com)
* @author Sascha Brawer (brawer@dandelis.ch)
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
*/
public class BasicTreeUI extends TreeUI
{
+ /**
+ * The tree cell editing may be started by the single mouse click on the
+ * selected cell. To separate it from the double mouse click, the editing
+ * session starts after this time (in ms) after that single click, and only
+ * no other clicks were performed during that time.
+ */
+ static int WAIT_TILL_EDITING = 900;
+
/** Collapse Icon for the tree. */
protected transient Icon collapsedIcon;
@@ -225,12 +235,6 @@ public class BasicTreeUI extends TreeUI
/** Set to true if the editor has a different size than the renderer. */
protected boolean editorHasDifferentSize;
- /** The action listener for the editor's Timer. */
- Timer editorTimer = new EditorUpdateTimer();
-
- /** The new value of the node after editing. */
- Object newVal;
-
/** The action bound to KeyStrokes. */
TreeAction action;
@@ -266,6 +270,20 @@ public class BasicTreeUI extends TreeUI
private TreeExpansionListener treeExpansionListener;
private TreeModelListener treeModelListener;
+
+ /**
+ * This timer fires the editing action after about 1200 ms if not reset during
+ * that time. It handles the editing start with the single mouse click
+ * (and not the double mouse click) on the selected tree node.
+ */
+ Timer startEditTimer;
+
+ /**
+ * The special value of the mouse event is sent indicating that this is not
+ * just the mouse click, but the mouse click on the selected node. Sending
+ * such event forces to start the cell editing session.
+ */
+ static final MouseEvent EDIT = new MouseEvent(new Label(), 7,7,7,7,7,7, false);
/**
* Creates a new BasicTreeUI object.
@@ -303,7 +321,7 @@ public class BasicTreeUI extends TreeUI
{
return new BasicTreeUI();
}
-
+
/**
* Returns the Hash color.
*
@@ -796,7 +814,10 @@ public class BasicTreeUI extends TreeUI
public boolean stopEditing(JTree tree)
{
if (isEditing(tree))
- completeEditing(true, false, false);
+ {
+ completeEditing(false, false, true);
+ finish();
+ }
return !isEditing(tree);
}
@@ -807,9 +828,12 @@ public class BasicTreeUI extends TreeUI
* is the tree to cancel the editing session on.
*/
public void cancelEditing(JTree tree)
- {
- if (isEditing(tree))
- completeEditing(false, true, false);
+ {
+ // There is no need to send the cancel message to the editor,
+ // as the cancellation event itself arrives from it. This would
+ // only be necessary when cancelling the editing programatically.
+ completeEditing(false, false, false);
+ finish();
}
/**
@@ -1213,6 +1237,7 @@ public class BasicTreeUI extends TreeUI
protected void updateCachedPreferredSize()
{
int maxWidth = 0;
+ updateCurrentVisiblePath();
boolean isLeaf = false;
if (currentVisiblePath != null)
{
@@ -1246,7 +1271,7 @@ public class BasicTreeUI extends TreeUI
protected void pathWasExpanded(TreePath path)
{
validCachedPreferredSize = false;
- tree.repaint();
+ tree.repaint();
}
/**
@@ -1271,7 +1296,6 @@ public class BasicTreeUI extends TreeUI
leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
setRowHeight(UIManager.getInt("Tree.rowHeight"));
tree.setRowHeight(getRowHeight());
- tree.requestFocusInWindow(false);
tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
setExpandedIcon(UIManager.getIcon("Tree.expandedIcon"));
setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon"));
@@ -1621,7 +1645,14 @@ public class BasicTreeUI extends TreeUI
}
if (messageTree)
- treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal);
+ {
+ TreeCellEditor editor = getCellEditor();
+ if (editor != null)
+ {
+ Object value = editor.getCellEditorValue();
+ treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value);
+ }
+ }
}
/**
@@ -1636,44 +1667,48 @@ public class BasicTreeUI extends TreeUI
*/
protected boolean startEditing(TreePath path, MouseEvent event)
{
- int x;
- int y;
- if (event == null)
- {
- Rectangle bounds = getPathBounds(tree, path);
- x = bounds.x;
- y = bounds.y;
- }
- else
- {
- x = event.getX();
- y = event.getY();
- }
+ // Force to recalculate the maximal row height.
+ maxHeight = 0;
+
+ // Force to recalculate the cached preferred size.
+ validCachedPreferredSize = false;
updateCellEditor();
TreeCellEditor ed = getCellEditor();
- if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event))
+
+ if (ed != null
+ && (event == EDIT || ed.shouldSelectCell(event))
+ && ed.isCellEditable(event))
{
+ Rectangle bounds = getPathBounds(tree, path);
+
+ // Extend the right boundary till the tree width.
+ bounds.width = tree.getWidth() - bounds.x;
+
editingPath = path;
editingRow = tree.getRowForPath(editingPath);
- Object val = editingPath.getLastPathComponent();
- cellEditor.addCellEditorListener(cellEditorListener);
+ Object value = editingPath.getLastPathComponent();
+
stopEditingInCompleteEditing = false;
boolean expanded = tree.isExpanded(editingPath);
isEditing = true;
- editingComponent = ed.getTreeCellEditorComponent(tree, val, true,
+ editingComponent = ed.getTreeCellEditorComponent(tree, value, true,
expanded,
isLeaf(editingRow),
editingRow);
- editingComponent.getParent().setVisible(true);
- editingComponent.getParent().validate();
- tree.add(editingComponent.getParent());
- editingComponent.getParent().validate();
- validCachedPreferredSize = false;
-
- ((JTextField) editingComponent).requestFocusInWindow(false);
- editorTimer.start();
+
+ // Remove all previous components (if still present). Only one
+ // container with the editing component inside is allowed in the tree.
+ tree.removeAll();
+
+ // The editing component must be added to its container. We add the
+ // container, not the editing component itself.
+ Component container = editingComponent.getParent();
+ container.setBounds(bounds);
+ tree.add(container);
+ editingComponent.requestFocus();
+
return true;
}
return false;
@@ -1922,7 +1957,7 @@ public class BasicTreeUI extends TreeUI
tree.clearSelection();
if (tree.isEditing() && !e.getActionCommand().equals("startEditing"))
- tree.cancelEditing();
+ tree.stopEditing();
tree.scrollPathToVisible(lead);
}
@@ -1957,51 +1992,7 @@ public class BasicTreeUI extends TreeUI
}
}
- /**
- * The timer that updates the editor component.
- */
- private class EditorUpdateTimer extends Timer implements ActionListener
- {
- /**
- * Creates a new EditorUpdateTimer object with a default delay of 0.3
- * seconds.
- */
- public EditorUpdateTimer()
- {
- super(300, null);
- addActionListener(this);
- }
-
- /**
- * Lets the caret blink and repaints the table.
- */
- public void actionPerformed(ActionEvent ev)
- {
- Caret c = ((JTextField) editingComponent).getCaret();
- if (c != null)
- c.setVisible(!c.isVisible());
- tree.repaint();
- }
-
- /**
- * Updates the blink delay according to the current caret.
- */
- public void update()
- {
- stop();
- Caret c = ((JTextField) editingComponent).getCaret();
- if (c != null)
- {
- setDelay(c.getBlinkRate());
- if (((JTextField) editingComponent).isEditable())
- start();
- else
- c.setVisible(false);
- }
- }
- }
-
- /**
+ /**
* Updates the preferred size when scrolling, if necessary.
*/
public class ComponentHandler extends ComponentAdapter implements
@@ -2089,29 +2080,7 @@ public class BasicTreeUI extends TreeUI
*/
public void editingStopped(ChangeEvent e)
{
- editingPath = null;
- editingRow = -1;
- stopEditingInCompleteEditing = false;
- if (editingComponent != null)
- {
- tree.remove(editingComponent.getParent());
- editingComponent = null;
- }
- if (cellEditor != null)
- {
- newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText();
- completeEditing(false, false, true);
- if (cellEditor instanceof DefaultTreeCellEditor)
- tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
- cellEditor.removeCellEditorListener(cellEditorListener);
- setCellEditor(null);
- createdCellEditor = false;
- }
- isEditing = false;
- tree.requestFocusInWindow(false);
- editorTimer.stop();
- validCachedPreferredSize = false;
- tree.repaint();
+ stopEditing(tree);
}
/**
@@ -2123,25 +2092,7 @@ public class BasicTreeUI extends TreeUI
*/
public void editingCanceled(ChangeEvent e)
{
- editingPath = null;
- editingRow = -1;
- stopEditingInCompleteEditing = false;
- if (editingComponent != null)
- tree.remove(editingComponent.getParent());
- editingComponent = null;
- if (cellEditor != null)
- {
- if (cellEditor instanceof DefaultTreeCellEditor)
- tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
- cellEditor.removeCellEditorListener(cellEditorListener);
- setCellEditor(null);
- createdCellEditor = false;
- }
- tree.requestFocusInWindow(false);
- editorTimer.stop();
- isEditing = false;
- validCachedPreferredSize = false;
- tree.repaint();
+ cancelEditing(tree);
}
}// CellEditorHandler
@@ -2261,7 +2212,15 @@ public class BasicTreeUI extends TreeUI
* is the mouse event that occured
*/
public void mousePressed(MouseEvent e)
- {
+ {
+ // Any mouse click cancels the previous waiting edit action, initiated
+ // by the single click on the selected node.
+ if (startEditTimer != null)
+ {
+ startEditTimer.stop();
+ startEditTimer = null;
+ }
+
Point click = e.getPoint();
TreePath path = getClosestPathForLocation(tree, click.x, click.y);
@@ -2298,9 +2257,37 @@ public class BasicTreeUI extends TreeUI
{
if (inBounds)
{
- selectPath(tree, path);
- if (e.getClickCount() == 2 && !isLeaf(row))
- toggleExpandState(path);
+ TreePath currentLead = tree.getLeadSelectionPath();
+ if (
+ currentLead != null &&
+ currentLead.equals(path) &&
+ e.getClickCount() == 1 &&
+ tree.isEditable()
+ )
+ {
+ // Schedule the editing session.
+ final TreePath editPath = path;
+
+ if (startEditTimer != null)
+ startEditTimer.stop();
+
+ startEditTimer = new Timer(WAIT_TILL_EDITING,
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ startEditing(editPath, EDIT);
+ }
+ });
+ startEditTimer.setRepeats(false);
+ startEditTimer.start();
+ }
+ else
+ {
+ selectPath(tree, path);
+ if (e.getClickCount() == 2 && !isLeaf(row))
+ toggleExpandState(path);
+ }
}
if (cntlClick)
@@ -2686,7 +2673,7 @@ public class BasicTreeUI extends TreeUI
public class TreeHomeAction extends AbstractAction
{
- /** direction is either home or end */
+ /** The direction, either home or end */
protected int direction;
/**
@@ -2983,7 +2970,7 @@ public class BasicTreeUI extends TreeUI
public void valueChanged(TreeSelectionEvent event)
{
if (tree.isEditing())
- tree.cancelEditing();
+ tree.stopEditing();
}
}// TreeSelectionHandler
@@ -3650,25 +3637,14 @@ public class BasicTreeUI extends TreeUI
if (row != 0)
bounds.x += gap;
bounds.width = preferredSize.width + bounds.x;
- if (editingComponent != null && editingPath != null && isEditing(tree)
- && node.equals(editingPath.getLastPathComponent()))
- {
- rendererPane.paintComponent(g, editingComponent.getParent(), null,
- bounds);
- }
- else
- {
- TreeCellRenderer dtcr = tree.getCellRenderer();
- if (dtcr == null)
- dtcr = createDefaultCellRenderer();
-
- Component c = dtcr.getTreeCellRendererComponent(tree, node,
- selected,
- isExpanded, isLeaf,
- row,
- tree.hasFocus());
- rendererPane.paintComponent(g, c, c.getParent(), bounds);
- }
+ TreeCellRenderer dtcr = tree.getCellRenderer();
+ if (dtcr == null)
+ dtcr = createDefaultCellRenderer();
+
+ Component c = dtcr.getTreeCellRendererComponent(tree, node, selected,
+ isExpanded, isLeaf,
+ row, tree.hasFocus());
+ rendererPane.paintComponent(g, c, c.getParent(), bounds);
}
}
@@ -3801,4 +3777,21 @@ public class BasicTreeUI extends TreeUI
}
return null;
}
+
+ /**
+ * Finish the editing session.
+ */
+ void finish()
+ {
+ editingPath = null;
+ editingRow = -1;
+ stopEditingInCompleteEditing = false;
+ isEditing = false;
+ tree.removeAll();
+ validCachedPreferredSize = false;
+
+ // Repaint the region, where was the editing component.
+ tree.repaint(editingComponent.getParent().getBounds());
+ editingComponent = null;
+ }
} // BasicTreeUI
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java
index 28143d51ecd..99c90acdbee 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java
@@ -1,5 +1,5 @@
/* MetalBorders.java
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -249,30 +249,27 @@ public class MetalBorders
/**
* Returns the insets of the <code>ButtonBorder</code>.
*
- * @param c the component for which the border is used
+ * @param c the component for which the border is used (ignored).
*
- * @return The insets of the ButtonBorder
+ * @return The insets of the <code>ButtonBorder</code>.
*/
public Insets getBorderInsets(Component c)
{
- return getBorderInsets(c, null);
+ return borderInsets;
}
/**
* Returns the insets of the <code>ButtonBorder</code> in the specified
* <code>newInsets</code> object.
*
- * @param c the component for which the border is used
- * @param newInsets the insets object where to put the values (if
- * <code>null</code>, a new instance is created).
+ * @param c the component for which the border is used (ignored).
+ * @param newInsets the insets object where to put the values (
+ * <code>null</code> not permitted).
*
- * @return The insets.
+ * @return The <code>newInsets</code> reference.
*/
public Insets getBorderInsets(Component c, Insets newInsets)
{
- if (newInsets == null)
- newInsets = new Insets(0, 0, 0, 0);
-
newInsets.bottom = borderInsets.bottom;
newInsets.left = borderInsets.left;
newInsets.right = borderInsets.right;
@@ -352,6 +349,8 @@ public class MetalBorders
public static class Flush3DBorder extends AbstractBorder
implements UIResource
{
+ private static final Insets borderInsets = new Insets(2, 2, 2, 2);
+
/**
* Creates a new border instance.
*/
@@ -369,26 +368,25 @@ public class MetalBorders
*/
public Insets getBorderInsets(Component c)
{
- return getBorderInsets(c, null);
+ return borderInsets;
}
/**
* Returns the border insets.
*
* @param c the component (ignored).
- * @return The border insets.
+ * @param newInsets an existing insets instance, that will be populated
+ * with the border insets and returned as the result
+ * (<code>null</code> not permitted).
+ *
+ * @return The <code>newInsets</code> reference.
*/
public Insets getBorderInsets(Component c, Insets newInsets)
{
- if (newInsets == null)
- newInsets = new Insets(2, 2, 2, 2);
- else
- {
- newInsets.top = 2;
- newInsets.left = 2;
- newInsets.bottom = 2;
- newInsets.right = 2;
- }
+ newInsets.top = borderInsets.top;
+ newInsets.left = borderInsets.left;
+ newInsets.bottom = borderInsets.bottom;
+ newInsets.right = borderInsets.right;
return newInsets;
}
@@ -427,6 +425,8 @@ public class MetalBorders
public static class PaletteBorder extends AbstractBorder
implements UIResource
{
+ private static final Insets borderInsets = new Insets(1, 1, 1, 1);
+
/**
* Creates a new <code>PaletteBorder</code>.
*/
@@ -444,29 +444,25 @@ public class MetalBorders
*/
public Insets getBorderInsets(Component c)
{
- return getBorderInsets(c, null);
+ return borderInsets;
}
/**
* Returns the border insets.
*
* @param c the component (ignored).
- * @param newInsets the insets object that, if non-<code>null</code>, will
- * be populated with the result from this method.
- *
- * @return The border insets.
+ * @param newInsets an existing insets instance, that will be populated
+ * with the border insets and returned as the result
+ * (<code>null</code> not permitted).
+ *
+ * @return The <code>newInsets</code> reference.
*/
public Insets getBorderInsets(Component c, Insets newInsets)
{
- if (newInsets == null)
- newInsets = new Insets(1, 1, 1, 1);
- else
- {
- newInsets.top = 1;
- newInsets.left = 1;
- newInsets.bottom = 1;
- newInsets.right = 1;
- }
+ newInsets.top = borderInsets.top;
+ newInsets.left = borderInsets.left;
+ newInsets.bottom = borderInsets.bottom;
+ newInsets.right = borderInsets.right;
return newInsets;
}
@@ -555,6 +551,8 @@ public class MetalBorders
public static class InternalFrameBorder extends AbstractBorder
implements UIResource
{
+ private static final Insets borderInsets = new Insets(5, 5, 5, 5);
+
/**
* Creates a new border instance.
*/
@@ -572,26 +570,25 @@ public class MetalBorders
*/
public Insets getBorderInsets(Component c)
{
- return getBorderInsets(c, null);
+ return borderInsets;
}
/**
* Returns the border insets.
*
* @param c the component (ignored).
- * @return The border insets.
+ * @param newInsets an existing insets instance, that will be populated
+ * with the border insets and returned as the result
+ * (<code>null</code> not permitted).
+ *
+ * @return The <code>newInsets</code> reference.
*/
public Insets getBorderInsets(Component c, Insets newInsets)
{
- if (newInsets == null)
- newInsets = new Insets(5, 5, 5, 5);
- else
- {
- newInsets.top = 5;
- newInsets.left = 5;
- newInsets.bottom = 5;
- newInsets.right = 5;
- }
+ newInsets.top = borderInsets.top;
+ newInsets.left = borderInsets.left;
+ newInsets.bottom = borderInsets.bottom;
+ newInsets.right = borderInsets.right;
return newInsets;
}
@@ -763,7 +760,7 @@ public class MetalBorders
implements UIResource
{
/** The border insets. */
- protected static Insets borderInsets = new Insets(1, 1, 1, 1);
+ protected static Insets borderInsets = new Insets(2, 2, 2, 2);
/**
* Creates a new border instance.
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
index 967c40d29ad..cb94c87b846 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
@@ -1545,8 +1545,6 @@ public class MetalFileChooserUI
fileListPanel = new JPanel(new BorderLayout());
fileList = new JList(getModel());
scrollPane = new JScrollPane(fileList);
- scrollPane.setVerticalScrollBarPolicy
- (JScrollPane.VERTICAL_SCROLLBAR_NEVER);
fileList.setLayoutOrientation(JList.VERTICAL_WRAP);
fileList.setCellRenderer(new FileRenderer());
}
@@ -1557,7 +1555,10 @@ public class MetalFileChooserUI
scrollPane.getViewport().setView(fileList);
}
fileListPanel.add(scrollPane);
-
+ // This size was determined using BeanShell and dumping the JFileChooser
+ // component hierarchy. Sun has an internal FilePane class in there, but
+ // that probably doesn't matter atm.
+ fileListPanel.setPreferredSize(new Dimension(405, 135));
return fileListPanel;
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java
index c60b55c9e7b..e84644615ce 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java
@@ -1171,6 +1171,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"Spinner.arrowButtonInsets", new InsetsUIResource(0, 0, 0, 0),
"Spinner.background", getControl(),
+ "Spinner.border", MetalBorders.getTextFieldBorder(),
"Spinner.font", new FontUIResource("Dialog", Font.BOLD, 12),
"Spinner.foreground", getControl(),
@@ -1342,4 +1343,16 @@ public class MetalLookAndFeel extends BasicLookAndFeel
{
return theme;
}
+
+ /**
+ * Returns <code>true</code> because the Metal look
+ * and feel supports window decorations for toplevel
+ * containers.
+ *
+ * @return <code>true</code>
+ */
+ public boolean getSupportsWindowDecorations()
+ {
+ return true;
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java
index faed80382d0..23051e9bcea 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java
@@ -1,5 +1,5 @@
/* MetalRootPaneUI.java
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,23 +38,842 @@ exception statement from your version. */
package javax.swing.plaf.metal;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.LayoutManager2;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowFocusListener;
+import java.beans.PropertyChangeEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
import javax.swing.JRootPane;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.AbstractBorder;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicRootPaneUI;
/**
- * A UI delegate for the {@link JRootPane} component. This class is not fully
- * implemented.
+ * A UI delegate for the {@link JRootPane} component. This implementation
+ * supports the JRootPane <code>windowDecorationStyle</code> property.
*
+ * @author Roman Kennke (kennke@aicas.com)
+ *
* @since 1.4
*/
public class MetalRootPaneUI
extends BasicRootPaneUI
{
- // FIXME: maybe replace by a Map of instances when this becomes stateful
- /** The shared UI instance for MetalRootPaneUIs */
+ /**
+ * The border that is used on JRootPane when the windowDecorationStyle
+ * property of the JRootPane is set to a different value than NONE.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private static class MetalFrameBorder
+ extends AbstractBorder
+ {
+ /**
+ * Returns the border insets.
+ *
+ * @param c the component
+ * @param newInsets the insets to be filled with the return value, may be
+ * <code>null</code> in which case a new object is created
+ *
+ * @return the border insets
+ */
+ public Insets getBorderInsets(Component c, Insets newInsets)
+ {
+ if (newInsets == null)
+ newInsets = new Insets(5, 5, 5, 5);
+ else
+ {
+ newInsets.top = 5;
+ newInsets.left = 5;
+ newInsets.bottom = 5;
+ newInsets.right = 5;
+ }
+ return newInsets;
+ }
+
+ /**
+ * Returns the border insets.
+ *
+ * @param c the component
+ *
+ * @return the border insets
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return getBorderInsets(c, null);
+ }
+
+ /**
+ * Paints the border for the specified component.
+ *
+ * @param c the component
+ * @param g the graphics device
+ * @param x the x-coordinate
+ * @param y the y-coordinate
+ * @param w the width
+ * @param h the height
+ */
+ public void paintBorder(Component c, Graphics g, int x, int y, int w,
+ int h)
+ {
+ JRootPane f = (JRootPane) c;
+ Window frame = SwingUtilities.getWindowAncestor(f);
+ if (frame.isActive())
+ g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
+ else
+ g.setColor(MetalLookAndFeel.getControlDarkShadow());
+
+ // Fill the border background.
+ g.fillRect(x, y, w, 5);
+ g.fillRect(x, y, 5, h);
+ g.fillRect(x + w - 5, y, 5, h);
+ g.fillRect(x, y + h - 5, w, 5);
+
+ // Draw a dot in each corner.
+ g.setColor(MetalLookAndFeel.getControl());
+ g.fillRect(x, y, 1, 1);
+ g.fillRect(x + w - 1, y, 1, 1);
+ g.fillRect(x + w - 1, y + h - 1, 1, 1);
+ g.fillRect(x, y + h - 1, 1, 1);
+
+ // Draw the lines.
+ g.setColor(MetalLookAndFeel.getBlack());
+ g.drawLine(x + 14, y + 2, x + w - 15, y + 2);
+ g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3);
+ g.drawLine(x + 2, y + 14, x + 2, y + h - 15);
+ g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15);
+
+ // Draw the line highlights.
+ if (frame.isActive())
+ g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
+ else
+ g.setColor(MetalLookAndFeel.getControlShadow());
+ g.drawLine(x + 15, y + 3, x + w - 14, y + 3);
+ g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2);
+ g.drawLine(x + 3, y + 15, x + 3, y + h - 14);
+ g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14);
+ }
+ }
+
+ /**
+ * The component that renders the title bar for frames. This duplicates
+ * most of {@link MetalInternalFrameTitlePane}. It is not reasonably possible
+ * to reuse that class because that is bound to the JInternalFrame and we
+ * need to handle JFrames/JRootPanes here.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private static class MetalTitlePane extends JComponent
+ {
+ /**
+ * The Action responsible for closing the JInternalFrame.
+ */
+ private class CloseAction extends AbstractAction
+ {
+ /**
+ * Creates a new action.
+ */
+ public CloseAction()
+ {
+ super("Close");
+ }
+
+ /**
+ * This method is called when something closes the frame.
+ *
+ * @param e the ActionEvent
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ Window frame = SwingUtilities.getWindowAncestor(rootPane);
+ if (frame instanceof JFrame)
+ {
+ JFrame jframe = (JFrame) frame;
+ switch (jframe.getDefaultCloseOperation())
+ {
+ case JFrame.EXIT_ON_CLOSE:
+ jframe.setVisible(false);
+ jframe.dispose();
+ System.exit(0);
+ break;
+ case JFrame.DISPOSE_ON_CLOSE:
+ jframe.setVisible(false);
+ jframe.dispose();
+ break;
+ case JFrame.HIDE_ON_CLOSE:
+ jframe.setVisible(false);
+ break;
+ case JFrame.DO_NOTHING_ON_CLOSE:
+ default:
+ break;
+ }
+ }
+ else if (frame instanceof JDialog)
+ {
+ JDialog jdialog = (JDialog) frame;
+ switch (jdialog.getDefaultCloseOperation())
+ {
+ case JFrame.DISPOSE_ON_CLOSE:
+ jdialog.setVisible(false);
+ jdialog.dispose();
+ break;
+ case JFrame.HIDE_ON_CLOSE:
+ jdialog.setVisible(false);
+ break;
+ case JFrame.DO_NOTHING_ON_CLOSE:
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * This helper class is used to create the minimize, maximize and close
+ * buttons in the top right corner of the Title Pane. These buttons are
+ * special since they cannot be given focus and have no border.
+ */
+ private class PaneButton extends JButton
+ {
+ /**
+ * Creates a new PaneButton object with the given Action.
+ *
+ * @param a The Action that the button uses.
+ */
+ public PaneButton(Action a)
+ {
+ super(a);
+ setMargin(new Insets(0, 0, 0, 0));
+ }
+
+ /**
+ * This method returns true if the Component can be focused.
+ *
+ * @return false.
+ */
+ public boolean isFocusable()
+ {
+ // These buttons cannot be given focus.
+ return false;
+ }
+
+ }
+
+ /**
+ * The layout for the JRootPane when the <code>windowDecorationStyle</code>
+ * property is set. In addition to the usual JRootPane.RootLayout behaviour
+ * this lays out the titlePane.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private class MetalTitlePaneLayout implements LayoutManager
+ {
+ /**
+ * Creates a new <code>TitlePaneLayout</code> object.
+ */
+ public MetalTitlePaneLayout()
+ {
+ // Do nothing.
+ }
+
+ /**
+ * Adds a Component to the Container.
+ *
+ * @param name The name to reference the added Component by.
+ * @param c The Component to add.
+ */
+ public void addLayoutComponent(String name, Component c)
+ {
+ // Do nothing.
+ }
+
+ /**
+ * This method is called to lay out the children of the Title Pane.
+ *
+ * @param c The Container to lay out.
+ */
+ public void layoutContainer(Container c)
+ {
+
+ Dimension size = c.getSize();
+ Insets insets = c.getInsets();
+ int width = size.width - insets.left - insets.right;
+ int height = size.height - insets.top - insets.bottom;
+
+ int loc = width - insets.right - 1;
+ int top = insets.top + 2;
+ int buttonHeight = height - 4;
+ if (closeButton.isVisible())
+ {
+ int buttonWidth = closeIcon.getIconWidth();
+ loc -= buttonWidth + 2;
+ closeButton.setBounds(loc, top, buttonWidth, buttonHeight);
+ loc -= 6;
+ }
+
+ if (maxButton.isVisible())
+ {
+ int buttonWidth = maxIcon.getIconWidth();
+ loc -= buttonWidth + 4;
+ maxButton.setBounds(loc, top, buttonWidth, buttonHeight);
+ }
+
+ if (iconButton.isVisible())
+ {
+ int buttonWidth = minIcon.getIconWidth();
+ loc -= buttonWidth + 4;
+ iconButton.setBounds(loc, top, buttonWidth, buttonHeight);
+ loc -= 2;
+ }
+
+ Dimension titlePreferredSize = title.getPreferredSize();
+ title.setBounds(insets.left + 5, insets.top,
+ Math.min(titlePreferredSize.width, loc - insets.left - 10),
+ height);
+
+ }
+
+ /**
+ * This method returns the minimum size of the given Container given the
+ * children that it has.
+ *
+ * @param c The Container to get a minimum size for.
+ *
+ * @return The minimum size of the Container.
+ */
+ public Dimension minimumLayoutSize(Container c)
+ {
+ return preferredLayoutSize(c);
+ }
+
+ /**
+ * Returns the preferred size of the given Container taking
+ * into account the children that it has.
+ *
+ * @param c The Container to lay out.
+ *
+ * @return The preferred size of the Container.
+ */
+ public Dimension preferredLayoutSize(Container c)
+ {
+ return new Dimension(22, 22);
+ }
+
+ /**
+ * Removes a Component from the Container.
+ *
+ * @param c The Component to remove.
+ */
+ public void removeLayoutComponent(Component c)
+ {
+ // Nothing to do here.
+ }
+ }
+
+ JRootPane rootPane;
+
+ /** The button that closes the JInternalFrame. */
+ JButton closeButton;
+
+ /** The button that iconifies the JInternalFrame. */
+ JButton iconButton;
+
+ /** The button that maximizes the JInternalFrame. */
+ JButton maxButton;
+
+ Icon minIcon;
+
+ /** The icon displayed in the maximize button. */
+ Icon maxIcon;
+
+ /** The icon displayed in the iconify button. */
+ private Icon iconIcon;
+
+ /** The icon displayed in the close button. */
+ Icon closeIcon;
+
+ /**
+ * The background color of the TitlePane when the JInternalFrame is not
+ * selected.
+ */
+ private Color notSelectedTitleColor;
+
+ /**
+ * The background color of the TitlePane when the JInternalFrame is
+ * selected.
+ */
+ private Color selectedTitleColor;
+
+ /**
+ * The label used to display the title. This label is not added to the
+ * TitlePane.
+ */
+ JLabel title;
+
+ /** The action associated with closing the JInternalFrame. */
+ private Action closeAction;
+
+ /** The action associated with iconifying the JInternalFrame. */
+ private Action iconifyAction;
+
+ /** The action associated with maximizing the JInternalFrame. */
+ private Action maximizeAction;
+
+ /** The JMenuBar that is located at the top left of the Title Pane. */
+ private JMenuBar menuBar;
+
+ /** The JMenu inside the menuBar. */
+ protected JMenu windowMenu;
+
+ MetalTitlePane(JRootPane rp)
+ {
+ rootPane = rp;
+ setLayout(createLayout());
+ title = new JLabel();
+ title.setHorizontalAlignment(SwingConstants.LEFT);
+ title.setHorizontalTextPosition(SwingConstants.LEFT);
+ title.setOpaque(false);
+ installTitlePane();
+ }
+
+ protected LayoutManager createLayout()
+ {
+ return new MetalTitlePaneLayout();
+ }
+
+ /**
+ * This method installs the TitlePane onto the JInternalFrameTitlePane. It
+ * also creates any children components that need to be created and adds
+ * listeners to the appropriate components.
+ */
+ protected void installTitlePane()
+ {
+ installDefaults();
+ installListeners();
+ createActions();
+ assembleSystemMenu();
+ createButtons();
+ setButtonIcons();
+ addSubComponents();
+ enableActions();
+ }
+
+ private void enableActions()
+ {
+ // TODO: Implement this.
+ }
+
+ private void addSubComponents()
+ {
+ add(menuBar);
+ add(closeButton);
+ add(iconButton);
+ add(maxButton);
+ }
+
+ private void installListeners()
+ {
+ Window window = SwingUtilities.getWindowAncestor(rootPane);
+ window.addWindowFocusListener(new WindowFocusListener()
+ {
+ public void windowGainedFocus(WindowEvent ev)
+ {
+ repaint();
+ }
+ public void windowLostFocus(WindowEvent ev)
+ {
+ repaint();
+ }
+ });
+ }
+
+ private void createActions()
+ {
+ closeAction = new CloseAction();
+ }
+
+ private void assembleSystemMenu()
+ {
+ menuBar = createSystemMenuBar();
+ windowMenu = createSystemMenu();
+ menuBar.add(windowMenu);
+ addSystemMenuItems(windowMenu);
+ enableActions();
+ }
+
+ protected JMenuBar createSystemMenuBar()
+ {
+ if (menuBar == null)
+ menuBar = new JMenuBar();
+ menuBar.removeAll();
+ return menuBar;
+ }
+
+ protected JMenu createSystemMenu()
+ {
+ if (windowMenu == null)
+ windowMenu = new JMenu();
+ windowMenu.removeAll();
+ return windowMenu;
+ }
+
+ private void addSystemMenuItems(JMenu menu)
+ {
+ // TODO: Implement this.
+ }
+
+ protected void createButtons()
+ {
+ closeButton = new PaneButton(closeAction);
+ closeButton.setText(null);
+ iconButton = new PaneButton(iconifyAction);
+ iconButton.setText(null);
+ maxButton = new PaneButton(maximizeAction);
+ maxButton.setText(null);
+ closeButton.setBorderPainted(false);
+ closeButton.setContentAreaFilled(false);
+ iconButton.setBorderPainted(false);
+ iconButton.setContentAreaFilled(false);
+ maxButton.setBorderPainted(false);
+ maxButton.setContentAreaFilled(false);
+ }
+
+ protected void setButtonIcons()
+ {
+ if (closeIcon != null && closeButton != null)
+ closeButton.setIcon(closeIcon);
+ if (iconIcon != null && iconButton != null)
+ iconButton.setIcon(iconIcon);
+ if (maxIcon != null && maxButton != null)
+ maxButton.setIcon(maxIcon);
+ }
+
+ /**
+ * Paints a representation of the current state of the internal frame.
+ *
+ * @param g the graphics device.
+ */
+ public void paintComponent(Graphics g)
+ {
+ Window frame = SwingUtilities.getWindowAncestor(rootPane);
+ Color savedColor = g.getColor();
+ paintTitleBackground(g);
+ paintChildren(g);
+ Dimension d = getSize();
+ if (frame.isActive())
+ g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
+ else
+ g.setColor(MetalLookAndFeel.getControlDarkShadow());
+
+ // put a dot in each of the top corners
+ g.drawLine(0, 0, 0, 0);
+ g.drawLine(d.width - 1, 0, d.width - 1, 0);
+
+ g.drawLine(0, d.height - 1, d.width - 1, d.height - 1);
+
+ // draw the metal pattern
+ if (UIManager.get("InternalFrame.activeTitleGradient") != null
+ && frame.isActive())
+ {
+ MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(),
+ SwingConstants.VERTICAL,
+ "InternalFrame.activeTitleGradient");
+ }
+
+ Rectangle b = title.getBounds();
+ int startX = b.x + b.width + 5;
+ int endX = startX;
+ if (iconButton.isVisible())
+ endX = Math.max(iconButton.getX(), endX);
+ else if (maxButton.isVisible())
+ endX = Math.max(maxButton.getX(), endX);
+ else if (closeButton.isVisible())
+ endX = Math.max(closeButton.getX(), endX);
+ endX -= 7;
+ if (endX > startX)
+ MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray);
+ g.setColor(savedColor);
+ }
+
+ /**
+ * This method paints the TitlePane's background.
+ *
+ * @param g The Graphics object to paint with.
+ */
+ protected void paintTitleBackground(Graphics g)
+ {
+ Window frame = SwingUtilities.getWindowAncestor(rootPane);
+
+ if (!isOpaque())
+ return;
+
+ Color saved = g.getColor();
+ Dimension dims = getSize();
+
+ Color bg = getBackground();
+ if (frame.isActive())
+ bg = selectedTitleColor;
+ else
+ bg = notSelectedTitleColor;
+ g.setColor(bg);
+ g.fillRect(0, 0, dims.width, dims.height);
+ g.setColor(saved);
+ }
+
+ /**
+ * This method installs the defaults determined by the look and feel.
+ */
+ private void installDefaults()
+ {
+ title.setFont(UIManager.getFont("InternalFrame.titleFont"));
+ selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground");
+ notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground");
+ closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
+ iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon");
+ maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
+ minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16);
+ Frame frame = (Frame) SwingUtilities.getWindowAncestor(rootPane);
+ title = new JLabel(frame.getTitle(),
+ MetalIconFactory.getInternalFrameDefaultMenuIcon(),
+ SwingConstants.LEFT);
+ }
+ }
+
+ private static class MetalRootLayout
+ implements LayoutManager2
+ {
+
+ /**
+ * The cached layout info for the glass pane.
+ */
+ private Rectangle glassPaneBounds;
+
+ /**
+ * The cached layout info for the layered pane.
+ */
+ private Rectangle layeredPaneBounds;
+
+ /**
+ * The cached layout info for the content pane.
+ */
+ private Rectangle contentPaneBounds;
+
+ /**
+ * The cached layout info for the menu bar.
+ */
+ private Rectangle menuBarBounds;
+
+ /**
+ * The cached layout info for the title pane.
+ */
+ private Rectangle titlePaneBounds;
+
+ /**
+ * The cached preferred size.
+ */
+ private Dimension prefSize;
+
+ public void addLayoutComponent(Component component, Object constraints)
+ {
+ // Nothing to do here.
+ }
+
+ public Dimension maximumLayoutSize(Container target)
+ {
+ return preferredLayoutSize(target);
+ }
+
+ public float getLayoutAlignmentX(Container target)
+ {
+ return 0.0F;
+ }
+
+ public float getLayoutAlignmentY(Container target)
+ {
+ return 0.0F;
+ }
+
+ public void invalidateLayout(Container target)
+ {
+ synchronized (this)
+ {
+ glassPaneBounds = null;
+ layeredPaneBounds = null;
+ contentPaneBounds = null;
+ menuBarBounds = null;
+ titlePaneBounds = null;
+ prefSize = null;
+ }
+ }
+
+ public void addLayoutComponent(String name, Component component)
+ {
+ // Nothing to do here.
+ }
+
+ public void removeLayoutComponent(Component component)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ JRootPane rp = (JRootPane) parent;
+ JLayeredPane layeredPane = rp.getLayeredPane();
+ Component contentPane = layeredPane.getComponent(0);
+ Component titlePane = layeredPane.getComponent(1);
+ Component menuBar = null;
+ if (layeredPane.getComponentCount() > 2
+ && layeredPane.getComponent(2) instanceof JMenuBar)
+ menuBar = layeredPane.getComponent(2);
+
+ // We must synchronize here, otherwise we cannot guarantee that the
+ // prefSize is still non-null when returning.
+ synchronized (this)
+ {
+ if (prefSize == null)
+ {
+ Insets i = parent.getInsets();
+ prefSize = new Dimension(i.left + i.right, i.top + i.bottom);
+ Dimension contentPrefSize = contentPane.getPreferredSize();
+ prefSize.width += contentPrefSize.width;
+ prefSize.height += contentPrefSize.height
+ + titlePane.getPreferredSize().height;
+ if (menuBar != null)
+ {
+ Dimension menuBarSize = menuBar.getPreferredSize();
+ if (menuBarSize.width > contentPrefSize.width)
+ prefSize.width += menuBarSize.width - contentPrefSize.width;
+ prefSize.height += menuBarSize.height;
+ }
+ }
+ // Return a copy here so the cached value won't get trashed by some
+ // other component.
+ return new Dimension(prefSize);
+ }
+ }
+
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ return preferredLayoutSize(parent);
+ }
+
+ public void layoutContainer(Container parent)
+ {
+ JRootPane rp = (JRootPane) parent;
+ JLayeredPane layeredPane = rp.getLayeredPane();
+ Component contentPane = layeredPane.getComponent(0);
+ Component titlePane = layeredPane.getComponent(1);
+ Component menuBar = null;
+ if (layeredPane.getComponentCount() > 2
+ && layeredPane.getComponent(2) instanceof JMenuBar)
+ menuBar = layeredPane.getComponent(2);
+ Component glassPane = rp.getGlassPane();
+
+ if (glassPaneBounds == null || layeredPaneBounds == null
+ || contentPaneBounds == null || menuBarBounds == null)
+ {
+ Insets i = rp.getInsets();
+ int containerWidth = parent.getBounds().width - i.left - i.right;
+ int containerHeight = parent.getBounds().height - i.top - i.bottom;
+
+ // 1. The glassPane fills entire viewable region (bounds - insets).
+ // 2. The layeredPane filles entire viewable region.
+ // 3. The titlePane is placed at the upper edge of the layeredPane.
+ // 4. The menuBar is positioned at the upper edge of layeredPane.
+ // 5. The contentPane fills viewable region minus menuBar minus
+ // titlePane, if present.
+
+ // +-------------------------------+
+ // | JLayeredPane |
+ // | +--------------------------+ |
+ // | | titlePane + |
+ // | +--------------------------+ |
+ // | +--------------------------+ |
+ // | | menuBar | |
+ // | +--------------------------+ |
+ // | +--------------------------+ |
+ // | |contentPane | |
+ // | | | |
+ // | | | |
+ // | | | |
+ // | +--------------------------+ |
+ // +-------------------------------+
+
+ // Setup titlePaneBounds.
+ if (titlePaneBounds == null)
+ titlePaneBounds = new Rectangle();
+ titlePaneBounds.width = containerWidth;
+ titlePaneBounds.height = titlePane.getPreferredSize().height;
+
+ // Setup menuBarBounds.
+ if (menuBarBounds == null)
+ menuBarBounds = new Rectangle();
+ menuBarBounds.setBounds(0,
+ titlePaneBounds.y + titlePaneBounds.height,
+ containerWidth, 0);
+ if (menuBar != null)
+ {
+ Dimension menuBarSize = menuBar.getPreferredSize();
+ if (menuBarSize.height > containerHeight)
+ menuBarBounds.height = containerHeight;
+ else
+ menuBarBounds.height = menuBarSize.height;
+ }
+
+ // Setup contentPaneBounds.
+ if (contentPaneBounds == null)
+ contentPaneBounds = new Rectangle();
+ contentPaneBounds.setBounds(0,
+ menuBarBounds.y + menuBarBounds.height,
+ containerWidth,
+ containerHeight - menuBarBounds.y
+ - menuBarBounds.height);
+ glassPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
+ layeredPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
+ }
+
+ // Layout components.
+ glassPane.setBounds(glassPaneBounds);
+ layeredPane.setBounds(layeredPaneBounds);
+ if (menuBar != null)
+ menuBar.setBounds(menuBarBounds);
+ contentPane.setBounds(contentPaneBounds);
+ titlePane.setBounds(titlePaneBounds);
+ }
+
+ }
+
+ /**
+ * The shared UI instance for MetalRootPaneUIs.
+ */
private static MetalRootPaneUI instance = null;
/**
@@ -78,4 +897,84 @@ public class MetalRootPaneUI
instance = new MetalRootPaneUI();
return instance;
}
+
+ /**
+ * Installs this UI to the root pane. If the
+ * <code>windowDecorationsStyle</code> property is set on the root pane,
+ * the Metal window decorations are installed on the root pane.
+ *
+ * @param c
+ */
+ public void installUI(JComponent c)
+ {
+ super.installUI(c);
+ JRootPane rp = (JRootPane) c;
+ if (rp.getWindowDecorationStyle() != JRootPane.NONE)
+ installWindowDecorations(rp);
+ }
+
+ /**
+ * Uninstalls the UI from the root pane. This performs the superclass
+ * behaviour and uninstalls the window decorations that have possibly been
+ * installed by {@link #installUI}.
+ *
+ * @param c the root pane
+ */
+ public void uninstallUI(JComponent c)
+ {
+ JRootPane rp = (JRootPane) c;
+ if (rp.getWindowDecorationStyle() != JRootPane.NONE)
+ uninstallWindowDecorations(rp);
+ super.uninstallUI(c);
+ }
+
+ /**
+ * Receives notification if any of the JRootPane's property changes. In
+ * particular this catches changes to the <code>windowDecorationStyle</code>
+ * property and installs the window decorations accordingly.
+ *
+ * @param ev the property change event
+ */
+ public void propertyChange(PropertyChangeEvent ev)
+ {
+ String propertyName = ev.getPropertyName();
+ if (propertyName.equals("windowDecorationStyle"))
+ {
+ JRootPane rp = (JRootPane) ev.getSource();
+ if (rp.getWindowDecorationStyle() != JRootPane.NONE)
+ installWindowDecorations(rp);
+ else
+ uninstallWindowDecorations(rp);
+ }
+ }
+
+ /**
+ * Installs the window decorations to the root pane. This sets up a border,
+ * a title pane and a layout manager that can layout the root pane with that
+ * title pane.
+ *
+ * @param rp the root pane.
+ */
+ private void installWindowDecorations(JRootPane rp)
+ {
+ rp.setBorder(new MetalFrameBorder());
+ rp.setLayout(new MetalRootLayout());
+ // We should have a contentPane already.
+ assert rp.getLayeredPane().getComponentCount() == 1
+ : "We should have a contentPane already";
+ rp.getLayeredPane().add(new MetalTitlePane(rp),
+ JLayeredPane.FRAME_CONTENT_LAYER);
+ }
+
+ /**
+ * Uninstalls the window decorations from the root pane. This should rarely
+ * be necessary, but we do it anyway.
+ *
+ * @param rp the root pane
+ */
+ private void uninstallWindowDecorations(JRootPane rp)
+ {
+ rp.setBorder(null);
+ rp.getLayeredPane().remove(1);
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java
index 0ff501f89a9..155bb814689 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java
@@ -41,6 +41,7 @@ package javax.swing.plaf.metal;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -48,6 +49,7 @@ import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JScrollBar;
+import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
@@ -465,11 +467,60 @@ public class MetalScrollBarUI extends BasicScrollBarUI
*/
protected Dimension getMinimumThumbSize()
{
- if (isFreeStanding)
- return MIN_THUMB_SIZE_FREE_STANDING;
+ Dimension retVal;
+ if (scrollbar != null)
+ {
+ if (isFreeStanding)
+ retVal = MIN_THUMB_SIZE_FREE_STANDING;
+ else
+ retVal = MIN_THUMB_SIZE;
+ }
else
- return MIN_THUMB_SIZE;
+ retVal = new Dimension(0, 0);
+ return retVal;
}
-
+
+ /**
+ * Returns the <code>preferredSize</code> for the specified scroll bar.
+ * For a vertical scrollbar the height is the sum of the preferred heights
+ * of the buttons plus <code>30</code>. The width is fetched from the
+ * <code>UIManager</code> property <code>ScrollBar.width</code>.
+ *
+ * For horizontal scrollbars the width is the sum of the preferred widths
+ * of the buttons plus <code>30</code>. The height is fetched from the
+ * <code>UIManager</code> property <code>ScrollBar.height</code>.
+ *
+ * @param c the scrollbar for which to calculate the preferred size
+ *
+ * @return the <code>preferredSize</code> for the specified scroll bar
+ */
+ public Dimension getPreferredSize(JComponent c)
+ {
+ int height;
+ int width;
+ height = width = 0;
+
+ if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
+ {
+ width += incrButton.getPreferredSize().getWidth();
+ width += decrButton.getPreferredSize().getWidth();
+ width += 30;
+ height = UIManager.getInt("ScrollBar.width");
+ }
+ else
+ {
+ height += incrButton.getPreferredSize().getHeight();
+ height += decrButton.getPreferredSize().getHeight();
+ height += 30;
+ width = UIManager.getInt("ScrollBar.width");
+ }
+
+ Insets insets = scrollbar.getInsets();
+
+ height += insets.top + insets.bottom;
+ width += insets.left + insets.right;
+
+ return new Dimension(width, height);
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java
index 34a964cb339..9c592bd5116 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java
@@ -42,11 +42,13 @@ import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import javax.swing.JSplitPane;
import javax.swing.SwingConstants;
+import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
@@ -93,6 +95,12 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider
public void paint(Graphics g)
{
Dimension s = getSize();
+
+ // Paint border if one exists.
+ Border border = getBorder();
+ if (border != null)
+ border.paintBorder(this, g, 0, 0, s.width, s.height);
+
MetalUtils.fillMetalPattern(splitPane, g, 2, 2, s.width - 4, s.height - 4,
light, dark);
if (splitPane.isOneTouchExpandable())
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java
index 50112ce2161..b9d5ea76434 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package javax.swing.plaf.metal;
+import gnu.classpath.SystemProperties;
+
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
@@ -88,7 +90,8 @@ class MetalUtils
static void fillMetalPattern(Component c, Graphics g, int x, int y, int w, int h,
Color light, Color dark)
{
- if (g instanceof Graphics2D)
+ if (g instanceof Graphics2D
+ && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") != null)
fillMetalPattern2D((Graphics2D) g, x, y, w, h, light, dark);
else
{
diff --git a/libjava/classpath/javax/swing/plaf/synth/ColorType.java b/libjava/classpath/javax/swing/plaf/synth/ColorType.java
new file mode 100644
index 00000000000..954e309e1d6
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/ColorType.java
@@ -0,0 +1,130 @@
+/* ColorType.java -- En enumeration of color types
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+/**
+ * A typesafe enumeration of color types.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public class ColorType
+{
+
+ /**
+ * A constant used to identify the foreground color of a component.
+ */
+ public static final ColorType FOREGROUND = new ColorType("Foreground");
+
+ /**
+ * A constant used to identify the background color of a component.
+ */
+ public static final ColorType BACKGROUND = new ColorType("Background");
+
+ /**
+ * A constant used to identify the foreground color of text of a component.
+ */
+ public static final ColorType TEXT_FOREGROUND
+ = new ColorType("TextForeground");
+
+ /**
+ * A constant used to identify the background color of text of a component.
+ */
+ public static final ColorType TEXT_BACKGROUND
+ = new ColorType("TextBackground");
+
+ /**
+ * A constant used to identify the focus color of a component.
+ */
+ public static final ColorType FOCUS = new ColorType("Focus");
+
+ /**
+ * The maximum number of color types.
+ */
+ public static final int MAX_COUNT = 5;
+
+ /**
+ * A counter used to assign an ID to the created color types.
+ */
+ private static int count = 0;
+
+ /**
+ * The ID of the color type.
+ */
+ private int id;
+
+ /**
+ * The description of the color type.
+ */
+ private String description;
+
+ /**
+ * Creates a new <code>Color</code> color type with the specified
+ * description.
+ *
+ * @param desc the textual description of the color type
+ */
+ protected ColorType(String desc)
+ {
+ description = desc;
+ id = count;
+ count++;
+ }
+
+ /**
+ * Returns the unique ID of the color type.
+ *
+ * @return the unique ID of the color type
+ */
+ public final int getID()
+ {
+ return id;
+ }
+
+ /**
+ * Returns the textual description of the color type.
+ *
+ * @return the textual description of the color type
+ */
+ public String toString()
+ {
+ return description;
+ }
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/Region.java b/libjava/classpath/javax/swing/plaf/synth/Region.java
new file mode 100644
index 00000000000..7ede65fc87b
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/Region.java
@@ -0,0 +1,474 @@
+/* Region.java -- Describes a region within a component
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+/**
+ * Describes a region of a component or the complete component.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public class Region
+{
+
+ // FIXME: What should ui be for the non-component regions that have
+ // subregion==false?
+
+ /**
+ * Specifies an arrow button region.
+ */
+ public static final Region ARROW_BUTTON =
+ new Region("ArrowButton", null, false);
+
+ /**
+ * Specifies the region of a standard button.
+ */
+ public static final Region BUTTON =
+ new Region("Button", "ButtonUI", false);
+
+ /**
+ * Specifies the region of a check box.
+ */
+ public static final Region CHECK_BOX =
+ new Region("CheckBox", "CheckBoxUI", false);
+
+ /**
+ * Specifies the region of a check box menu item.
+ */
+ public static final Region CHECK_BOX_MENU_ITEM =
+ new Region("CheckBoxMenuItem", "CheckBoxMenuItemUI", false);
+
+ /**
+ * Specifies the region of a colorchooser.
+ */
+ public static final Region COLOR_CHOOSER =
+ new Region("ColorChooser", "ColorChooserUI", false);
+
+ /**
+ * Specifies the region of a combo box.
+ */
+ public static final Region COMBO_BOX =
+ new Region("ComboBox", "ComboBoxUI", false);
+
+ /**
+ * Specifies the region of a desktop pane.
+ */
+ public static final Region DESKTOP_PANE =
+ new Region("DesktopPane", "DesktopPaneUI", false);
+
+ /**
+ * Specifies the region of a desktop icon.
+ */
+ public static final Region DESKTOP_ICON =
+ new Region("DesktopIcon", "DesktopIconUI", false);
+
+ /**
+ * Specifies the region of an editor pane.
+ */
+ public static final Region EDITOR_PANE =
+ new Region("EditorPane", "EditorPaneUI", false);
+
+ /**
+ * Specifies the region of a file chooser.
+ */
+ public static final Region FILECHOOSER =
+ new Region("FileChooser", "FileChooserUI", false);
+
+ /**
+ * Specifies the region of a formatted text field.
+ */
+ public static final Region FormattedTextField =
+ new Region("FormattedTextField", "FormattedTextFieldUI", false);
+
+ /**
+ * Specifies the region of an internal frame.
+ */
+ public static final Region INTERNAL_FRAME =
+ new Region("InternalFrame", "InternalFrameUI", false);
+
+ /**
+ * Specifies the region of the title pane of an internal frame.
+ */
+ public static final Region INTERNAL_FRAME_TITLE_PANE =
+ new Region("InternalFrameTitlePane", "InternalFrameTitlePaneUI", false);
+
+ /**
+ * Specifies the region of a label.
+ */
+ public static final Region LABEL =
+ new Region("Label", "LabelUI", false);
+
+ /**
+ * Specifies the region of a list.
+ */
+ public static final Region LIST =
+ new Region("List", "ListUI", false);
+
+ /**
+ * Specifies the region of a menu.
+ */
+ public static final Region MENU =
+ new Region("Menu", "MenuUI", false);
+
+ /**
+ * Specifies the region of a menu bar.
+ */
+ public static final Region MENU_BAR =
+ new Region("MenuBar", "MenuBarUI", false);
+
+ /**
+ * Specifies the region of a menu item.
+ */
+ public static final Region MENU_ITEM =
+ new Region("MenuItem", "MenuItemUI", false);
+
+ /**
+ * Specifies the region of a menu item accelerator. This is a subregion
+ * of menu item.
+ */
+ public static final Region MENU_ITEM_ACCELERATOR =
+ new Region("MenuItemAccelerator", null, true);
+
+ /**
+ * Specifies the region of an option pane.
+ */
+ public static final Region OPTION_PANE =
+ new Region("OptionPane", "OptionPaneUI", false);
+
+ /**
+ * Specifies the region of a panel.
+ */
+ public static final Region PANEL =
+ new Region("Panel", "PanelUI", false);
+
+ /**
+ * Specifies the region of a password field.
+ */
+ public static final Region PASSWORD_FIELD =
+ new Region("PasswordField", "PasswordFieldUI", false);
+
+ /**
+ * Specifies the region of a popup menu.
+ */
+ public static final Region POPUP_MENU =
+ new Region("PopupMenu", "PopupMenuUI", false);
+
+ /**
+ * Specifies the region of a popup menu separator.
+ */
+ public static final Region POPUP_MENU_SEPARATOR =
+ new Region("PopupMenuSeparator", null, false);
+
+ /**
+ * Specifies the region of a progress bar.
+ */
+ public static final Region PROGRESS_BAR =
+ new Region("ProgressBar", "ProgressBarUI", false);
+
+ /**
+ * Specifies the region of a radio button.
+ */
+ public static final Region RADIO_BUTTON =
+ new Region("RadioButton", "RadioButtonUI", false);
+
+ /**
+ * Specifies the region of a radio button menu item.
+ */
+ public static final Region RADIO_BUTTON_MENU_ITEM =
+ new Region("RadioButtonMenuItem", "RadioButtonMenuItemUI", false);
+
+ /**
+ * Specifies the region of a root pane.
+ */
+ public static final Region ROOT_PANE =
+ new Region("RootPane", "RootPaneUI", false);
+
+ /**
+ * Specifies the region of a scroll bar.
+ */
+ public static final Region SCROLL_BAR =
+ new Region("ScrollBar", "ScrollBarUI", false);
+
+ /**
+ * Specifies the region of a scroll bar track. This is a subregion of
+ * scroll bars.
+ */
+ public static final Region SCROLL_BAR_TRACK =
+ new Region("ScrollBarTrack", null, true);
+
+ /**
+ * Specifies the region of a scroll bar thumb. This is a subregion of
+ * scroll bars.
+ */
+ public static final Region SCROLL_BAR_THUMB =
+ new Region("ScrollBarThumb", null, true);
+
+ /**
+ * Specifies the region of a scroll pane.
+ */
+ public static final Region SCROLL_PANE =
+ new Region("ScrollPane", "ScrollPaneUI", false);
+
+ /**
+ * Specifies the region of a separator.
+ */
+ public static final Region SEPARATOR =
+ new Region("Separator", "SeparatorUI", false);
+
+ /**
+ * Specifies the region of a slider.
+ */
+ public static final Region SLIDER =
+ new Region("Slider", "SliderUI", false);
+
+ /**
+ * Specifies the region of a slider track. This is a subregion of a slider.
+ */
+ public static final Region SLIDER_TRACK =
+ new Region("SliderTrack", null, true);
+
+ /**
+ * Specifies the region of a slider thumb. This is a subregion of a slider.
+ */
+ public static final Region SLIDER_THUMB =
+ new Region("SliderThumb", null, true);
+
+ /**
+ * Specifies the region of a spinner.
+ */
+ public static final Region SPINNER =
+ new Region("Spinner", "SpinnerUI", false);
+
+ /**
+ * Specifies the region of a split pane.
+ */
+ public static final Region SPLIT_PANE =
+ new Region("SplitPane", "SplitPaneUI", false);
+
+ /**
+ * Specifies the region of a split pane divider. This is a subregion of
+ * a split pane.
+ */
+ public static final Region SPLIT_PANE_DIVIDER =
+ new Region("SplitPaneDivider", null, true);
+
+ /**
+ * Specifies the region of a tabbed pane.
+ */
+ public static final Region TABBED_PANE =
+ new Region("TabbedPane", "TabbedPaneUI", false);
+
+ /**
+ * This specifies the region of a tab of a tabbed pane. This is a subregion
+ * of a tabbed pane.
+ */
+ public static final Region TABBED_PANE_TAB =
+ new Region("TabbedPaneTab", null, true);
+
+ /**
+ * This specifies the region underneath the tabs of a tabbed pane. This is a
+ * subregion of a tabbed pane.
+ */
+ public static final Region TABBED_PANE_TAB_AREA =
+ new Region("TabbedPaneTabArea", null, true);
+
+ /**
+ * This specifies the region for the content of a tabbed pane. This is a
+ * subregion of a tabbed pane.
+ */
+ public static final Region TABBED_PANE_CONTENT =
+ new Region("TabbedPaneContent", null, true);
+
+ /**
+ * Specifies the region of a table.
+ */
+ public static final Region TABLE =
+ new Region("Table", "TableUI", false);
+
+ /**
+ * Specifies the region of a table header.
+ */
+ public static final Region TABLE_HEADER =
+ new Region("TableHeader", "TableHeaderUI", false);
+
+ /**
+ * Specifies the region of a text area.
+ */
+ public static final Region TEXT_AREA =
+ new Region("TextArea", "TextAreaUI", false);
+
+ /**
+ * Specifies the region of a text field.
+ */
+ public static final Region TEXT_FIELD =
+ new Region("TextField", "TextFieldUI", false);
+
+ /**
+ * Specifies the region of a text pane.
+ */
+ public static final Region TEXT_PANE =
+ new Region("TextPane", "TextPaneUI", false);
+
+ /**
+ * Specifies the region of a toggle button.
+ */
+ public static final Region TOGGLE_BUTTON =
+ new Region("ToggleButton", "ToggleButtonUI", false);
+
+ /**
+ * Specifies the region of a tool bar.
+ */
+ public static final Region TOOL_BAR =
+ new Region("ToolBar", "ToolBarUI", false);
+
+ /**
+ * Specifies the content region of a tool bar. This is a subregion of a tool
+ * bar.
+ */
+ public static final Region TOOL_BAR_CONTENT =
+ new Region("ToolBarContent", null, true);
+
+ /**
+ * Specifies the drag window region of a tool bar. This is a subregion of a
+ * tool bar.
+ */
+ public static final Region TOOL_BAR_DRAG_WINDOW =
+ new Region("ToolBarDragWindow", null, false);
+
+ /**
+ * Specifies the region of a tool tip.
+ */
+ public static final Region TOOL_TIP =
+ new Region("ToolTip", "ToolTipUI", false);
+
+ /**
+ * Specifies the region of a separator of a tool bar. This is a subregion of
+ * a tool bar.
+ */
+ public static final Region TOOL_BAR_SEPARATOR =
+ new Region("ToolBarSeparator", null, false);
+
+ /**
+ * Specifies the region of a tree.
+ */
+ public static final Region TREE =
+ new Region("Tree", "TreeUI", false);
+
+ /**
+ * Specifies the region of a tree cell. This is a subregion of a tree.
+ */
+ public static final Region TREE_CELL =
+ new Region("TreeCell", null, true);
+
+ /**
+ * Specifies the region of a viewport.
+ */
+ public static final Region VIEWPORT =
+ new Region("Viewport", "ViewportUI", false);
+
+
+ /**
+ * The UI class id for the region. This is package private because this will
+ * be used by other classes in that package.
+ */
+ String ui;
+
+ /**
+ * The name of the region.
+ */
+ private String name;
+
+ /**
+ * If this region is a subregion or not.
+ */
+ private boolean subregion;
+
+ /**
+ * Creates a new <code>Region</code> with the specified name and ui ID.
+ * The <code>ui</code> must be the same what
+ * {@link javax.swing.JComponent#getUIClassID()} returns for toplevel regions. For
+ * subregions this should be <code>null</code>.
+ *
+ * @param name the name of the region
+ * @param ui the UI class ID of the region or <code>null</code> for
+ * subregions
+ * @param subregion <code>true</code> if this region is a subregion,
+ * <code>false</code> otherwise
+ */
+ protected Region(String name, String ui, boolean subregion)
+ {
+ this.name = name;
+ this.ui = ui;
+ this.subregion = subregion;
+ }
+
+ /**
+ * Returns <code>true</code> if this region describes a subregion of a
+ * component, <code>false</code> if it describes a component region itself.
+ *
+ * @return <code>true</code> if this region describes a subregion of a
+ * component, <code>false</code> if it describes a component region
+ * itself
+ */
+ public boolean isSubregion()
+ {
+ return subregion;
+ }
+
+ /**
+ * Returns the name of the region.
+ *
+ * @return the name of the region
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns the name of the region.
+ *
+ * @return the name of the region
+ */
+ public String toString()
+ {
+ return name;
+ }
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthConstants.java b/libjava/classpath/javax/swing/plaf/synth/SynthConstants.java
new file mode 100644
index 00000000000..306024c00b0
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/SynthConstants.java
@@ -0,0 +1,85 @@
+/* SynthConstants.java -- A couple of constants used by Synth
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+/**
+ * A couple of constants used by the Synth Look and Feel.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public interface SynthConstants
+{
+ /**
+ * A primary state indicating that a component is enabled.
+ */
+ static final int ENABLED = 1;
+
+ /**
+ * A primary state indicating that a component is disabled.
+ */
+ static final int DISABLED = 8;
+
+ /**
+ * A primary state indicating that the mouse is over a region.
+ */
+ static final int MOUSE_OVER = 2;
+
+ /**
+ * A primary state indicating that the component is in a pressed state (which
+ * does not necessarily mean that the mouse is pressed over the component).
+ */
+ static final int PRESSED = 4;
+
+ /**
+ * Indicates that a region has focus.
+ */
+ static final int FOCUSED = 256;
+
+ /**
+ * Indicates that a region is selected.
+ */
+ static final int SELECTED = 512;
+
+ /**
+ * Indicates that a region is in its default state.
+ */
+ static final int DEFAULT = 1024;
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthContext.java b/libjava/classpath/javax/swing/plaf/synth/SynthContext.java
new file mode 100644
index 00000000000..83536dae948
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/SynthContext.java
@@ -0,0 +1,134 @@
+/* SynthContext.java -- Contextual information about a region
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+import javax.swing.JComponent;
+
+/**
+ * Contains some contextual information about a region. The information passed
+ * in objects of this class can only be considered valid during the method call
+ * that it was passed to.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public class SynthContext
+{
+
+ /**
+ * The component.
+ */
+ private JComponent component;
+
+ /**
+ * The region of the component.
+ */
+ private Region region;
+
+ /**
+ * The style of the component.
+ */
+ private SynthStyle style;
+
+ /**
+ * The state of the component.
+ */
+ private int state;
+
+ /**
+ * Creates a new <code>SynthContext</code> object.
+ *
+ * @param component the component for which this context is used
+ * @param region the region of the component
+ * @param style the style associated with the component
+ * @param state a or'ed bitmask of the constants from {@link SynthConstants}
+ */
+ public SynthContext(JComponent component, Region region, SynthStyle style,
+ int state)
+ {
+ this.component = component;
+ this.region = region;
+ this.style = style;
+ this.state = state;
+ }
+
+ /**
+ * Returns the component that contains the region.
+ *
+ * @return the component that contains the region
+ */
+ public JComponent getComponent()
+ {
+ return component;
+ }
+
+ /**
+ * Returns the region that identifies this state.
+ *
+ * @return the region that identifies this state
+ */
+ public Region getRegion()
+ {
+ return region;
+ }
+
+ /**
+ * Returns the style of the region.
+ *
+ * @return the style of the region
+ */
+ public SynthStyle getStyle()
+ {
+ return style;
+ }
+
+ /**
+ * Returns the state of the component. This is a or'ed bitmask of the
+ * constants defined in {@link SynthConstants}.
+ *
+ * @return the state of the component
+ *
+ * @see SynthConstants
+ */
+ public int getComponentState()
+ {
+ return state;
+ }
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java
new file mode 100644
index 00000000000..a68b6f6ec2f
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java
@@ -0,0 +1,283 @@
+/* SynthGraphicsUtils.java -- Wrapper for graphics primitives used in Synth
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+import javax.swing.Icon;
+import javax.swing.SwingUtilities;
+
+/**
+ * Wrapper for graphics primitives used in Synth.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public class SynthGraphicsUtils
+
+{
+ /**
+ * Creates a new <code>SynthGraphicsUtils</code> object.
+ */
+ public SynthGraphicsUtils()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Draws a line from (x1,y1) to (x2,y2).
+ *
+ * @param ctx the synth context, identifies the region
+ * @param paintKey identifies the portion of the component to be painted, may
+ * be <code>null</code>
+ * @param g the graphics context to use for painting
+ * @param x1 the x coordinate of the start point
+ * @param y1 the y coordinate of the start point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public void drawLine(SynthContext ctx, Object paintKey, Graphics g, int x1,
+ int y1, int x2, int y2)
+ {
+ // TODO: Correct?
+ g.drawLine(x1, y1, x2, y2);
+ }
+
+ /**
+ * Lays out a label and (if non-null) an icon. The calculated coordinates are
+ * then stored in <code>viewR</code>, <code>iconR</code> and
+ * <code>textR</code>.
+ *
+ * The alignment and position parameters may be one of the alignment or
+ * position constants defined in {@link javax.swing.SwingConstants}.
+ *
+ * @param ctx the synth context, identifies the current region
+ * @param fm the font metrics to use to fetch the text measures
+ * @param text the text to lay out, may be <code>null</code>
+ * @param icon the icon to lay out, may be <code>null</code>
+ * @param hAlign the horizontal alignment of the label
+ * @param vAlign the vertical alignment of the label
+ * @param hTextPos the horizontal text position
+ * @param vTextPos the vertical text position
+ * @param viewR the view rectangle (return parameter)
+ * @param iconR the icon rectangle (return parameter)
+ * @param textR the text rectangle (return parameter)
+ * @param iconTextGap the gap between text and label
+ *
+ * @return the label text, may be shortened
+ */
+ public String layoutText(SynthContext ctx, FontMetrics fm, String text,
+ Icon icon, int hAlign, int vAlign, int hTextPos,
+ int vTextPos, Rectangle viewR, Rectangle iconR,
+ Rectangle textR, int iconTextGap)
+ {
+ return SwingUtilities.layoutCompoundLabel(fm, text, icon, vAlign, hAlign,
+ vTextPos, hTextPos, viewR, iconR,
+ textR, iconTextGap);
+ }
+
+ /**
+ * Returns the width of the string <code>text</code> for the specified font
+ * and font metrics.
+ *
+ * @param ctx identifies the current region
+ * @param font the font
+ * @param fm the font metrics to use
+ * @param text the text to be measured
+ *
+ * @return the width of the string <code>text</code> for the specified font
+ * and font metrics
+ */
+ public int computeStringWidth(SynthContext ctx, Font font, FontMetrics fm,
+ String text)
+ {
+ return fm.stringWidth(text);
+ }
+
+ /**
+ * Calculates the minimums size that is needed to render the label with
+ * <code>text</code> and <code>icon</code> correctly.
+ *
+ * @param ctx identifies the current region
+ * @param font the font to use
+ * @param text the label text
+ * @param icon the label icon
+ * @param hAlign the horizontal alignment
+ * @param vAlign the vertical alignment
+ * @param hTextPosition the horizontal text position
+ * @param vTextPosition the vertical text position
+ * @param iconTextGap the gap between icon and text
+ * @param mnemonicIndex index to the mnemonic character within
+ * <code>text</code>
+ *
+ * @return the minimums size that is needed to render the label with
+ * <code>text</code> and <code>icon</code> correctly
+ */
+ public Dimension getMinimumSize(SynthContext ctx, Font font, String text,
+ Icon icon, int hAlign, int vAlign,
+ int hTextPosition,int vTextPosition,
+ int iconTextGap,int mnemonicIndex)
+ {
+ // FIXME: Implement this correctly.
+ return new Dimension(0, 0);
+ }
+
+ /**
+ * Calculates the preferred size that is needed to render the label with
+ * <code>text</code> and <code>icon</code> correctly.
+ *
+ * @param ctx identifies the current region
+ * @param font the font to use
+ * @param text the label text
+ * @param icon the label icon
+ * @param hAlign the horizontal alignment
+ * @param vAlign the vertical alignment
+ * @param hTextPosition the horizontal text position
+ * @param vTextPosition the vertical text position
+ * @param iconTextGap the gap between icon and text
+ * @param mnemonicIndex index to the mnemonic character within
+ * <code>text</code>
+ *
+ * @return the preferred size that is needed to render the label with
+ * <code>text</code> and <code>icon</code> correctly
+ */
+ public Dimension getPreferredSize(SynthContext ctx, Font font, String text,
+ Icon icon, int hAlign, int vAlign,
+ int hTextPosition,int vTextPosition,
+ int iconTextGap,int mnemonicIndex)
+ {
+ // FIXME: Implement this correctly.
+ return new Dimension(0, 0);
+ }
+
+ /**
+ * Calculates the maximum size that is needed to render the label with
+ * <code>text</code> and <code>icon</code> correctly.
+ *
+ * @param ctx identifies the current region
+ * @param font the font to use
+ * @param text the label text
+ * @param icon the label icon
+ * @param hAlign the horizontal alignment
+ * @param vAlign the vertical alignment
+ * @param hTextPosition the horizontal text position
+ * @param vTextPosition the vertical text position
+ * @param iconTextGap the gap between icon and text
+ * @param mnemonicIndex index to the mnemonic character within
+ * <code>text</code>
+ *
+ * @return the maximum size that is needed to render the label with
+ * <code>text</code> and <code>icon</code> correctly
+ */
+ public Dimension getMaximumSize(SynthContext ctx, Font font, String text,
+ Icon icon, int hAlign, int vAlign,
+ int hTextPosition,int vTextPosition,
+ int iconTextGap,int mnemonicIndex)
+ {
+ // FIXME: Implement this correctly.
+ return new Dimension(0, 0);
+ }
+
+ /**
+ * Returns the maximum character height of the font from the component of the
+ * passed in <code>context</code>.
+ *
+ * @param context identifies the current component and region
+ *
+ * @return the maximum character height of the font from the component of the
+ * passed in <code>context</code>
+ */
+ public int getMaximumCharHeight(SynthContext context)
+ {
+ Component comp = context.getComponent();
+ Font font = comp.getFont();
+ return comp.getFontMetrics(font).getHeight();
+ }
+
+ /**
+ * Renders the specified <code>text</code> within the <code>bounds</code>.
+ *
+ * @param ctx identifies the component and region
+ * @param g the graphics context for drawing the tetx
+ * @param text the text to be rendered
+ * @param bounds the bounds within which the text should be rendered
+ * @param mnemonicIndex the index of the mnemonic character within
+ * <code>text</code>
+ */
+ public void paintText(SynthContext ctx, Graphics g, String text,
+ Rectangle bounds, int mnemonicIndex)
+ {
+ // FIXME: This is very primitive and should be improved to paint the
+ // mnemonic char.
+ g.drawString(text, bounds.x, bounds.y);
+ }
+
+ /**
+ * Renders the specified <code>text</code> at the specified location.
+ *
+ * @param ctx identifies the component and region
+ * @param g the graphics context for drawing the tetx
+ * @param text the text to be rendered
+ * @param x the X location where the text should be rendered
+ * @param y the Y location where the text should be rendered
+ * @param mnemonicIndex the index of the mnemonic character within
+ * <code>text</code>
+ */
+ public void paintText(SynthContext ctx, Graphics g, String text,
+ int x, int y, int mnemonicIndex)
+ {
+ // FIXME: This is very primitive and should be improved to paint the
+ // mnemonic char.
+ g.drawString(text, x, y);
+ }
+
+ public void paintText(SynthContext ctx, Graphics g, String text, Icon icon,
+ int hAlign, int vAlign, int hTextPosition,
+ int vTextPosition, int iconTextGap, int mnemonicIndex,
+ int textOffset)
+ {
+ // FIXME: Implement this correctly.
+ }
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java b/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java
new file mode 100644
index 00000000000..8d0596d416e
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java
@@ -0,0 +1,272 @@
+/* SynthLookAndFeel.java -- A skinnable Swing look and feel
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+import java.awt.Component;
+import java.io.InputStream;
+import java.text.ParseException;
+
+import javax.swing.JComponent;
+import javax.swing.UIDefaults;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicLookAndFeel;
+
+
+/**
+ * A look and feel that can be customized either by providing a file to
+ * {@link #load} or by setting a {@link SynthStyleFactory} using
+ * {@link #setStyleFactory}.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public class SynthLookAndFeel
+ extends BasicLookAndFeel
+{
+
+ /**
+ * The style factory that will be used by the UI classes to load their
+ * style sets from.
+ */
+ private static SynthStyleFactory styleFactory;
+
+ /**
+ * Creates a new instance of <code>SynthLookAndFeel</code>. In order to use
+ * the Synth look and feel you either need to call {@link #load} to load a
+ * set of styles from an XML file, or you need to call
+ * {@link #setStyleFactory} to provide your own style factory.
+ */
+ public SynthLookAndFeel()
+ {
+ // FIXME: What to do here, if anything?
+ }
+
+ /**
+ * Sets the style factory that the UI classes of Synth will use to load their
+ * sets of styles.
+ *
+ * @param sf the style factory to set
+ */
+ public static void setStyleFactory(SynthStyleFactory sf)
+ {
+ styleFactory = sf;
+ }
+
+ /**
+ * Returns the current style factory that the UI classes of Synth will use to
+ * load their sets of styles.
+ *
+ * @return the current style factory
+ */
+ public static SynthStyleFactory getStyleFactory()
+ {
+ return styleFactory;
+ }
+
+ /**
+ * Returns the style for the specified component and region.
+ *
+ * @param c the component for which to return the style
+ * @param r the region of the component for which to return the style
+ *
+ * @return the style for the specified component and region
+ */
+ public static SynthStyle getStyle(JComponent c, Region r)
+ {
+ return getStyleFactory().getStyle(c, r);
+ }
+
+ /**
+ * Updates all style information of the component and it's children.
+ *
+ * @param c the componenent for which to update the style
+ */
+ public static void updateStyles(Component c)
+ {
+ // FIXME: Implement this properly.
+ }
+
+ /**
+ * Returns the region for a given Swing component.
+ *
+ * @param c the Swing component for which to fetch the region
+ *
+ * @return the region for a given Swing component
+ */
+ public static Region getRegion(JComponent c)
+ {
+ // FIXME: This can be implemented as soon as we have the component UI
+ // classes in place, since this region will be matched via the UI classes.
+ return null;
+ }
+
+ /**
+ * Creates the Synth look and feel component UI instance for the given
+ * component.
+ *
+ * @param c the component for which to create a UI instance
+ *
+ * @return the Synth look and feel component UI instance for the given
+ * component
+ */
+ public static ComponentUI createUI(JComponent c)
+ {
+ // FIXME: This can be implemented as soon as we have the component UI
+ // classes in place.
+ return null;
+ }
+
+ /**
+ * Initializes this look and feel.
+ */
+ public void initialize()
+ {
+ super.initialize();
+ // TODO: Implement at least the following here:
+ // if (styleFactory != null)
+ // styleFactory = new DefaultStyleFactory();
+ }
+
+ /**
+ * Uninitializes the look and feel.
+ */
+ public void uninitialize()
+ {
+ super.uninitialize();
+ // TODO: What to do here?
+ }
+
+ /**
+ * Returns the UI defaults of this look and feel.
+ *
+ * @return the UI defaults of this look and feel
+ */
+ public UIDefaults getDefaults()
+ {
+ // FIXME: This is certainly wrong. The defaults should be fetched/merged
+ // from the file from which the l&f is loaded.
+ return super.getDefaults();
+ }
+
+ /**
+ * FIXME: DOCUMENT ME!
+ *
+ * @return FIXME
+ */
+ public boolean shouldUpdateStyleOnAncestorChanged()
+ {
+ return false;
+ }
+
+ /**
+ * Loads a set of {@link SynthStyle}s that are used for the look and feel of
+ * the components. The <code>resourceBase</code> parameter is used to resolve
+ * references against, like icons and other files.
+ *
+ * @param in the input stream from where to load the styles
+ * @param resourceBase the base against which references are resolved.
+ *
+ * @throws ParseException if the input stream cannot be parsed
+ * @throws IllegalArgumentException if one of the parameters is
+ * <code>null</code>
+ */
+ // FIXME: The signature in the JDK has a Class<?> here. Should be fixed as
+ // soon as we switch to the generics branch.
+ public void load(InputStream in, Class resourceBase)
+ throws ParseException, IllegalArgumentException
+ {
+ // FIXME: Implement this correctly.
+ }
+
+ /**
+ * Returns a textual description of the Synth look and feel. This returns
+ * &quot;Synt look and feel&quot;.
+ *
+ * @return a textual description of the Synth look and feel
+ */
+ public String getDescription()
+ {
+ return "Synth look and feel";
+ }
+
+ /**
+ * Returns the ID of the Synth look and feel. This returns &quot;Synth&quot;.
+ *
+ * @return the ID of the Synth look and feel
+ */
+ public String getID()
+ {
+ return "Synth";
+ }
+
+ /**
+ * Returns the name of the Synth look and feel. This returns
+ * &quot;Synt look and feel&quot;.
+ *
+ * @return the name of the Synth look and feel
+ */
+ public String getName()
+ {
+ return "Synth look and feel";
+ }
+
+ /**
+ * Returns <code>false</code> since the Synth look and feel is not a native
+ * look and feel.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isNativeLookAndFeel()
+ {
+ return false;
+ }
+
+ /**
+ * Returns <code>true</code> since the Synth look and feel is always a
+ * supported look and feel.
+ *
+ * @return <code>true</code>
+ */
+ public boolean isSupportedLookAndFeel()
+ {
+ return true;
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java
new file mode 100644
index 00000000000..0d63c6db76f
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java
@@ -0,0 +1,80 @@
+/* SynthPainter.java -- An abstract painter for synth components
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+import java.awt.Graphics;
+
+/**
+ * The abstract definition of a delegate that takes the responsibility of
+ * painting for the components.
+ *
+ * This class is defined to be abstract and all methods are no-ops.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public abstract class SynthPainter
+{
+
+ /**
+ * Creates a new <code>SynthPainter</code> object.
+ */
+ public SynthPainter()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Paints the background of an arrow button.
+ *
+ * @param ctx the synth context identifying the component and region for
+ * painting
+ * @param g the graphics context to use for painting
+ * @param x the X coordinate of the area to paint
+ * @param y the Y coordinate of the area to paint
+ * @param w the width of the area to paint
+ * @param h the height of the area to paint
+ */
+ public void paintArrowButtonBackground(SynthContext ctx, Graphics g, int x,
+ int y, int w, int h)
+ {
+ // Nothing to do here.
+ }
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java b/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java
new file mode 100644
index 00000000000..e0a8dbcc7b9
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java
@@ -0,0 +1,144 @@
+/* SynthStyle.java -- A set of style properties
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Insets;
+
+import javax.swing.Icon;
+
+/**
+ * A set of style properties that can be installed on a component.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.5
+ */
+public abstract class SynthStyle
+{
+
+ /**
+ * Creates a new <code>SynthStyle</code> object.
+ */
+ public SynthStyle()
+ {
+ // FIXME: Implement this correctly.
+ }
+
+ public SynthGraphicsUtils getGraphicsUtils(SynthContext ctx)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+
+ public Color getColor(SynthContext ctx, ColorType type)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+
+ public abstract Color getColorForState(SynthContext ctx, ColorType type);
+
+ public Font getFont(SynthContext ctx)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+
+ public abstract Font getFontForState(SynthContext ctx);
+
+ public Insets getInsets(SynthContext ctx)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+
+ public SynthPainter getPainted(SynthContext ctx)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+
+ public boolean isOpaque(SynthContext ctx)
+ {
+ // FIXME: Implement this correctly.
+ return true;
+ }
+
+ public Object get(SynthContext ctx, Object key)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+
+ public void installDefaults(SynthContext ctx)
+ {
+ // FIXME: Implement this correctly.
+ }
+
+ public void uninstallDefaults(SynthContext ctx)
+ {
+ // FIXME: Implement this correctly.
+ }
+
+ public int getInt(SynthContext ctx, Object key, int defaultValue)
+ {
+ // FIXME: Implement this correctly.
+ return -1;
+ }
+
+ public boolean getBoolean(SynthContext ctx, Object key, boolean defaultValue)
+ {
+ // FIXME: Implement this correctly.
+ return false;
+ }
+
+ public Icon getIcon(SynthContext ctx, Object key)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+
+ public String getString(SynthContext ctx, Object key, String defaultValue)
+ {
+ // FIXME: Implement this correctly.
+ return null;
+ }
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthStyleFactory.java b/libjava/classpath/javax/swing/plaf/synth/SynthStyleFactory.java
new file mode 100644
index 00000000000..569753d8ad7
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/SynthStyleFactory.java
@@ -0,0 +1,64 @@
+/* SynthStyleFactory.java -- A factory for SynthStyles
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.synth;
+
+import javax.swing.JComponent;
+
+public abstract class SynthStyleFactory
+{
+
+ /**
+ * Creates a new <code>SynthStyleFactory</code>.
+ */
+ public SynthStyleFactory()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Returns a {@link SynthStyle} for the specified region of the specified
+ * component.
+ *
+ * @param c the component for which to create a style
+ * @param id the region of the component
+ *
+ * @return a style for the specified region of the specified component
+ */
+ public abstract SynthStyle getStyle(JComponent c, Region id);
+}
diff --git a/libjava/classpath/javax/swing/plaf/synth/package.html b/libjava/classpath/javax/swing/plaf/synth/package.html
new file mode 100644
index 00000000000..b977e468c90
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/synth/package.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in javax.swing.plaf.metal package.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - javax.swing.plaf.synth</title></head>
+
+<body>
+<p>Provides a look and feel that can be customized by and XML file or by
+ providing a custom {@link SynthStyleFactory}.
+</p>
+</body>
+</html>
diff --git a/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java
index 233528c7d67..0d9b62567f6 100644
--- a/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java
+++ b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java
@@ -127,7 +127,8 @@ public class DefaultTableCellRenderer extends JLabel
* Get the string value of the object and pass it to setText().
*
* @param table the JTable
- * @param value the value of the object
+ * @param value the value of the object. For the text content,
+ * null is rendered as an empty cell.
* @param isSelected is the cell selected?
* @param hasFocus has the cell the focus?
* @param row the row to render
@@ -140,13 +141,7 @@ public class DefaultTableCellRenderer extends JLabel
boolean hasFocus,
int row, int column)
{
- if (value != null)
- {
- if (value instanceof JTextField)
- return new JTextField(((JTextField)value).getText());
- super.setText(value.toString());
- }
-
+ setValue(value);
setOpaque(true);
if (table == null)
@@ -274,6 +269,10 @@ public class DefaultTableCellRenderer extends JLabel
*/
protected void setValue(Object value)
{
- super.setText((value!=null) ? value.toString() : "");
+ if (value != null)
+ setText(value.toString());
+ else
+ // null is rendered as an empty cell.
+ setText("");
}
}
diff --git a/libjava/classpath/javax/swing/table/DefaultTableModel.java b/libjava/classpath/javax/swing/table/DefaultTableModel.java
index 6844f2a27ec..c281caa0791 100644
--- a/libjava/classpath/javax/swing/table/DefaultTableModel.java
+++ b/libjava/classpath/javax/swing/table/DefaultTableModel.java
@@ -486,7 +486,10 @@ public class DefaultTableModel extends AbstractTableModel
}
/**
- * Returns the name of the specified column.
+ * Get the name of the column. If the column has the column identifier set,
+ * the return value is the result of the .toString() method call on that
+ * identifier. If the identifier is not explicitly set, the returned value
+ * is calculated by {@link AbstractTableModel#getColumnName(int)}.
*
* @param column the column index.
*
diff --git a/libjava/classpath/javax/swing/table/JTableHeader.java b/libjava/classpath/javax/swing/table/JTableHeader.java
index 163509a45c2..4e8dcd7b7ef 100644
--- a/libjava/classpath/javax/swing/table/JTableHeader.java
+++ b/libjava/classpath/javax/swing/table/JTableHeader.java
@@ -67,6 +67,11 @@ import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.plaf.TableHeaderUI;
+/**
+ * Represents the table header. The header displays the column header values,
+ * is always visible event if the rest of the table scrolls up and down and
+ * supports column reordering and resizing with mouse.
+ */
public class JTableHeader extends JComponent
implements TableColumnModelListener, Accessible
{
@@ -306,7 +311,10 @@ public class JTableHeader extends JComponent
}
};
}
-
+
+ /**
+ * Use serialVersionUid for interoperability.
+ */
private static final long serialVersionUID = 5144633983372967710L;
/**
@@ -409,9 +417,10 @@ public class JTableHeader extends JComponent
}
/**
- * Get the value of the {@link #draggedColumn} property.
+ * Get the column that is currently being dragged. This is used when
+ * handling the column reordering with mouse.
*
- * @return The current value of the property
+ * @return the column being dragged, null if none.
*/
public TableColumn getDraggedColumn()
{
@@ -429,29 +438,34 @@ public class JTableHeader extends JComponent
}
/**
- * Get the value of the {@link #reorderingAllowed} property.
+ * Check if it is possible to reorder the table columns by dragging column
+ * header with mouse. The table reordering is enabled by default, but can be
+ * disabled with {@link #setReorderingAllowed(boolean)}.
*
- * @return The current value of the property
- */
+ * @return true if reordering is allowed, false otherwise.
+ */
public boolean getReorderingAllowed()
{
return reorderingAllowed;
}
/**
- * Get the value of the {@link #resizingAllowed} property.
+ * Check if it is possible to resize the table columns by dragging the column
+ * boundary in the table header with mouse. The resizing is enabled
+ * by default, but can be disabled with {@link #setResizingAllowed(boolean)}.
*
- * @return The current value of the property
- */
+ * @return true if resizing is allowed, false otherwise.
+ */
public boolean getResizingAllowed()
{
return resizingAllowed;
}
/**
- * Get the value of the {@link #resizingColumn} property.
+ * Get the column that is currently being resized. This is used when
+ * handling the column resizing with mouse.
*
- * @return The current value of the property
+ * @return the column being currently resized, null if none.
*/
public TableColumn getResizingColumn()
{
@@ -459,9 +473,9 @@ public class JTableHeader extends JComponent
}
/**
- * Get the value of the {@link #table} property.
+ * Get the table, having this header.
*
- * @return The current value of the property
+ * @return the table, having this header.
*/
public JTable getTable()
{
@@ -501,13 +515,15 @@ public class JTableHeader extends JComponent
}
/**
- * Set the value of the {@link #draggedColumn} property.
+ * Set the column that is currently being dragged. This is used when
+ * dragging the column with mouse. Setting to null will stop the
+ * dragging session immediately.
*
- * @param d The new value of the property
+ * @param draggingIt the column being currently dragged, null if none.
*/
- public void setDraggedColumn(TableColumn d)
+ public void setDraggedColumn(TableColumn draggingIt)
{
- draggedColumn = d;
+ draggedColumn = draggingIt;
}
/**
@@ -531,33 +547,39 @@ public class JTableHeader extends JComponent
}
/**
- * Set the value of the {@link #reorderingAllowed} property.
+ * Set the table ability to reorder columns by dragging column header
+ * with mouse. The table reordering is enabled by default, but can be
+ * disabled with this method.
*
- * @param r The new value of the property
+ * @param allowed true if reordering is allowed, false otherwise.
*/
- public void setReorderingAllowed(boolean r)
+ public void setReorderingAllowed(boolean allowed)
{
- reorderingAllowed = r;
+ reorderingAllowed = allowed;
}
/**
- * Set the value of the {@link #resizingAllowed} property.
+ * Set the table ability to resize columns by dragging the column
+ * boundary in the table header with mouse. The resizing is enabled
+ * by default, but can be disabled using this method.
*
- * @param r The new value of the property
+ * @param allowed true if resizing is allowed, false otherwise.
*/
- public void setResizingAllowed(boolean r)
+ public void setResizingAllowed(boolean allowed)
{
- resizingAllowed = r;
+ resizingAllowed = allowed;
}
/**
- * Set the value of the {@link #resizingColumn} property.
+ * The the column that is currently being resized. This property is used
+ * when handling table resizing with mouse. Setting to null would stop
+ * the resizing session immediately.
*
- * @param r The new value of the property
+ * @param resizingIt the column being currently resized
*/
- public void setResizingColumn(TableColumn r)
+ public void setResizingColumn(TableColumn resizingIt)
{
- resizingColumn = r;
+ resizingColumn = resizingIt;
}
/**
@@ -609,7 +631,14 @@ public class JTableHeader extends JComponent
{
this.cellRenderer = cellRenderer;
}
-
+
+ /**
+ * Get the rectangle, occupied by the header of the given column.
+ *
+ * @param column the column, for that the header area is requested.
+ *
+ * @return the column header area.
+ */
public Rectangle getHeaderRect(int column)
{
Rectangle r = getTable().getCellRect(-1, column, false);
diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java
index c7353885e12..a3e8c463bd3 100644
--- a/libjava/classpath/javax/swing/text/AbstractDocument.java
+++ b/libjava/classpath/javax/swing/text/AbstractDocument.java
@@ -538,18 +538,24 @@ public abstract class AbstractDocument implements Document, Serializable
DefaultDocumentEvent event =
new DefaultDocumentEvent(offset, text.length(),
DocumentEvent.EventType.INSERT);
-
- writeLock();
- UndoableEdit undo = content.insertString(offset, text);
- if (undo != null)
- event.addEdit(undo);
- insertUpdate(event, attributes);
- writeUnlock();
+ try
+ {
+ writeLock();
+ UndoableEdit undo = content.insertString(offset, text);
+ if (undo != null)
+ event.addEdit(undo);
+
+ insertUpdate(event, attributes);
- fireInsertUpdate(event);
- if (undo != null)
- fireUndoableEditUpdate(new UndoableEditEvent(this, undo));
+ fireInsertUpdate(event);
+ if (undo != null)
+ fireUndoableEditUpdate(new UndoableEditEvent(this, undo));
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
/**
@@ -640,6 +646,12 @@ public abstract class AbstractDocument implements Document, Serializable
// more times than you've previously called lock, but it doesn't make
// sure that the threads calling unlock were the same ones that called lock
+ // If the current thread holds the write lock, and attempted to also obtain
+ // a readLock, then numReaders hasn't been incremented and we don't need
+ // to unlock it here.
+ if (currentWriter == Thread.currentThread())
+ return;
+
// FIXME: the reference implementation throws a
// javax.swing.text.StateInvariantError here
if (numReaders == 0)
@@ -675,18 +687,21 @@ public abstract class AbstractDocument implements Document, Serializable
new DefaultDocumentEvent(offset, length,
DocumentEvent.EventType.REMOVE);
- removeUpdate(event);
-
- boolean shouldFire = content.getString(offset, length).length() != 0;
-
- writeLock();
- UndoableEdit temp = content.remove(offset, length);
- writeUnlock();
-
- postRemoveUpdate(event);
-
- if (shouldFire)
- fireRemoveUpdate(event);
+ try
+ {
+ writeLock();
+
+ // The order of the operations below is critical!
+ removeUpdate(event);
+ UndoableEdit temp = content.remove(offset, length);
+
+ postRemoveUpdate(event);
+ fireRemoveUpdate(event);
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
/**
@@ -841,7 +856,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
protected void writeLock()
{
- if (currentWriter!= null && currentWriter.equals(Thread.currentThread()))
+ if (currentWriter != null && currentWriter.equals(Thread.currentThread()))
return;
synchronized (documentCV)
{
@@ -1330,11 +1345,11 @@ public abstract class AbstractDocument implements Document, Serializable
public Object getAttribute(Object key)
{
Object result = attributes.getAttribute(key);
- if (result == null && element_parent != null)
+ if (result == null)
{
- AttributeSet parentSet = element_parent.getAttributes();
- if (parentSet != null)
- result = parentSet.getAttribute(key);
+ AttributeSet resParent = getResolveParent();
+ if (resParent != null)
+ result = resParent.getAttribute(key);
}
return result;
}
@@ -1371,9 +1386,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public AttributeSet getResolveParent()
{
- if (attributes.getResolveParent() != null)
- return attributes.getResolveParent();
- return element_parent.getAttributes();
+ return attributes.getResolveParent();
}
/**
@@ -1573,6 +1586,18 @@ public abstract class AbstractDocument implements Document, Serializable
private Element[] children = new Element[0];
/**
+ * The cached startOffset value. This is used in the case when a
+ * BranchElement (temporarily) has no child elements.
+ */
+ private int startOffset;
+
+ /**
+ * The cached endOffset value. This is used in the case when a
+ * BranchElement (temporarily) has no child elements.
+ */
+ private int endOffset;
+
+ /**
* Creates a new <code>BranchElement</code> with the specified
* parent and attributes.
*
@@ -1583,6 +1608,8 @@ public abstract class AbstractDocument implements Document, Serializable
public BranchElement(Element parent, AttributeSet attributes)
{
super(parent, attributes);
+ startOffset = -1;
+ endOffset = -1;
}
/**
@@ -1655,7 +1682,7 @@ public abstract class AbstractDocument implements Document, Serializable
// return 0
if (offset < getStartOffset())
return 0;
-
+
// XXX: There is surely a better algorithm
// as beginning from first element each time.
for (int index = 0; index < children.length - 1; ++index)
@@ -1695,9 +1722,15 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getEndOffset()
{
- if (getElementCount() == 0)
- throw new NullPointerException("This BranchElement has no children.");
- return children[children.length - 1].getEndOffset();
+ if (children.length == 0)
+ {
+ if (endOffset == -1)
+ throw new NullPointerException("BranchElement has no children.");
+ }
+ else
+ endOffset = children[children.length - 1].getEndOffset();
+
+ return endOffset;
}
/**
@@ -1718,13 +1751,20 @@ public abstract class AbstractDocument implements Document, Serializable
*
* @return the start offset of this element inside the document model
*
- * @throws NullPointerException if this branch element has no children
+ * @throws NullPointerException if this branch element has no children and
+ * no startOffset value has been cached
*/
public int getStartOffset()
{
- if (getElementCount() == 0)
- throw new NullPointerException("This BranchElement has no children.");
- return children[0].getStartOffset();
+ if (children.length == 0)
+ {
+ if (startOffset == -1)
+ throw new NullPointerException("BranchElement has no children.");
+ }
+ else
+ startOffset = children[0].getStartOffset();
+
+ return startOffset;
}
/**
@@ -2022,13 +2062,29 @@ public abstract class AbstractDocument implements Document, Serializable
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = -8906306331347768017L;
- /** Manages the start offset of this element. */
- Position startPos;
+ /**
+ * Manages the start offset of this element.
+ */
+ private Position startPos;
+
+ /**
+ * Manages the end offset of this element.
+ */
+ private Position endPos;
- /** Manages the end offset of this element. */
- Position endPos;
+ /**
+ * This gets possible added to the startOffset when a startOffset
+ * outside the document range is requested.
+ */
+ private int startDelta;
/**
+ * This gets possible added to the endOffset when a endOffset
+ * outside the document range is requested.
+ */
+ private int endDelta;
+
+ /**
* Creates a new <code>LeafElement</code>.
*
* @param parent the parent of this <code>LeafElement</code>
@@ -2040,20 +2096,18 @@ public abstract class AbstractDocument implements Document, Serializable
int end)
{
super(parent, attributes);
- {
- try
+ int len = content.length();
+ startDelta = 0;
+ if (start > len)
+ startDelta = start - len;
+ endDelta = 0;
+ if (end > len)
+ endDelta = end - len;
+ try
{
- if (parent != null)
- {
- startPos = parent.getDocument().createPosition(start);
- endPos = parent.getDocument().createPosition(end);
- }
- else
- {
- startPos = createPosition(start);
- endPos = createPosition(end);
+ startPos = createPosition(start - startDelta);
+ endPos = createPosition(end - endDelta);
}
- }
catch (BadLocationException ex)
{
AssertionError as;
@@ -2064,7 +2118,6 @@ public abstract class AbstractDocument implements Document, Serializable
as.initCause(ex);
throw as;
}
- }
}
/**
@@ -2136,7 +2189,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getEndOffset()
{
- return endPos.getOffset();
+ return endPos.getOffset() + endDelta;
}
/**
@@ -2162,7 +2215,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getStartOffset()
{
- return startPos.getOffset();
+ return startPos.getOffset() + startDelta;
}
/**
diff --git a/libjava/classpath/javax/swing/text/AsyncBoxView.java b/libjava/classpath/javax/swing/text/AsyncBoxView.java
new file mode 100644
index 00000000000..1988bbadcc8
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/AsyncBoxView.java
@@ -0,0 +1,1480 @@
+/* AsyncBoxView.java -- A box view that performs layout asynchronously
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.ArrayList;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.Position.Bias;
+
+/**
+ * A {@link View} implementation that lays out its child views in a box, either
+ * vertically or horizontally. The difference to {@link BoxView} is that the
+ * layout is performed in an asynchronous manner. This helps to keep the
+ * eventqueue free from non-GUI related tasks.
+ *
+ * This view is currently not used in standard text components. In order to
+ * use it you would have to implement a special {@link EditorKit} with a
+ * {@link ViewFactory} that returns this view. For example:
+ *
+ * <pre>
+ * static class AsyncEditorKit extends StyledEditorKit implements ViewFactory
+ * {
+ * public View create(Element el)
+ * {
+ * if (el.getName().equals(AbstractDocument.SectionElementName))
+ * return new AsyncBoxView(el, View.Y_AXIS);
+ * return super.getViewFactory().create(el);
+ * }
+ * public ViewFactory getViewFactory() {
+ * return this;
+ * }
+ * }
+ * </pre>
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @since 1.3
+ */
+public class AsyncBoxView
+ extends View
+{
+
+ /**
+ * Manages the effective position of child views. That keeps the visible
+ * layout stable while the AsyncBoxView might be changing until the layout
+ * thread decides to publish the new layout.
+ */
+ public class ChildLocator
+ {
+
+ /**
+ * The last valid location.
+ */
+ protected ChildState lastValidOffset;
+
+ /**
+ * The last allocation.
+ */
+ protected Rectangle lastAlloc;
+
+ /**
+ * A Rectangle used for child allocation calculation to avoid creation
+ * of lots of garbage Rectangle objects.
+ */
+ protected Rectangle childAlloc;
+
+ /**
+ * Creates a new ChildLocator.
+ */
+ public ChildLocator()
+ {
+ lastAlloc = new Rectangle();
+ childAlloc = new Rectangle();
+ }
+
+ /**
+ * Receives notification that a child has changed. This is called by
+ * child state objects that have changed it's major span.
+ *
+ * This sets the {@link #lastValidOffset} field to <code>cs</code> if
+ * the new child state's view start offset is smaller than the start offset
+ * of the current child state's view or when <code>lastValidOffset</code>
+ * is <code>null</code>.
+ *
+ * @param cs the child state object that has changed
+ */
+ public synchronized void childChanged(ChildState cs)
+ {
+ if (lastValidOffset == null
+ || cs.getChildView().getStartOffset()
+ < lastValidOffset.getChildView().getStartOffset())
+ {
+ lastValidOffset = cs;
+ }
+ }
+
+ /**
+ * Returns the view index of the view that occupies the specified area, or
+ * <code>-1</code> if there is no such child view.
+ *
+ * @param x the x coordinate (relative to <code>a</code>)
+ * @param y the y coordinate (relative to <code>a</code>)
+ * @param a the current allocation of this view
+ *
+ * @return the view index of the view that occupies the specified area, or
+ * <code>-1</code> if there is no such child view
+ */
+ public int getViewIndexAtPoint(float x, float y, Shape a)
+ {
+ setAllocation(a);
+ float targetOffset = (getMajorAxis() == X_AXIS) ? x - lastAlloc.x
+ : y - lastAlloc.y;
+ int index = getViewIndexAtVisualOffset(targetOffset);
+ return index;
+ }
+
+ /**
+ * Returns the current allocation for a child view. This updates the
+ * offsets for all children <em>before</em> the requested child view.
+ *
+ * @param index the index of the child view
+ * @param a the current allocation of this view
+ *
+ * @return the current allocation for a child view
+ */
+ public synchronized Shape getChildAllocation(int index, Shape a)
+ {
+ if (a == null)
+ return null;
+ setAllocation(a);
+ ChildState cs = getChildState(index);
+ if (cs.getChildView().getStartOffset()
+ > lastValidOffset.getChildView().getStartOffset())
+ {
+ updateChildOffsetsToIndex(index);
+ }
+ Shape ca = getChildAllocation(index);
+ return ca;
+ }
+
+ /**
+ * Paints all child views.
+ *
+ * @param g the graphics context to use
+ */
+ public synchronized void paintChildren(Graphics g)
+ {
+ Rectangle clip = g.getClipBounds();
+ float targetOffset = (getMajorAxis() == X_AXIS) ? clip.x - lastAlloc.x
+ : clip.y - lastAlloc.y;
+ int index = getViewIndexAtVisualOffset(targetOffset);
+ int n = getViewCount();
+ float offs = getChildState(index).getMajorOffset();
+ for (int i = index; i < n; i++)
+ {
+ ChildState cs = getChildState(i);
+ cs.setMajorOffset(offs);
+ Shape ca = getChildAllocation(i);
+ if (ca.intersects(clip))
+ {
+ synchronized (cs)
+ {
+ View v = cs.getChildView();
+ v.paint(g, ca);
+ }
+ }
+ else
+ {
+ // done painting intersection
+ break;
+ }
+ offs += cs.getMajorSpan();
+ }
+ }
+
+ /**
+ * Returns the current allocation of the child view with the specified
+ * index. Note that this will <em>not</em> update any location information.
+ *
+ * @param index the index of the requested child view
+ *
+ * @return the current allocation of the child view with the specified
+ * index
+ */
+ protected Shape getChildAllocation(int index)
+ {
+ ChildState cs = getChildState(index);
+ if (! cs.isLayoutValid())
+ cs.run();
+
+ if (getMajorAxis() == X_AXIS)
+ {
+ childAlloc.x = lastAlloc.x + (int) cs.getMajorOffset();
+ childAlloc.y = lastAlloc.y + (int) cs.getMinorOffset();
+ childAlloc.width = (int) cs.getMajorSpan();
+ childAlloc.height = (int) cs.getMinorSpan();
+ }
+ else
+ {
+ childAlloc.y = lastAlloc.y + (int) cs.getMajorOffset();
+ childAlloc.x = lastAlloc.x + (int) cs.getMinorOffset();
+ childAlloc.height = (int) cs.getMajorSpan();
+ childAlloc.width = (int) cs.getMinorSpan();
+ }
+ return childAlloc;
+ }
+
+ /**
+ * Sets the current allocation for this view.
+ *
+ * @param a the allocation to set
+ */
+ protected void setAllocation(Shape a)
+ {
+ if (a instanceof Rectangle)
+ lastAlloc.setBounds((Rectangle) a);
+ else
+ lastAlloc.setBounds(a.getBounds());
+
+ setSize(lastAlloc.width, lastAlloc.height);
+ }
+
+ /**
+ * Returns the index of the view at the specified offset along the major
+ * layout axis.
+ *
+ * @param targetOffset the requested offset
+ *
+ * @return the index of the view at the specified offset along the major
+ * layout axis
+ */
+ protected int getViewIndexAtVisualOffset(float targetOffset)
+ {
+ int n = getViewCount();
+ if (n > 0)
+ {
+ if (lastValidOffset == null)
+ lastValidOffset = getChildState(0);
+ if (targetOffset > majorSpan)
+ return 0;
+ else if (targetOffset > lastValidOffset.getMajorOffset())
+ return updateChildOffsets(targetOffset);
+ else
+ {
+ float offs = 0f;
+ for (int i = 0; i < n; i++)
+ {
+ ChildState cs = getChildState(i);
+ float nextOffs = offs + cs.getMajorSpan();
+ if (targetOffset < nextOffs)
+ return i;
+ offs = nextOffs;
+ }
+ }
+ }
+ return n - 1;
+ }
+
+ /**
+ * Updates all the child view offsets up to the specified targetOffset.
+ *
+ * @param targetOffset the offset up to which the child view offsets are
+ * updated
+ *
+ * @return the index of the view at the specified offset
+ */
+ private int updateChildOffsets(float targetOffset)
+ {
+ int n = getViewCount();
+ int targetIndex = n - 1;;
+ int pos = lastValidOffset.getChildView().getStartOffset();
+ int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward);
+ float start = lastValidOffset.getMajorOffset();
+ float lastOffset = start;
+ for (int i = startIndex; i < n; i++)
+ {
+ ChildState cs = getChildState(i);
+ cs.setMajorOffset(lastOffset);
+ lastOffset += cs.getMajorSpan();
+ if (targetOffset < lastOffset)
+ {
+ targetIndex = i;
+ lastValidOffset = cs;
+ break;
+ }
+ }
+ return targetIndex;
+ }
+
+ /**
+ * Updates the offsets of the child views up to the specified index.
+ *
+ * @param index the index up to which the offsets are updated
+ */
+ private void updateChildOffsetsToIndex(int index)
+ {
+ int pos = lastValidOffset.getChildView().getStartOffset();
+ int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward);
+ float lastOffset = lastValidOffset.getMajorOffset();
+ for (int i = startIndex; i <= index; i++)
+ {
+ ChildState cs = getChildState(i);
+ cs.setMajorOffset(lastOffset);
+ lastOffset += cs.getMajorSpan();
+ }
+ }
+ }
+
+ /**
+ * Represents the layout state of a child view.
+ */
+ public class ChildState
+ implements Runnable
+ {
+
+ /**
+ * The child view for this state record.
+ */
+ private View childView;
+
+ /**
+ * Indicates if the minor axis requirements of this child view are valid
+ * or not.
+ */
+ private boolean minorValid;
+
+ /**
+ * Indicates if the major axis requirements of this child view are valid
+ * or not.
+ */
+ private boolean majorValid;
+
+ /**
+ * Indicates if the current child size is valid. This is package private
+ * to avoid synthetic accessor method.
+ */
+ boolean childSizeValid;
+
+ /**
+ * The child views minimumSpan. This is package private to avoid accessor
+ * method.
+ */
+ float minimum;
+
+ /**
+ * The child views preferredSpan. This is package private to avoid accessor
+ * method.
+ */
+ float preferred;
+
+ /**
+ * The current span of the child view along the major axis.
+ */
+ private float majorSpan;
+
+ /**
+ * The current offset of the child view along the major axis.
+ */
+ private float majorOffset;
+
+ /**
+ * The current span of the child view along the minor axis.
+ */
+ private float minorSpan;
+
+ /**
+ * The current offset of the child view along the major axis.
+ */
+ private float minorOffset;
+
+ /**
+ * The child views maximumSpan.
+ */
+ private float maximum;
+
+ /**
+ * Creates a new <code>ChildState</code> object for the specified child
+ * view.
+ *
+ * @param view the child view for which to create the state record
+ */
+ public ChildState(View view)
+ {
+ childView = view;
+ }
+
+ /**
+ * Returns the child view for which this <code>ChildState</code> represents
+ * the layout state.
+ *
+ * @return the child view for this child state object
+ */
+ public View getChildView()
+ {
+ return childView;
+ }
+
+ /**
+ * Returns <code>true</code> if the current layout information is valid,
+ * <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if the current layout information is valid,
+ * <code>false</code> otherwise
+ */
+ public boolean isLayoutValid()
+ {
+ return minorValid && majorValid && childSizeValid;
+ }
+
+ /**
+ * Performs the layout update for the child view managed by this
+ * <code>ChildState</code>.
+ */
+ public void run()
+ {
+ Document doc = getDocument();
+ if (doc instanceof AbstractDocument)
+ {
+ AbstractDocument abstractDoc = (AbstractDocument) doc;
+ abstractDoc.readLock();
+ }
+
+ try
+ {
+
+ if (!(minorValid && majorValid && childSizeValid)
+ && childView.getParent() == AsyncBoxView.this)
+ {
+ synchronized(AsyncBoxView.this)
+ {
+ changing = this;
+ }
+ update();
+ synchronized(AsyncBoxView.this)
+ {
+ changing = null;
+ }
+ // Changing the major axis may cause the minor axis
+ // requirements to have changed, so we need to do this again.
+ update();
+ }
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ {
+ AbstractDocument abstractDoc = (AbstractDocument) doc;
+ abstractDoc.readUnlock();
+ }
+ }
+ }
+
+ /**
+ * Performs the actual update after the run methods has made its checks
+ * and locked the document.
+ */
+ private void update()
+ {
+ int majorAxis = getMajorAxis();
+ boolean minorUpdated = false;
+ synchronized (this)
+ {
+ if (! minorValid)
+ {
+ int minorAxis = getMinorAxis();
+ minimum = childView.getMinimumSpan(minorAxis);
+ preferred = childView.getPreferredSpan(minorAxis);
+ maximum = childView.getMaximumSpan(minorAxis);
+ minorValid = true;
+ minorUpdated = true;
+ }
+ }
+ if (minorUpdated)
+ minorRequirementChange(this);
+
+ boolean majorUpdated = false;
+ float delta = 0.0F;
+ synchronized (this)
+ {
+ if (! majorValid)
+ {
+ float oldSpan = majorSpan;
+ majorSpan = childView.getPreferredSpan(majorAxis);
+ delta = majorSpan - oldSpan;
+ majorValid = true;
+ majorUpdated = true;
+ }
+ }
+ if (majorUpdated)
+ {
+ majorRequirementChange(this, delta);
+ locator.childChanged(this);
+ }
+
+ synchronized (this)
+ {
+ if (! childSizeValid)
+ {
+ float w;
+ float h;
+ if (majorAxis == X_AXIS)
+ {
+ w = majorSpan;
+ h = getMinorSpan();
+ }
+ else
+ {
+ w = getMinorSpan();
+ h = majorSpan;
+ }
+ childSizeValid = true;
+ childView.setSize(w, h);
+ }
+ }
+ }
+
+ /**
+ * Returns the span of the child view along the minor layout axis.
+ *
+ * @return the span of the child view along the minor layout axis
+ */
+ public float getMinorSpan()
+ {
+ float retVal;
+ if (maximum < minorSpan)
+ retVal = maximum;
+ else
+ retVal = Math.max(minimum, minorSpan);
+ return retVal;
+ }
+
+ /**
+ * Returns the offset of the child view along the minor layout axis.
+ *
+ * @return the offset of the child view along the minor layout axis
+ */
+ public float getMinorOffset()
+ {
+ float retVal;
+ if (maximum < minorSpan)
+ {
+ float align = childView.getAlignment(getMinorAxis());
+ retVal = ((minorSpan - maximum) * align);
+ }
+ else
+ retVal = 0f;
+
+ return retVal;
+ }
+
+ /**
+ * Returns the span of the child view along the major layout axis.
+ *
+ * @return the span of the child view along the major layout axis
+ */
+
+ public float getMajorSpan()
+ {
+ return majorSpan;
+ }
+
+ /**
+ * Returns the offset of the child view along the major layout axis.
+ *
+ * @return the offset of the child view along the major layout axis
+ */
+ public float getMajorOffset()
+ {
+ return majorOffset;
+ }
+
+ /**
+ * Sets the offset of the child view along the major layout axis. This
+ * should only be called by the ChildLocator of that child view.
+ *
+ * @param offset the offset to set
+ */
+ public void setMajorOffset(float offset)
+ {
+ majorOffset = offset;
+ }
+
+ /**
+ * Mark the preferences changed for that child. This forwards to
+ * {@link AsyncBoxView#preferenceChanged}.
+ *
+ * @param width <code>true</code> if the width preference has changed
+ * @param height <code>true</code> if the height preference has changed
+ */
+ public void preferenceChanged(boolean width, boolean height)
+ {
+ if (getMajorAxis() == X_AXIS)
+ {
+ if (width)
+ majorValid = false;
+ if (height)
+ minorValid = false;
+ }
+ else
+ {
+ if (width)
+ minorValid = false;
+ if (height)
+ majorValid = false;
+ }
+ childSizeValid = false;
+ }
+ }
+
+ /**
+ * Flushes the requirements changes upwards asynchronously.
+ */
+ private class FlushTask implements Runnable
+ {
+ /**
+ * Starts the flush task. This obtains a readLock on the document
+ * and then flushes all the updates using
+ * {@link AsyncBoxView#flushRequirementChanges()} after updating the
+ * requirements.
+ */
+ public void run()
+ {
+ try
+ {
+ // Acquire a lock on the document.
+ Document doc = getDocument();
+ if (doc instanceof AbstractDocument)
+ {
+ AbstractDocument abstractDoc = (AbstractDocument) doc;
+ abstractDoc.readLock();
+ }
+
+ int n = getViewCount();
+ if (minorChanged && (n > 0))
+ {
+ LayoutQueue q = getLayoutQueue();
+ ChildState min = getChildState(0);
+ ChildState pref = getChildState(0);
+ for (int i = 1; i < n; i++)
+ {
+ ChildState cs = getChildState(i);
+ if (cs.minimum > min.minimum)
+ min = cs;
+ if (cs.preferred > pref.preferred)
+ pref = cs;
+ }
+ synchronized (AsyncBoxView.this)
+ {
+ minReq = min;
+ prefReq = pref;
+ }
+ }
+
+ flushRequirementChanges();
+ }
+ finally
+ {
+ // Release the lock on the document.
+ Document doc = getDocument();
+ if (doc instanceof AbstractDocument)
+ {
+ AbstractDocument abstractDoc = (AbstractDocument) doc;
+ abstractDoc.readUnlock();
+ }
+ }
+ }
+
+ }
+
+ /**
+ * The major layout axis.
+ */
+ private int majorAxis;
+
+ /**
+ * The top inset.
+ */
+ private float topInset;
+
+ /**
+ * The bottom inset.
+ */
+ private float bottomInset;
+
+ /**
+ * The left inset.
+ */
+ private float leftInset;
+
+ /**
+ * Indicates if the major span should be treated as beeing estimated or not.
+ */
+ private boolean estimatedMajorSpan;
+
+ /**
+ * The right inset.
+ */
+ private float rightInset;
+
+ /**
+ * The children and their layout statistics.
+ */
+ private ArrayList childStates;
+
+ /**
+ * The currently changing child state. May be null if there is no child state
+ * updating at the moment. This is package private to avoid a synthetic
+ * accessor method inside ChildState.
+ */
+ ChildState changing;
+
+ /**
+ * Represents the minimum requirements. This is used in
+ * {@link #getMinimumSpan(int)}.
+ */
+ ChildState minReq;
+
+ /**
+ * Represents the minimum requirements. This is used in
+ * {@link #getPreferredSpan(int)}.
+ */
+ ChildState prefReq;
+
+ /**
+ * Indicates that the major axis requirements have changed.
+ */
+ private boolean majorChanged;
+
+ /**
+ * Indicates that the minor axis requirements have changed. This is package
+ * private to avoid synthetic accessor method.
+ */
+ boolean minorChanged;
+
+ /**
+ * The current span along the major layout axis. This is package private to
+ * avoid synthetic accessor method.
+ */
+ float majorSpan;
+
+ /**
+ * The current span along the minor layout axis. This is package private to
+ * avoid synthetic accessor method.
+ */
+ float minorSpan;
+
+ /**
+ * This tasked is placed on the layout queue to flush updates up to the
+ * parent view.
+ */
+ private Runnable flushTask;
+
+ /**
+ * The child locator for this view.
+ */
+ protected ChildLocator locator;
+
+ /**
+ * Creates a new <code>AsyncBoxView</code> that represents the specified
+ * element and layouts its children along the specified axis.
+ *
+ * @param elem the element
+ * @param axis the layout axis
+ */
+ public AsyncBoxView(Element elem, int axis)
+ {
+ super(elem);
+ majorAxis = axis;
+ childStates = new ArrayList();
+ flushTask = new FlushTask();
+ locator = new ChildLocator();
+ minorSpan = Short.MAX_VALUE;
+ }
+
+ /**
+ * Returns the major layout axis.
+ *
+ * @return the major layout axis
+ */
+ public int getMajorAxis()
+ {
+ return majorAxis;
+ }
+
+ /**
+ * Returns the minor layout axis, that is the axis orthogonal to the major
+ * layout axis.
+ *
+ * @return the minor layout axis
+ */
+ public int getMinorAxis()
+ {
+ return majorAxis == X_AXIS ? Y_AXIS : X_AXIS;
+ }
+
+ /**
+ * Returns the view at the specified <code>index</code>.
+ *
+ * @param index the index of the requested child view
+ *
+ * @return the view at the specified <code>index</code>
+ */
+ public View getView(int index)
+ {
+ View view = null;
+ synchronized(childStates)
+ {
+ if ((index >= 0) && (index < childStates.size()))
+ {
+ ChildState cs = (ChildState) childStates.get(index);
+ view = cs.getChildView();
+ }
+ }
+ return view;
+ }
+
+ /**
+ * Returns the number of child views.
+ *
+ * @return the number of child views
+ */
+ public int getViewCount()
+ {
+ synchronized(childStates)
+ {
+ return childStates.size();
+ }
+ }
+
+ /**
+ * Returns the view index of the child view that represents the specified
+ * model position.
+ *
+ * @param pos the model position for which we search the view index
+ * @param bias the bias
+ *
+ * @return the view index of the child view that represents the specified
+ * model position
+ */
+ public int getViewIndex(int pos, Position.Bias bias)
+ {
+ int retVal = -1;
+
+ if (bias == Position.Bias.Backward)
+ pos = Math.max(0, pos - 1);
+
+ // TODO: A possible optimization would be to implement a binary search
+ // here.
+ int numChildren = childStates.size();
+ if (numChildren > 0)
+ {
+ for (int i = 0; i < numChildren; ++i)
+ {
+ View child = ((ChildState) childStates.get(i)).getChildView();
+ if (child.getStartOffset() <= pos && child.getEndOffset() > pos)
+ {
+ retVal = i;
+ break;
+ }
+ }
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns the top inset.
+ *
+ * @return the top inset
+ */
+ public float getTopInset()
+ {
+ return topInset;
+ }
+
+ /**
+ * Sets the top inset.
+ *
+ * @param top the top inset
+ */
+ public void setTopInset(float top)
+ {
+ topInset = top;
+ }
+
+ /**
+ * Returns the bottom inset.
+ *
+ * @return the bottom inset
+ */
+ public float getBottomInset()
+ {
+ return bottomInset;
+ }
+
+ /**
+ * Sets the bottom inset.
+ *
+ * @param bottom the bottom inset
+ */
+ public void setBottomInset(float bottom)
+ {
+ bottomInset = bottom;
+ }
+
+ /**
+ * Returns the left inset.
+ *
+ * @return the left inset
+ */
+ public float getLeftInset()
+ {
+ return leftInset;
+ }
+
+ /**
+ * Sets the left inset.
+ *
+ * @param left the left inset
+ */
+ public void setLeftInset(float left)
+ {
+ leftInset = left;
+ }
+
+ /**
+ * Returns the right inset.
+ *
+ * @return the right inset
+ */
+ public float getRightInset()
+ {
+ return rightInset;
+ }
+
+ /**
+ * Sets the right inset.
+ *
+ * @param right the right inset
+ */
+ public void setRightInset(float right)
+ {
+ rightInset = right;
+ }
+
+ /**
+ * Loads the child views of this view. This is triggered by
+ * {@link #setParent(View)}.
+ *
+ * @param f the view factory to build child views with
+ */
+ protected void loadChildren(ViewFactory f)
+ {
+ Element e = getElement();
+ int n = e.getElementCount();
+ if (n > 0)
+ {
+ View[] added = new View[n];
+ for (int i = 0; i < n; i++)
+ {
+ added[i] = f.create(e.getElement(i));
+ }
+ replace(0, 0, added);
+ }
+ }
+
+ /**
+ * Returns the span along an axis that is taken up by the insets.
+ *
+ * @param axis the axis
+ *
+ * @return the span along an axis that is taken up by the insets
+ *
+ * @since 1.4
+ */
+ protected float getInsetSpan(int axis)
+ {
+ float span;
+ if (axis == X_AXIS)
+ span = leftInset + rightInset;
+ else
+ span = topInset + bottomInset;
+ return span;
+ }
+
+ /**
+ * Sets the <code>estimatedMajorSpan</code> property that determines if
+ * the major span should be treated as beeing estimated.
+ *
+ * @param estimated if the major span should be treated as estimated or not
+ *
+ * @since 1.4
+ */
+ public void setEstimatedMajorSpan(boolean estimated)
+ {
+ estimatedMajorSpan = estimated;
+ }
+
+ /**
+ * Determines whether the major span should be treated as estimated or as
+ * beeing accurate.
+ *
+ * @return <code>true</code> if the major span should be treated as
+ * estimated, <code>false</code> if the major span should be treated
+ * as accurate
+ *
+ * @since 1.4
+ */
+ public boolean getEstimatedMajorSpan()
+ {
+ return estimatedMajorSpan;
+ }
+
+ /**
+ * Receives notification from the child states that the requirements along
+ * the minor axis have changed.
+ *
+ * @param cs the child state from which this notification is messaged
+ */
+ protected synchronized void minorRequirementChange(ChildState cs)
+ {
+ minorChanged = true;
+ }
+
+ /**
+ * Receives notification from the child states that the requirements along
+ * the major axis have changed.
+ *
+ * @param cs the child state from which this notification is messaged
+ */
+ protected void majorRequirementChange(ChildState cs, float delta)
+ {
+ if (! estimatedMajorSpan)
+ majorSpan += delta;
+ majorChanged = true;
+ }
+
+ /**
+ * Sets the parent for this view. This calls loadChildren if
+ * <code>parent</code> is not <code>null</code> and there have not been any
+ * child views initializes.
+ *
+ * @param parent the new parent view; <code>null</code> if this view is
+ * removed from the view hierarchy
+ *
+ * @see View#setParent(View)
+ */
+ public void setParent(View parent)
+ {
+ super.setParent(parent);
+ if ((parent != null) && (getViewCount() == 0))
+ {
+ ViewFactory f = getViewFactory();
+ loadChildren(f);
+ }
+ }
+
+ /**
+ * Sets the size of this view. This is ususally called before {@link #paint}
+ * is called to make sure the view has a valid layout.
+ *
+ * This implementation queues layout requests for every child view if the
+ * minor axis span has changed. (The major axis span is requested to never
+ * change for this view).
+ *
+ * @param width the width of the view
+ * @param height the height of the view
+ */
+ public void setSize(float width, float height)
+ {
+ float targetSpan;
+ if (majorAxis == X_AXIS)
+ targetSpan = height - getTopInset() - getBottomInset();
+ else
+ targetSpan = width - getLeftInset() - getRightInset();
+
+ if (targetSpan != minorSpan)
+ {
+ minorSpan = targetSpan;
+
+ int n = getViewCount();
+ LayoutQueue q = getLayoutQueue();
+ for (int i = 0; i < n; i++)
+ {
+ ChildState cs = getChildState(i);
+ cs.childSizeValid = false;
+ q.addTask(cs);
+ }
+ q.addTask(flushTask);
+ }
+ }
+
+ /**
+ * Replaces child views with new child views.
+ *
+ * This creates ChildState objects for all the new views and adds layout
+ * requests for them to the layout queue.
+ *
+ * @param offset the offset at which to remove/insert
+ * @param length the number of child views to remove
+ * @param views the new child views to insert
+ */
+ public void replace(int offset, int length, View[] views)
+ {
+ synchronized(childStates)
+ {
+ LayoutQueue q = getLayoutQueue();
+ for (int i = 0; i < length; i++)
+ childStates.remove(offset);
+
+ for (int i = views.length - 1; i >= 0; i--)
+ childStates.add(offset, createChildState(views[i]));
+
+ // We need to go through the new child states _after_ they have been
+ // added to the childStates list, otherwise the layout tasks may find
+ // an incomplete child list. That means we have to loop through
+ // them again, but what else can we do?
+ if (views.length != 0)
+ {
+ for (int i = 0; i < views.length; i++)
+ {
+ ChildState cs = (ChildState) childStates.get(i + offset);
+ cs.getChildView().setParent(this);
+ q.addTask(cs);
+ }
+ q.addTask(flushTask);
+ }
+ }
+ }
+
+ /**
+ * Paints the view. This requests the {@link ChildLocator} to paint the views
+ * after setting the allocation on it.
+ *
+ * @param g the graphics context to use
+ * @param s the allocation for this view
+ */
+ public void paint(Graphics g, Shape s)
+ {
+ synchronized (locator)
+ {
+ locator.setAllocation(s);
+ locator.paintChildren(g);
+ }
+ }
+
+ /**
+ * Returns the preferred span of this view along the specified layout axis.
+ *
+ * @return the preferred span of this view along the specified layout axis
+ */
+ public float getPreferredSpan(int axis)
+ {
+ float retVal;
+ if (majorAxis == axis)
+ retVal = majorSpan;
+
+ else if (prefReq != null)
+ {
+ View child = prefReq.getChildView();
+ retVal = child.getPreferredSpan(axis);
+ }
+
+ // If we have no layout information yet, then return insets + 30 as
+ // an estimation.
+ else
+ {
+ if (axis == X_AXIS)
+ retVal = getLeftInset() + getRightInset() + 30;
+ else
+ retVal = getTopInset() + getBottomInset() + 30;
+ }
+ return retVal;
+ }
+
+ /**
+ * Maps a model location to view coordinates.
+ *
+ * @param pos the model location
+ * @param a the current allocation of this view
+ * @param b the bias
+ *
+ * @return the view allocation for the specified model location
+ */
+ public Shape modelToView(int pos, Shape a, Bias b)
+ throws BadLocationException
+ {
+ int index = getViewIndexAtPosition(pos, b);
+ Shape ca = locator.getChildAllocation(index, a);
+
+ ChildState cs = getChildState(index);
+ synchronized (cs)
+ {
+ View cv = cs.getChildView();
+ Shape v = cv.modelToView(pos, ca, b);
+ return v;
+ }
+ }
+
+ /**
+ * Maps view coordinates to a model location.
+ *
+ * @param x the x coordinate (relative to <code>a</code>)
+ * @param y the y coordinate (relative to <code>a</code>)
+ * @param b holds the bias of the model location on method exit
+ *
+ * @return the model location for the specified view location
+ */
+ public int viewToModel(float x, float y, Shape a, Bias[] b)
+ {
+ int pos;
+ int index;
+ Shape ca;
+
+ synchronized (locator)
+ {
+ index = locator.getViewIndexAtPoint(x, y, a);
+ ca = locator.getChildAllocation(index, a);
+ }
+
+ ChildState cs = getChildState(index);
+ synchronized (cs)
+ {
+ View v = cs.getChildView();
+ pos = v.viewToModel(x, y, ca, b);
+ }
+ return pos;
+ }
+
+ /**
+ * Returns the child allocation for the child view with the specified
+ * <code>index</code>.
+ *
+ * @param index the index of the child view
+ * @param a the current allocation of this view
+ *
+ * @return the allocation of the child view
+ */
+ public Shape getChildAllocation(int index, Shape a)
+ {
+ Shape ca = locator.getChildAllocation(index, a);
+ return ca;
+ }
+
+ /**
+ * Returns the maximum span of this view along the specified axis.
+ * This is implemented to return the <code>preferredSpan</code> for the
+ * major axis (that means the box can't be resized along the major axis) and
+ * {@link Short#MAX_VALUE} for the minor axis.
+ *
+ * @param axis the axis
+ *
+ * @return the maximum span of this view along the specified axis
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float max;
+ if (axis == majorAxis)
+ max = getPreferredSpan(axis);
+ else
+ max = Short.MAX_VALUE;
+ return max;
+ }
+
+ /**
+ * Returns the minimum span along the specified axis.
+ */
+ public float getMinimumSpan(int axis)
+ {
+ float min;
+ if (axis == majorAxis)
+ min = getPreferredSpan(axis);
+ else
+ {
+ if (minReq != null)
+ {
+ View child = minReq.getChildView();
+ min = child.getMinimumSpan(axis);
+ }
+ else
+ {
+ // No layout information yet. Return insets + 5 as some kind of
+ // estimation.
+ if (axis == X_AXIS)
+ min = getLeftInset() + getRightInset() + 5;
+ else
+ min = getTopInset() + getBottomInset() + 5;
+ }
+ }
+ return min;
+ }
+
+ /**
+ * Receives notification that one of the child views has changed its
+ * layout preferences along one or both axis.
+ *
+ * This queues a layout request for that child view if necessary.
+ *
+ * @param view the view that has changed its preferences
+ * @param width <code>true</code> if the width preference has changed
+ * @param height <code>true</code> if the height preference has changed
+ */
+ public synchronized void preferenceChanged(View view, boolean width,
+ boolean height)
+ {
+ if (view == null)
+ getParent().preferenceChanged(this, width, height);
+ else
+ {
+ if (changing != null)
+ {
+ View cv = changing.getChildView();
+ if (cv == view)
+ {
+ changing.preferenceChanged(width, height);
+ return;
+ }
+ }
+ int index = getViewIndexAtPosition(view.getStartOffset(),
+ Position.Bias.Forward);
+ ChildState cs = getChildState(index);
+ cs.preferenceChanged(width, height);
+ LayoutQueue q = getLayoutQueue();
+ q.addTask(cs);
+ q.addTask(flushTask);
+ }
+ }
+
+ /**
+ * Updates the layout for this view. This is implemented to trigger
+ * {link ChildLocator#childChanged} for the changed view, if there is
+ * any.
+ *
+ * @param ec the element change, may be <code>null</code> if there were
+ * no changes to the element of this view
+ * @param e the document event
+ * @param a the current allocation of this view
+ */
+ protected void updateLayout(DocumentEvent.ElementChange ec,
+ DocumentEvent e, Shape a)
+ {
+ if (ec != null)
+ {
+ int index = Math.max(ec.getIndex() - 1, 0);
+ ChildState cs = getChildState(index);
+ locator.childChanged(cs);
+ }
+ }
+
+
+ /**
+ * Returns the <code>ChildState</code> object associated with the child view
+ * at the specified <code>index</code>.
+ *
+ * @param index the index of the child view for which to query the state
+ *
+ * @return the child state for the specified child view
+ */
+ protected ChildState getChildState(int index) {
+ synchronized (childStates)
+ {
+ return (ChildState) childStates.get(index);
+ }
+ }
+
+ /**
+ * Returns the <code>LayoutQueue</code> used for layouting the box view.
+ * This simply returns {@link LayoutQueue#getDefaultQueue()}.
+ *
+ * @return the <code>LayoutQueue</code> used for layouting the box view
+ */
+ protected LayoutQueue getLayoutQueue()
+ {
+ return LayoutQueue.getDefaultQueue();
+ }
+
+ /**
+ * Returns the child view index of the view that represents the specified
+ * position in the document model.
+ *
+ * @param pos the position in the model
+ * @param b the bias
+ *
+ * @return the child view index of the view that represents the specified
+ * position in the document model
+ */
+ protected synchronized int getViewIndexAtPosition(int pos, Position.Bias b)
+ {
+ if (b == Position.Bias.Backward)
+ pos = Math.max(0, pos - 1);
+ Element elem = getElement();
+ return elem.getElementIndex(pos);
+ }
+
+ /**
+ * Creates a <code>ChildState</code> object for the specified view.
+ *
+ * @param v the view for which to create a child state object
+ *
+ * @return the created child state
+ */
+ protected ChildState createChildState(View v)
+ {
+ return new ChildState(v);
+ }
+
+ /**
+ * Flushes the requirements changes upwards to the parent view. This is
+ * called from the layout thread.
+ */
+ protected synchronized void flushRequirementChanges()
+ {
+ if (majorChanged || minorChanged)
+ {
+ View p = getParent();
+ if (p != null)
+ {
+ boolean horizontal;
+ boolean vertical;
+ if (majorAxis == X_AXIS)
+ {
+ horizontal = majorChanged;
+ vertical = minorChanged;
+ }
+ else
+ {
+ vertical = majorChanged;
+ horizontal = minorChanged;
+ }
+
+ p.preferenceChanged(this, horizontal, vertical);
+ majorChanged = false;
+ minorChanged = false;
+
+ Component c = getContainer();
+ if (c != null)
+ c.repaint();
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/BoxView.java b/libjava/classpath/javax/swing/text/BoxView.java
index 5c9587dfe5d..b5907dcbbe6 100644
--- a/libjava/classpath/javax/swing/text/BoxView.java
+++ b/libjava/classpath/javax/swing/text/BoxView.java
@@ -43,6 +43,7 @@ import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.SizeRequirements;
+import javax.swing.event.DocumentEvent;
/**
* An implementation of {@link CompositeView} that arranges its children in
@@ -58,49 +59,37 @@ public class BoxView
/**
* The axis along which this <code>BoxView</code> is laid out.
*/
- int myAxis;
+ private int myAxis;
/**
- * Indicates wether the layout in X_AXIS is valid.
+ * Indicates if the layout is valid along X_AXIS or Y_AXIS.
*/
- boolean xLayoutValid;
+ private boolean[] layoutValid = new boolean[2];
/**
- * Indicates whether the layout in Y_AXIS is valid.
+ * The spans along the X_AXIS and Y_AXIS.
*/
- boolean yLayoutValid;
+ private int[][] spans = new int[2][];
/**
- * The spans in X direction of the children.
+ * The offsets of the children along the X_AXIS and Y_AXIS.
*/
- int[] spansX;
+ private int[][] offsets = new int[2][];
/**
- * The spans in Y direction of the children.
+ * The size requirements along the X_AXIS and Y_AXIS.
*/
- int[] spansY;
+ private SizeRequirements[] requirements = new SizeRequirements[2];
/**
- * The offsets of the children in X direction relative to this BoxView's
- * inner bounds.
+ * The current span along X_AXIS or Y_AXIS.
*/
- int[] offsetsX;
+ private int[] span = new int[2];
/**
- * The offsets of the children in Y direction relative to this BoxView's
- * inner bounds.
+ * The SizeRequirements of the child views along the X_AXIS and Y_AXIS.
*/
- int[] offsetsY;
-
- /**
- * The current width.
- */
- int width;
-
- /**
- * The current height.
- */
- int height;
+ private SizeRequirements[][] childReqs = new SizeRequirements[2][];
/**
* Creates a new <code>BoxView</code> for the given
@@ -114,23 +103,26 @@ public class BoxView
{
super(element);
myAxis = axis;
- xLayoutValid = false;
- yLayoutValid = false;
+ layoutValid[0] = false;
+ layoutValid[1] = false;
+ span[0] = 0;
+ span[1] = 0;
+ requirements[0] = new SizeRequirements();
+ requirements[1] = new SizeRequirements();
// Initialize the cache arrays.
- spansX = new int[0];
- spansY = new int[0];
- offsetsX = new int[0];
- offsetsY = new int[0];
-
- width = 0;
- height = 0;
+ spans[0] = new int[0];
+ spans[1] = new int[0];
+ offsets[0] = new int[0];
+ offsets[1] = new int[0];
}
/**
* Returns the axis along which this <code>BoxView</code> is laid out.
*
* @return the axis along which this <code>BoxView</code> is laid out
+ *
+ * @since 1.3
*/
public int getAxis()
{
@@ -144,6 +136,8 @@ public class BoxView
* {@link View#Y_AXIS}.
*
* @param axis the axis along which this <code>BoxView</code> is laid out
+ *
+ * @since 1.3
*/
public void setAxis(int axis)
{
@@ -163,20 +157,14 @@ public class BoxView
* {@link View#Y_AXIS}.
*
* @param axis an <code>int</code> value
+ *
+ * @since 1.3
*/
public void layoutChanged(int axis)
{
- switch (axis)
- {
- case X_AXIS:
- xLayoutValid = false;
- break;
- case Y_AXIS:
- yLayoutValid = false;
- break;
- default:
- throw new IllegalArgumentException("Invalid axis parameter.");
- }
+ if (axis != X_AXIS && axis != Y_AXIS)
+ throw new IllegalArgumentException("Invalid axis parameter.");
+ layoutValid[axis] = false;
}
/**
@@ -190,22 +178,14 @@ public class BoxView
*
* @return <code>true</code> if the layout along the specified
* <code>axis</code> is valid, <code>false</code> otherwise
+ *
+ * @since 1.4
*/
protected boolean isLayoutValid(int axis)
{
- boolean valid = false;
- switch (axis)
- {
- case X_AXIS:
- valid = xLayoutValid;
- break;
- case Y_AXIS:
- valid = yLayoutValid;
- break;
- default:
- throw new IllegalArgumentException("Invalid axis parameter.");
- }
- return valid;
+ if (axis != X_AXIS && axis != Y_AXIS)
+ throw new IllegalArgumentException("Invalid axis parameter.");
+ return layoutValid[axis];
}
/**
@@ -242,40 +222,44 @@ public class BoxView
*/
public void replace(int offset, int length, View[] views)
{
+ int numViews = 0;
+ if (views != null)
+ numViews = views.length;
+
// Resize and copy data for cache arrays.
// The spansX cache.
int oldSize = getViewCount();
- int[] newSpansX = new int[oldSize - length + views.length];
- System.arraycopy(spansX, 0, newSpansX, 0, offset);
- System.arraycopy(spansX, offset + length, newSpansX,
- offset + views.length,
+ 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));
- spansX = newSpansX;
+ spans[X_AXIS] = newSpansX;
// The spansY cache.
- int[] newSpansY = new int[oldSize - length + views.length];
- System.arraycopy(spansY, 0, newSpansY, 0, offset);
- System.arraycopy(spansY, offset + length, newSpansY,
- offset + views.length,
+ 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));
- spansY = newSpansY;
+ spans[Y_AXIS] = newSpansY;
// The offsetsX cache.
- int[] newOffsetsX = new int[oldSize - length + views.length];
- System.arraycopy(offsetsX, 0, newOffsetsX, 0, offset);
- System.arraycopy(offsetsX, offset + length, newOffsetsX,
- offset + views.length,
+ 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));
- offsetsX = newOffsetsX;
+ offsets[X_AXIS] = newOffsetsX;
// The offsetsY cache.
- int[] newOffsetsY = new int[oldSize - length + views.length];
- System.arraycopy(offsetsY, 0, newOffsetsY, 0, offset);
- System.arraycopy(offsetsY, offset + length, newOffsetsY,
- offset + views.length,
+ 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));
- offsetsY = newOffsetsY;
+ offsets[Y_AXIS] = newOffsetsY;
// Actually perform the replace.
super.replace(offset, length, views);
@@ -294,13 +278,10 @@ public class BoxView
*/
public void paint(Graphics g, Shape a)
{
- // Adjust size if the size is changed.
- Rectangle bounds = a.getBounds();
-
- if (bounds.width != getWidth() || bounds.height != getHeight())
- setSize(bounds.width, bounds.height);
-
Rectangle inside = getInsideAllocation(a);
+ // TODO: Used for debugging.
+ //g.drawRect(inside.x, inside.y, inside.width, inside.height);
+
Rectangle copy = new Rectangle(inside);
int count = getViewCount();
for (int i = 0; i < count; ++i)
@@ -323,22 +304,50 @@ public class BoxView
*/
public float getPreferredSpan(int axis)
{
- SizeRequirements sr = new SizeRequirements();
- int pref = baselineRequirements(axis, sr).preferred;
- return (float) pref;
+ updateRequirements(axis);
+ return requirements[axis].preferred;
}
+ /**
+ * Returns the maximum span of this view along the specified axis.
+ * This returns <code>Integer.MAX_VALUE</code> for the minor axis
+ * and the preferred span for the major axis.
+ *
+ * @param axis the axis
+ *
+ * @return the maximum span of this view along the specified axis
+ */
public float getMaximumSpan(int axis)
{
- if (axis == getAxis())
- return getPreferredSpan(axis);
+ float max;
+ if (axis == myAxis)
+ max = getPreferredSpan(axis);
else
- return Integer.MAX_VALUE;
+ max = Integer.MAX_VALUE;
+ return max;
}
/**
- * Calculates the size requirements for this <code>BoxView</code> along
- * the specified axis.
+ * Returns the minimum span of this view along the specified axis.
+ * This calculates the minimum span using
+ * {@link #calculateMajorAxisRequirements} or
+ * {@link #calculateMinorAxisRequirements} (depending on the axis) and
+ * returns the resulting minimum span.
+ *
+ * @param axis the axis
+ *
+ * @return the minimum span of this view along the specified axis
+ */
+ public float getMinimumSpan(int axis)
+ {
+ updateRequirements(axis);
+ return requirements[axis].minimum;
+ }
+
+ /**
+ * This method is obsolete and no longer in use. It is replaced by
+ * {@link #calculateMajorAxisRequirements(int, SizeRequirements)} and
+ * {@link #calculateMinorAxisRequirements(int, SizeRequirements)}.
*
* @param axis the axis that is examined
* @param sr the <code>SizeRequirements</code> object to hold the result,
@@ -350,12 +359,45 @@ public class BoxView
protected SizeRequirements baselineRequirements(int axis,
SizeRequirements sr)
{
- SizeRequirements result;
- if (axis == myAxis)
- result = calculateMajorAxisRequirements(axis, sr);
- else
- result = calculateMinorAxisRequirements(axis, sr);
- return result;
+ updateChildRequirements(axis);
+
+ SizeRequirements res = sr;
+ if (res == null)
+ res = new SizeRequirements();
+
+ float minLeft = 0;
+ float minRight = 0;
+ float prefLeft = 0;
+ float prefRight = 0;
+ float maxLeft = 0;
+ float maxRight = 0;
+ for (int i = 0; i < childReqs[axis].length; i++)
+ {
+ float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment;
+ float myMinRight = childReqs[axis][i].minimum - myMinLeft;
+ minLeft = Math.max(myMinLeft, minLeft);
+ minRight = Math.max(myMinRight, minRight);
+ float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment;
+ float myPrefRight = childReqs[axis][i].preferred - myPrefLeft;
+ prefLeft = Math.max(myPrefLeft, prefLeft);
+ prefRight = Math.max(myPrefRight, prefRight);
+ float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment;
+ float myMaxRight = childReqs[axis][i].maximum - myMaxLeft;
+ maxLeft = Math.max(myMaxLeft, maxLeft);
+ maxRight = Math.max(myMaxRight, maxRight);
+ }
+ int minSize = (int) (minLeft + minRight);
+ int prefSize = (int) (prefLeft + prefRight);
+ int maxSize = (int) (maxLeft + maxRight);
+ float align = prefLeft / (prefRight + prefLeft);
+ if (Float.isNaN(align))
+ align = 0;
+
+ res.alignment = align;
+ res.maximum = maxSize;
+ res.preferred = prefSize;
+ res.minimum = minSize;
+ return res;
}
/**
@@ -370,10 +412,13 @@ public class BoxView
protected void baselineLayout(int span, int axis, int[] offsets,
int[] spans)
{
- if (axis == myAxis)
- layoutMajorAxis(span, axis, offsets, spans);
- else
- layoutMinorAxis(span, axis, offsets, spans);
+ updateChildRequirements(axis);
+ updateRequirements(axis);
+
+ // Calculate the spans and offsets using the SizeRequirements uility
+ // methods.
+ SizeRequirements.calculateAlignedPositions(span, requirements[axis],
+ childReqs[axis], offsets, spans);
}
/**
@@ -390,8 +435,34 @@ public class BoxView
protected SizeRequirements calculateMajorAxisRequirements(int axis,
SizeRequirements sr)
{
- SizeRequirements[] childReqs = getChildRequirements(axis);
- return SizeRequirements.getTiledSizeRequirements(childReqs);
+ updateChildRequirements(axis);
+
+ SizeRequirements result = sr;
+ if (result == null)
+ result = new SizeRequirements();
+
+ long minimum = 0;
+ long preferred = 0;
+ long maximum = 0;
+ for (int i = 0; i < children.length; i++)
+ {
+ minimum += childReqs[axis][i].minimum;
+ preferred += childReqs[axis][i].preferred;
+ maximum += childReqs[axis][i].maximum;
+ }
+ // Overflow check.
+ if (minimum > Integer.MAX_VALUE)
+ minimum = Integer.MAX_VALUE;
+ if (preferred > Integer.MAX_VALUE)
+ preferred = Integer.MAX_VALUE;
+ if (maximum > Integer.MAX_VALUE)
+ maximum = Integer.MAX_VALUE;
+
+ result.minimum = (int) minimum;
+ result.preferred = (int) preferred;
+ result.maximum = (int) maximum;
+ result.alignment = 0.5F;
+ return result;
}
/**
@@ -407,11 +478,49 @@ public class BoxView
* the specified axis
*/
protected SizeRequirements calculateMinorAxisRequirements(int axis,
- SizeRequirements sr)
+ SizeRequirements sr)
{
- SizeRequirements[] childReqs = getChildRequirements(axis);
- return SizeRequirements.getAlignedSizeRequirements(childReqs);
+ updateChildRequirements(axis);
+
+ SizeRequirements res = sr;
+ if (res == null)
+ res = new SizeRequirements();
+
+ float minLeft = 0;
+ float minRight = 0;
+ float prefLeft = 0;
+ float prefRight = 0;
+ float maxLeft = 0;
+ float maxRight = 0;
+ for (int i = 0; i < childReqs[axis].length; i++)
+ {
+ float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment;
+ float myMinRight = childReqs[axis][i].minimum - myMinLeft;
+ minLeft = Math.max(myMinLeft, minLeft);
+ minRight = Math.max(myMinRight, minRight);
+ float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment;
+ float myPrefRight = childReqs[axis][i].preferred - myPrefLeft;
+ prefLeft = Math.max(myPrefLeft, prefLeft);
+ prefRight = Math.max(myPrefRight, prefRight);
+ float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment;
+ float myMaxRight = childReqs[axis][i].maximum - myMaxLeft;
+ maxLeft = Math.max(myMaxLeft, maxLeft);
+ maxRight = Math.max(myMaxRight, maxRight);
+ }
+ int minSize = (int) (minLeft + minRight);
+ int prefSize = (int) (prefLeft + prefRight);
+ int maxSize = (int) (maxLeft + maxRight);
+ float align = prefLeft / (prefRight + prefLeft);
+ if (Float.isNaN(align))
+ align = 0;
+
+ res.alignment = align;
+ res.maximum = maxSize;
+ res.preferred = prefSize;
+ res.minimum = minSize;
+ return res;
}
+
/**
* Returns <code>true</code> if the specified point lies before the
@@ -511,10 +620,10 @@ public class BoxView
if (! isAllocationValid())
layout(a.width, a.height);
- a.x += offsetsX[index];
- a.y += offsetsY[index];
- a.width = spansX[index];
- a.height = spansY[index];
+ a.x += offsets[X_AXIS][index];
+ a.y += offsets[Y_AXIS][index];
+ a.width = spans[X_AXIS][index];
+ a.height = spans[Y_AXIS][index];
}
/**
@@ -528,8 +637,49 @@ public class BoxView
*/
protected void layout(int width, int height)
{
- baselineLayout(width, X_AXIS, offsetsX, spansX);
- baselineLayout(height, Y_AXIS, offsetsY, spansY);
+ 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]);
+ }
+ layoutValid[minorAxis] = true;
+ }
+
+
+ // Update major axis as appropriate.
+ if ((! isLayoutValid(myAxis)) || newSpan[myAxis] != span[myAxis])
+ {
+ layoutValid[myAxis] = false;
+ span[myAxis] = newSpan[myAxis];
+ layoutMajorAxis(span[myAxis], myAxis, offsets[myAxis],
+ spans[myAxis]);
+
+ // Update the child view's sizes.
+ for (int i = 0; i < count; ++i)
+ {
+ getView(i).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");
}
/**
@@ -544,12 +694,15 @@ public class BoxView
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
int[] spans)
{
- SizeRequirements[] childReqs = getChildRequirements(axis);
+ updateChildRequirements(axis);
+ updateRequirements(axis);
+
// Calculate the spans and offsets using the SizeRequirements uility
// methods.
- SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
+ SizeRequirements.calculateTiledPositions(targetSpan, requirements[axis],
+ childReqs[axis],
offsets, spans);
- validateLayout(axis);
+
}
/**
@@ -564,18 +717,14 @@ public class BoxView
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
int[] spans)
{
- SizeRequirements[] childReqs = getChildRequirements(axis);
+ updateChildRequirements(axis);
+ updateRequirements(axis);
+
// Calculate the spans and offsets using the SizeRequirements uility
// methods.
- // TODO: This might be an opportunity for performance optimization. Here
- // we could use a cached instance of SizeRequirements instead of passing
- // null to baselineRequirements. However, this would involve rewriting
- // the baselineRequirements() method to not use the SizeRequirements
- // utility method, since they cannot reuse a cached instance.
- SizeRequirements total = baselineRequirements(axis, null);
- SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs,
- offsets, spans);
- validateLayout(axis);
+ SizeRequirements.calculateAlignedPositions(targetSpan, requirements[axis],
+ childReqs[axis], offsets,
+ spans);
}
/**
@@ -597,7 +746,7 @@ public class BoxView
*/
public int getWidth()
{
- return width;
+ return span[X_AXIS];
}
/**
@@ -607,7 +756,7 @@ public class BoxView
*/
public int getHeight()
{
- return height;
+ return span[Y_AXIS];
}
/**
@@ -619,54 +768,7 @@ public class BoxView
*/
public void setSize(float width, float height)
{
- if (this.width != (int) width)
- layoutChanged(X_AXIS);
- if (this.height != (int) height)
- layoutChanged(Y_AXIS);
-
- this.width = (int) width;
- this.height = (int) height;
-
- Rectangle outside = new Rectangle(0, 0, this.width, this.height);
- Rectangle inside = getInsideAllocation(outside);
- if (!isAllocationValid())
- layout(inside.width, inside.height);
- }
-
- /**
- * Sets the layout to valid for a specific axis.
- *
- * @param axis the axis for which to validate the layout
- */
- void validateLayout(int axis)
- {
- if (axis == X_AXIS)
- xLayoutValid = true;
- if (axis == Y_AXIS)
- yLayoutValid = true;
- }
-
- /**
- * Returns the size requirements of this view's children for the major
- * axis.
- *
- * @return the size requirements of this view's children for the major
- * axis
- */
- SizeRequirements[] getChildRequirements(int axis)
- {
- // Allocate SizeRequirements for each child view.
- int count = getViewCount();
- SizeRequirements[] childReqs = new SizeRequirements[count];
- for (int i = 0; i < count; ++i)
- {
- View view = getView(i);
- childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
- (int) view.getPreferredSpan(axis),
- (int) view.getMaximumSpan(axis),
- view.getAlignment(axis));
- }
- return childReqs;
+ layout((int) width, (int) height);
}
/**
@@ -682,10 +784,9 @@ public class BoxView
*/
protected int getSpan(int axis, int childIndex)
{
- if (axis == X_AXIS)
- return spansX[childIndex];
- else
- return spansY[childIndex];
+ if (axis != X_AXIS && axis != Y_AXIS)
+ throw new IllegalArgumentException("Illegal axis argument");
+ return spans[axis][childIndex];
}
/**
@@ -701,10 +802,9 @@ public class BoxView
*/
protected int getOffset(int axis, int childIndex)
{
- if (axis == X_AXIS)
- return offsetsX[childIndex];
- else
- return offsetsY[childIndex];
+ if (axis != X_AXIS && axis != Y_AXIS)
+ throw new IllegalArgumentException("Illegal axis argument");
+ return offsets[axis][childIndex];
}
/**
@@ -719,10 +819,15 @@ public class BoxView
*/
public float getAlignment(int axis)
{
+ float align;
if (axis == myAxis)
- return 0.5F;
+ align = 0.5F;
else
- return baselineRequirements(axis, null).alignment;
+ {
+ updateRequirements(axis);
+ align = requirements[axis].alignment;
+ }
+ return align;
}
/**
@@ -732,12 +837,12 @@ public class BoxView
* @param height indicates that the preferred height of the child changed.
* @param child the child View.
*/
- public void preferenceChanged (View child, boolean width, boolean height)
+ public void preferenceChanged(View child, boolean width, boolean height)
{
if (width)
- xLayoutValid = false;
+ layoutValid[X_AXIS] = false;
if (height)
- yLayoutValid = false;
+ layoutValid[Y_AXIS] = false;
super.preferenceChanged(child, width, height);
}
@@ -751,11 +856,118 @@ public class BoxView
throws BadLocationException
{
// Make sure everything is allocated properly and then call super
- if (!isAllocationValid())
+ if (! isAllocationValid())
{
Rectangle bounds = a.getBounds();
- setSize(bounds.width, bounds.height);
+ layout(bounds.width, bounds.height);
}
return super.modelToView(pos, a, bias);
}
+
+ /**
+ * Returns the resize weight of this view. A value of <code>0</code> or less
+ * means this view is not resizeable. Positive values make the view
+ * resizeable. This implementation returns <code>0</code> for the major
+ * axis and <code>1</code> for the minor axis of this box view.
+ *
+ * @param axis the axis
+ *
+ * @return the resizability of this view along the specified axis
+ *
+ * @throws IllegalArgumentException if <code>axis</code> is invalid
+ */
+ public int getResizeWeight(int axis)
+ {
+ if (axis != X_AXIS && axis != Y_AXIS)
+ throw new IllegalArgumentException("Illegal axis argument");
+ int weight = 1;
+ if (axis == myAxis)
+ weight = 0;
+ return weight;
+ }
+
+ /**
+ * Returns the child allocation for the child view with the specified
+ * <code>index</code>. If the layout is invalid, this returns
+ * <code>null</code>.
+ *
+ * @param index the child view index
+ * @param a the allocation to this view
+ *
+ * @return the child allocation for the child view with the specified
+ * <code>index</code> or <code>null</code> if the layout is invalid
+ * or <code>a</code> is null
+ */
+ public Shape getChildAllocation(int index, Shape a)
+ {
+ Shape ret = null;
+ if (isAllocationValid() && a != null)
+ ret = super.getChildAllocation(index, a);
+ return ret;
+ }
+
+ protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e,
+ Shape a, ViewFactory vf)
+ {
+ // FIXME: What to do here?
+ super.forwardUpdate(ec, e, a, vf);
+ }
+
+ public int viewToModel(float x, float y, Shape a, Position.Bias[] bias)
+ {
+ // FIXME: What to do here?
+ return super.viewToModel(x, y, a, bias);
+ }
+
+ protected boolean flipEastAndWestEnds(int position, Position.Bias bias)
+ {
+ // FIXME: What to do here?
+ return super.flipEastAndWestAtEnds(position, bias);
+ }
+
+ /**
+ * Updates the child requirements along the specified axis. The requirements
+ * are only updated if the layout for the specified axis is marked as
+ * invalid.
+ *
+ * @param axis the axis to be updated
+ */
+ private void updateChildRequirements(int axis)
+ {
+ if (! isLayoutValid(axis))
+ {
+ int numChildren = getViewCount();
+ if (childReqs[axis] == null || childReqs[axis].length != numChildren)
+ childReqs[axis] = new SizeRequirements[numChildren];
+ for (int i = 0; i < numChildren; ++i)
+ {
+ View child = getView(i);
+ childReqs[axis][i] =
+ new SizeRequirements((int) child.getMinimumSpan(axis),
+ (int) child.getPreferredSpan(axis),
+ (int) child.getMaximumSpan(axis),
+ child.getAlignment(axis));
+ }
+ }
+ }
+
+ /**
+ * Updates the view's cached requirements along the specified axis if
+ * necessary. The requirements are only updated if the layout for the
+ * specified axis is marked as invalid.
+ *
+ * @param axis the axis
+ */
+ private void updateRequirements(int axis)
+ {
+ if (! layoutValid[axis])
+ {
+ if (axis == myAxis)
+ requirements[axis] = calculateMajorAxisRequirements(axis,
+ requirements[axis]);
+ else
+ requirements[axis] = calculateMinorAxisRequirements(axis,
+ requirements[axis]);
+ }
+ }
}
diff --git a/libjava/classpath/javax/swing/text/ComponentView.java b/libjava/classpath/javax/swing/text/ComponentView.java
index 2846f8b536b..a7d237ab73a 100644
--- a/libjava/classpath/javax/swing/text/ComponentView.java
+++ b/libjava/classpath/javax/swing/text/ComponentView.java
@@ -228,8 +228,9 @@ public class ComponentView extends View
*
* @param p the parent view to set
*/
- void setParentImpl(View p)
+ private void setParentImpl(View p)
{
+ super.setParent(p);
if (p != null)
{
Component c = getComponent();
diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java
index cd664521542..a10aca7e625 100644
--- a/libjava/classpath/javax/swing/text/CompositeView.java
+++ b/libjava/classpath/javax/swing/text/CompositeView.java
@@ -218,20 +218,43 @@ public abstract class CompositeView
throws BadLocationException
{
int childIndex = getViewIndex(pos, bias);
+ Shape ret = null;
if (childIndex != -1)
{
View child = getView(childIndex);
- Rectangle r = a.getBounds();
- childAllocation(childIndex, r);
- Shape result = child.modelToView(pos, r, bias);
- if (result == null)
- throw new AssertionError("" + child.getClass().getName()
- + ".modelToView() must not return null");
- return result;
+ Shape childAlloc = getChildAllocation(childIndex, a);
+ if (childAlloc == null)
+ ret = createDefaultLocation(a, bias);
+ Shape result = child.modelToView(pos, childAlloc, bias);
+ if (result != null)
+ ret = result;
+ else
+ ret = createDefaultLocation(a, bias);
}
else
- throw new BadLocationException("No child view for the specified location",
- pos);
+ ret = createDefaultLocation(a, bias);
+ return ret;
+ }
+
+ /**
+ * A helper method for {@link #modelToView(int, Position.Bias, int,
+ * Position.Bias, Shape)}. This creates a default location when there is
+ * no child view that can take responsibility for mapping the position to
+ * view coordinates. Depending on the specified bias this will be the
+ * left or right edge of this view's allocation.
+ *
+ * @param a the allocation for this view
+ * @param bias the bias
+ *
+ * @return a default location
+ */
+ private Shape createDefaultLocation(Shape a, Position.Bias bias)
+ {
+ Rectangle alloc = a.getBounds();
+ Rectangle location = new Rectangle(alloc.x, alloc.y, 1, alloc.height);
+ if (bias == Position.Bias.Forward)
+ location.x = alloc.x + alloc.width;
+ return location;
}
/**
@@ -350,7 +373,8 @@ public abstract class CompositeView
*/
public int getViewIndex(int pos, Position.Bias b)
{
- // FIXME: Handle bias somehow.
+ if (b == Position.Bias.Backward && pos != 0)
+ pos -= 1;
return getViewIndexAtPosition(pos);
}
diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java
index 776ef69e5b3..f2a68c00db1 100644
--- a/libjava/classpath/javax/swing/text/DefaultCaret.java
+++ b/libjava/classpath/javax/swing/text/DefaultCaret.java
@@ -148,14 +148,16 @@ public class DefaultCaret extends Rectangle
*/
public void removeUpdate(DocumentEvent event)
{
- if (policy == ALWAYS_UPDATE ||
- (SwingUtilities.isEventDispatchThread() &&
- policy == UPDATE_WHEN_ON_EDT))
+ if (policy == ALWAYS_UPDATE
+ || (SwingUtilities.isEventDispatchThread()
+ && policy == UPDATE_WHEN_ON_EDT))
{
int dot = getDot();
setDot(dot - event.getLength());
}
- else if (policy == NEVER_UPDATE)
+ else if (policy == NEVER_UPDATE
+ || (! SwingUtilities.isEventDispatchThread()
+ && policy == UPDATE_WHEN_ON_EDT))
{
int docLength = event.getDocument().getLength();
if (getDot() > docLength)
@@ -364,7 +366,8 @@ public class DefaultCaret extends Rectangle
* <ul>
* <li>If we receive a double click, the caret position (dot) is set
* to the position associated to the mouse click and the word at
- * this location is selected.</li>
+ * this location is selected. If there is no word at the pointer
+ * the gap is selected instead.</li>
* <li>If we receive a triple click, the caret position (dot) is set
* to the position associated to the mouse click and the line at
* this location is selected.</li>
@@ -374,7 +377,50 @@ public class DefaultCaret extends Rectangle
*/
public void mouseClicked(MouseEvent event)
{
- // TODO: Implement double- and triple-click behaviour here.
+ int count = event.getClickCount();
+
+ if (count >= 2)
+ {
+ int newDot = getComponent().viewToModel(event.getPoint());
+ JTextComponent t = getComponent();
+
+ try
+ {
+ if (count == 3)
+ t.select(Utilities.getRowStart(t, newDot), Utilities.getRowEnd(t, newDot));
+ else
+ {
+ int nextWord = Utilities.getNextWord(t, newDot);
+
+ // When the mouse points at the offset of the first character
+ // in a word Utilities().getPreviousWord will not return that
+ // word but we want to select that. We have to use
+ // Utilities.nextWord() to get it.
+ if (newDot == nextWord)
+ t.select(nextWord, Utilities.getNextWord(t, nextWord));
+ else
+ {
+ int previousWord = Utilities.getPreviousWord(t, newDot);
+ int previousWordEnd = Utilities.getWordEnd(t, previousWord);
+
+ // If the user clicked in the space between two words,
+ // then select the space.
+ if (newDot >= previousWordEnd && newDot <= nextWord)
+ t.select(previousWordEnd, nextWord);
+ // Otherwise select the word under the mouse pointer.
+ else
+ t.select(previousWord, previousWordEnd);
+ }
+ }
+ }
+ catch(BadLocationException ble)
+ {
+ // TODO: Swallowing ok here?
+ }
+
+ dot = newDot;
+ }
+
}
/**
@@ -409,7 +455,10 @@ public class DefaultCaret extends Rectangle
*/
public void mousePressed(MouseEvent event)
{
- positionCaret(event);
+ if (event.isShiftDown())
+ moveCaret(event);
+ else
+ positionCaret(event);
}
/**
@@ -575,7 +624,39 @@ public class DefaultCaret extends Rectangle
{
return mark;
}
-
+
+ private void clearHighlight()
+ {
+ Highlighter highlighter = textComponent.getHighlighter();
+
+ if (highlighter == null)
+ return;
+
+ if (selectionVisible)
+ {
+ try
+ {
+ if (highlightEntry == null)
+ highlightEntry = highlighter.addHighlight(0, 0, getSelectionPainter());
+ else
+ highlighter.changeHighlight(highlightEntry, 0, 0);
+ }
+ catch (BadLocationException e)
+ {
+ // This should never happen.
+ throw new InternalError();
+ }
+ }
+ else
+ {
+ if (highlightEntry != null)
+ {
+ highlighter.removeHighlight(highlightEntry);
+ highlightEntry = null;
+ }
+ }
+ }
+
private void handleHighlight()
{
Highlighter highlighter = textComponent.getHighlighter();
@@ -586,7 +667,7 @@ public class DefaultCaret extends Rectangle
int p0 = Math.min(dot, mark);
int p1 = Math.max(dot, mark);
- if (selectionVisible && p0 != p1)
+ if (selectionVisible)
{
try
{
@@ -659,7 +740,10 @@ public class DefaultCaret extends Rectangle
if (comp == null)
return;
- int dot = getDot();
+ // Make sure the dot has a sane position.
+ dot = Math.min(dot, textComponent.getDocument().getLength());
+ dot = Math.max(dot, 0);
+
Rectangle rect = null;
try
@@ -668,10 +752,10 @@ public class DefaultCaret extends Rectangle
}
catch (BadLocationException e)
{
- AssertionError ae;
- ae = new AssertionError("Unexpected bad caret location: " + dot);
- ae.initCause(e);
- throw ae;
+ AssertionError ae;
+ ae = new AssertionError("Unexpected bad caret location: " + dot);
+ ae.initCause(e);
+ throw ae;
}
if (rect == null)
@@ -812,7 +896,11 @@ public class DefaultCaret extends Rectangle
{
if (dot >= 0)
{
- this.dot = dot;
+ Document doc = textComponent.getDocument();
+ if (doc != null)
+ this.dot = Math.min(dot, doc.getLength());
+ this.dot = Math.max(this.dot, 0);
+
handleHighlight();
adjustVisibility(this);
appear();
@@ -836,8 +924,9 @@ public class DefaultCaret extends Rectangle
if (doc != null)
this.dot = Math.min(dot, doc.getLength());
this.dot = Math.max(this.dot, 0);
- this.mark = dot;
- handleHighlight();
+ this.mark = this.dot;
+
+ clearHighlight();
adjustVisibility(this);
appear();
}
diff --git a/libjava/classpath/javax/swing/text/DefaultEditorKit.java b/libjava/classpath/javax/swing/text/DefaultEditorKit.java
index 88094b898f7..c0056963c78 100644
--- a/libjava/classpath/javax/swing/text/DefaultEditorKit.java
+++ b/libjava/classpath/javax/swing/text/DefaultEditorKit.java
@@ -707,16 +707,14 @@ public class DefaultEditorKit extends EditorKit
JTextComponent t = getTextComponent(event);
try
{
- // TODO: There is a more efficent solution, but
- // viewToModel doesn't work properly.
- Point p = t.modelToView(t.getCaret().getDot()).getLocation();
- int cur = t.getCaretPosition();
- int y = p.y;
- while (y == p.y && cur > 0)
- y = t.modelToView(--cur).getLocation().y;
- if (cur != 0)
- cur++;
- t.setCaretPosition(cur);
+ int offs = Utilities.getRowStart(t, t.getCaretPosition());
+
+ if (offs > -1)
+ {
+ Caret c = t.getCaret();
+ c.setDot(offs);
+ c.setMagicCaretPosition(t.modelToView(offs).getLocation());
+ }
}
catch (BadLocationException ble)
{
@@ -729,17 +727,16 @@ public class DefaultEditorKit extends EditorKit
public void actionPerformed(ActionEvent event)
{
JTextComponent t = getTextComponent(event);
- try
+ try
{
- Point p = t.modelToView(t.getCaret().getDot()).getLocation();
- int cur = t.getCaretPosition();
- int y = p.y;
- int length = t.getDocument().getLength();
- while (y == p.y && cur < length)
- y = t.modelToView(++cur).getLocation().y;
- if (cur != length)
- cur--;
- t.setCaretPosition(cur);
+ int offs = Utilities.getRowEnd(t, t.getCaretPosition());
+
+ if (offs > -1)
+ {
+ Caret c = t.getCaret();
+ c.setDot(offs);
+ c.setMagicCaretPosition(t.modelToView(offs).getLocation());
+ }
}
catch (BadLocationException ble)
{
@@ -756,11 +753,17 @@ public class DefaultEditorKit extends EditorKit
{
try
{
- int pos = t.getCaret().getDot();
- if (pos < t.getDocument().getEndPosition().getOffset())
- {
- t.getDocument().remove(t.getCaret().getDot(), 1);
- }
+ int pos = t.getSelectionStart();
+ int len = t.getSelectionEnd() - pos;
+
+ if (len > 0)
+ t.getDocument().remove(pos, len);
+ else if (pos < t.getDocument().getLength())
+ t.getDocument().remove(pos, 1);
+
+ Caret c = t.getCaret();
+ c.setDot(pos);
+ c.setMagicCaretPosition(t.modelToView(pos).getLocation());
}
catch (BadLocationException e)
{
@@ -778,11 +781,18 @@ public class DefaultEditorKit extends EditorKit
{
try
{
- int pos = t.getCaret().getDot();
- if (pos > t.getDocument().getStartPosition().getOffset())
+ int pos = t.getSelectionStart();
+ int len = t.getSelectionEnd() - pos;
+
+ if (len > 0)
+ t.getDocument().remove(pos, len);
+ else if (pos > 0)
{
- t.getDocument().remove(pos - 1, 1);
- t.getCaret().setDot(pos - 1);
+ pos--;
+ t.getDocument().remove(pos, 1);
+ Caret c = t.getCaret();
+ c.setDot(pos);
+ c.setMagicCaretPosition(t.modelToView(pos).getLocation());
}
}
catch (BadLocationException e)
@@ -799,8 +809,21 @@ public class DefaultEditorKit extends EditorKit
JTextComponent t = getTextComponent(event);
if (t != null)
{
- t.getCaret().setDot(Math.max(t.getCaret().getDot() - 1,
- t.getDocument().getStartPosition().getOffset()));
+ int offs = t.getCaretPosition() - 1;
+ if (offs >= 0)
+ {
+ Caret c = t.getCaret();
+ c.setDot(offs);
+
+ try
+ {
+ c.setMagicCaretPosition(t.modelToView(offs).getLocation());
+ }
+ catch (BadLocationException ble)
+ {
+ // Should not happen.
+ }
+ }
}
}
},
@@ -811,8 +834,74 @@ public class DefaultEditorKit extends EditorKit
JTextComponent t = getTextComponent(event);
if (t != null)
{
- t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1,
- t.getDocument().getEndPosition().getOffset()));
+ int offs = t.getCaretPosition() + 1;
+ if (offs <= t.getDocument().getLength())
+ {
+ Caret c = t.getCaret();
+ c.setDot(offs);
+
+ try
+ {
+ c.setMagicCaretPosition(t.modelToView(offs).getLocation());
+ }
+ catch (BadLocationException ble)
+ {
+ // Should not happen.
+ }
+ }
+ }
+
+ }
+ },
+ new TextAction(upAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+ try
+ {
+ if (t != null)
+ {
+ Caret c = t.getCaret();
+ // The magic caret position may be null when the caret
+ // has not moved yet.
+ Point mcp = c.getMagicCaretPosition();
+ int x = (mcp != null) ? mcp.x : 0;
+ int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x);
+
+ if (pos > -1)
+ t.setCaretPosition(pos);
+ }
+ }
+ catch(BadLocationException ble)
+ {
+ // FIXME: Swallowing allowed?
+ }
+ }
+ },
+ new TextAction(downAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+ try
+ {
+ if (t != null)
+ {
+ Caret c = t.getCaret();
+ // The magic caret position may be null when the caret
+ // has not moved yet.
+ Point mcp = c.getMagicCaretPosition();
+ int x = (mcp != null) ? mcp.x : 0;
+ int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x);
+
+ if (pos > -1)
+ t.setCaretPosition(pos);
+ }
+ }
+ catch(BadLocationException ble)
+ {
+ // FIXME: Swallowing allowed?
}
}
},
@@ -823,8 +912,21 @@ public class DefaultEditorKit extends EditorKit
JTextComponent t = getTextComponent(event);
if (t != null)
{
- t.getCaret().moveDot(Math.max(t.getCaret().getDot() - 1,
- t.getDocument().getStartPosition().getOffset()));
+ int offs = t.getCaretPosition() - 1;
+
+ if(offs >= 0)
+ {
+ Caret c = t.getCaret();
+ c.moveDot(offs);
+ try
+ {
+ c.setMagicCaretPosition(t.modelToView(offs).getLocation());
+ }
+ catch(BadLocationException ble)
+ {
+ // Can't happen.
+ }
+ }
}
}
},
@@ -835,11 +937,167 @@ public class DefaultEditorKit extends EditorKit
JTextComponent t = getTextComponent(event);
if (t != null)
{
- t.getCaret().moveDot(Math.min(t.getCaret().getDot() + 1,
- t.getDocument().getEndPosition().getOffset()));
+ int offs = t.getCaretPosition() + 1;
+
+ if(offs <= t.getDocument().getLength())
+ {
+ Caret c = t.getCaret();
+ c.moveDot(offs);
+ try
+ {
+ c.setMagicCaretPosition(t.modelToView(offs).getLocation());
+ }
+ catch(BadLocationException ble)
+ {
+ // Can't happen.
+ }
+ }
+ }
+ }
+ },
+ new TextAction(selectionUpAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+ try
+ {
+ if (t != null)
+ {
+ Caret c = t.getCaret();
+ // The magic caret position may be null when the caret
+ // has not moved yet.
+ Point mcp = c.getMagicCaretPosition();
+ int x = (mcp != null) ? mcp.x : 0;
+ int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x);
+
+ if (pos > -1)
+ t.moveCaretPosition(pos);
+ }
+ }
+ catch(BadLocationException ble)
+ {
+ // FIXME: Swallowing allowed?
+ }
+ }
+ },
+ new TextAction(selectionDownAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+ try
+ {
+ if (t != null)
+ {
+ Caret c = t.getCaret();
+ // The magic caret position may be null when the caret
+ // has not moved yet.
+ Point mcp = c.getMagicCaretPosition();
+ int x = (mcp != null) ? mcp.x : 0;
+ int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x);
+
+ if (pos > -1)
+ t.moveCaretPosition(pos);
+ }
+ }
+ catch(BadLocationException ble)
+ {
+ // FIXME: Swallowing allowed?
}
}
},
+ new TextAction(selectionBeginLineAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+
+ try
+ {
+ // TODO: There is a more efficent solution, but
+ // viewToModel doesn't work properly.
+ Point p = t.modelToView(t.getCaret().getDot()).getLocation();
+
+ int cur = t.getCaretPosition();
+ int y = p.y;
+
+ while (y == p.y && cur > 0)
+ y = t.modelToView(--cur).getLocation().y;
+ if (cur != 0)
+ cur++;
+
+ Caret c = t.getCaret();
+ c.moveDot(cur);
+ c.setMagicCaretPosition(t.modelToView(cur).getLocation());
+ }
+ catch (BadLocationException ble)
+ {
+ // Do nothing here.
+ }
+ }
+ },
+ new TextAction(selectionEndLineAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+ try
+ {
+ Point p = t.modelToView(t.getCaret().getDot()).getLocation();
+ int cur = t.getCaretPosition();
+ int y = p.y;
+ int length = t.getDocument().getLength();
+ while (y == p.y && cur < length)
+ y = t.modelToView(++cur).getLocation().y;
+ if (cur != length)
+ cur--;
+
+ Caret c = t.getCaret();
+ c.moveDot(cur);
+ c.setMagicCaretPosition(t.modelToView(cur).getLocation());
+ }
+ catch (BadLocationException ble)
+ {
+ // Nothing to do here
+ }
+ }
+ },
+ new TextAction(selectionEndAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+ int offs = t.getDocument().getLength();
+ Caret c = t.getCaret();
+ c.moveDot(offs);
+ try
+ {
+ c.setMagicCaretPosition(t.modelToView(offs).getLocation());
+ }
+ catch(BadLocationException ble)
+ {
+ // Can't happen.
+ }
+ }
+ },
+ new TextAction(selectionBeginAction)
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ JTextComponent t = getTextComponent(event);
+ Caret c = t.getCaret();
+ c.moveDot(0);
+ try
+ {
+ c.setMagicCaretPosition(t.modelToView(0).getLocation());
+ }
+ catch(BadLocationException ble)
+ {
+ // Can't happen.
+ }
+ }
+ }
};
/**
diff --git a/libjava/classpath/javax/swing/text/DefaultFormatter.java b/libjava/classpath/javax/swing/text/DefaultFormatter.java
index 493699dacba..e42b1698af8 100644
--- a/libjava/classpath/javax/swing/text/DefaultFormatter.java
+++ b/libjava/classpath/javax/swing/text/DefaultFormatter.java
@@ -219,7 +219,6 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter
commitsOnValidEdit = true;
overwriteMode = true;
allowsInvalid = true;
- valueClass = Object.class;
}
/**
@@ -368,7 +367,11 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter
Object value = string;
Class valueClass = getValueClass();
if (valueClass == null)
- valueClass = getFormattedTextField().getValue().getClass();
+ {
+ JFormattedTextField jft = getFormattedTextField();
+ if (jft != null)
+ valueClass = jft.getValue().getClass();
+ }
if (valueClass != null)
try
{
diff --git a/libjava/classpath/javax/swing/text/DefaultHighlighter.java b/libjava/classpath/javax/swing/text/DefaultHighlighter.java
index 40ea4f80aab..33b5fcab8bf 100644
--- a/libjava/classpath/javax/swing/text/DefaultHighlighter.java
+++ b/libjava/classpath/javax/swing/text/DefaultHighlighter.java
@@ -1,5 +1,5 @@
/* DefaultHighlighter.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,9 +40,12 @@ package javax.swing.text;
import java.awt.Color;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
-import java.util.Vector;
+import java.util.ArrayList;
+
+import javax.swing.plaf.TextUI;
public class DefaultHighlighter extends LayeredHighlighter
{
@@ -84,7 +87,7 @@ public class DefaultHighlighter extends LayeredHighlighter
// This should never occur.
return;
}
-
+
if (r0 == null || r1 == null)
return;
@@ -100,7 +103,7 @@ public class DefaultHighlighter extends LayeredHighlighter
paintHighlight(g, r0);
return;
}
-
+
// First line, from p0 to end-of-line.
r0.width = rect.x + rect.width - r0.x;
paintHighlight(g, r0);
@@ -109,15 +112,19 @@ public class DefaultHighlighter extends LayeredHighlighter
// have the same height -- not a good assumption with JEditorPane/JTextPane).
r0.y += r0.height;
r0.x = rect.x;
-
+ r0.width = rect.width;
+
while (r0.y < r1.y)
{
paintHighlight(g, r0);
r0.y += r0.height;
}
- // Last line, from beginnin-of-line to p1.
- paintHighlight(g, r1);
+ // Last line, from beginning-of-line to p1.
+ // The "-1" is neccessary else we would paint one pixel column more
+ // than in the case where the selection is only on one line.
+ r0.width = r1.x + r1.width - 1;
+ paintHighlight(g, r0);
}
public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds,
@@ -127,7 +134,7 @@ public class DefaultHighlighter extends LayeredHighlighter
}
}
- private class HighlightEntry
+ private class HighlightEntry implements Highlighter.Highlight
{
int p0;
int p1;
@@ -140,12 +147,12 @@ public class DefaultHighlighter extends LayeredHighlighter
this.painter = painter;
}
- public int getStartPosition()
+ public int getStartOffset()
{
return p0;
}
- public int getEndPosition()
+ public int getEndOffset()
{
return p1;
}
@@ -163,7 +170,7 @@ public class DefaultHighlighter extends LayeredHighlighter
new DefaultHighlightPainter(null);
private JTextComponent textComponent;
- private Vector highlights = new Vector();
+ private ArrayList highlights = new ArrayList();
private boolean drawsLayeredHighlights = true;
public DefaultHighlighter()
@@ -208,12 +215,20 @@ public class DefaultHighlighter extends LayeredHighlighter
checkPositions(p0, p1);
HighlightEntry entry = new HighlightEntry(p0, p1, painter);
highlights.add(entry);
+
+ textComponent.getUI().damageRange(textComponent, p0, p1);
+
return entry;
}
public void removeHighlight(Object tag)
{
highlights.remove(tag);
+
+ HighlightEntry entry = (HighlightEntry) tag;
+ textComponent.getUI().damageRange(textComponent,
+ entry.p0,
+ entry.p1);
}
public void removeAllHighlights()
@@ -223,16 +238,93 @@ public class DefaultHighlighter extends LayeredHighlighter
public Highlighter.Highlight[] getHighlights()
{
- return null;
+ return (Highlighter.Highlight[])
+ highlights.toArray(new Highlighter.Highlight[highlights.size()]);
}
- public void changeHighlight(Object tag, int p0, int p1)
+ public void changeHighlight(Object tag, int n0, int n1)
throws BadLocationException
{
- checkPositions(p0, p1);
+ int o0, o1;
+
+ checkPositions(n0, n1);
HighlightEntry entry = (HighlightEntry) tag;
- entry.p0 = p0;
- entry.p1 = p1;
+ o0 = entry.p0;
+ o1 = entry.p1;
+
+ // Prevent useless write & repaint operations.
+ if (o0 == n0 && o1 == n1)
+ return;
+
+ entry.p0 = n0;
+ entry.p1 = n1;
+
+ TextUI ui = textComponent.getUI();
+
+ // Special situation where the old area has to be cleared simply.
+ if (n0 == n1)
+ ui.damageRange(textComponent, o0, o1);
+ // Calculates the areas where a change is really neccessary
+ else if ((o1 > n0 && o1 <= n1)
+ || (n1 > o0 && n1 <= o1))
+ {
+ // [fds, fde) - the first damage region
+ // [sds, sde] - the second damage region
+ int fds, sds;
+ int fde, sde;
+
+ // Calculate first damaged region.
+ if(o0 < n0)
+ {
+ // Damaged region will be cleared as
+ // the old highlight region starts first.
+ fds = o0;
+ fde = n0;
+ }
+ else
+ {
+ // Damaged region will be painted as
+ // the new highlight region starts first.
+ fds = n0;
+ fde = o0;
+ }
+
+ if (o1 < n1)
+ {
+ // Final region will be painted as the
+ // old highlight region finishes first
+ sds = o1;
+ sde = n1;
+ }
+ else
+ {
+ // Final region will be cleared as the
+ // new highlight region finishes first.
+ sds = n1;
+ sde = o1;
+ }
+
+ // If there is no undamaged region in between
+ // call damageRange only once.
+ if (fde == sds)
+ ui.damageRange(textComponent, fds, sde);
+ else
+ {
+ if (fds != fde)
+ ui.damageRange(textComponent, fds, fde);
+
+ if (sds != sde)
+ ui.damageRange(textComponent, sds, sde);
+ }
+ }
+ else
+ {
+ // The two regions do not overlap. So mark
+ // both areas as damaged.
+ ui.damageRange(textComponent, o0, o1);
+ ui.damageRange(textComponent, n0, n1);
+ }
+
}
public void paintLayeredHighlights(Graphics g, int p0, int p1,
@@ -244,13 +336,21 @@ public class DefaultHighlighter extends LayeredHighlighter
public void paint(Graphics g)
{
+ int size = highlights.size();
+
// Check if there are any highlights.
- if (highlights.size() == 0)
+ if (size == 0)
return;
+
+ // Prepares the rectangle of the inner drawing area.
+ Insets insets = textComponent.getInsets();
+ Shape bounds =
+ new Rectangle(insets.left,
+ insets.top,
+ textComponent.getWidth() - insets.left - insets.right,
+ textComponent.getHeight() - insets.top - insets.bottom);
- Shape bounds = textComponent.getBounds();
-
- for (int index = 0; index < highlights.size(); ++index)
+ for (int index = 0; index < size; ++index)
{
HighlightEntry entry = (HighlightEntry) highlights.get(index);
entry.painter.paint(g, entry.p0, entry.p1, bounds, textComponent);
diff --git a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java
index 46b82259b65..625ba4c3dcc 100644
--- a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java
+++ b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java
@@ -53,27 +53,25 @@ import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.UndoableEdit;
/**
- * The default implementation of {@link StyledDocument}.
- *
- * The document is modeled as an {@link Element} tree, which has
- * a {@link SectionElement} as single root, which has one or more
- * {@link AbstractDocument.BranchElement}s as paragraph nodes
- * and each paragraph node having one or more
+ * The default implementation of {@link StyledDocument}. The document is
+ * modeled as an {@link Element} tree, which has a {@link SectionElement} as
+ * single root, which has one or more {@link AbstractDocument.BranchElement}s
+ * as paragraph nodes and each paragraph node having one or more
* {@link AbstractDocument.LeafElement}s as content nodes.
- *
+ *
* @author Michael Koch (konqueror@gmx.de)
* @author Roman Kennke (roman@kennke.org)
*/
-public class DefaultStyledDocument extends AbstractDocument
- implements StyledDocument
+public class DefaultStyledDocument extends AbstractDocument implements
+ StyledDocument
{
+
/**
* An {@link UndoableEdit} that can undo attribute changes to an element.
- *
+ *
* @author Roman Kennke (kennke@aicas.com)
*/
- public static class AttributeUndoableEdit
- extends AbstractUndoableEdit
+ public static class AttributeUndoableEdit extends AbstractUndoableEdit
{
/**
* A copy of the old attributes.
@@ -98,11 +96,13 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Creates a new <code>AttributeUndoableEdit</code>.
- *
- * @param el the element that changes attributes
- * @param newAtts the new attributes
- * @param replacing if the new attributes replace the old or only append to
- * them
+ *
+ * @param el
+ * the element that changes attributes
+ * @param newAtts
+ * the new attributes
+ * @param replacing
+ * if the new attributes replace the old or only append to them
*/
public AttributeUndoableEdit(Element el, AttributeSet newAtts,
boolean replacing)
@@ -149,21 +149,19 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Carries specification information for new {@link Element}s that should
- * be created in {@link ElementBuffer}. This allows the parsing process
- * to be decoupled from the <code>Element</code> creation process.
+ * Carries specification information for new {@link Element}s that should be
+ * created in {@link ElementBuffer}. This allows the parsing process to be
+ * decoupled from the <code>Element</code> creation process.
*/
public static class ElementSpec
{
/**
- * This indicates a start tag. This is a possible value for
- * {@link #getType}.
+ * This indicates a start tag. This is a possible value for {@link #getType}.
*/
public static final short StartTagType = 1;
/**
- * This indicates an end tag. This is a possible value for
- * {@link #getType}.
+ * This indicates an end tag. This is a possible value for {@link #getType}.
*/
public static final short EndTagType = 2;
@@ -175,22 +173,19 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* This indicates that the data associated with this spec should be joined
- * with what precedes it. This is a possible value for
- * {@link #getDirection}.
+ * with what precedes it. This is a possible value for {@link #getDirection}.
*/
public static final short JoinPreviousDirection = 4;
/**
* This indicates that the data associated with this spec should be joined
- * with what follows it. This is a possible value for
- * {@link #getDirection}.
+ * with what follows it. This is a possible value for {@link #getDirection}.
*/
public static final short JoinNextDirection = 5;
/**
- * This indicates that the data associated with this spec should be used
- * to create a new element. This is a possible value for
- * {@link #getDirection}.
+ * This indicates that the data associated with this spec should be used to
+ * create a new element. This is a possible value for {@link #getDirection}.
*/
public static final short OriginateDirection = 6;
@@ -234,9 +229,11 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Creates a new <code>ElementSpec</code> with no content, length or
* offset. This is most useful for start and end tags.
- *
- * @param a the attributes for the element to be created
- * @param type the type of the tag
+ *
+ * @param a
+ * the attributes for the element to be created
+ * @param type
+ * the type of the tag
*/
public ElementSpec(AttributeSet a, short type)
{
@@ -247,27 +244,34 @@ public class DefaultStyledDocument extends AbstractDocument
* Creates a new <code>ElementSpec</code> that specifies the length but
* not the offset of an element. Such <code>ElementSpec</code>s are
* processed sequentially from a known starting point.
- *
- * @param a the attributes for the element to be created
- * @param type the type of the tag
- * @param len the length of the element
+ *
+ * @param a
+ * the attributes for the element to be created
+ * @param type
+ * the type of the tag
+ * @param len
+ * the length of the element
*/
public ElementSpec(AttributeSet a, short type, int len)
{
this(a, type, null, 0, len);
}
-
+
/**
* Creates a new <code>ElementSpec</code> with document content.
- *
- * @param a the attributes for the element to be created
- * @param type the type of the tag
- * @param txt the actual content
- * @param offs the offset into the <code>txt</code> array
- * @param len the length of the element
+ *
+ * @param a
+ * the attributes for the element to be created
+ * @param type
+ * the type of the tag
+ * @param txt
+ * the actual content
+ * @param offs
+ * the offset into the <code>txt</code> array
+ * @param len
+ * the length of the element
*/
- public ElementSpec(AttributeSet a, short type, char[] txt, int offs,
- int len)
+ public ElementSpec(AttributeSet a, short type, char[] txt, int offs, int len)
{
attributes = a;
this.type = type;
@@ -279,8 +283,9 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Sets the type of the element.
- *
- * @param type the type of the element to be set
+ *
+ * @param type
+ * the type of the element to be set
*/
public void setType(short type)
{
@@ -289,7 +294,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the type of the element.
- *
+ *
* @return the type of the element
*/
public short getType()
@@ -299,8 +304,9 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Sets the direction of the element.
- *
- * @param dir the direction of the element to be set
+ *
+ * @param dir
+ * the direction of the element to be set
*/
public void setDirection(short dir)
{
@@ -309,7 +315,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the direction of the element.
- *
+ *
* @return the direction of the element
*/
public short getDirection()
@@ -319,7 +325,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the attributes of the element.
- *
+ *
* @return the attributes of the element
*/
public AttributeSet getAttributes()
@@ -329,7 +335,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the actual content of the element.
- *
+ *
* @return the actual content of the element
*/
public char[] getArray()
@@ -339,7 +345,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the offset of the content.
- *
+ *
* @return the offset of the content
*/
public int getOffset()
@@ -349,7 +355,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the length of the content.
- *
+ *
* @return the length of the content
*/
public int getLength()
@@ -361,7 +367,7 @@ public class DefaultStyledDocument extends AbstractDocument
* Returns a String representation of this <code>ElementSpec</code>
* describing the type, direction and length of this
* <code>ElementSpec</code>.
- *
+ *
* @return a String representation of this <code>ElementSpec</code>
*/
public String toString()
@@ -413,7 +419,8 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Performs all <em>structural</code> changes to the <code>Element</code>
- * hierarchy.
+ * hierarchy. This class was implemented with much help from the document:
+ * http://java.sun.com/products/jfc/tsc/articles/text/element_buffer/index.html.
*/
public class ElementBuffer implements Serializable
{
@@ -426,25 +433,20 @@ public class DefaultStyledDocument extends AbstractDocument
/** Holds the offset for structural changes. */
private int offset;
+ /** Holds the end offset for structural changes. */
+ private int endOffset;
+
/** Holds the length of structural changes. */
private int length;
-
- /** Holds the end offset for structural changes. **/
- private int endOffset;
- /**
- * The number of inserted end tags. This is a counter which always gets
- * incremented when an end tag is inserted. This is evaluated before
- * content insertion to go up the element stack.
- */
- private int numEndTags;
+ /** Holds the position of the change. */
+ private int pos;
- /**
- * The number of inserted start tags. This is a counter which always gets
- * incremented when an end tag is inserted. This is evaluated before
- * content insertion to go up the element stack.
- */
- private int numStartTags;
+ /** Holds the element that was last fractured. */
+ private Element lastFractured;
+
+ /** True if a fracture was not created during a insertFracture call. */
+ private boolean fracNotCreated;
/**
* The current position in the element tree. This is used for bulk inserts
@@ -453,14 +455,6 @@ public class DefaultStyledDocument extends AbstractDocument
private Stack elementStack;
/**
- * Holds fractured elements during insertion of end and start tags.
- * Inserting an end tag may lead to fracturing of the current paragraph
- * element. The elements that have been cut off may be added to the
- * next paragraph that is created in the next start tag.
- */
- Element[] fracture;
-
- /**
* The ElementChange that describes the latest changes.
*/
DefaultDocumentEvent documentEvent;
@@ -468,8 +462,9 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Creates a new <code>ElementBuffer</code> for the specified
* <code>root</code> element.
- *
- * @param root the root element for this <code>ElementBuffer</code>
+ *
+ * @param root
+ * the root element for this <code>ElementBuffer</code>
*/
public ElementBuffer(Element root)
{
@@ -479,7 +474,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the root element of this <code>ElementBuffer</code>.
- *
+ *
* @return the root element of this <code>ElementBuffer</code>
*/
public Element getRootElement()
@@ -488,21 +483,23 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Updates the element structure of the document in response to removal of
- * content. It removes the affected {@link Element}s from the document
- * structure.
- *
- * This method sets some internal parameters and delegates the work
- * to {@link #removeUpdate}.
- *
- * @param offs the offset from which content is remove
- * @param len the length of the removed content
- * @param ev the document event that records the changes
+ * Removes the content. This method sets some internal parameters and
+ * delegates the work to {@link #removeUpdate}.
+ *
+ * @param offs
+ * the offset from which content is remove
+ * @param len
+ * the length of the removed content
+ * @param ev
+ * the document event that records the changes
*/
public void remove(int offs, int len, DefaultDocumentEvent ev)
{
+ if (len == 0)
+ return;
offset = offs;
length = len;
+ pos = offset;
documentEvent = ev;
removeUpdate();
}
@@ -519,9 +516,9 @@ public class DefaultStyledDocument extends AbstractDocument
Element[] empty = new Element[0];
int removeStart = -1;
int removeEnd = -1;
- for (int i = startParagraph; i < endParagraph; i++)
+ for (int i = startParagraph; i < endParagraph; i++)
{
- Element paragraph = root.getElement(i);
+ BranchElement paragraph = (BranchElement) root.getElement(i);
int contentStart = paragraph.getElementIndex(offset);
int contentEnd = paragraph.getElementIndex(offset + length);
if (contentStart == paragraph.getStartOffset()
@@ -546,10 +543,8 @@ public class DefaultStyledDocument extends AbstractDocument
Element[] removed = new Element[removeLen];
for (int j = contentStart; j < contentEnd; j++)
removed[j] = paragraph.getElement(j);
- ((BranchElement) paragraph).replace(contentStart, removeLen,
- empty);
- documentEvent.addEdit(new ElementEdit(paragraph, contentStart,
- removed, empty));
+ Edit edit = getEditForParagraphAndIndex(paragraph, contentStart);
+ edit.addRemovedElements(removed);
}
}
// Now we remove paragraphs from the root that have been tagged for
@@ -560,265 +555,234 @@ public class DefaultStyledDocument extends AbstractDocument
Element[] removed = new Element[removeLen];
for (int i = removeStart; i < removeEnd; i++)
removed[i] = root.getElement(i);
- ((BranchElement) root).replace(removeStart, removeLen, empty);
- documentEvent.addEdit(new ElementEdit(root, removeStart, removed,
- empty));
+ Edit edit = getEditForParagraphAndIndex((BranchElement) root,
+ removeStart);
+ edit.addRemovedElements(removed);
}
}
/**
- * Modifies the element structure so that the specified interval starts
- * and ends at an element boundary. Content and paragraph elements
- * are split and created as necessary.
- *
- * This also updates the <code>DefaultDocumentEvent</code> to reflect the
- * structural changes.
- *
- * The bulk work is delegated to {@link #changeUpdate()}.
- *
- * @param offset the start index of the interval to be changed
- * @param length the length of the interval to be changed
- * @param ev the <code>DefaultDocumentEvent</code> describing the change
- */
- public void change(int offset, int length, DefaultDocumentEvent ev)
- {
- this.offset = offset;
- this.length = length;
- documentEvent = ev;
- changeUpdate();
- }
-
- /**
- * Performs the actual work for {@link #change}.
- * The elements at the interval boundaries are split up (if necessary)
- * so that the interval boundaries are located at element boundaries.
+ * Performs the actual work for {@link #change}. The elements at the
+ * interval boundaries are split up (if necessary) so that the interval
+ * boundaries are located at element boundaries.
*/
protected void changeUpdate()
{
// Split up the element at the start offset if necessary.
Element el = getCharacterElement(offset);
- Element[] res = split(el, offset, 0);
+ Element[] res = split(el, offset, 0, el.getElementIndex(offset));
BranchElement par = (BranchElement) el.getParentElement();
+ int index = par.getElementIndex(offset);
+ Edit edit = getEditForParagraphAndIndex(par, index);
if (res[1] != null)
{
- int index = par.getElementIndex(offset);
Element[] removed;
Element[] added;
if (res[0] == null)
{
removed = new Element[0];
- added = new Element[]{ res[1] };
+ added = new Element[] { res[1] };
index++;
}
else
{
- removed = new Element[]{ el };
- added = new Element[]{ res[0], res[1] };
+ removed = new Element[] { el };
+ added = new Element[] { res[0], res[1] };
}
- par.replace(index, removed.length, added);
- addEdit(par, index, removed, added);
+ edit.addRemovedElements(removed);
+
+ edit.addAddedElements(added);
}
int endOffset = offset + length;
el = getCharacterElement(endOffset);
- res = split(el, endOffset, 0);
+ res = split(el, endOffset, 0, el.getElementIndex(endOffset));
par = (BranchElement) el.getParentElement();
- if (res[1] != null)
+ if (res[0] != null)
{
- int index = par.getElementIndex(offset);
Element[] removed;
Element[] added;
if (res[1] == null)
{
removed = new Element[0];
- added = new Element[]{ res[1] };
+ added = new Element[] { res[1] };
}
else
{
- removed = new Element[]{ el };
- added = new Element[]{ res[0], res[1] };
+ removed = new Element[] { el };
+ added = new Element[] { res[0], res[1] };
}
- par.replace(index, removed.length, added);
- addEdit(par, index, removed, added);
+ edit.addRemovedElements(removed);
+ edit.addAddedElements(added);
}
}
/**
- * Splits an element if <code>offset</code> is not alread at its boundary.
+ * Modifies the element structure so that the specified interval starts and
+ * ends at an element boundary. Content and paragraph elements are split and
+ * created as necessary. This also updates the
+ * <code>DefaultDocumentEvent</code> to reflect the structural changes.
+ * The bulk work is delegated to {@link #changeUpdate()}.
+ *
+ * @param offset
+ * the start index of the interval to be changed
+ * @param length
+ * the length of the interval to be changed
+ * @param ev
+ * the <code>DefaultDocumentEvent</code> describing the change
+ */
+ public void change(int offset, int length, DefaultDocumentEvent ev)
+ {
+ if (length == 0)
+ return;
+ this.offset = offset;
+ this.pos = offset;
+ this.length = length;
+ documentEvent = ev;
+ changeUpdate();
+ }
+
+ /**
+ * Creates and returns a deep clone of the specified <code>clonee</code>
+ * with the specified parent as new parent.
*
- * @param el the Element to possibly split
- * @param offset the offset at which to possibly split
- * @param space the amount of space to create between the splitted parts
+ * This method can only clone direct instances of {@link BranchElement}
+ * or {@link LeafElement}.
*
- * @return An array of elements which represent the split result. This
- * array has two elements, the two parts of the split. The first
- * element might be null, which means that the element which should
- * be splitted can remain in place. The second element might also
- * be null, which means that the offset is already at an element
- * boundary and the element doesn't need to be splitted.
- *
+ * @param parent the new parent
+ * @param clonee the element to be cloned
+ *
+ * @return the cloned element with the new parent
*/
- private Element[] split(Element el, int offset, int space)
+ public Element clone(Element parent, Element clonee)
{
- // If we are at an element boundary, then return an empty array.
- if ((offset == el.getStartOffset() || offset == el.getEndOffset())
- && space == 0 && el.isLeaf())
- return new Element[2];
-
- // If the element is an instance of BranchElement, then we recursivly
- // call this method to perform the split.
- Element[] res = new Element[2];
- if (el instanceof BranchElement)
+ Element clone = clonee;
+ // We can only handle AbstractElements here.
+ if (clonee instanceof BranchElement)
{
- int index = el.getElementIndex(offset);
- Element child = el.getElement(index);
- Element[] result = split(child, offset, space);
- Element[] removed;
- Element[] added;
- Element[] newAdded;
-
- int count = el.getElementCount();
- if (!(result[1] == null))
- {
- // This is the case when we can keep the first element.
- if (result[0] == null)
- {
- removed = new Element[count - index - 1];
- newAdded = new Element[count - index - 1];
- added = new Element[]{};
- }
- // This is the case when we may not keep the first element.
- else
- {
- removed = new Element[count - index];
- newAdded = new Element[count - index];
- added = new Element[]{result[0]};
- }
- newAdded[0] = result[1];
- for (int i = index; i < count; i++)
- {
- Element el2 = el.getElement(i);
- int ind = i - count + removed.length;
- removed[ind] = el2;
- if (ind != 0)
- newAdded[ind] = el2;
- }
-
- ((BranchElement) el).replace(index, removed.length, added);
- addEdit(el, index, removed, added);
- BranchElement newPar =
- (BranchElement) createBranchElement(el.getParentElement(),
- el.getAttributes());
- newPar.replace(0, 0, newAdded);
- res = new Element[]{ null, newPar };
- }
- else
+ BranchElement branchEl = (BranchElement) clonee;
+ BranchElement branchClone =
+ new BranchElement(parent, branchEl.getAttributes());
+ // Also clone all of the children.
+ int numChildren = branchClone.getElementCount();
+ Element[] cloneChildren = new Element[numChildren];
+ for (int i = 0; i < numChildren; ++i)
{
- removed = new Element[count - index];
- for (int i = index; i < count; ++i)
- removed[i - index] = el.getElement(i);
- added = new Element[0];
- ((BranchElement) el).replace(index, removed.length,
- added);
- addEdit(el, index, removed, added);
- BranchElement newPar =
- (BranchElement) createBranchElement(el.getParentElement(),
- el.getAttributes());
- newPar.replace(0, 0, removed);
- res = new Element[]{ null, newPar };
+ cloneChildren[i] = clone(branchClone,
+ branchClone.getElement(i));
}
+ branchClone.replace(0, 0, cloneChildren);
+ clone = branchClone;
}
- else if (el instanceof LeafElement)
+ else if (clonee instanceof LeafElement)
{
- BranchElement par = (BranchElement) el.getParentElement();
- Element el1 = createLeafElement(par, el.getAttributes(),
- el.getStartOffset(), offset);
- Element el2 = createLeafElement(par, el.getAttributes(),
- offset + space, el.getEndOffset());
- res = new Element[]{ el1, el2 };
+ clone = new LeafElement(parent, clonee.getAttributes(),
+ clonee.getStartOffset(),
+ clonee.getEndOffset());
}
- return res;
+ return clone;
}
/**
* Inserts new <code>Element</code> in the document at the specified
- * position.
- *
- * Most of the work is done by {@link #insertUpdate}, after some fields
- * have been prepared for it.
- *
- * @param offset the location in the document at which the content is
- * inserted
- * @param length the length of the inserted content
- * @param data the element specifications for the content to be inserted
- * @param ev the document event that is updated to reflect the structural
- * changes
+ * position. Most of the work is done by {@link #insertUpdate}, after some
+ * fields have been prepared for it.
+ *
+ * @param offset
+ * the location in the document at which the content is inserted
+ * @param length
+ * the length of the inserted content
+ * @param data
+ * the element specifications for the content to be inserted
+ * @param ev
+ * the document event that is updated to reflect the structural
+ * changes
*/
public void insert(int offset, int length, ElementSpec[] data,
DefaultDocumentEvent ev)
{
if (length == 0)
return;
+
this.offset = offset;
- this.length = length;
+ this.pos = offset;
this.endOffset = offset + length;
+ this.length = length;
documentEvent = ev;
- // Push the root and the paragraph at offset onto the element stack.
- elementStack.clear();
- elementStack.push(root);
- elementStack.push(root.getElement(root.getElementIndex(offset)));
- numEndTags = 0;
- numStartTags = 0;
+
+ edits.removeAllElements();
+ elementStack.removeAllElements();
+ lastFractured = null;
+ fracNotCreated = false;
insertUpdate(data);
+ // This for loop applies all the changes that were made and updates the
+ // DocumentEvent.
+ int size = edits.size();
+ for (int i = 0; i < size; i++)
+ {
+ Edit curr = (Edit) edits.get(i);
+ BranchElement e = (BranchElement) curr.e;
+ Element[] removed = curr.getRemovedElements();
+ Element[] added = curr.getAddedElements();
+ // FIXME: We probably shouldn't create the empty Element[] in the
+ // first place.
+ if (removed.length > 0 || added.length > 0)
+ {
+ if (curr.index + removed.length <= e.getElementCount())
+ {
+ e.replace(curr.index, removed.length, added);
+ ElementEdit ee = new ElementEdit(e, curr.index, removed, added);
+ ev.addEdit(ee);
+ }
+ else
+ {
+ System.err.println("WARNING: Tried to replace elements ");
+ System.err.print("beyond boundaries: elementCount: ");
+ System.err.println(e.getElementCount());
+ System.err.print("index: " + curr.index);
+ System.err.println(", removed.length: " + removed.length);
+ }
+ }
+ }
}
/**
- * Performs the actual structural change for {@link #insert}. This
- * creates a bunch of {@link Element}s as specified by <code>data</code>
- * and inserts it into the document as specified in the arguments to
- * {@link #insert}.
- *
- * @param data the element specifications for the elements to be inserte
- */
+ * Inserts new content
+ *
+ * @param data
+ * the element specifications for the elements to be inserted
+ */
protected void insertUpdate(ElementSpec[] data)
{
- if (data[0].getType() == ElementSpec.EndTagType)
+ // Push the root and the paragraph at offset onto the element stack.
+ Element current = root;
+ int index;
+ while (!current.isLeaf())
{
- // fracture deepest child here
- BranchElement paragraph = (BranchElement) elementStack.peek();
- Element curr = paragraph.getParentElement();
- int index = curr.getElementIndex(offset);
- while (!curr.isLeaf())
- {
- index = curr.getElementIndex(offset);
- curr = curr.getElement(index);
- }
- Element parent = curr.getParentElement();
- Element newEl1 = createLeafElement(parent,
- curr.getAttributes(),
- curr.getStartOffset(), offset);
- Element grandParent = parent.getParentElement();
- BranchElement nextBranch =
- (BranchElement) grandParent.getElement
- (grandParent.getElementIndex(parent.getEndOffset()));
- Element firstLeaf = nextBranch.getElement(0);
- while (!firstLeaf.isLeaf())
- {
- firstLeaf = firstLeaf.getElement(0);
- }
- BranchElement parent2 = (BranchElement) firstLeaf.getParentElement();
- Element newEl2 =
- createLeafElement(parent2,
- firstLeaf.getAttributes(),
- offset, firstLeaf.getEndOffset());
- parent2.replace(0, 1, new Element[] { newEl2 });
-
-
- ((BranchElement) parent).
- replace(index, 1, new Element[] { newEl1 });
+ index = current.getElementIndex(offset);
+ elementStack.push(current);
+ current = current.getElement(index);
}
- for (int i = 0; i < data.length; i++)
+ int i = 0;
+ int type = data[0].getType();
+ if (type == ElementSpec.ContentType)
+ {
+ // If the first tag is content we must treat it separately to allow
+ // for joining properly to previous Elements and to ensure that
+ // no extra LeafElements are erroneously inserted.
+ insertFirstContentTag(data);
+ pos += data[0].length;
+ i = 1;
+ }
+ else
+ {
+ createFracture(data);
+ i = 0;
+ }
+
+ // Handle each ElementSpec individually.
+ for (; i < data.length; i++)
{
BranchElement paragraph = (BranchElement) elementStack.peek();
switch (data[i].getType())
@@ -827,19 +791,41 @@ public class DefaultStyledDocument extends AbstractDocument
switch (data[i].getDirection())
{
case ElementSpec.JoinFractureDirection:
+ // Fracture the tree and ensure the appropriate element
+ // is on top of the stack.
+ fracNotCreated = false;
insertFracture(data[i]);
+ if (fracNotCreated)
+ {
+ if (lastFractured != null)
+ elementStack.push(lastFractured.getParentElement());
+ else
+ elementStack.push(paragraph.getElement(0));
+ }
break;
case ElementSpec.JoinNextDirection:
- int index = paragraph.getElementIndex(offset);
- elementStack.push(paragraph.getElement(index));
- break;
- case ElementSpec.OriginateDirection:
- Element current = (Element) elementStack.peek();
- Element newParagraph =
- insertParagraph((BranchElement) current, offset);
- elementStack.push(newParagraph);
+ // Push the next paragraph element onto the stack so
+ // future insertions are added to it.
+ int ix = paragraph.getElementIndex(pos) + 1;
+ elementStack.push(paragraph.getElement(ix));
break;
default:
+ Element br = null;
+ if (data.length > i + 1)
+ {
+ // leaves will be added to paragraph later
+ int x = 0;
+ if (paragraph.getElementCount() > 0)
+ x = paragraph.getElementIndex(pos) + 1;
+ Edit e = getEditForParagraphAndIndex(paragraph, x);
+ br = (BranchElement) createBranchElement(paragraph,
+ data[i].getAttributes());
+ e.added.add(br);
+ elementStack.push(br);
+ }
+ else
+ // need to add leaves to paragraph now
+ br = insertParagraph(paragraph, pos);
break;
}
break;
@@ -848,50 +834,27 @@ public class DefaultStyledDocument extends AbstractDocument
break;
case ElementSpec.ContentType:
insertContentTag(data[i]);
+ offset = pos;
break;
}
}
- endEdit();
}
-
- /**
- * Finishes an insertion by possibly evaluating the outstanding start and
- * end tags. However, this is only performed if the event has received any
- * modifications.
- */
- private void endEdit()
- {
- if (documentEvent.modified)
- prepareContentInsertion();
- }
-
+
/**
- * Evaluates the number of inserted end tags and performs the corresponding
- * structural changes.
+ * Inserts a new paragraph.
+ *
+ * @param par -
+ * the parent
+ * @param offset -
+ * the offset
+ * @return the new paragraph
*/
- private void prepareContentInsertion()
- {
- while (numEndTags > 0)
- {
- elementStack.pop();
- numEndTags--;
- }
-
- while (numStartTags > 0)
- {
- Element current = (Element) elementStack.peek();
- Element newParagraph =
- insertParagraph((BranchElement) current, offset);
- elementStack.push(newParagraph);
- numStartTags--;
- }
- }
-
private Element insertParagraph(BranchElement par, int offset)
{
- Element current = par.getElement(par.getElementIndex(offset));
- Element[] res = split(current, offset, 0);
int index = par.getElementIndex(offset);
+ Element current = par.getElement(index);
+ Element[] res = split(current, offset, 0, 0);
+ Edit e = getEditForParagraphAndIndex(par, index + 1);
Element ret;
if (res[1] != null)
{
@@ -902,334 +865,757 @@ public class DefaultStyledDocument extends AbstractDocument
removed = new Element[0];
if (res[1] instanceof BranchElement)
{
- added = new Element[]{ res[1] };
+ added = new Element[] { res[1] };
ret = res[1];
}
else
{
ret = createBranchElement(par, null);
- added = new Element[]{ ret, res[1] };
+ added = new Element[] { ret, res[1] };
}
index++;
}
else
{
- removed = new Element[]{ current };
+ removed = new Element[] { current };
if (res[1] instanceof BranchElement)
{
ret = res[1];
- added = new Element[]{ res[0], res[1] };
+ added = new Element[] { res[0], res[1] };
}
else
{
ret = createBranchElement(par, null);
- added = new Element[]{ res[0], ret, res[1] };
+ added = new Element[] { res[0], ret, res[1] };
}
}
- par.replace(index, removed.length, added);
- addEdit(par, index, removed, added);
+
+ e.addAddedElements(added);
+ e.addRemovedElements(removed);
}
else
{
ret = createBranchElement(par, null);
- Element[] added = new Element[]{ ret };
- par.replace(index, 0, added);
- addEdit(par, index, new Element[0], added);
+ e.addAddedElement(ret);
}
return ret;
}
/**
- * Inserts a fracture into the document structure.
+ * Inserts the first tag into the document.
*
- * @param tag - the element spec.
+ * @param data -
+ * the data to be inserted.
*/
- private void insertFracture(ElementSpec tag)
+ private void insertFirstContentTag(ElementSpec[] data)
{
- // This is the parent of the paragraph about to be fractured. We will
- // create a new child of this parent.
- BranchElement parent = (BranchElement) elementStack.peek();
- int parentIndex = parent.getElementIndex(offset);
-
- // This is the old paragraph. We must remove all its children that
- // occur after offset and move them to a new paragraph. We must
- // also recreate its child that occurs at offset to have the proper
- // end offset. The remainder of this child will also go in the new
- // paragraph.
- BranchElement previous = (BranchElement) parent.getElement(parentIndex);
-
- // This is the new paragraph.
- BranchElement newBranch =
- (BranchElement) createBranchElement(parent, previous.getAttributes());
-
-
- // The steps we must take to properly fracture are:
- // 1. Recreate the LeafElement at offset to have the correct end offset.
- // 2. Create a new LeafElement with the remainder of the LeafElement in
- // #1 ==> this is whatever was in that LeafElement to the right of the
- // inserted newline.
- // 3. Find the paragraph at offset and remove all its children that
- // occur _after_ offset. These will be moved to the newly created
- // paragraph.
- // 4. Move the LeafElement created in #2 and all the LeafElements removed
- // in #3 to the newly created paragraph.
- // 5. Add the new paragraph to the parent.
- int previousIndex = previous.getElementIndex(offset);
- int numReplaced = previous.getElementCount() - previousIndex;
- Element previousLeaf = previous.getElement(previousIndex);
- AttributeSet prevLeafAtts = previous.getAttributes();
-
- // This recreates the child at offset to have the proper end offset.
- // (Step 1).
- Element newPreviousLeaf =
- createLeafElement(previous,
- prevLeafAtts, previousLeaf.getStartOffset(),
- offset);
- // This creates the new child, which is the remainder of the old child.
- // (Step 2).
-
- Element firstLeafInNewBranch =
- createLeafElement(newBranch, prevLeafAtts,
- offset, previousLeaf.getEndOffset());
-
- // Now we move the new LeafElement and all the old children that occurred
- // after the offset to the new paragraph. (Step 4).
- Element[] newLeaves = new Element[numReplaced];
- newLeaves[0] = firstLeafInNewBranch;
- for (int i = 1; i < numReplaced; i++)
- newLeaves[i] = previous.getElement(previousIndex + i);
- newBranch.replace(0, 0, newLeaves);
- addEdit(newBranch, 0, null, newLeaves);
-
- // Now we remove the children after the offset from the previous
- // paragraph. (Step 3).
- int removeSize = previous.getElementCount() - previousIndex;
- Element[] add = new Element[] { newPreviousLeaf };
- Element[] remove = new Element[removeSize];
- for (int j = 0; j < removeSize; j++)
- remove[j] = previous.getElement(previousIndex + j);
- previous.replace(previousIndex, removeSize, add);
- addEdit(previous, previousIndex, remove, add);
-
- // Finally we add the new paragraph to the parent. (Step 5).
- Element[] nb = new Element[] { newBranch };
- int index = parentIndex + 1;
- parent.replace(index, 0, nb);
- addEdit(parent, index, null, nb);
+ ElementSpec first = data[0];
+ BranchElement paragraph = (BranchElement) elementStack.peek();
+ int index = paragraph.getElementIndex(pos);
+ Element current = paragraph.getElement(index);
+ int newEndOffset = pos + first.length;
+ boolean onlyContent = data.length == 1;
+ Edit edit = getEditForParagraphAndIndex(paragraph, index);
+ switch (first.getDirection())
+ {
+ case ElementSpec.JoinPreviousDirection:
+ if (current.getEndOffset() != newEndOffset && !onlyContent)
+ {
+ Element newEl1 = createLeafElement(paragraph,
+ current.getAttributes(),
+ current.getStartOffset(),
+ newEndOffset);
+ edit.addAddedElement(newEl1);
+ edit.addRemovedElement(current);
+ offset = newEndOffset;
+ }
+ break;
+ case ElementSpec.JoinNextDirection:
+ if (pos != 0)
+ {
+ Element newEl1 = createLeafElement(paragraph,
+ current.getAttributes(),
+ current.getStartOffset(),
+ pos);
+ edit.addAddedElement(newEl1);
+ Element next = paragraph.getElement(index + 1);
+
+ if (onlyContent)
+ newEl1 = createLeafElement(paragraph, next.getAttributes(),
+ pos, next.getEndOffset());
+ else
+ {
+ newEl1 = createLeafElement(paragraph, next.getAttributes(),
+ pos, newEndOffset);
+ pos = newEndOffset;
+ }
+ edit.addAddedElement(newEl1);
+ edit.addRemovedElement(current);
+ edit.addRemovedElement(next);
+ }
+ break;
+ default:
+ if (current.getStartOffset() != pos)
+ {
+ Element newEl = createLeafElement(paragraph,
+ current.getAttributes(),
+ current.getStartOffset(),
+ pos);
+ edit.addAddedElement(newEl);
+ }
+ edit.addRemovedElement(current);
+ Element newEl1 = createLeafElement(paragraph, first.getAttributes(),
+ pos, newEndOffset);
+ edit.addAddedElement(newEl1);
+ if (current.getEndOffset() != endOffset)
+ recreateLeaves(newEndOffset, paragraph, onlyContent);
+ else
+ offset = newEndOffset;
+ break;
+ }
}
-
+
/**
* Inserts a content element into the document structure.
*
- * @param tag the element spec
+ * @param tag -
+ * the element spec
*/
private void insertContentTag(ElementSpec tag)
{
- prepareContentInsertion();
+ BranchElement paragraph = (BranchElement) elementStack.peek();
int len = tag.getLength();
int dir = tag.getDirection();
AttributeSet tagAtts = tag.getAttributes();
- if (dir == ElementSpec.JoinPreviousDirection)
- {
- // The mauve tests to this class show that a JoinPrevious insertion
- // does not add any edits to the document event. To me this means
- // that nothing is done here. The previous element naturally should
- // expand so that it covers the new characters.
- }
- else if (dir == ElementSpec.JoinNextDirection)
+
+ if (dir == ElementSpec.JoinNextDirection)
{
- // FIXME:
- // Have to handle JoinNext differently depending on whether
- // or not it comes after a fracture. If comes after a fracture,
- // the insertFracture method takes care of everything and nothing
- // needs to be done here. Otherwise, we need to adjust the
- // Element structure. For now, I check if the elementStack's
- // top Element is the immediate parent of the LeafElement at
- // offset - if so, we did not come immediately after a
- // fracture. This seems awkward and should probably be improved.
- // We may be doing too much in insertFracture because we are
- // adjusting the offsets, the correct thing to do may be to
- // create a new branch element and push it on to element stack
- // and then this method here can be more general.
-
- BranchElement paragraph = (BranchElement) elementStack.peek();
- int index = paragraph.getElementIndex(offset);
+ int index = paragraph.getElementIndex(pos);
Element target = paragraph.getElement(index);
- if (target.isLeaf() && paragraph.getElementCount() > (index + 1))
+ Edit edit = getEditForParagraphAndIndex(paragraph, index);
+
+ if (paragraph.getStartOffset() > pos)
+ {
+ Element first = paragraph.getElement(0);
+ Element newEl = createLeafElement(paragraph,
+ first.getAttributes(), pos,
+ first.getEndOffset());
+ edit.addAddedElement(newEl);
+ edit.addRemovedElement(first);
+ }
+ else if (paragraph.getElementCount() > (index + 1)
+ && (pos == target.getStartOffset() && !target.equals(lastFractured)))
{
Element next = paragraph.getElement(index + 1);
- Element newEl1 = createLeafElement(paragraph,
- target.getAttributes(),
- target.getStartOffset(),
- offset);
- Element newEl2 = createLeafElement(paragraph,
- next.getAttributes(), offset,
- next.getEndOffset());
- Element[] add = new Element[] { newEl1, newEl2 };
- paragraph.replace (index, 2, add);
- addEdit(paragraph, index, new Element[] { target, next }, add);
+ Element newEl = createLeafElement(paragraph,
+ next.getAttributes(), pos,
+ next.getEndOffset());
+ edit.addAddedElement(newEl);
+ edit.addRemovedElement(next);
+ edit.addRemovedElement(target);
+ }
+ else
+ {
+ BranchElement parent = (BranchElement) paragraph.getParentElement();
+ int i = parent.getElementIndex(pos);
+ BranchElement next = (BranchElement) parent.getElement(i + 1);
+ AttributeSet atts = tag.getAttributes();
+
+ if (next != null)
+ {
+ Element nextLeaf = next.getElement(0);
+ Edit e = getEditForParagraphAndIndex(next, 0);
+ Element newEl2 = createLeafElement(next, atts, pos, nextLeaf.getEndOffset());
+ e.addAddedElement(newEl2);
+ e.addRemovedElement(nextLeaf);
+ }
}
}
- else if (dir == ElementSpec.OriginateDirection)
+ else
{
- BranchElement paragraph = (BranchElement) elementStack.peek();
- int index = paragraph.getElementIndex(offset);
- Element current = paragraph.getElement(index);
+ int end = pos + len;
+ Element leaf = createLeafElement(paragraph, tag.getAttributes(), pos, end);
- Element[] added;
- Element[] removed = new Element[] {current};
- Element[] splitRes = split(current, offset, length);
- if (splitRes[0] == null)
+ // Check for overlap with other leaves/branches
+ if (paragraph.getElementCount() > 0)
{
- added = new Element[2];
- added[0] = createLeafElement(paragraph, tagAtts,
- offset, endOffset);
- added[1] = splitRes[1];
- removed = new Element[0];
- index++;
- }
- else if (current.getStartOffset() == offset)
- {
- // This is if the new insertion happens immediately before
- // the <code>current</code> Element. In this case there are 2
- // resulting Elements.
- added = new Element[2];
- added[0] = createLeafElement(paragraph, tagAtts, offset,
- endOffset);
- added[1] = splitRes[1];
- }
- else if (current.getEndOffset() == endOffset)
- {
- // This is if the new insertion happens right at the end of
- // the <code>current</code> Element. In this case there are
- // 2 resulting Elements.
- added = new Element[2];
- added[0] = splitRes[0];
- added[1] = createLeafElement(paragraph, tagAtts, offset,
- endOffset);
+ int index = paragraph.getElementIndex(pos);
+ Element target = paragraph.getElement(index);
+ boolean onlyContent = target.isLeaf();
+
+ BranchElement toRec = paragraph;
+ if (!onlyContent)
+ toRec = (BranchElement) target;
+
+ // Check if we should place the leaf before or after target
+ if (pos > target.getStartOffset())
+ index++;
+
+ Edit edit = getEditForParagraphAndIndex(paragraph, index);
+ edit.addAddedElement(leaf);
+
+ if (end != toRec.getEndOffset())
+ {
+ recreateLeaves(end, toRec, onlyContent);
+
+ if (onlyContent)
+ edit.addRemovedElement(target);
+ }
}
else
- {
- // This is if the new insertion is in the middle of the
- // <code>current</code> Element. In this case
- // there will be 3 resulting Elements.
- added = new Element[3];
- added[0] = splitRes[0];
- added[1] = createLeafElement(paragraph, tagAtts, offset,
- endOffset);
- added[2] = splitRes[1];
- }
- paragraph.replace(index, removed.length, added);
- addEdit(paragraph, index, removed, added);
+ paragraph.replace(0, 0, new Element[] { leaf });
}
- offset += len;
+
+ pos += len;
}
-
+
/**
- * Creates a copy of the element <code>clonee</code> that has the parent
- * <code>parent</code>.
- * @param parent the parent of the newly created Element
- * @param clonee the Element to clone
- * @return the cloned Element
+ * This method fractures the child at offset.
+ *
+ * @param data
+ * the ElementSpecs used for the entire insertion
*/
- public Element clone (Element parent, Element clonee)
+ private void createFracture(ElementSpec[] data)
{
- // If the Element we want to clone is a leaf, then simply copy it
- if (clonee.isLeaf())
- return createLeafElement(parent, clonee.getAttributes(),
- clonee.getStartOffset(), clonee.getEndOffset());
+ BranchElement paragraph = (BranchElement) elementStack.peek();
+ int index = paragraph.getElementIndex(offset);
+ Element child = paragraph.getElement(index);
+ Edit edit = getEditForParagraphAndIndex(paragraph, index);
+ AttributeSet atts = child.getAttributes();
- // Otherwise create a new BranchElement with the desired parent and
- // the clonee's attributes
- BranchElement result = (BranchElement) createBranchElement(parent, clonee.getAttributes());
-
- // And clone all the of clonee's children
- Element[] children = new Element[clonee.getElementCount()];
- for (int i = 0; i < children.length; i++)
- children[i] = clone(result, clonee.getElement(i));
-
- // Make the cloned children the children of the BranchElement
- result.replace(0, 0, children);
- return result;
+ if (offset != 0)
+ {
+ Element newEl1 = createLeafElement(paragraph, atts,
+ child.getStartOffset(), offset);
+ edit.addAddedElement(newEl1);
+ edit.addRemovedElement(child);
+ }
}
/**
- * Adds an ElementChange for a given element modification to the document
- * event. If there already is an ElementChange registered for this element,
- * this method tries to merge the ElementChanges together. However, this
- * is only possible if the indices of the new and old ElementChange are
- * equal.
- *
- * @param e the element
- * @param i the index of the change
- * @param removed the removed elements, or <code>null</code>
- * @param added the added elements, or <code>null</code>
+ * Recreates a specified part of a the tree after a new leaf
+ * has been inserted.
+ *
+ * @param start - where to start recreating from
+ * @param paragraph - the paragraph to recreate
+ * @param onlyContent - true if this is the only content
+ */
+ private void recreateLeaves(int start, BranchElement paragraph, boolean onlyContent)
+ {
+ int index = paragraph.getElementIndex(start);
+ Element child = paragraph.getElement(index);
+ AttributeSet atts = child.getAttributes();
+
+ if (!onlyContent)
+ {
+ BranchElement newBranch = (BranchElement) createBranchElement(paragraph,
+ atts);
+ Element newLeaf = createLeafElement(newBranch, atts, start,
+ child.getEndOffset());
+ newBranch.replace(0, 0, new Element[] { newLeaf });
+
+ BranchElement parent = (BranchElement) paragraph.getParentElement();
+ int parSize = parent.getElementCount();
+ Edit edit = getEditForParagraphAndIndex(parent, parSize);
+ edit.addAddedElement(newBranch);
+
+ int paragraphSize = paragraph.getElementCount();
+ Element[] removed = new Element[paragraphSize - (index + 1)];
+ int s = 0;
+ for (int j = index + 1; j < paragraphSize; j++)
+ removed[s++] = paragraph.getElement(j);
+
+ edit = getEditForParagraphAndIndex(paragraph, index);
+ edit.addRemovedElements(removed);
+ Element[] added = recreateAfterFracture(removed, newBranch, 0, child.getEndOffset());
+ newBranch.replace(1, 0, added);
+
+ lastFractured = newLeaf;
+ pos = newBranch.getEndOffset();
+ }
+ else
+ {
+ Element newLeaf = createLeafElement(paragraph, atts, start,
+ child.getEndOffset());
+ Edit edit = getEditForParagraphAndIndex(paragraph, index);
+ edit.addAddedElement(newLeaf);
+ }
+ }
+
+ /**
+ * Splits an element if <code>offset</code> is not already at its
+ * boundary.
+ *
+ * @param el
+ * the Element to possibly split
+ * @param offset
+ * the offset at which to possibly split
+ * @param space
+ * the amount of space to create between the splitted parts
+ * @param editIndex
+ * the index of the edit to use
+ * @return An array of elements which represent the split result. This array
+ * has two elements, the two parts of the split. The first element
+ * might be null, which means that the element which should be
+ * splitted can remain in place. The second element might also be
+ * null, which means that the offset is already at an element
+ * boundary and the element doesn't need to be splitted.
*/
- private void addEdit(Element e, int i, Element[] removed, Element[] added)
+ private Element[] split(Element el, int offset, int space, int editIndex)
{
- // Perform sanity check first.
- DocumentEvent.ElementChange ec = documentEvent.getChange(e);
+ // If we are at an element boundary, then return an empty array.
+ if ((offset == el.getStartOffset() || offset == el.getEndOffset())
+ && space == 0 && el.isLeaf())
+ return new Element[2];
- // Merge the existing stuff with the new stuff.
- Element[] oldAdded = ec == null ? null: ec.getChildrenAdded();
- Element[] newAdded;
- if (oldAdded != null && added != null)
+ // If the element is an instance of BranchElement, then we
+ // recursivly
+ // call this method to perform the split.
+ Element[] res = new Element[2];
+ if (el instanceof BranchElement)
{
- if (ec.getIndex() <= i)
+ int index = el.getElementIndex(offset);
+ Element child = el.getElement(index);
+ Element[] result = split(child, offset, space, editIndex);
+ Element[] removed;
+ Element[] added;
+ Element[] newAdded;
+
+ int count = el.getElementCount();
+ if (result[1] != null)
{
- int index = i - ec.getIndex();
- // Merge adds together.
- newAdded = new Element[oldAdded.length + added.length];
- System.arraycopy(oldAdded, 0, newAdded, 0, index);
- System.arraycopy(added, 0, newAdded, index, added.length);
- System.arraycopy(oldAdded, index, newAdded, index + added.length,
- oldAdded.length - index);
- i = ec.getIndex();
+ // This is the case when we can keep the first element.
+ if (result[0] == null)
+ {
+ removed = new Element[count - index - 1];
+ newAdded = new Element[count - index - 1];
+ added = new Element[] {};
+
+ }
+ // This is the case when we may not keep the first
+ // element.
+ else
+ {
+ removed = new Element[count - index];
+ newAdded = new Element[count - index];
+ added = new Element[] { result[0] };
+ }
+ newAdded[0] = result[1];
+ for (int i = index; i < count; i++)
+ {
+ Element el2 = el.getElement(i);
+ int ind = i - count + removed.length;
+ removed[ind] = el2;
+ if (ind != 0)
+ newAdded[ind] = el2;
+ }
+
+ Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex);
+ edit.addRemovedElements(removed);
+ edit.addAddedElements(added);
+
+ BranchElement newPar =
+ (BranchElement) createBranchElement(el.getParentElement(),
+ el.getAttributes());
+ newPar.replace(0, 0, newAdded);
+ res = new Element[] { null, newPar };
}
else
- throw new AssertionError("Not yet implemented case.");
+ {
+ removed = new Element[count - index];
+ for (int i = index; i < count; ++i)
+ removed[i - index] = el.getElement(i);
+
+ Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex);
+ edit.addRemovedElements(removed);
+
+ BranchElement newPar = (BranchElement) createBranchElement(el.getParentElement(),
+ el.getAttributes());
+ newPar.replace(0, 0, removed);
+ res = new Element[] { null, newPar };
+ }
}
- else if (added != null)
- newAdded = added;
- else if (oldAdded != null)
- newAdded = oldAdded;
- else
- newAdded = new Element[0];
+ else if (el instanceof LeafElement)
+ {
+ BranchElement par = (BranchElement) el.getParentElement();
+ Element el1 = createLeafElement(par, el.getAttributes(),
+ el.getStartOffset(), offset);
+
+ Element el2 = createLeafElement(par, el.getAttributes(),
+ offset + space,
+ el.getEndOffset());
+ res = new Element[] { el1, el2 };
+ }
+ return res;
+ }
- Element[] oldRemoved = ec == null ? null: ec.getChildrenRemoved();
- Element[] newRemoved;
- if (oldRemoved != null && removed != null)
+ /**
+ * Inserts a fracture into the document structure.
+ *
+ * @param tag -
+ * the element spec.
+ */
+ private void insertFracture(ElementSpec tag)
+ {
+ // insert the fracture at offset.
+ BranchElement parent = (BranchElement) elementStack.peek();
+ int parentIndex = parent.getElementIndex(pos);
+ AttributeSet parentAtts = parent.getAttributes();
+ Element toFracture = parent.getElement(parentIndex);
+ int parSize = parent.getElementCount();
+ Edit edit = getEditForParagraphAndIndex(parent, parentIndex);
+ Element frac = toFracture;
+ int leftIns = 0;
+ int indexOfFrac = toFracture.getElementIndex(pos);
+ int size = toFracture.getElementCount();
+
+ // gets the leaf that falls along the fracture
+ frac = toFracture.getElement(indexOfFrac);
+ while (!frac.isLeaf())
+ frac = frac.getElement(frac.getElementIndex(pos));
+
+ AttributeSet atts = frac.getAttributes();
+ int fracStart = frac.getStartOffset();
+ int fracEnd = frac.getEndOffset();
+ if (pos >= fracStart && pos < fracEnd)
{
- if (ec.getIndex() <= i)
+ // recreate left-side of branch and all its children before offset
+ // add the fractured leaves to the right branch
+ BranchElement rightBranch =
+ (BranchElement) createBranchElement(parent, parentAtts);
+
+ // Check if left branch has already been edited. If so, we only
+ // need to create the right branch.
+ BranchElement leftBranch = null;
+ Element[] added = null;
+ if (edit.added.size() > 0 || edit.removed.size() > 0)
{
- int index = i - ec.getIndex();
- // Merge removes together.
- newRemoved = new Element[oldRemoved.length + removed.length];
- System.arraycopy(oldAdded, 0, newRemoved, 0, index);
- System.arraycopy(removed, 0, newRemoved, index, removed.length);
- System.arraycopy(oldRemoved, index, newRemoved,
- index + removed.length,
- oldRemoved.length - index);
- i = ec.getIndex();
+ added = new Element[] { rightBranch };
+
+ // don't try to remove left part of tree
+ parentIndex++;
}
else
- throw new AssertionError("Not yet implemented case.");
+ {
+ leftBranch =
+ (BranchElement) createBranchElement(parent, parentAtts);
+ added = new Element[] { leftBranch, rightBranch };
+
+ // add fracture to leftBranch
+ if (fracStart != pos)
+ {
+ Element leftFracturedLeaf =
+ createLeafElement(leftBranch, atts, fracStart, pos);
+ leftBranch.replace(leftIns, 0,
+ new Element[] { leftFracturedLeaf });
+ }
+ }
+
+ if (!toFracture.isLeaf())
+ {
+ // add all non-fracture elements to the branches
+ if (indexOfFrac > 0 && leftBranch != null)
+ {
+ Element[] add = new Element[indexOfFrac];
+ for (int i = 0; i < indexOfFrac; i++)
+ add[i] = toFracture.getElement(i);
+ leftIns = add.length;
+ leftBranch.replace(0, 0, add);
+ }
+
+ int count = size - indexOfFrac - 1;
+ if (count > 0)
+ {
+ Element[] add = new Element[count];
+ int j = 0;
+ int i = indexOfFrac + 1;
+ while (j < count)
+ add[j++] = toFracture.getElement(i++);
+ rightBranch.replace(0, 0, add);
+ }
+ }
+
+ // add to fracture to rightBranch
+ // Check if we can join the right frac leaf with the next leaf
+ int rm = 0;
+ int end = fracEnd;
+ Element next = rightBranch.getElement(0);
+ if (next != null && next.isLeaf()
+ && next.getAttributes().isEqual(atts))
+ {
+ end = next.getEndOffset();
+ rm = 1;
+ }
+
+ Element rightFracturedLeaf = createLeafElement(rightBranch, atts,
+ pos, end);
+ rightBranch.replace(0, rm, new Element[] { rightFracturedLeaf });
+
+ // recreate those elements after parentIndex and add/remove all
+ // new/old elements to parent
+ int remove = parSize - parentIndex;
+ Element[] removed = new Element[0];
+ Element[] added2 = new Element[0];
+ if (remove > 0)
+ {
+ removed = new Element[remove];
+ int s = 0;
+ for (int j = parentIndex; j < parSize; j++)
+ removed[s++] = parent.getElement(j);
+ edit.addRemovedElements(removed);
+ added2 = recreateAfterFracture(removed, parent, 1,
+ rightBranch.getEndOffset());
+ }
+
+ edit.addAddedElements(added);
+ edit.addAddedElements(added2);
+ elementStack.push(rightBranch);
+ lastFractured = rightFracturedLeaf;
}
- else if (removed != null)
- newRemoved = removed;
- else if (oldRemoved != null)
- newRemoved = oldRemoved;
else
- newRemoved = new Element[0];
+ fracNotCreated = true;
+ }
+
+ /**
+ * Recreates all the elements from the parent to the element on the top of
+ * the stack, starting from startFrom with the starting offset of
+ * startOffset.
+ *
+ * @param recreate -
+ * the elements to recreate
+ * @param parent -
+ * the element to add the new elements to
+ * @param startFrom -
+ * where to start recreating from
+ * @param startOffset -
+ * the offset of the first element
+ * @return the array of added elements
+ */
+ private Element[] recreateAfterFracture(Element[] recreate,
+ BranchElement parent, int startFrom,
+ int startOffset)
+ {
+ Element[] added = new Element[recreate.length - startFrom];
+ int j = 0;
+ for (int i = startFrom; i < recreate.length; i++)
+ {
+ Element curr = recreate[i];
+ int len = curr.getEndOffset() - curr.getStartOffset();
+ if (curr instanceof LeafElement)
+ added[j] = createLeafElement(parent, curr.getAttributes(),
+ startOffset, startOffset + len);
+ else
+ {
+ BranchElement br =
+ (BranchElement) createBranchElement(parent,
+ curr.getAttributes());
+ int bSize = curr.getElementCount();
+ for (int k = 0; k < bSize; k++)
+ {
+ Element bCurr = curr.getElement(k);
+ Element[] add = recreateAfterFracture(new Element[] { bCurr }, br, 0,
+ startOffset);
+ br.replace(0, 0, add);
+
+ }
+ added[j] = br;
+ }
+ startOffset += len;
+ j++;
+ }
+
+ return added;
+ }
+ }
+
+ /**
+ * This method looks through the Vector of Edits to see if there is already an
+ * Edit object associated with the given paragraph. If there is, then we
+ * return it. Otherwise we create a new Edit object, add it to the vector, and
+ * return it. Note: this method is package private to avoid accessors.
+ *
+ * @param index
+ * the index associated with the Edit we want to create
+ * @param para
+ * the paragraph associated with the Edit we want
+ * @return the found or created Edit object
+ */
+ Edit getEditForParagraphAndIndex(BranchElement para, int index)
+ {
+ Edit curr;
+ int size = edits.size();
+ for (int i = 0; i < size; i++)
+ {
+ curr = (Edit) edits.elementAt(i);
+ if (curr.e.equals(para))
+ return curr;
+ }
+ curr = new Edit(para, index, null, null);
+ edits.add(curr);
+
+ return curr;
+ }
+ /**
+ * Instance of all editing information for an object in the Vector. This class
+ * is used to add information to the DocumentEvent associated with an
+ * insertion/removal/change as well as to store the changes that need to be
+ * made so they can be made all at the same (appropriate) time.
+ */
+ class Edit
+ {
+ /** The element to edit . */
+ Element e;
+
+ /** The index of the change. */
+ int index;
+
+ /** The removed elements. */
+ Vector removed = new Vector();
+
+ /** The added elements. */
+ Vector added = new Vector();
+
+ /**
+ * Return an array containing the Elements that have been removed from the
+ * paragraph associated with this Edit.
+ *
+ * @return an array of removed Elements
+ */
+ public Element[] getRemovedElements()
+ {
+ int size = removed.size();
+ Element[] removedElements = new Element[size];
+ for (int i = 0; i < size; i++)
+ removedElements[i] = (Element) removed.elementAt(i);
+ return removedElements;
+ }
+
+ /**
+ * Return an array containing the Elements that have been added to the
+ * paragraph associated with this Edit.
+ *
+ * @return an array of added Elements
+ */
+ public Element[] getAddedElements()
+ {
+ int size = added.size();
+ Element[] addedElements = new Element[size];
+ for (int i = 0; i < size; i++)
+ addedElements[i] = (Element) added.elementAt(i);
+ return addedElements;
+ }
+
+ /**
+ * Checks if e is already in the vector.
+ *
+ * @param e - the Element to look for
+ * @param v - the vector to search
+ * @return true if e is in v.
+ */
+ private boolean contains(Vector v, Element e)
+ {
+ if (e == null)
+ return false;
+
+ int i = v.size();
+ for (int j = 0; j < i; j++)
+ {
+ Element e1 = (Element) v.get(j);
+ if ((e1 != null) && (e1.getAttributes().isEqual(e.getAttributes()))
+ && (e1.getName().equals(e.getName()))
+ && (e1.getStartOffset() == e.getStartOffset())
+ && (e1.getEndOffset() == e.getEndOffset())
+ && (e1.getParentElement().equals(e.getParentElement()))
+ && (e1.getElementCount() == e.getElementCount()))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Adds one Element to the vector of removed Elements.
+ *
+ * @param e
+ * the Element to add
+ */
+ public void addRemovedElement(Element e)
+ {
+ if (!contains(removed, e))
+ removed.add(e);
+ }
+
+ /**
+ * Adds each Element in the given array to the vector of removed Elements
+ *
+ * @param e
+ * the array containing the Elements to be added
+ */
+ public void addRemovedElements(Element[] e)
+ {
+ if (e == null || e.length == 0)
+ return;
+ for (int i = 0; i < e.length; i++)
+ {
+ if (!contains(removed, e[i]))
+ removed.add(e[i]);
+ }
+ }
- // Replace the existing edit for the element with the merged.
- documentEvent.addEdit(new ElementEdit(e, i, newRemoved, newAdded));
+ /**
+ * Adds one Element to the vector of added Elements.
+ *
+ * @param e
+ * the Element to add
+ */
+ public void addAddedElement(Element e)
+ {
+ if (!contains(added, e))
+ added.add(e);
+ }
+
+ /**
+ * Adds each Element in the given array to the vector of added Elements.
+ *
+ * @param e
+ * the array containing the Elements to be added
+ */
+ public void addAddedElements(Element[] e)
+ {
+ if (e == null || e.length == 0)
+ return;
+ for (int i = 0; i < e.length; i++)
+ {
+ if (!contains(added, e[i]))
+ added.add(e[i]);
+ }
+ }
+
+ /**
+ * Creates a new Edit object with the given parameters
+ *
+ * @param e
+ * the paragraph Element associated with this Edit
+ * @param i
+ * the index within the paragraph where changes are started
+ * @param removed
+ * an array containing Elements that should be removed from the
+ * paragraph Element
+ * @param added
+ * an array containing Elements that should be added to the
+ * paragraph Element
+ */
+ public Edit(Element e, int i, Element[] removed, Element[] added)
+ {
+ this.e = e;
+ this.index = i;
+ addRemovedElements(removed);
+ addAddedElements(added);
}
}
/**
- * An element type for sections. This is a simple BranchElement with
- * a unique name.
+ * An element type for sections. This is a simple BranchElement with a unique
+ * name.
*/
protected class SectionElement extends BranchElement
{
@@ -1244,7 +1630,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the name of the element. This method always returns
* &quot;section&quot;.
- *
+ *
* @return the name of the element
*/
public String getName()
@@ -1256,18 +1642,18 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Receives notification when any of the document's style changes and calls
* {@link DefaultStyledDocument#styleChanged(Style)}.
- *
+ *
* @author Roman Kennke (kennke@aicas.com)
*/
- private class StyleChangeListener
- implements ChangeListener
+ private class StyleChangeListener implements ChangeListener
{
/**
* Receives notification when any of the document's style changes and calls
* {@link DefaultStyledDocument#styleChanged(Style)}.
- *
- * @param event the change event
+ *
+ * @param event
+ * the change event
*/
public void stateChanged(ChangeEvent event)
{
@@ -1296,6 +1682,11 @@ public class DefaultStyledDocument extends AbstractDocument
private StyleChangeListener styleChangeListener;
/**
+ * Vector that contains all the edits. Maybe replace by a HashMap.
+ */
+ Vector edits = new Vector();
+
+ /**
* Creates a new <code>DefaultStyledDocument</code>.
*/
public DefaultStyledDocument()
@@ -1304,10 +1695,11 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Creates a new <code>DefaultStyledDocument</code> that uses the
- * specified {@link StyleContext}.
- *
- * @param context the <code>StyleContext</code> to use
+ * Creates a new <code>DefaultStyledDocument</code> that uses the specified
+ * {@link StyleContext}.
+ *
+ * @param context
+ * the <code>StyleContext</code> to use
*/
public DefaultStyledDocument(StyleContext context)
{
@@ -1315,14 +1707,16 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Creates a new <code>DefaultStyledDocument</code> that uses the
- * specified {@link StyleContext} and {@link Content} buffer.
- *
- * @param content the <code>Content</code> buffer to use
- * @param context the <code>StyleContext</code> to use
+ * Creates a new <code>DefaultStyledDocument</code> that uses the specified
+ * {@link StyleContext} and {@link Content} buffer.
+ *
+ * @param content
+ * the <code>Content</code> buffer to use
+ * @param context
+ * the <code>StyleContext</code> to use
*/
public DefaultStyledDocument(AbstractDocument.Content content,
- StyleContext context)
+ StyleContext context)
{
super(content, context);
buffer = new ElementBuffer(createDefaultRoot());
@@ -1330,10 +1724,9 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Adds a style into the style hierarchy. Unspecified style attributes
- * can be resolved in the <code>parent</code> style, if one is specified.
- *
- * While it is legal to add nameless styles (<code>nm == null</code),
+ * Adds a style into the style hierarchy. Unspecified style attributes can be
+ * resolved in the <code>parent</code> style, if one is specified. While it
+ * is legal to add nameless styles (<code>nm == null</code),
* you must be aware that the client application is then responsible
* for managing the style hierarchy, since unnamed styles cannot be
* looked up by their name.
@@ -1360,14 +1753,12 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Create the default root element for this kind of <code>Document</code>.
- *
+ *
* @return the default root element for this kind of <code>Document</code>
*/
protected AbstractDocument.AbstractElement createDefaultRoot()
{
Element[] tmp;
- // FIXME: Create a SecionElement here instead of a BranchElement.
- // Use createBranchElement() and createLeafElement instead.
SectionElement section = new SectionElement();
BranchElement paragraph = new BranchElement(section, null);
@@ -1375,7 +1766,7 @@ public class DefaultStyledDocument extends AbstractDocument
tmp[0] = paragraph;
section.replace(0, 0, tmp);
- LeafElement leaf = new LeafElement(paragraph, null, 0, 1);
+ Element leaf = new LeafElement(paragraph, null, 0, 1);
tmp = new Element[1];
tmp[0] = leaf;
paragraph.replace(0, 0, tmp);
@@ -1384,14 +1775,14 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Returns the <code>Element</code> that corresponds to the character
- * at the specified position.
- *
- * @param position the position of which we query the corresponding
- * <code>Element</code>
- *
- * @return the <code>Element</code> that corresponds to the character
- * at the specified position
+ * Returns the <code>Element</code> that corresponds to the character at the
+ * specified position.
+ *
+ * @param position
+ * the position of which we query the corresponding
+ * <code>Element</code>
+ * @return the <code>Element</code> that corresponds to the character at the
+ * specified position
*/
public Element getCharacterElement(int position)
{
@@ -1402,15 +1793,15 @@ public class DefaultStyledDocument extends AbstractDocument
int index = element.getElementIndex(position);
element = element.getElement(index);
}
-
+
return element;
}
/**
* Extracts a background color from a set of attributes.
- *
- * @param attributes the attributes from which to get a background color
- *
+ *
+ * @param attributes
+ * the attributes from which to get a background color
* @return the background color that correspond to the attributes
*/
public Color getBackground(AttributeSet attributes)
@@ -1421,7 +1812,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the default root element.
- *
+ *
* @return the default root element
*/
public Element getDefaultRootElement()
@@ -1431,9 +1822,9 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Extracts a font from a set of attributes.
- *
- * @param attributes the attributes from which to get a font
- *
+ *
+ * @param attributes
+ * the attributes from which to get a font
* @return the font that correspond to the attributes
*/
public Font getFont(AttributeSet attributes)
@@ -1441,12 +1832,12 @@ public class DefaultStyledDocument extends AbstractDocument
StyleContext context = (StyleContext) getAttributeContext();
return context.getFont(attributes);
}
-
+
/**
* Extracts a foreground color from a set of attributes.
- *
- * @param attributes the attributes from which to get a foreground color
- *
+ *
+ * @param attributes
+ * the attributes from which to get a foreground color
* @return the foreground color that correspond to the attributes
*/
public Color getForeground(AttributeSet attributes)
@@ -1457,9 +1848,9 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns the logical <code>Style</code> for the specified position.
- *
- * @param position the position from which to query to logical style
- *
+ *
+ * @param position
+ * the position from which to query to logical style
* @return the logical <code>Style</code> for the specified position
*/
public Style getLogicalStyle(int position)
@@ -1474,37 +1865,32 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Returns the paragraph element for the specified position.
- * If the position is outside the bounds of the document's root element,
- * then the closest element is returned. That is the last paragraph if
+ * Returns the paragraph element for the specified position. If the position
+ * is outside the bounds of the document's root element, then the closest
+ * element is returned. That is the last paragraph if
* <code>position >= endIndex</code> or the first paragraph if
* <code>position < startIndex</code>.
- *
- * @param position the position for which to query the paragraph element
- *
+ *
+ * @param position
+ * the position for which to query the paragraph element
* @return the paragraph element for the specified position
*/
public Element getParagraphElement(int position)
{
- BranchElement root = (BranchElement) getDefaultRootElement();
- int start = root.getStartOffset();
- int end = root.getEndOffset();
- if (position >= end)
- position = end - 1;
- else if (position < start)
- position = start;
-
- Element par = root.positionToElement(position);
-
- assert par != null : "The paragraph element must not be null";
- return par;
+ Element e = getDefaultRootElement();
+ while (!e.isLeaf())
+ e = e.getElement(e.getElementIndex(position));
+
+ if (e != null)
+ return e.getParentElement();
+ return e;
}
/**
* Looks up and returns a named <code>Style</code>.
- *
- * @param nm the name of the <code>Style</code>
- *
+ *
+ * @param nm
+ * the name of the <code>Style</code>
* @return the found <code>Style</code> of <code>null</code> if no such
* <code>Style</code> exists
*/
@@ -1516,8 +1902,9 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Removes a named <code>Style</code> from the style hierarchy.
- *
- * @param nm the name of the <code>Style</code> to be removed
+ *
+ * @param nm
+ * the name of the <code>Style</code> to be removed
*/
public void removeStyle(String nm)
{
@@ -1528,31 +1915,32 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Sets text attributes for the fragment specified by <code>offset</code>
* and <code>length</code>.
- *
- * @param offset the start offset of the fragment
- * @param length the length of the fragment
- * @param attributes the text attributes to set
- * @param replace if <code>true</code>, the attributes of the current
- * selection are overridden, otherwise they are merged
+ *
+ * @param offset
+ * the start offset of the fragment
+ * @param length
+ * the length of the fragment
+ * @param attributes
+ * the text attributes to set
+ * @param replace
+ * if <code>true</code>, the attributes of the current selection
+ * are overridden, otherwise they are merged
*/
public void setCharacterAttributes(int offset, int length,
- AttributeSet attributes,
- boolean replace)
+ AttributeSet attributes, boolean replace)
{
// Exit early if length is 0, so no DocumentEvent is created or fired.
if (length == 0)
return;
try
{
- // Must obtain a write lock for this method. writeLock() and
+ // Must obtain a write lock for this method. writeLock() and
// writeUnlock() should always be in try/finally block to make
// sure that locking happens in a balanced manner.
writeLock();
- DefaultDocumentEvent ev =
- new DefaultDocumentEvent(
- offset,
- length,
- DocumentEvent.EventType.CHANGE);
+ DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
+ length,
+ DocumentEvent.EventType.CHANGE);
// Modify the element structure so that the interval begins at an
// element
@@ -1563,13 +1951,13 @@ public class DefaultStyledDocument extends AbstractDocument
// Visit all paragraph elements within the specified interval
int end = offset + length;
Element curr;
- for (int pos = offset; pos < end; )
+ for (int pos = offset; pos < end;)
{
// Get the CharacterElement at offset pos.
curr = getCharacterElement(pos);
if (pos == curr.getEndOffset())
break;
-
+
MutableAttributeSet a = (MutableAttributeSet) curr.getAttributes();
ev.addEdit(new AttributeUndoableEdit(curr, attributes, replace));
// If replace is true, remove all the old attributes.
@@ -1588,12 +1976,14 @@ public class DefaultStyledDocument extends AbstractDocument
writeUnlock();
}
}
-
+
/**
* Sets the logical style for the paragraph at the specified position.
- *
- * @param position the position at which the logical style is added
- * @param style the style to set for the current paragraph
+ *
+ * @param position
+ * the position at which the logical style is added
+ * @param style
+ * the style to set for the current paragraph
*/
public void setLogicalStyle(int position, Style style)
{
@@ -1603,60 +1993,59 @@ public class DefaultStyledDocument extends AbstractDocument
if (el == null)
return;
try
- {
- writeLock();
- if (el instanceof AbstractElement)
- {
- AbstractElement ael = (AbstractElement) el;
- ael.setResolveParent(style);
- int start = el.getStartOffset();
- int end = el.getEndOffset();
- DefaultDocumentEvent ev =
- new DefaultDocumentEvent (
- start,
- end - start,
- DocumentEvent.EventType.CHANGE);
- // FIXME: Add an UndoableEdit to this event and fire it.
- fireChangedUpdate(ev);
- }
- else
- throw new
- AssertionError("paragraph elements are expected to be"
- + "instances of AbstractDocument.AbstractElement");
- }
+ {
+ writeLock();
+ if (el instanceof AbstractElement)
+ {
+ AbstractElement ael = (AbstractElement) el;
+ ael.setResolveParent(style);
+ int start = el.getStartOffset();
+ int end = el.getEndOffset();
+ DefaultDocumentEvent ev = new DefaultDocumentEvent(start,
+ end - start,
+ DocumentEvent.EventType.CHANGE);
+ fireChangedUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
+ }
+ else
+ throw new AssertionError(
+ "paragraph elements are expected to be"
+ + "instances of AbstractDocument.AbstractElement");
+ }
finally
- {
- writeUnlock();
- }
+ {
+ writeUnlock();
+ }
}
/**
* Sets text attributes for the paragraph at the specified fragment.
- *
- * @param offset the beginning of the fragment
- * @param length the length of the fragment
- * @param attributes the text attributes to set
- * @param replace if <code>true</code>, the attributes of the current
- * selection are overridden, otherwise they are merged
+ *
+ * @param offset
+ * the beginning of the fragment
+ * @param length
+ * the length of the fragment
+ * @param attributes
+ * the text attributes to set
+ * @param replace
+ * if <code>true</code>, the attributes of the current selection
+ * are overridden, otherwise they are merged
*/
public void setParagraphAttributes(int offset, int length,
- AttributeSet attributes,
- boolean replace)
+ AttributeSet attributes, boolean replace)
{
try
{
- // Must obtain a write lock for this method. writeLock() and
+ // Must obtain a write lock for this method. writeLock() and
// writeUnlock() should always be in try/finally blocks to make
// sure that locking occurs in a balanced manner.
writeLock();
-
+
// Create a DocumentEvent to use for changedUpdate().
- DefaultDocumentEvent ev =
- new DefaultDocumentEvent (
- offset,
- length,
- DocumentEvent.EventType.CHANGE);
-
+ DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
+ length,
+ DocumentEvent.EventType.CHANGE);
+
// Have to iterate through all the _paragraph_ elements that are
// contained or partially contained in the interval
// (offset, offset + length).
@@ -1665,7 +2054,7 @@ public class DefaultStyledDocument extends AbstractDocument
int endElement = rootElement.getElementIndex(offset + length - 1);
if (endElement < startElement)
endElement = startElement;
-
+
for (int i = startElement; i <= endElement; i++)
{
Element par = rootElement.getElement(i);
@@ -1688,11 +2077,13 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
- * Called in response to content insert actions. This is used to
- * update the element structure.
- *
- * @param ev the <code>DocumentEvent</code> describing the change
- * @param attr the attributes for the change
+ * Called in response to content insert actions. This is used to update the
+ * element structure.
+ *
+ * @param ev
+ * the <code>DocumentEvent</code> describing the change
+ * @param attr
+ * the attributes for the change
*/
protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
{
@@ -1703,8 +2094,7 @@ public class DefaultStyledDocument extends AbstractDocument
int offset = ev.getOffset();
int length = ev.getLength();
int endOffset = offset + length;
- AttributeSet paragraphAttributes =
- getParagraphElement(endOffset).getAttributes();
+ AttributeSet paragraphAttributes = getParagraphElement(endOffset).getAttributes();
Segment txt = new Segment();
try
{
@@ -1723,91 +2113,75 @@ public class DefaultStyledDocument extends AbstractDocument
short finalStartDirection = ElementSpec.OriginateDirection;
boolean prevCharWasNewline = false;
Element prev = getCharacterElement(offset);
- Element next = getCharacterElement(endOffset);
+ Element next = getCharacterElement(endOffset);
Element prevParagraph = getParagraphElement(offset);
Element paragraph = getParagraphElement(endOffset);
-
+
int segmentEnd = txt.offset + txt.count;
-
+
// Check to see if we're inserting immediately after a newline.
if (offset > 0)
{
try
- {
- String s = getText(offset - 1, 1);
- if (s.equals("\n"))
- {
- finalStartDirection =
- handleInsertAfterNewline(specs, offset, endOffset,
- prevParagraph,
- paragraph,
- paragraphAttributes);
-
- prevCharWasNewline = true;
- // Find the final start tag from the ones just created.
- for (int i = 0; i < specs.size(); i++)
- if (((ElementSpec) specs.get(i)).getType()
- == ElementSpec.StartTagType)
- finalStartTag = (ElementSpec)specs.get(i);
- }
- }
+ {
+ String s = getText(offset - 1, 1);
+ if (s.equals("\n"))
+ {
+ finalStartDirection = handleInsertAfterNewline(specs, offset,
+ endOffset,
+ prevParagraph,
+ paragraph,
+ paragraphAttributes);
+
+ prevCharWasNewline = true;
+ // Find the final start tag from the ones just created.
+ for (int i = 0; i < specs.size(); i++)
+ if (((ElementSpec) specs.get(i)).getType() == ElementSpec.StartTagType)
+ finalStartTag = (ElementSpec) specs.get(i);
+ }
+ }
catch (BadLocationException ble)
- {
- // This shouldn't happen.
- AssertionError ae = new AssertionError();
- ae.initCause(ble);
- throw ae;
- }
+ {
+ // This shouldn't happen.
+ AssertionError ae = new AssertionError();
+ ae.initCause(ble);
+ throw ae;
+ }
}
-
for (int i = txt.offset; i < segmentEnd; ++i)
{
len++;
if (txt.array[i] == '\n')
{
// Add the ElementSpec for the content.
- specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
+ specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
// Add ElementSpecs for the newline.
specs.add(new ElementSpec(null, ElementSpec.EndTagType));
finalStartTag = new ElementSpec(paragraphAttributes,
- ElementSpec.StartTagType);
+ ElementSpec.StartTagType);
specs.add(finalStartTag);
len = 0;
}
}
// Create last element if last character hasn't been a newline.
- if (len > 0)
+ if (len > 0)
specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
- // Set the direction of the last spec of type StartTagType.
- // If we are inserting after a newline then this value comes from
+ // Set the direction of the last spec of type StartTagType.
+ // If we are inserting after a newline then this value comes from
// handleInsertAfterNewline.
if (finalStartTag != null)
- {
+ {
if (prevCharWasNewline)
finalStartTag.setDirection(finalStartDirection);
else if (prevParagraph.getEndOffset() != endOffset)
- {
- try
- {
- String last = getText(endOffset - 1, 1);
- if (!last.equals("\n"))
- finalStartTag.setDirection(ElementSpec.JoinFractureDirection);
- }
- catch (BadLocationException ble)
- {
- // This shouldn't happen.
- AssertionError ae = new AssertionError();
- ae.initCause(ble);
- throw ae;
- }
- }
+ finalStartTag.setDirection(ElementSpec.JoinFractureDirection);
else
{
- // If there is an element AFTER this one, then set the
+ // If there is an element AFTER this one, then set the
// direction to JoinNextDirection.
Element parent = prevParagraph.getParentElement();
int index = parent.getElementIndex(offset);
@@ -1816,19 +2190,18 @@ public class DefaultStyledDocument extends AbstractDocument
finalStartTag.setDirection(ElementSpec.JoinNextDirection);
}
}
-
+
// If we are at the last index, then check if we could probably be
// joined with the next element.
// This means:
- // - we must be a ContentTag
- // - if there is a next Element, we must have the same attributes
- // - if there is no next Element, but one will be created,
- // we must have the same attributes as the higher-level run.
+ // - we must be a ContentTag
+ // - if there is a next Element, we must have the same attributes
+ // - if there is no next Element, but one will be created,
+ // we must have the same attributes as the higher-level run.
ElementSpec last = (ElementSpec) specs.lastElement();
if (last.getType() == ElementSpec.ContentType)
{
- Element currentRun =
- prevParagraph.getElement(prevParagraph.getElementIndex(offset));
+ Element currentRun = prevParagraph.getElement(prevParagraph.getElementIndex(offset));
if (currentRun.getEndOffset() == endOffset)
{
if (endOffset < getLength() && next.getAttributes().isEqual(attr)
@@ -1838,62 +2211,58 @@ public class DefaultStyledDocument extends AbstractDocument
else
{
if (finalStartTag != null
- && finalStartTag.getDirection() ==
- ElementSpec.JoinFractureDirection
+ && finalStartTag.getDirection() == ElementSpec.JoinFractureDirection
&& currentRun.getAttributes().isEqual(attr))
{
last.setDirection(ElementSpec.JoinNextDirection);
}
}
}
-
+
// If we are at the first new element, then check if it could be
// joined with the previous element.
ElementSpec first = (ElementSpec) specs.firstElement();
if (prev.getAttributes().isEqual(attr)
&& first.getType() == ElementSpec.ContentType)
first.setDirection(ElementSpec.JoinPreviousDirection);
-
- ElementSpec[] elSpecs =
- (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
+ ElementSpec[] elSpecs = (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
buffer.insert(offset, length, elSpecs, ev);
}
/**
- * A helper method to set up the ElementSpec buffer for the special
- * case of an insertion occurring immediately after a newline.
- * @param specs the ElementSpec buffer to initialize.
+ * A helper method to set up the ElementSpec buffer for the special case of an
+ * insertion occurring immediately after a newline.
+ *
+ * @param specs
+ * the ElementSpec buffer to initialize.
*/
short handleInsertAfterNewline(Vector specs, int offset, int endOffset,
- Element prevParagraph, Element paragraph,
- AttributeSet a)
+ Element prevParagraph, Element paragraph,
+ AttributeSet a)
{
if (prevParagraph.getParentElement() == paragraph.getParentElement())
{
specs.add(new ElementSpec(a, ElementSpec.EndTagType));
specs.add(new ElementSpec(a, ElementSpec.StartTagType));
- if (prevParagraph.getEndOffset() != endOffset)
+ if (paragraph.getStartOffset() != endOffset)
return ElementSpec.JoinFractureDirection;
// If there is an Element after this one, use JoinNextDirection.
Element parent = paragraph.getParentElement();
- if (parent.getElementCount() > parent.getElementIndex(offset) + 1)
+ if (parent.getElementCount() > (parent.getElementIndex(offset) + 1))
return ElementSpec.JoinNextDirection;
}
- else
- {
- // TODO: What to do here?
- }
return ElementSpec.OriginateDirection;
}
-
+
/**
* Updates the document structure in response to text removal. This is
- * forwarded to the {@link ElementBuffer} of this document. Any changes to
- * the document structure are added to the specified document event and
- * sent to registered listeners.
- *
- * @param ev the document event that records the changes to the document
+ * forwarded to the {@link ElementBuffer} of this document. Any changes to the
+ * document structure are added to the specified document event and sent to
+ * registered listeners.
+ *
+ * @param ev
+ * the document event that records the changes to the document
*/
protected void removeUpdate(DefaultDocumentEvent ev)
{
@@ -1903,7 +2272,7 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Returns an enumeration of all style names.
- *
+ *
* @return an enumeration of all style names
*/
public Enumeration getStyleNames()
@@ -1914,61 +2283,35 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Called when any of this document's styles changes.
- *
- * @param style the style that changed
+ *
+ * @param style
+ * the style that changed
*/
protected void styleChanged(Style style)
{
// Nothing to do here. This is intended to be overridden by subclasses.
}
- void printElements (Element start, int pad)
- {
- for (int i = 0; i < pad; i++)
- System.out.print(" ");
- if (pad == 0)
- System.out.println ("ROOT ELEMENT ("+start.getStartOffset()+", "+start.getEndOffset()+")");
- else if (start instanceof AbstractDocument.BranchElement)
- System.out.println ("BranchElement ("+start.getStartOffset()+", "+start.getEndOffset()+")");
- else
- {
- {
- try
- {
- System.out.println ("LeafElement ("+start.getStartOffset()+", "
- + start.getEndOffset()+"): "+
- start.getDocument().
- getText(start.getStartOffset(),
- start.getEndOffset() -
- start.getStartOffset()));
- }
- catch (BadLocationException ble)
- {
- }
- }
- }
- for (int i = 0; i < start.getElementCount(); i ++)
- printElements (start.getElement(i), pad+3);
- }
-
/**
* Inserts a bulk of structured content at once.
- *
- * @param offset the offset at which the content should be inserted
- * @param data the actual content spec to be inserted
+ *
+ * @param offset
+ * the offset at which the content should be inserted
+ * @param data
+ * the actual content spec to be inserted
*/
protected void insert(int offset, ElementSpec[] data)
- throws BadLocationException
+ throws BadLocationException
{
if (data == null || data.length == 0)
return;
try
{
// writeLock() and writeUnlock() should always be in a try/finally
- // block so that locking balance is guaranteed even if some
+ // block so that locking balance is guaranteed even if some
// exception is thrown.
writeLock();
-
+
// First we collect the content to be inserted.
StringBuffer contentBuffer = new StringBuffer();
for (int i = 0; i < data.length; i++)
@@ -1986,15 +2329,14 @@ public class DefaultStyledDocument extends AbstractDocument
// If there was no content inserted then exit early.
if (length == 0)
return;
-
+
UndoableEdit edit = content.insertString(offset,
contentBuffer.toString());
// Create the DocumentEvent with the ElementEdit added
- DefaultDocumentEvent ev =
- new DefaultDocumentEvent(offset,
- length,
- DocumentEvent.EventType.INSERT);
+ DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
+ length,
+ DocumentEvent.EventType.INSERT);
ev.addEdit(edit);
// Finally we must update the document structure and fire the insert
@@ -2012,20 +2354,66 @@ public class DefaultStyledDocument extends AbstractDocument
/**
* Initializes the <code>DefaultStyledDocument</code> with the specified
* data.
- *
- * @param data the specification of the content with which the document is
- * initialized
+ *
+ * @param data
+ * the specification of the content with which the document is
+ * initialized
*/
protected void create(ElementSpec[] data)
{
+ writeLock();
try
{
- // Clear content.
- content.remove(0, content.length());
- // Clear buffer and root element.
- buffer = new ElementBuffer(createDefaultRoot());
- // Insert the data.
- insert(0, data);
+ // Clear content if there is some.
+ int len = getLength();
+ if (len > 0)
+ remove(0, len);
+
+ // Now we insert the content.
+ StringBuilder b = new StringBuilder();
+ for (int i = 0; i < data.length; ++i)
+ {
+ ElementSpec el = data[i];
+ if (el.getArray() != null && el.getLength() > 0)
+ b.append(el.getArray(), el.getOffset(), el.getLength());
+ }
+ Content content = getContent();
+ UndoableEdit cEdit = content.insertString(0, b.toString());
+
+ 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);
+
+ // 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));
+
+ fireInsertUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
}
catch (BadLocationException ex)
{
@@ -2033,10 +2421,9 @@ public class DefaultStyledDocument extends AbstractDocument
err.initCause(ex);
throw err;
}
- }
-
- static boolean attributeSetsAreSame (AttributeSet a, AttributeSet b)
- {
- return (a == null && b == null) || (a != null && a.isEqual(b));
+ finally
+ {
+ writeUnlock();
+ }
}
}
diff --git a/libjava/classpath/javax/swing/text/DefaultTextUI.java b/libjava/classpath/javax/swing/text/DefaultTextUI.java
index e7ff01845e6..c347668b996 100644
--- a/libjava/classpath/javax/swing/text/DefaultTextUI.java
+++ b/libjava/classpath/javax/swing/text/DefaultTextUI.java
@@ -45,6 +45,7 @@ import javax.swing.plaf.basic.BasicTextUI;
* all text components is now {@link BasicTextUI}.
*
* @author Roman Kennke (kennke@aicas.com)
+ * @deprecated as of 1.5 use {@link BasicTextUI} instead
*/
public abstract class DefaultTextUI extends BasicTextUI
{
diff --git a/libjava/classpath/javax/swing/text/FlowView.java b/libjava/classpath/javax/swing/text/FlowView.java
index 6d4b9cd3174..8be8f41e939 100644
--- a/libjava/classpath/javax/swing/text/FlowView.java
+++ b/libjava/classpath/javax/swing/text/FlowView.java
@@ -38,14 +38,10 @@ exception statement from your version. */
package javax.swing.text;
-import java.awt.Container;
-import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
-import java.util.Iterator;
-import java.util.Vector;
-import javax.swing.SwingConstants;
+import javax.swing.SizeRequirements;
import javax.swing.event.DocumentEvent;
/**
@@ -89,7 +85,7 @@ public abstract class FlowView extends BoxView
*/
public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- layout(fv);
+ // The default implementation does nothing.
}
/**
@@ -105,7 +101,7 @@ public abstract class FlowView extends BoxView
*/
public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- layout(fv);
+ // The default implementation does nothing.
}
/**
@@ -121,7 +117,7 @@ public abstract class FlowView extends BoxView
*/
public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- layout(fv);
+ // The default implementation does nothing.
}
/**
@@ -131,7 +127,7 @@ public abstract class FlowView extends BoxView
*
* @return the logical view of the managed <code>FlowView</code>
*/
- public View getLogicalView(FlowView fv)
+ protected View getLogicalView(FlowView fv)
{
return fv.layoutPool;
}
@@ -166,43 +162,60 @@ public abstract class FlowView extends BoxView
* Lays out one row of the flow view. This is called by {@link #layout}
* to fill one row with child views until the available span is exhausted.
*
+ * The default implementation fills the row by calling
+ * {@link #createView(FlowView, int, int, int)} until the available space
+ * is exhausted, a forced break is encountered or there are no more views
+ * in the logical view. If the available space is exhausted,
+ * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row
+ * into the available span.
+ *
* @param fv the flow view for which we perform the layout
* @param rowIndex the index of the row
- * @param pos the start position for the row
+ * @param pos the model position for the beginning of the row
*
* @return the start position of the next row
*/
protected int layoutRow(FlowView fv, int rowIndex, int pos)
{
- int spanLeft = fv.getFlowSpan(rowIndex);
- if (spanLeft <= 0)
- return -1;
-
- int offset = pos;
View row = fv.getView(rowIndex);
- int flowAxis = fv.getFlowAxis();
+ 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;
- while (spanLeft > 0)
+ while (span > 0)
{
- View child = createView(fv, offset, spanLeft, rowIndex);
- if (child == null)
- {
- offset = -1;
- break;
- }
-
- int span = (int) child.getPreferredSpan(flowAxis);
- if (span > spanLeft)
- {
- offset = -1;
- break;
- }
-
- row.append(child);
- spanLeft -= span;
- offset = child.getEndOffset();
+ if (logicalView.getViewIndex(offset, Position.Bias.Forward) == -1)
+ break;
+ View view = createView(fv, offset, span, rowIndex);
+ if (view == null)
+ break;
+ int viewSpan = (int) view.getPreferredSpan(axis);
+ row.append(view);
+ int breakWeight = view.getBreakWeight(axis, x, span);
+ if (breakWeight >= View.ForcedBreakWeight)
+ break;
+ x += viewSpan;
+ span -= viewSpan;
+ offset += (view.getEndOffset() - view.getStartOffset());
}
- return offset;
+ if (span < 0)
+ {
+ 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();
+ else
+ offset = -1;
+ }
+ return offset != pos ? offset : -1;
}
/**
@@ -212,189 +225,106 @@ public abstract class FlowView extends BoxView
* available span and can be broken down) or <code>null</code> (if it does
* not fit in the available span and also cannot be broken down).
*
+ * The default implementation fetches the logical view at the specified
+ * <code>startOffset</code>. If that view has a different startOffset than
+ * specified in the argument, a fragment is created using
+ * {@link View#createFragment(int, int)} that has the correct startOffset
+ * and the logical view's endOffset.
+ *
* @param fv the flow view
- * @param offset the start offset for the view to be created
+ * @param startOffset the start offset for the view to be created
* @param spanLeft the available span
* @param rowIndex the index of the row
*
* @return a view to fill the row with, or <code>null</code> if there
* is no view or view fragment that fits in the available span
*/
- protected View createView(FlowView fv, int offset, int spanLeft,
+ protected View createView(FlowView fv, int startOffset, int spanLeft,
int rowIndex)
{
- // Find the logical element for the given offset.
- View logicalView = getLogicalView(fv);
-
- int viewIndex = logicalView.getViewIndex(offset, Position.Bias.Forward);
- if (viewIndex == -1)
- return null;
-
- View child = logicalView.getView(viewIndex);
- int flowAxis = fv.getFlowAxis();
- int span = (int) child.getPreferredSpan(flowAxis);
-
- if (span <= spanLeft)
- return child;
- else if (child.getBreakWeight(flowAxis, offset, spanLeft)
- > BadBreakWeight)
- // FIXME: What to do with the pos parameter here?
- return child.breakView(flowAxis, offset, 0, spanLeft);
- else
- return null;
- }
- }
-
- /**
- * This special subclass of <code>View</code> is used to represent
- * the logical representation of this view. It does not support any
- * visual representation, this is handled by the physical view implemented
- * in the <code>FlowView</code>.
- */
- class LogicalView extends View
- {
- /**
- * The child views of this logical view.
- */
- Vector children;
-
- /**
- * Creates a new LogicalView instance.
- */
- LogicalView(Element el)
- {
- super(el);
- children = new Vector();
- }
-
- /**
- * Returns the container that holds this view. The logical view returns
- * the enclosing FlowView's container here.
- *
- * @return the container that holds this view
- */
- public Container getContainer()
- {
- return FlowView.this.getContainer();
- }
-
- /**
- * Returns the number of child views of this logical view.
- *
- * @return the number of child views of this logical view
- */
- public int getViewCount()
- {
- return children.size();
- }
-
- /**
- * Returns the child view at the specified index.
- *
- * @param index the index
- *
- * @return the child view at the specified index
- */
- public View getView(int index)
- {
- return (View) children.get(index);
- }
-
- /**
- * Replaces some child views with other child views.
- *
- * @param offset the offset at which to replace child views
- * @param length the number of children to remove
- * @param views the views to be inserted
- */
- public void replace(int offset, int length, View[] views)
- {
- if (length > 0)
- {
- for (int count = 0; count < length; ++count)
- children.remove(offset);
- }
-
- int endOffset = offset + views.length;
- for (int i = offset; i < endOffset; ++i)
- {
- children.add(i, views[i - offset]);
- // Set the parent of the child views to the flow view itself so
- // it has something to resolve.
- views[i - offset].setParent(FlowView.this);
- }
+ View logicalView = getLogicalView(fv);
+ // FIXME: Handle the bias thing correctly.
+ int index = logicalView.getViewIndex(startOffset, Position.Bias.Forward);
+ View retVal = null;
+ if (index >= 0)
+ {
+ retVal = logicalView.getView(index);
+ if (retVal.getStartOffset() != startOffset)
+ retVal = retVal.createFragment(startOffset, retVal.getEndOffset());
+ }
+ return retVal;
}
/**
- * Returns the index of the child view that contains the specified
- * position in the document model.
+ * Tries to adjust the specified row to fit within the desired span. The
+ * default implementation iterates through the children of the specified
+ * row to find the view that has the highest break weight and - if there
+ * is more than one view with such a break weight - which is nearest to
+ * the end of the row. If there is such a view that has a break weight >
+ * {@link View#BadBreakWeight}, this view is broken using the
+ * {@link View#breakView(int, int, float, float)} method and this view and
+ * all views after the now broken view are replaced by the broken view.
*
- * @param pos the position for which we are searching the child view
- * @param b the bias
- *
- * @return the index of the child view that contains the specified
- * position in the document model
+ * @param fv the flow view
+ * @param rowIndex the index of the row to be adjusted
+ * @param desiredSpan the layout span
+ * @param x the X location at which the row starts
*/
- public int getViewIndex(int pos, Position.Bias b)
- {
- int index = -1;
- int i = 0;
- for (Iterator it = children.iterator(); it.hasNext(); i++)
+ protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) {
+ // Determine the last view that has the highest break weight.
+ int axis = fv.getFlowAxis();
+ View row = fv.getView(rowIndex);
+ int count = row.getViewCount();
+ int breakIndex = -1;
+ int maxBreakWeight = View.BadBreakWeight;
+ int breakX = x;
+ int breakSpan = desiredSpan;
+ int currentX = x;
+ int currentSpan = desiredSpan;
+ for (int i = 0; i < count; ++i)
{
- View child = (View) it.next();
- if (child.getStartOffset() >= pos
- && child.getEndOffset() < pos)
+ View view = row.getView(i);
+ int weight = view.getBreakWeight(axis, currentX, currentSpan);
+ if (weight >= maxBreakWeight)
{
- index = i;
- break;
+ breakIndex = i;
+ breakX = currentX;
+ breakSpan = currentSpan;
+ maxBreakWeight = weight;
}
+ int size = (int) view.getPreferredSpan(axis);
+ currentX += size;
+ currentSpan -= size;
}
- return index;
- }
- /**
- * Throws an AssertionError because it must never be called. LogicalView
- * only serves as a holder for child views and has no visual
- * representation.
- */
- public float getPreferredSpan(int axis)
- {
- throw new AssertionError("This method must not be called in "
- + "LogicalView.");
- }
-
- /**
- * Throws an AssertionError because it must never be called. LogicalView
- * only serves as a holder for child views and has no visual
- * representation.
- */
- public Shape modelToView(int pos, Shape a, Position.Bias b)
- throws BadLocationException
- {
- throw new AssertionError("This method must not be called in "
- + "LogicalView.");
- }
-
- /**
- * Throws an AssertionError because it must never be called. LogicalView
- * only serves as a holder for child views and has no visual
- * representation.
- */
- public void paint(Graphics g, Shape s)
- {
- throw new AssertionError("This method must not be called in "
- + "LogicalView.");
+ // If there is a potential break location found, break the row at
+ // this location.
+ if (breakIndex > -1)
+ {
+ View toBeBroken = row.getView(breakIndex);
+ View brokenView = toBeBroken.breakView(axis,
+ toBeBroken.getStartOffset(),
+ breakX, breakSpan);
+ row.replace(breakIndex, count - breakIndex,
+ new View[]{brokenView});
+ }
}
+ }
+ /**
+ * This special subclass of <code>View</code> is used to represent
+ * the logical representation of this view. It does not support any
+ * visual representation, this is handled by the physical view implemented
+ * in the <code>FlowView</code>.
+ */
+ class LogicalView extends BoxView
+ {
/**
- * Throws an AssertionError because it must never be called. LogicalView
- * only serves as a holder for child views and has no visual
- * representation.
+ * Creates a new LogicalView instance.
*/
- public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
+ LogicalView(Element el, int axis)
{
- throw new AssertionError("This method must not be called in "
- + "LogicalView.");
+ super(el, axis);
}
}
@@ -424,6 +354,11 @@ public abstract class FlowView extends BoxView
protected FlowStrategy strategy;
/**
+ * Indicates if the flow should be rebuild during the next layout.
+ */
+ private boolean layoutDirty;
+
+ /**
* Creates a new <code>FlowView</code> for the given
* <code>Element</code> and <code>axis</code>.
*
@@ -436,6 +371,7 @@ public abstract class FlowView extends BoxView
{
super(element, axis);
strategy = sharedStrategy;
+ layoutDirty = true;
}
/**
@@ -510,16 +446,8 @@ public abstract class FlowView extends BoxView
{
if (layoutPool == null)
{
- layoutPool = new LogicalView(getElement());
-
- Element el = getElement();
- int count = el.getElementCount();
- for (int i = 0; i < count; ++i)
- {
- Element childEl = el.getElement(i);
- View childView = vf.create(childEl);
- layoutPool.append(childView);
- }
+ layoutPool = new LogicalView(getElement(), getAxis());
+ layoutPool.setParent(this);
}
}
@@ -534,27 +462,32 @@ public abstract class FlowView extends BoxView
*/
protected void layout(int width, int height)
{
- boolean rebuild = false;
-
int flowAxis = getFlowAxis();
if (flowAxis == X_AXIS)
{
- rebuild = !(width == layoutSpan);
- layoutSpan = width;
+ if (layoutSpan != width)
+ {
+ layoutChanged(Y_AXIS);
+ layoutSpan = width;
+ }
}
else
{
- rebuild = !(height == layoutSpan);
- layoutSpan = height;
+ if (layoutSpan != height)
+ {
+ layoutChanged(X_AXIS);
+ layoutSpan = height;
+ }
}
- if (rebuild)
- strategy.layout(this);
+ if (layoutDirty)
+ {
+ strategy.layout(this);
+ layoutDirty = false;
+ }
- // TODO: If the span along the box axis has changed in the process of
- // relayouting the rows (that is, if rows have been added or removed),
- // call preferenceChanged in order to throw away cached layout information
- // of the surrounding BoxView.
+ if (getPreferredSpan(getAxis()) != height)
+ preferenceChanged(this, false, true);
super.layout(width, height);
}
@@ -574,6 +507,7 @@ public abstract class FlowView extends BoxView
// be updated accordingly.
layoutPool.insertUpdate(changes, a, vf);
strategy.insertUpdate(this, changes, getInsideAllocation(a));
+ layoutDirty = true;
}
/**
@@ -588,6 +522,7 @@ public abstract class FlowView extends BoxView
public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
{
strategy.removeUpdate(this, changes, getInsideAllocation(a));
+ layoutDirty = true;
}
/**
@@ -602,6 +537,7 @@ public abstract class FlowView extends BoxView
public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
{
strategy.changedUpdate(this, changes, getInsideAllocation(a));
+ layoutDirty = true;
}
/**
@@ -640,4 +576,30 @@ public abstract class FlowView extends BoxView
}
return result;
}
+
+ /**
+ * Calculates the size requirements of this <code>BoxView</code> along
+ * its minor axis, that is the axis opposite to the axis specified in the
+ * constructor.
+ *
+ * This is overridden and forwards the request to the logical view.
+ *
+ * @param axis the axis that is examined
+ * @param r the <code>SizeRequirements</code> object to hold the result,
+ * if <code>null</code>, a new one is created
+ *
+ * @return the size requirements for this <code>BoxView</code> along
+ * the specified axis
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ // We need to call super here so that the alignment is properly
+ // calculated.
+ SizeRequirements res = super.calculateMinorAxisRequirements(axis, r);
+ res.minimum = (int) layoutPool.getMinimumSpan(axis);
+ res.preferred = (int) layoutPool.getPreferredSpan(axis);
+ res.maximum = (int) layoutPool.getMaximumSpan(axis);
+ return res;
+ }
}
diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java
index 80dcfa56e06..28d1d6ee01f 100644
--- a/libjava/classpath/javax/swing/text/GapContent.java
+++ b/libjava/classpath/javax/swing/text/GapContent.java
@@ -1,5 +1,5 @@
/* GapContent.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,8 +39,10 @@ exception statement from your version. */
package javax.swing.text;
import java.io.Serializable;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Vector;
@@ -68,8 +70,8 @@ public class GapContent
/**
* A {@link Position} implementation for <code>GapContent</code>.
*/
- class GapContentPosition
- implements Position, Comparable
+ private class GapContentPosition
+ implements Position, Comparable
{
/** The index within the buffer array. */
@@ -130,7 +132,7 @@ public class GapContent
}
}
- class InsertUndo extends AbstractUndoableEdit
+ private class InsertUndo extends AbstractUndoableEdit
{
public int where, length;
String text;
@@ -169,7 +171,7 @@ public class GapContent
}
- class UndoRemove extends AbstractUndoableEdit
+ private class UndoRemove extends AbstractUndoableEdit
{
public int where;
String text;
@@ -206,7 +208,41 @@ public class GapContent
}
}
-
+
+ /**
+ * Compares WeakReference objects in a List by comparing the referenced
+ * objects instead.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private class WeakPositionComparator
+ implements Comparator
+ {
+
+ /**
+ * Compares two objects of type WeakReference. The objects are compared
+ * using the referenced objects compareTo() method.
+ */
+ public int compare(Object o1, Object o2)
+ {
+ // Unwrap references.
+ if (o1 instanceof WeakReference)
+ o1 = ((WeakReference) o1).get();
+ if (o2 instanceof WeakReference)
+ o2 = ((WeakReference) o2).get();
+
+ GapContentPosition p1 = (GapContentPosition) o1;
+ GapContentPosition p2 = (GapContentPosition) o2;
+
+ int retVal;
+ if (p1 == null || p2 == null)
+ retVal = -1;
+ else
+ retVal = p1.compareTo(p2);
+ return retVal;
+ }
+ }
+
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = -6226052713477823730L;
@@ -233,9 +269,10 @@ public class GapContent
/**
* The positions generated by this GapContent. They are kept in an ordered
- * fashion, so they can be looked up easily.
+ * fashion, so they can be looked up easily. The value objects will be
+ * WeakReference objects that in turn hold GapContentPosition objects.
*/
- ArrayList positions;
+ private ArrayList positions;
/**
* Creates a new GapContent object.
@@ -310,8 +347,12 @@ public class GapContent
int length = length();
int strLen = str.length();
+ if (where < 0)
+ throw new BadLocationException("The where argument cannot be smaller"
+ + " than the zero", where);
+
if (where >= length)
- throw new BadLocationException("the where argument cannot be greater"
+ throw new BadLocationException("The where argument cannot be greater"
+ " than the content length", where);
replace(where, 0, str.toCharArray(), strLen);
@@ -446,18 +487,22 @@ public class GapContent
throw new BadLocationException("The offset was out of the bounds of this"
+ " buffer", offset);
+ clearPositionReferences();
+
// We store the actual array index in the GapContentPosition. The real
// offset is then calculated in the GapContentPosition.
int mark = offset;
if (offset >= gapStart)
mark += gapEnd - gapStart;
GapContentPosition pos = new GapContentPosition(mark);
+ WeakReference r = new WeakReference(pos);
// Add this into our list in a sorted fashion.
- int index = Collections.binarySearch(positions, pos);
+ int index = Collections.binarySearch(positions, r,
+ new WeakPositionComparator());
if (index < 0)
index = -(index + 1);
- positions.add(index, pos);
+ positions.add(index, r);
return pos;
}
@@ -557,7 +602,7 @@ public class GapContent
assert newGapEnd > gapEnd : "The new gap end must be greater than the "
+ "old gap end.";
- setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd + 1);
+ setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd);
gapEnd = newGapEnd;
}
@@ -566,7 +611,7 @@ public class GapContent
*
* @return the allocated buffer array
*/
- protected Object getArray()
+ protected final Object getArray()
{
return buffer;
}
@@ -642,19 +687,30 @@ public class GapContent
int endOffset = offset + length;
int index1 = Collections.binarySearch(positions,
- new GapContentPosition(offset));
+ new GapContentPosition(offset),
+ new WeakPositionComparator());
if (index1 < 0)
index1 = -(index1 + 1);
// Search the first index with the specified offset. The binarySearch does
// not necessarily find the first one.
- while (index1 > 0
- && ((GapContentPosition) positions.get(index1 - 1)).mark == offset)
- index1--;
+ while (index1 > 0)
+ {
+ WeakReference r = (WeakReference) positions.get(index1 - 1);
+ GapContentPosition p = (GapContentPosition) r.get();
+ if (p != null && p.mark == offset || p == null)
+ index1--;
+ else
+ break;
+ }
for (ListIterator i = positions.listIterator(index1); i.hasNext();)
{
- GapContentPosition p = (GapContentPosition) i.next();
+ WeakReference r = (WeakReference) i.next();
+ GapContentPosition p = (GapContentPosition) r.get();
+ if (p == null)
+ continue;
+
if (p.mark > endOffset)
break;
if (p.mark >= offset && p.mark <= endOffset)
@@ -672,24 +728,35 @@ public class GapContent
* @param length the length of the range to search
* @param value the new value for each mark
*/
- void setPositionsInRange(int offset, int length, int value)
+ private void setPositionsInRange(int offset, int length, int value)
{
int endOffset = offset + length;
int index1 = Collections.binarySearch(positions,
- new GapContentPosition(offset));
+ new GapContentPosition(offset),
+ new WeakPositionComparator());
if (index1 < 0)
index1 = -(index1 + 1);
// Search the first index with the specified offset. The binarySearch does
// not necessarily find the first one.
- while (index1 > 0
- && ((GapContentPosition) positions.get(index1 - 1)).mark == offset)
- index1--;
+ while (index1 > 0)
+ {
+ WeakReference r = (WeakReference) positions.get(index1 - 1);
+ GapContentPosition p = (GapContentPosition) r.get();
+ if (p != null && p.mark == offset || p == null)
+ index1--;
+ else
+ break;
+ }
for (ListIterator i = positions.listIterator(index1); i.hasNext();)
{
- GapContentPosition p = (GapContentPosition) i.next();
+ WeakReference r = (WeakReference) i.next();
+ GapContentPosition p = (GapContentPosition) r.get();
+ if (p == null)
+ continue;
+
if (p.mark > endOffset)
break;
@@ -707,23 +774,35 @@ public class GapContent
* @param length the length of the range to search
* @param incr the increment
*/
- void adjustPositionsInRange(int offset, int length, int incr)
+ private void adjustPositionsInRange(int offset, int length, int incr)
{
int endOffset = offset + length;
int index1 = Collections.binarySearch(positions,
- new GapContentPosition(offset));
+ new GapContentPosition(offset),
+ new WeakPositionComparator());
if (index1 < 0)
index1 = -(index1 + 1);
// Search the first index with the specified offset. The binarySearch does
// not necessarily find the first one.
- while (index1 > 0
- && ((GapContentPosition) positions.get(index1 - 1)).mark == offset)
- index1--;
+ while (index1 > 0)
+ {
+ WeakReference r = (WeakReference) positions.get(index1 - 1);
+ GapContentPosition p = (GapContentPosition) r.get();
+ if (p != null && p.mark == offset || p == null)
+ index1--;
+ else
+ break;
+ }
+
for (ListIterator i = positions.listIterator(index1); i.hasNext();)
{
- GapContentPosition p = (GapContentPosition) i.next();
+ WeakReference r = (WeakReference) i.next();
+ GapContentPosition p = (GapContentPosition) r.get();
+ if (p == null)
+ continue;
+
if (p.mark > endOffset)
break;
@@ -747,6 +826,17 @@ public class GapContent
}
/**
+ * @specnote This method is not very well specified and the positions vector
+ * is implementation specific. The undo positions are managed
+ * differently in this implementation, this method is only here
+ * for binary compatibility.
+ */
+ protected void updateUndoPositions(Vector positions, int offset, int length)
+ {
+ // We do nothing here.
+ }
+
+ /**
* Outputs debugging info to System.err. It prints out the buffer array,
* the gapStart is marked by a &lt; sign, the gapEnd is marked by a &gt;
* sign and each position is marked by a # sign.
@@ -776,8 +866,23 @@ public class GapContent
{
for (Iterator i = positions.iterator(); i.hasNext();)
{
- GapContentPosition pos = (GapContentPosition) i.next();
+ WeakReference r = (WeakReference) i.next();
+ GapContentPosition pos = (GapContentPosition) r.get();
System.err.println("position at: " + pos.mark);
}
}
+
+ /**
+ * Clears all GC'ed references in the positions array.
+ */
+ private void clearPositionReferences()
+ {
+ Iterator i = positions.iterator();
+ while (i.hasNext())
+ {
+ WeakReference r = (WeakReference) i.next();
+ if (r.get() == null)
+ i.remove();
+ }
+ }
}
diff --git a/libjava/classpath/javax/swing/text/GlyphView.java b/libjava/classpath/javax/swing/text/GlyphView.java
index 47deb50d03a..d505274c91f 100644
--- a/libjava/classpath/javax/swing/text/GlyphView.java
+++ b/libjava/classpath/javax/swing/text/GlyphView.java
@@ -277,38 +277,41 @@ public class GlyphView extends View implements TabableView, Cloneable
public void paint(GlyphView view, Graphics g, Shape a, int p0,
int p1)
{
+ Color oldColor = g.getColor();
int height = (int) getHeight(view);
Segment txt = view.getText(p0, p1);
Rectangle bounds = a.getBounds();
-
TabExpander tabEx = null;
View parent = view.getParent();
if (parent instanceof TabExpander)
tabEx = (TabExpander) parent;
- // Fill the background of the text run.
- Color background = view.getBackground();
- g.setColor(background);
int width = Utilities.getTabbedTextWidth(txt, g.getFontMetrics(),
bounds.x, tabEx, txt.offset);
- g.fillRect(bounds.x, bounds.y, width, height);
-
+ // Fill the background of the text run.
+ Color background = view.getBackground();
+ if (background != null)
+ {
+ g.setColor(background);
+ g.fillRect(bounds.x, bounds.y, width, height);
+ }
// Draw the actual text.
g.setColor(view.getForeground());
g.setFont(view.getFont());
+ int ascent = g.getFontMetrics().getAscent();
if (view.isSuperscript())
// TODO: Adjust font for superscripting.
- Utilities.drawTabbedText(txt, bounds.x, bounds.y - height / 2, g, tabEx,
- txt.offset);
+ Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent - height / 2,
+ g, tabEx, txt.offset);
else if (view.isSubscript())
// TODO: Adjust font for subscripting.
- Utilities.drawTabbedText(txt, bounds.x, bounds.y + height / 2, g, tabEx,
- txt.offset);
+ Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent + height / 2,
+ g, tabEx, txt.offset);
else
- Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx,
+ Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent, g, tabEx,
txt.offset);
- if (view.isStikeThrough())
+ if (view.isStrikeThrough())
{
int strikeHeight = (int) (getAscent(view) / 2);
g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.height + width,
@@ -320,6 +323,7 @@ public class GlyphView extends View implements TabableView, Cloneable
g.drawLine(bounds.x, bounds.y + lineHeight, bounds.height + width,
bounds.y + lineHeight);
}
+ g.setColor(oldColor);
}
/**
@@ -470,12 +474,12 @@ public class GlyphView extends View implements TabableView, Cloneable
/**
* The start offset within the document for this view.
*/
- int startOffset;
+ private int startOffset;
/**
* The end offset within the document for this view.
*/
- int endOffset;
+ private int endOffset;
/**
* Creates a new <code>GlyphView</code> for the given <code>Element</code>.
@@ -485,8 +489,8 @@ public class GlyphView extends View implements TabableView, Cloneable
public GlyphView(Element element)
{
super(element);
- startOffset = element.getStartOffset();
- endOffset = element.getEndOffset();
+ startOffset = -1;
+ endOffset = -1;
}
/**
@@ -534,8 +538,7 @@ public class GlyphView extends View implements TabableView, Cloneable
{
Element el = getElement();
checkPainter();
- getGlyphPainter().paint(this, g, a, el.getStartOffset(),
- el.getEndOffset());
+ getGlyphPainter().paint(this, g, a, getStartOffset(), getEndOffset());
}
@@ -563,7 +566,8 @@ public class GlyphView extends View implements TabableView, Cloneable
tabEx, 0.F);
}
else
- span = painter.getHeight(this);
+ span = painter.getHeight(this);
+
return span;
}
@@ -682,7 +686,10 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public int getStartOffset()
{
- return startOffset;
+ int start = startOffset;
+ if (start < 0)
+ start = super.getStartOffset();
+ return start;
}
/**
@@ -694,7 +701,10 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public int getEndOffset()
{
- return endOffset;
+ int end = endOffset;
+ if (end < 0)
+ end = super.getEndOffset();
+ return end;
}
/**
@@ -771,7 +781,11 @@ public class GlyphView extends View implements TabableView, Cloneable
{
Element el = getElement();
AttributeSet atts = el.getAttributes();
- return StyleConstants.getBackground(atts);
+ // We cannot use StyleConstants.getBackground() here, because that returns
+ // BLACK as default (when background == null). What we need is the
+ // background setting of the text component instead, which is what we get
+ // when background == null anyway.
+ return (Color) atts.getAttribute(StyleConstants.Background);
}
/**
@@ -782,7 +796,7 @@ public class GlyphView extends View implements TabableView, Cloneable
*
* @return whether the text should be rendered strike-through or not
*/
- public boolean isStikeThrough()
+ public boolean isStrikeThrough()
{
Element el = getElement();
AttributeSet atts = el.getAttributes();
@@ -876,13 +890,15 @@ public class GlyphView extends View implements TabableView, Cloneable
checkPainter();
GlyphPainter painter = getGlyphPainter();
- int breakLocation = painter.getBoundedPosition(this, p0, pos, len);
+
// Try to find a suitable line break.
BreakIterator lineBreaker = BreakIterator.getLineInstance();
Segment txt = new Segment();
try
{
- getDocument().getText(getStartOffset(), getEndOffset(), txt);
+ int start = getStartOffset();
+ int length = getEndOffset() - start;
+ getDocument().getText(start, length, txt);
}
catch (BadLocationException ex)
{
@@ -891,11 +907,10 @@ public class GlyphView extends View implements TabableView, Cloneable
err.initCause(ex);
throw err;
}
- lineBreaker.setText(txt);
- int goodBreakLocation = lineBreaker.previous();
- if (goodBreakLocation != BreakIterator.DONE)
- breakLocation = goodBreakLocation;
-
+ int breakLocation =
+ Utilities.getBreakLocation(txt, getContainer().getFontMetrics(getFont()),
+ (int) pos, (int) (pos + len),
+ getTabExpander(), p0);
View brokenView = createFragment(p0, breakLocation);
return brokenView;
}
@@ -922,23 +937,24 @@ public class GlyphView extends View implements TabableView, Cloneable
weight = super.getBreakWeight(axis, pos, len);
else
{
- // Determine the model locations at pos and pos + len.
- int spanX = (int) getPreferredSpan(X_AXIS);
- int spanY = (int) getPreferredSpan(Y_AXIS);
- Rectangle dummyAlloc = new Rectangle(0, 0, spanX, spanY);
- Position.Bias[] biasRet = new Position.Bias[1];
- int offset1 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet);
- int offset2 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet);
- Segment txt = getText(offset1, offset2);
- BreakIterator lineBreaker = BreakIterator.getLineInstance();
- lineBreaker.setText(txt);
- int breakLoc = lineBreaker.previous();
- if (breakLoc == offset1)
- weight = View.BadBreakWeight;
- else if(breakLoc == BreakIterator.DONE)
- weight = View.GoodBreakWeight;
- else
- weight = View.ExcellentBreakWeight;
+ // FIXME: Commented out because the Utilities.getBreakLocation method
+ // is still buggy. The GoodBreakWeight is a reasonable workaround for
+ // now.
+// int startOffset = getStartOffset();
+// int endOffset = getEndOffset() - 1;
+// Segment s = getText(startOffset, endOffset);
+// Container c = getContainer();
+// FontMetrics fm = c.getFontMetrics(c.getFont());
+// int x0 = (int) pos;
+// int x = (int) (pos + len);
+// int breakLoc = Utilities.getBreakLocation(s, fm, x0, x,
+// getTabExpander(),
+// startOffset);
+// if (breakLoc == startOffset || breakLoc == endOffset)
+// weight = GoodBreakWeight;
+// else
+// weight = ExcellentBreakWeight;
+ weight = GoodBreakWeight;
}
return weight;
}
@@ -955,14 +971,14 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf)
{
- getParent().preferenceChanged(this, true, true);
+ preferenceChanged(this, true, true);
}
/**
* Receives notification that some text has been inserted within the
* text fragment that this view is responsible for. This calls
- * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for
- * width.
+ * {@link View#preferenceChanged(View, boolean, boolean)} for the
+ * direction in which the glyphs are rendered.
*
* @param e the document event describing the change; not used here
* @param a the view allocation on screen; not used here
@@ -970,7 +986,7 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory vf)
{
- getParent().preferenceChanged(this, true, false);
+ preferenceChanged(this, true, false);
}
/**
@@ -985,7 +1001,7 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory vf)
{
- getParent().preferenceChanged(this, true, false);
+ preferenceChanged(this, true, false);
}
/**
@@ -1000,8 +1016,10 @@ public class GlyphView extends View implements TabableView, Cloneable
public View createFragment(int p0, int p1)
{
GlyphView fragment = (GlyphView) clone();
- fragment.startOffset = p0;
- fragment.endOffset = p1;
+ if (p0 != getStartOffset())
+ fragment.startOffset = p0;
+ if (p1 != getEndOffset())
+ fragment.endOffset = p1;
return fragment;
}
diff --git a/libjava/classpath/javax/swing/text/IconView.java b/libjava/classpath/javax/swing/text/IconView.java
index af2581a8831..699cda90eba 100644
--- a/libjava/classpath/javax/swing/text/IconView.java
+++ b/libjava/classpath/javax/swing/text/IconView.java
@@ -130,8 +130,6 @@ public class IconView
throws BadLocationException
{
Element el = getElement();
- if (pos < el.getStartOffset() || pos >= el.getEndOffset())
- throw new BadLocationException("Illegal offset for this view", pos);
Rectangle r = a.getBounds();
Icon icon = StyleConstants.getIcon(el.getAttributes());
return new Rectangle(r.x, r.y, icon.getIconWidth(), icon.getIconHeight());
diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java
index afa1f24a6a4..6b8348ceaf5 100644
--- a/libjava/classpath/javax/swing/text/JTextComponent.java
+++ b/libjava/classpath/javax/swing/text/JTextComponent.java
@@ -60,7 +60,9 @@ import java.util.Enumeration;
import java.util.Hashtable;
import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleEditableText;
import javax.accessibility.AccessibleRole;
import javax.accessibility.AccessibleStateSet;
import javax.accessibility.AccessibleText;
@@ -86,200 +88,415 @@ public abstract class JTextComponent extends JComponent
implements Scrollable, Accessible
{
/**
- * AccessibleJTextComponent
+ * This class implements accessibility support for the JTextComponent class.
+ * It provides an implementation of the Java Accessibility API appropriate
+ * to menu user-interface elements.
*/
- // FIXME: This inner class is a complete stub and needs to be implemented.
- public class AccessibleJTextComponent extends AccessibleJComponent
- implements AccessibleText, CaretListener, DocumentListener
+ public class AccessibleJTextComponent extends AccessibleJComponent implements
+ AccessibleText, CaretListener, DocumentListener, AccessibleAction,
+ AccessibleEditableText
{
private static final long serialVersionUID = 7664188944091413696L;
+ /** The caret's offset. */
+ int dot = 0;
+
+ /** The current JTextComponent. */
+ JTextComponent textComp = JTextComponent.this;
+
/**
- * Constructor AccessibleJTextComponent
+ * Constructs an AccessibleJTextComponent.
+ * Adds a listener to track caret change.
*/
public AccessibleJTextComponent()
{
- // Nothing to do here.
+ super();
+ textComp.addCaretListener(this);
}
/**
- * getCaretPosition
- * @return int
+ * Returns the zero-based offset of the caret. Note: The character
+ * to the right of the caret will have the same index value as the
+ * offset (the caret is between two characters).
+ *
+ * @return offset of caret
*/
public int getCaretPosition()
{
- return 0; // TODO
+ dot = textComp.getCaretPosition();
+ return dot;
}
/**
- * getSelectedText
- * @return String
+ * Returns the portion of the text that is selected.
+ *
+ * @return null if no text is selected.
*/
public String getSelectedText()
{
- return null; // TODO
+ return textComp.getSelectedText();
}
/**
- * getSelectionStart
- * @return int
+ * Returns the start offset within the selected text. If there is no
+ * selection, but there is a caret, the start and end offsets will be
+ * the same. Return 0 if the text is empty, or the caret position if no selection.
+ *
+ * @return index of the start of the text >= 0.
*/
public int getSelectionStart()
{
- return 0; // TODO
+ if (getSelectedText() == null || (textComp.getText().equals("")))
+ return 0;
+ return textComp.getSelectionStart();
}
/**
- * getSelectionEnd
- * @return int
+ * Returns the end offset within the selected text. If there is no
+ * selection, but there is a caret, the start and end offsets will
+ * be the same. Return 0 if the text is empty, or the caret position
+ * if no selection.
+ *
+ * @return index of the end of the text >= 0.
*/
public int getSelectionEnd()
{
- return 0; // TODO
+ if (getSelectedText() == null || (textComp.getText().equals("")))
+ return 0;
+ return textComp.getSelectionEnd();
}
/**
- * caretUpdate
- * @param value0 TODO
+ * Handles caret updates (fire appropriate property change event, which are
+ * AccessibleContext.ACCESSIBLE_CARET_PROPERTY and
+ * AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY). This keeps track of
+ * the dot position internally. When the caret moves, the internal position
+ * is updated after firing the event.
+ *
+ * @param e - caret event
*/
- public void caretUpdate(CaretEvent value0)
+ public void caretUpdate(CaretEvent e)
{
- // TODO
+ // TODO: fire appropriate event.
+ dot = e.getDot();
}
/**
- * getAccessibleStateSet
- * @return AccessibleStateSet
+ * Returns the accessible state set of this component.
+ *
+ * @return the accessible state set of this component
*/
public AccessibleStateSet getAccessibleStateSet()
{
- return null; // TODO
+ AccessibleStateSet state = super.getAccessibleStateSet();
+ // TODO: Figure out what state must be added here to the super's state.
+ return state;
}
/**
- * getAccessibleRole
- * @return AccessibleRole
+ * Returns the accessible role of this component.
+ *
+ * @return the accessible role of this component
+ *
+ * @see AccessibleRole
*/
public AccessibleRole getAccessibleRole()
{
- return null; // TODO
+ return AccessibleRole.TEXT;
}
/**
- * getAccessibleText
- * @return AccessibleText
+ * Returns the AccessibleEditableText interface for this text component.
+ *
+ * @return this
+ */
+ public AccessibleEditableText getAccessibleEditableText()
+ {
+ return this;
+ }
+
+ /**
+ * Get the AccessibleText associated with this object. In the implementation
+ * of the Java Accessibility API for this class, return this object,
+ * which is responsible for implementing the AccessibleText interface on
+ * behalf of itself.
+ *
+ * @return this
+ *
+ * @see AccessibleText
*/
public AccessibleText getAccessibleText()
{
- return null; // TODO
+ return this;
}
-
+
/**
- * insertUpdate
- * @param value0 TODO
+ * Insert update. Fire appropriate property change event which
+ * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
+ *
+ * @param e - document event
*/
- public void insertUpdate(DocumentEvent value0)
+ public void insertUpdate(DocumentEvent e)
{
// TODO
}
/**
- * removeUpdate
- * @param value0 TODO
+ * Remove update. Fire appropriate property change event which
+ * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
+ *
+ * @param e - document event
*/
- public void removeUpdate(DocumentEvent value0)
+ public void removeUpdate(DocumentEvent e)
{
// TODO
}
/**
- * changedUpdate
- * @param value0 TODO
+ * Changed update. Fire appropriate property change event which
+ * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
+ *
+ * @param e - document event
*/
- public void changedUpdate(DocumentEvent value0)
+ public void changedUpdate(DocumentEvent e)
{
// TODO
}
/**
- * getIndexAtPoint
- * @param value0 TODO
- * @return int
+ * Given a point in the coordinate system of this object, return the
+ * 0-based index of the character at that point, or -1 if there is none.
+ *
+ * @param p the point to look at
+ * @return the character index, or -1
*/
- public int getIndexAtPoint(Point value0)
+ public int getIndexAtPoint(Point p)
{
return 0; // TODO
}
/**
- * getRootEditorRect
- * @return Rectangle
+ * Determines the bounding box of the indexed character. Returns an empty
+ * rectangle if the index is out of bounds. The bounds are returned in local coordinates.
+ * If the index is invalid a null rectangle is returned. The screen coordinates returned are
+ * "unscrolled coordinates" if the JTextComponent is contained in a JScrollPane in which
+ * case the resulting rectangle should be composed with the parent coordinates.
+ * Note: the JTextComponent must have a valid size (e.g. have been added to a parent
+ * container whose ancestor container is a valid top-level window) for this method to
+ * be able to return a meaningful (non-null) value.
+ *
+ * @param index the 0-based character index
+ * @return the bounding box, may be empty or null.
*/
- Rectangle getRootEditorRect()
+ public Rectangle getCharacterBounds(int index)
{
- return null;
+ return null; // TODO
}
/**
- * getCharacterBounds
- * @param value0 TODO
- * @return Rectangle
+ * Return the number of characters.
+ *
+ * @return the character count
*/
- public Rectangle getCharacterBounds(int value0)
+ public int getCharCount()
+ {
+ return textComp.getText().length();
+ }
+
+ /**
+ * Returns the attributes of a character at an index, or null if the index
+ * is out of bounds.
+ *
+ * @param index the 0-based character index
+ * @return the character's attributes
+ */
+ public AttributeSet getCharacterAttribute(int index)
{
return null; // TODO
}
/**
- * getCharCount
- * @return int
+ * Returns the section of text at the index, or null if the index or part
+ * is invalid.
+ *
+ * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index the 0-based character index
+ * @return the selection of text at that index, or null
*/
- public int getCharCount()
+ public String getAtIndex(int part, int index)
{
- return 0; // TODO
+ return null; // TODO
}
/**
- * getCharacterAttribute
- * @param value0 TODO
- * @return AttributeSet
+ * Returns the section of text after the index, or null if the index or part
+ * is invalid.
+ *
+ * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index the 0-based character index
+ * @return the selection of text after that index, or null
*/
- public AttributeSet getCharacterAttribute(int value0)
+ public String getAfterIndex(int part, int index)
{
return null; // TODO
}
/**
- * getAtIndex
- * @param value0 TODO
- * @param value1 TODO
- * @return String
+ * Returns the section of text before the index, or null if the index or part
+ * is invalid.
+ *
+ * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index the 0-based character index
+ * @return the selection of text before that index, or null
*/
- public String getAtIndex(int value0, int value1)
+ public String getBeforeIndex(int part, int index)
{
return null; // TODO
}
+
+ /**
+ * Get the number possible actions for this object, with the zeroth
+ * representing the default action.
+ *
+ * @return the 0-based number of actions
+ */
+ public int getAccessibleActionCount()
+ {
+ return 0; // TODO
+ }
+
+ /**
+ * Get a description for the specified action. Returns null if out of
+ * bounds.
+ *
+ * @param i
+ * the action to describe, 0-based
+ * @return description of the action
+ */
+ public String getAccessibleActionDescription(int i)
+ {
+ // TODO: Not implemented fully
+ return super.getAccessibleDescription();
+ }
+
+ /**
+ * Perform the specified action. Does nothing if out of bounds.
+ *
+ * @param i the action to perform, 0-based
+ * @return true if the action was performed
+ */
+ public boolean doAccessibleAction(int i)
+ {
+ return false; // TODO
+ }
+
+ /**
+ * Set the text contents to the given string.
+ *
+ * @param s the new text
+ */
+ public void setTextContents(String s)
+ {
+ // TODO
+ }
/**
- * getAfterIndex
- * @param value0 TODO
- * @param value1 TODO
- * @return String
+ * Inserts the given string at the specified location.
+ *
+ * @param index the index for insertion
+ * @param s the new text
*/
- public String getAfterIndex(int value0, int value1)
+ public void insertTextAtIndex(int index, String s)
{
- return null; // TODO
+ replaceText(index, index, s);
}
/**
- * getBeforeIndex
- * @param value0 TODO
- * @param value1 TODO
- * @return String
+ * Return the text between two points.
+ *
+ * @param start the start position, inclusive
+ * @param end the end position, exclusive
*/
- public String getBeforeIndex(int value0, int value1)
+ public String getTextRange(int start, int end)
{
- return null; // TODO
+ try
+ {
+ return textComp.getText(start, end - start);
+ }
+ catch (BadLocationException ble)
+ {
+ return "";
+ }
+ }
+
+ /**
+ * Delete the text between two points.
+ *
+ * @param start the start position, inclusive
+ * @param end the end position, exclusive
+ */
+ public void delete(int start, int end)
+ {
+ replaceText(start, end, "");
+ }
+
+ /**
+ * Cut the text between two points to the system clipboard.
+ *
+ * @param start the start position, inclusive
+ * @param end the end position, exclusive
+ */
+ public void cut(int start, int end)
+ {
+ textComp.select(start, end);
+ textComp.cut();
+ }
+
+ /**
+ * Paste the text from the system clipboard at the given index.
+ *
+ * @param start the start position
+ */
+ public void paste(int start)
+ {
+ textComp.setCaretPosition(start);
+ textComp.paste();
+ }
+
+ /**
+ * Replace the text between two points with the given string.
+ *
+ * @param start the start position, inclusive
+ * @param end the end position, exclusive
+ * @param s the string to paste
+ */
+ public void replaceText(int start, int end, String s)
+ {
+ textComp.select(start, end);
+ textComp.replaceSelection(s);
+ }
+
+ /**
+ * Select the text between two points.
+ *
+ * @param start the start position, inclusive
+ * @param end the end position, exclusive
+ */
+ public void selectText(int start, int end)
+ {
+ textComp.select(start, end);
+ }
+
+ /**
+ * Set the attributes of text between two points.
+ *
+ * @param start the start position, inclusive
+ * @param end the end position, exclusive
+ * @param s the new attribute set for the range
+ */
+ public void setAttributes(int start, int end, AttributeSet s)
+ {
+ // TODO
}
}
@@ -945,7 +1162,7 @@ public abstract class JTextComponent extends JComponent
*/
public AccessibleContext getAccessibleContext()
{
- return null;
+ return new AccessibleJTextComponent();
}
public void setMargin(Insets m)
@@ -1024,9 +1241,15 @@ public abstract class JTextComponent extends JComponent
*/
public String getSelectedText()
{
+ int start = getSelectionStart();
+ int offset = getSelectionEnd() - start;
+
+ if (offset <= 0)
+ return null;
+
try
{
- return doc.getText(getSelectionStart(), getSelectionEnd());
+ return doc.getText(start, offset);
}
catch (BadLocationException e)
{
@@ -1375,8 +1598,12 @@ public abstract class JTextComponent extends JComponent
// Insert new text.
doc.insertString(start, content, null);
- // Set dot to new position.
- setCaretPosition(start + content.length());
+ // Set dot to new position,
+ dot = start + content.length();
+ setCaretPosition(dot);
+
+ // and update it's magic position.
+ caret.setMagicCaretPosition(modelToView(dot).getLocation());
}
catch (BadLocationException e)
{
@@ -1387,7 +1614,7 @@ public abstract class JTextComponent extends JComponent
public boolean getScrollableTracksViewportHeight()
{
if (getParent() instanceof JViewport)
- return ((JViewport) getParent()).getHeight() > getPreferredSize().height;
+ return getParent().getHeight() > getPreferredSize().height;
return false;
}
@@ -1395,7 +1622,7 @@ public abstract class JTextComponent extends JComponent
public boolean getScrollableTracksViewportWidth()
{
if (getParent() instanceof JViewport)
- return ((JViewport) getParent()).getWidth() > getPreferredSize().width;
+ return getParent().getWidth() > getPreferredSize().width;
return false;
}
diff --git a/libjava/classpath/javax/swing/text/LabelView.java b/libjava/classpath/javax/swing/text/LabelView.java
index 4890735b925..03279c4b2b5 100644
--- a/libjava/classpath/javax/swing/text/LabelView.java
+++ b/libjava/classpath/javax/swing/text/LabelView.java
@@ -109,7 +109,11 @@ public class LabelView extends GlyphView
{
Element el = getElement();
AttributeSet atts = el.getAttributes();
- background = StyleConstants.getBackground(atts);
+ // We cannot use StyleConstants.getBackground() here, because that returns
+ // BLACK as default (when background == null). What we need is the
+ // background setting of the text component instead, which is what we get
+ // when background == null anyway.
+ background = (Color) atts.getAttribute(StyleConstants.Background);
foreground = StyleConstants.getForeground(atts);
strikeThrough = StyleConstants.isStrikeThrough(atts);
subscript = StyleConstants.isSubscript(atts);
diff --git a/libjava/classpath/javax/swing/text/MutableAttributeSet.java b/libjava/classpath/javax/swing/text/MutableAttributeSet.java
index 2fe9ad50f67..3728b9ce126 100644
--- a/libjava/classpath/javax/swing/text/MutableAttributeSet.java
+++ b/libjava/classpath/javax/swing/text/MutableAttributeSet.java
@@ -1,5 +1,5 @@
/* MutableAttributeSet.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,46 +40,78 @@ package javax.swing.text;
import java.util.Enumeration;
/**
- * MutableAttributeSet
+ * An {@link AttributeSet} that supports modification of the stored
+ * attributes.
+ *
* @author Andrew Selkirk
- * @version 1.0
+ * @since 1.2
*/
public interface MutableAttributeSet extends AttributeSet
{
/**
- * addAttribute
- * @param name TODO
- * @param value TODO
+ * Adds an attribute with the given <code>name</code> and <code>value</code>
+ * to the set. If the set already contains an attribute with the given
+ * <code>name</code>, the attribute value is updated.
+ *
+ * @param name the attribute name (<code>null</code> not permitted).
+ * @param value the value (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
*/
void addAttribute(Object name, Object value);
/**
- * addAttributes
- * @param attributes TODO
+ * Adds all the attributes from <code>attributes</code> to this set.
+ *
+ * @param attributes the set of attributes to add (<code>null</code> not
+ * permitted).
+ *
+ * @throws NullPointerException if <code>attributes</code> is
+ * <code>null</code>.
*/
void addAttributes(AttributeSet attributes);
/**
- * removeAttribute
- * @param name TODO
+ * Removes the attribute with the specified <code>name</code>, if this
+ * attribute is defined. This method will only remove an attribute from
+ * this set, not from the resolving parent.
+ *
+ * @param name the attribute name (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>name</code> is <code>null</code>.
*/
void removeAttribute(Object name);
/**
- * removeAttributes
- * @param names TODO
+ * Removes the attributes listed in <code>names</code>.
+ *
+ * @param names the attribute names (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>names</code> is <code>null</code>
+ * or contains any <code>null</code> values.
*/
void removeAttributes(Enumeration names);
/**
- * removeAttributes
- * @param attributes TODO
+ * Removes attributes from this set if they are found in the
+ * given set. Only attributes whose key AND value are removed.
+ * Removes attributes only from this set, not from the resolving parent.
+ * Since the resolving parent is stored as an attribute, if
+ * <code>attributes</code> has the same resolving parent as this set, the
+ * parent will be removed from this set.
+ *
+ * @param attributes the attributes (<code>null</code> not permitted).
*/
void removeAttributes(AttributeSet attributes);
/**
- * setResolveParent
- * @param parent TODO
+ * Sets the reolving parent for this set. When looking up an attribute, if
+ * it is not found in this set, then the resolving parent is also used for
+ * the lookup.
+ *
+ * @param parent the parent attribute set (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>parent</code> is <code>null</code>.
*/
void setResolveParent(AttributeSet parent);
}
diff --git a/libjava/classpath/javax/swing/text/NavigationFilter.java b/libjava/classpath/javax/swing/text/NavigationFilter.java
index 45f58f9e229..ea9b29db837 100644
--- a/libjava/classpath/javax/swing/text/NavigationFilter.java
+++ b/libjava/classpath/javax/swing/text/NavigationFilter.java
@@ -68,4 +68,31 @@ public class NavigationFilter
{
fb.setDot(dot, bias);
}
+
+ /**
+ * Returns the next visual position in the specified direction at which one
+ * would place a caret. The default implementation forwards to the text
+ * component's root view. Subclasses may wish to restrict that more.
+ *
+ * @param c the text component
+ * @param pos the current model position
+ * @param bias the bias of <code>pos</code>
+ * @param dir the direction, one of {@link javax.swing.SwingConstants#NORTH},
+ * {@link javax.swing.SwingConstants#SOUTH},
+ * {@link javax.swing.SwingConstants#WEST} or
+ * {@link javax.swing.SwingConstants#EAST}
+ * @param retBias the bias of the returned position
+ *
+ * @return the next model location to place the caret
+ *
+ * @throws BadLocationException when <code>pos</code> is not a valid model
+ * position
+ */
+ public int getNextVisualPositionFrom(JTextComponent c, int pos,
+ Position.Bias bias, int dir,
+ Position.Bias[] retBias)
+ throws BadLocationException
+ {
+ return c.getUI().getNextVisualPositionFrom(c, pos, bias, dir, retBias);
+ }
}
diff --git a/libjava/classpath/javax/swing/text/ParagraphView.java b/libjava/classpath/javax/swing/text/ParagraphView.java
index c4864503187..15bed781825 100644
--- a/libjava/classpath/javax/swing/text/ParagraphView.java
+++ b/libjava/classpath/javax/swing/text/ParagraphView.java
@@ -63,10 +63,20 @@ public class ParagraphView extends FlowView implements TabExpander
{
super(el, X_AXIS);
}
+
public float getAlignment(int axis)
{
- // FIXME: This is very likely not 100% correct. Work this out.
- return 0.0F;
+ float align;
+ if (axis == X_AXIS)
+ align = 0.0F; // TODO: Implement according to justification
+ else
+ align = super.getAlignment(axis);
+ return align;
+ }
+
+ protected void loadChildren(ViewFactory vf)
+ {
+ // Do nothing here. The children are added while layouting.
}
}
@@ -128,17 +138,18 @@ public class ParagraphView extends FlowView implements TabExpander
*/
public float getAlignment(int axis)
{
+ float align;
if (axis == X_AXIS)
- return 0.0F;
+ align = super.getAlignment(axis);
else if (getViewCount() > 0)
{
-
float prefHeight = getPreferredSpan(Y_AXIS);
float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS);
- return (firstRowHeight / 2.F) / prefHeight;
+ align = (firstRowHeight / 2.F) / prefHeight;
}
else
- return 0.0F;
+ align = 0.0F;
+ return align;
}
/**
@@ -229,4 +240,184 @@ public class ParagraphView extends FlowView implements TabExpander
{
return tabSet;
}
+
+ /**
+ * Finds the next offset in the document that has one of the characters
+ * specified in <code>string</code>. If there is no such character found,
+ * this returns -1.
+ *
+ * @param string the characters to search for
+ * @param start the start offset
+ *
+ * @return the next offset in the document that has one of the characters
+ * specified in <code>string</code>
+ */
+ protected int findOffsetToCharactersInString(char[] string, int start)
+ {
+ int offset = -1;
+ Document doc = getDocument();
+ Segment text = new Segment();
+ try
+ {
+ doc.getText(start, doc.getLength() - start, text);
+ int index = start;
+
+ searchLoop:
+ while (true)
+ {
+ char ch = text.next();
+ if (ch == Segment.DONE)
+ break;
+
+ for (int j = 0; j < string.length; ++j)
+ {
+ if (string[j] == ch)
+ {
+ offset = index;
+ break searchLoop;
+ }
+ }
+ index++;
+ }
+ }
+ catch (BadLocationException ex)
+ {
+ // Ignore this and return -1.
+ }
+ return offset;
+ }
+
+ protected int getClosestPositionTo(int pos, Position.Bias bias, Shape a,
+ int direction, Position.Bias[] biasRet,
+ int rowIndex, int x)
+ throws BadLocationException
+ {
+ // FIXME: Implement this properly. However, this looks like it might
+ // have been replaced by viewToModel.
+ return pos;
+ }
+
+ /**
+ * Returns the size that is used by this view (or it's child views) between
+ * <code>startOffset</code> and <code>endOffset</code>. If the child views
+ * implement the {@link TabableView} interface, then this is used to
+ * determine the span, otherwise we use the preferred span of the child
+ * views.
+ *
+ * @param startOffset the start offset
+ * @param endOffset the end offset
+ *
+ * @return the span used by the view between <code>startOffset</code> and
+ * <code>endOffset</cod>
+ */
+ protected float getPartialSize(int startOffset, int endOffset)
+ {
+ int startIndex = getViewIndex(startOffset, Position.Bias.Backward);
+ int endIndex = getViewIndex(endOffset, Position.Bias.Forward);
+ float span;
+ if (startIndex == endIndex)
+ {
+ View child = getView(startIndex);
+ if (child instanceof TabableView)
+ {
+ TabableView tabable = (TabableView) child;
+ span = tabable.getPartialSpan(startOffset, endOffset);
+ }
+ else
+ span = child.getPreferredSpan(X_AXIS);
+ }
+ else if (endIndex - startIndex == 1)
+ {
+ View child1 = getView(startIndex);
+ if (child1 instanceof TabableView)
+ {
+ TabableView tabable = (TabableView) child1;
+ span = tabable.getPartialSpan(startOffset, child1.getEndOffset());
+ }
+ else
+ span = child1.getPreferredSpan(X_AXIS);
+ View child2 = getView(endIndex);
+ if (child2 instanceof TabableView)
+ {
+ TabableView tabable = (TabableView) child2;
+ span += tabable.getPartialSpan(child2.getStartOffset(), endOffset);
+ }
+ else
+ span += child2.getPreferredSpan(X_AXIS);
+ }
+ else
+ {
+ // Start with the first view.
+ View child1 = getView(startIndex);
+ if (child1 instanceof TabableView)
+ {
+ TabableView tabable = (TabableView) child1;
+ span = tabable.getPartialSpan(startOffset, child1.getEndOffset());
+ }
+ else
+ span = child1.getPreferredSpan(X_AXIS);
+
+ // Add up the view spans between the start and the end view.
+ for (int i = startIndex + 1; i < endIndex; i++)
+ {
+ View child = getView(i);
+ span += child.getPreferredSpan(X_AXIS);
+ }
+
+ // Add the span of the last view.
+ View child2 = getView(endIndex);
+ if (child2 instanceof TabableView)
+ {
+ TabableView tabable = (TabableView) child2;
+ span += tabable.getPartialSpan(child2.getStartOffset(), endOffset);
+ }
+ else
+ span += child2.getPreferredSpan(X_AXIS);
+ }
+ return span;
+ }
+
+ /**
+ * Returns the location where the tabs are calculated from. This returns
+ * <code>0.0F</code> by default.
+ *
+ * @return the location where the tabs are calculated from
+ */
+ protected float getTabBase()
+ {
+ return 0.0F;
+ }
+
+ /**
+ * @specnote This method is specified to take a Row parameter, which is a
+ * private inner class of that class, which makes it unusable from
+ * application code. Also, this method seems to be replaced by
+ * {@link FlowStrategy#adjustRow(FlowView, int, int, int)}.
+ *
+ */
+ protected void adjustRow(Row r, int desiredSpan, int x)
+ {
+ }
+
+ /**
+ * @specnote This method's signature differs from the one defined in
+ * {@link View} and is therefore never called. It is probably there
+ * for historical reasons.
+ */
+ public View breakView(int axis, float len, Shape a)
+ {
+ // This method is not used.
+ return null;
+ }
+
+ /**
+ * @specnote This method's signature differs from the one defined in
+ * {@link View} and is therefore never called. It is probably there
+ * for historical reasons.
+ */
+ public int getBreakWeight(int axis, float len)
+ {
+ // This method is not used.
+ return 0;
+ }
}
diff --git a/libjava/classpath/javax/swing/text/PasswordView.java b/libjava/classpath/javax/swing/text/PasswordView.java
index e54331c5a8e..9d4c86a8388 100644
--- a/libjava/classpath/javax/swing/text/PasswordView.java
+++ b/libjava/classpath/javax/swing/text/PasswordView.java
@@ -107,8 +107,6 @@ public class PasswordView
protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
throws BadLocationException
{
- // FIXME: Throw BadLocationException somehow.
-
// Update font metrics.
updateMetrics();
@@ -119,25 +117,18 @@ public class PasswordView
g.setColor(selectedColor);
g.setColor(Color.BLACK);
- // Initialize buffer for faster drawing of all characters.
- int len = p1 - p0;
- char[] buffer = new char[len];
- for (int index = 0; index < len; ++index)
- buffer[index] = ch;
-
- // Draw echo charaters.
- g.drawChars(buffer, 0, len, x, y);
-
- // Return new x position right of all drawn characters.
- return x + len * metrics.charWidth(ch);
+ // Draw echo character using drawEchoCharacter() method.
+ for (int index = p0; index < p1; ++index)
+ x = drawEchoCharacter(g, x, y, ch);
+ return x;
}
/**
* Draws unselected text at a given position.
*
* @param g the <code>Graphics</code> object to draw to
- * @param x the x-position
- * @param y the y-position
+ * @param x the x-position of the start of the baseline
+ * @param y the y-position of the start of the baseline
* @param p0 the position of the first character to draw
* @param p1 the position of the first character not to draw
*
@@ -146,35 +137,20 @@ public class PasswordView
protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
throws BadLocationException
{
- // FIXME: Throw BadLocationException somehow.
-
// Update font metrics.
updateMetrics();
// Get echo character.
char ch = getEchoChar();
- Segment segment = new Segment();
// Set color for unselected text.
g.setColor(unselectedColor);
g.setColor(Color.BLACK);
- // Initialize buffer for faster drawing of all characters.
- p1--;
- getDocument().getText(p0, p1 - p0, segment);
- int len = segment.toString().length();
-
- char[] buffer = new char[len];
- for (int index = 0; index < len; ++index)
- buffer[index] = ch;
-
- y += getPreferredSpan(Y_AXIS)/2;
-
- // Draw echo charaters.
- g.drawChars(buffer, 0, len, x, y);
-
- // Return new x position right of all drawn characters.
- return x + (len * metrics.charWidth(ch));
+ // Draw echo character using drawEchoCharacter() method.
+ for (int index = p0; index < p1; ++index)
+ x = drawEchoCharacter(g, x, y, ch);
+ return x;
}
/**
diff --git a/libjava/classpath/javax/swing/text/PlainDocument.java b/libjava/classpath/javax/swing/text/PlainDocument.java
index 2200cae80a0..c699dcad2aa 100644
--- a/libjava/classpath/javax/swing/text/PlainDocument.java
+++ b/libjava/classpath/javax/swing/text/PlainDocument.java
@@ -1,5 +1,5 @@
/* PlainDocument.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,6 +40,15 @@ package javax.swing.text;
import java.util.ArrayList;
+/**
+ * A simple document class which maps lines to {@link Element}s.
+ *
+ * @author Anthony Balkissoon (abalkiss@redhat.com)
+ * @author Graydon Hoare (graydon@redhat.com)
+ * @author Roman Kennke (roman@kennke.org)
+ * @author Michael Koch (konqueror@gmx.de)
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
public class PlainDocument extends AbstractDocument
{
private static final long serialVersionUID = 4758290289196893664L;
@@ -109,18 +118,21 @@ public class PlainDocument extends AbstractDocument
AttributeSet attributes)
{
int offset = event.getOffset();
+ int eventLength = event.getLength();
int end = offset + event.getLength();
- int elementIndex = rootElement.getElementIndex(offset);
+ int oldElementIndex, elementIndex = rootElement.getElementIndex(offset);
Element firstElement = rootElement.getElement(elementIndex);
-
+ oldElementIndex = elementIndex;
+
// If we're inserting immediately after a newline we have to fix the
- // Element structure.
- if (offset > 0)
+ // Element structure (but only if we are dealing with a line which
+ // has not existed as Element before).
+ if (offset > 0 && firstElement.getStartOffset() != offset)
{
try
{
String s = getText(offset - 1, 1);
- if (s.equals("\n"))
+ if (s.equals("\n") )
{
int newEl2EndOffset = end;
boolean replaceNext = false;
@@ -159,33 +171,43 @@ public class PlainDocument extends AbstractDocument
Element[] added;
try
{
- String str = content.getString(0, content.length());
+ String str = content.getString(offset, eventLength);
ArrayList elts = new ArrayList();
// Determine how many NEW lines were added by finding the newline
// characters within the newly inserted text
int j = firstElement.getStartOffset();
- int i = str.indexOf('\n', offset);
- while (i != -1 && i <= end)
+ int i = str.indexOf('\n', 0);
+ int contentLength = content.length();
+
+ while (i != -1 && i <= eventLength)
{
// For each new line, create a new element
elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY,
- j, i + 1));
- j = i + 1;
- if (j >= str.length())
- break;
- i = str.indexOf('\n', j);
+ j, offset + i + 1));
+
+ j = offset + i + 1;
+ if (j >= contentLength)
+ break;
+ i = str.indexOf('\n', i + 1);
}
+
// If there were new lines added we have to add an ElementEdit to
// the DocumentEvent and we have to call rootElement.replace to
// insert the new lines
if (elts.size() != 0)
{
+ // If we have created new lines test whether there are remaining
+ // characters in firstElement after the inserted text and if so
+ // create a new element for them.
+ if (j < firstElement.getEndOffset())
+ elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, firstElement.getEndOffset()));
+
// Set up the ElementEdit by filling the added and removed
// arrays with the proper Elements
added = new Element[elts.size()];
- for (int k = 0; k < elts.size(); ++k)
- added[k] = (Element) elts.get(k);
+ elts.toArray(added);
+
removed[0] = firstElement;
// Now create and add the ElementEdit
@@ -204,6 +226,7 @@ public class PlainDocument extends AbstractDocument
ae.initCause(e);
throw ae;
}
+
super.insertUpdate(event, attributes);
}
diff --git a/libjava/classpath/javax/swing/text/PlainView.java b/libjava/classpath/javax/swing/text/PlainView.java
index a318ee71ae0..4bb3a8eda33 100644
--- a/libjava/classpath/javax/swing/text/PlainView.java
+++ b/libjava/classpath/javax/swing/text/PlainView.java
@@ -1,5 +1,5 @@
/* PlainView.java --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -46,7 +46,7 @@ import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
-import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentEvent.ElementChange;
@@ -137,22 +137,32 @@ public class PlainView extends View implements TabExpander
return rect;
}
+ /**
+ * Draws a line of text. The X and Y coordinates specify the start of
+ * the <em>baseline</em> of the line.
+ *
+ * @param lineIndex the index of the line
+ * @param g the graphics to use for drawing the text
+ * @param x the X coordinate of the baseline
+ * @param y the Y coordinate of the baseline
+ */
protected void drawLine(int lineIndex, Graphics g, int x, int y)
{
try
{
- metrics = g.getFontMetrics();
- // FIXME: Selected text are not drawn yet.
- Element line = getElement().getElement(lineIndex);
- drawUnselectedText(g, x, y, line.getStartOffset(), line.getEndOffset());
- //drawSelectedText(g, , , , );
+ metrics = g.getFontMetrics();
+ // FIXME: Selected text are not drawn yet.
+ Element line = getElement().getElement(lineIndex);
+ drawUnselectedText(g, x, y, line.getStartOffset(),
+ line.getEndOffset() - 1);
+ //drawSelectedText(g, , , , );
}
catch (BadLocationException e)
- {
- AssertionError ae = new AssertionError("Unexpected bad location");
- ae.initCause(e);
- throw ae;
- }
+ {
+ AssertionError ae = new AssertionError("Unexpected bad location");
+ ae.initCause(e);
+ throw ae;
+ }
}
protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
@@ -164,6 +174,20 @@ public class PlainView extends View implements TabExpander
return Utilities.drawTabbedText(segment, x, y, g, this, 0);
}
+ /**
+ * Draws a chunk of unselected text.
+ *
+ * @param g the graphics to use for drawing the text
+ * @param x the X coordinate of the baseline
+ * @param y the Y coordinate of the baseline
+ * @param p0 the start position in the text model
+ * @param p1 the end position in the text model
+ *
+ * @return the X location of the end of the range
+ *
+ * @throws BadLocationException if <code>p0</code> or <code>p1</code> are
+ * invalid
+ */
protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
throws BadLocationException
{
@@ -194,12 +218,12 @@ public class PlainView extends View implements TabExpander
// FIXME: Text may be scrolled.
Document document = textComponent.getDocument();
Element root = document.getDefaultRootElement();
- int y = rect.y;
+ int y = rect.y + metrics.getAscent();
for (int i = 0; i < root.getElementCount(); i++)
{
- drawLine(i, g, rect.x, y);
- y += metrics.getHeight();
+ drawLine(i, g, rect.x, y);
+ y += metrics.getHeight();
}
}
@@ -284,18 +308,20 @@ public class PlainView extends View implements TabExpander
// make sure we have the metrics
updateMetrics();
- float span = 0;
Element el = getElement();
+ float span;
switch (axis)
{
case X_AXIS:
span = determineMaxLineLength();
+ break;
case Y_AXIS:
default:
span = metrics.getHeight() * el.getElementCount();
break;
}
+
return span;
}
@@ -318,12 +344,19 @@ public class PlainView extends View implements TabExpander
Element root = doc.getDefaultRootElement();
// PlainView doesn't support line-wrapping so we can find out which
- // Element was clicked on just by the y-position
- int lineClicked = (int) (y - rec.y) / metrics.getHeight();
- if (lineClicked >= root.getElementCount())
- return getEndOffset() - 1;
+ // Element was clicked on just by the y-position.
+ // Since the coordinates may be outside of the coordinate space
+ // of the allocation area (e.g. user dragged mouse outside
+ // the component) we have to limit the values.
+ // This has the nice effect that the user can drag the
+ // mouse above or below the component and it will still
+ // react to the x values (e.g. when selecting).
+ int lineClicked
+ = Math.min(Math.max((int) (y - rec.y) / metrics.getHeight(), 0),
+ root.getElementCount() - 1);
Element line = root.getElement(lineClicked);
+
Segment s = getLineBuffer();
int start = line.getStartOffset();
// We don't want the \n at the end of the line.
@@ -353,6 +386,8 @@ public class PlainView extends View implements TabExpander
*/
protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
{
+ float oldMaxLineLength = maxLineLength;
+ Rectangle alloc = a.getBounds();
Element el = getElement();
ElementChange ec = changes.getChange(el);
@@ -360,7 +395,19 @@ public class PlainView extends View implements TabExpander
// repaint the changed line
if (ec == null)
{
- int line = getElement().getElementIndex(changes.getOffset());
+ int line = el.getElementIndex(changes.getOffset());
+
+ // If characters have been removed from the current longest line
+ // we have to find out which one is the longest now otherwise
+ // the preferred x-axis span will not shrink.
+ if (changes.getType() == DocumentEvent.EventType.REMOVE
+ && el.getElement(line) == longestLine)
+ {
+ maxLineLength = -1;
+ if (determineMaxLineLength() != alloc.width)
+ preferenceChanged(this, true, false);
+ }
+
damageLineRange(line, line, a, getContainer());
return;
}
@@ -373,12 +420,13 @@ public class PlainView extends View implements TabExpander
if (removed == null && newElements == null)
{
int line = getElement().getElementIndex(changes.getOffset());
+
damageLineRange(line, line, a, getContainer());
return;
}
// Check to see if we removed the longest line, if so we have to
- // search through all lines and find the longest one again
+ // search through all lines and find the longest one again.
if (removed != null)
{
for (int i = 0; i < removed.length; i++)
@@ -386,8 +434,11 @@ public class PlainView extends View implements TabExpander
{
// reset maxLineLength and search through all lines for longest one
maxLineLength = -1;
- determineMaxLineLength();
+ if (determineMaxLineLength() != alloc.width)
+ preferenceChanged(this, true, removed.length != newElements.length);
+
((JTextComponent)getContainer()).repaint();
+
return;
}
}
@@ -397,6 +448,7 @@ public class PlainView extends View implements TabExpander
{
// No lines were added, just repaint the container and exit
((JTextComponent)getContainer()).repaint();
+
return;
}
@@ -445,6 +497,14 @@ public class PlainView extends View implements TabExpander
maxLineLength = longestNewLength;
longestLine = longestNewLine;
}
+
+ // Report any changes to the preferred sizes of the view
+ // which may cause the underlying component to be revalidated.
+ boolean widthChanged = oldMaxLineLength != maxLineLength;
+ boolean heightChanged = removed.length != newElements.length;
+ if (widthChanged || heightChanged)
+ preferenceChanged(this, widthChanged, heightChanged);
+
// Repaint the container
((JTextComponent)getContainer()).repaint();
}
@@ -511,7 +571,9 @@ public class PlainView extends View implements TabExpander
host.repaint();
else
{
- Rectangle repaintRec = rec0.union(rec1);
+ Rectangle repaintRec = SwingUtilities.computeUnion(rec0.x, rec0.y,
+ rec0.width,
+ rec0.height, rec1);
host.repaint(repaintRec.x, repaintRec.y, repaintRec.width,
repaintRec.height);
}
diff --git a/libjava/classpath/javax/swing/text/Segment.java b/libjava/classpath/javax/swing/text/Segment.java
index 84e0e700f2e..875d9966c1f 100644
--- a/libjava/classpath/javax/swing/text/Segment.java
+++ b/libjava/classpath/javax/swing/text/Segment.java
@@ -1,5 +1,5 @@
/* Segment.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,20 +39,40 @@ package javax.swing.text;
import java.text.CharacterIterator;
+/**
+ * A text fragment represented by a sequence of characters stored in an array.
+ */
public class Segment implements Cloneable, CharacterIterator
{
private boolean partialReturn;
+
+ /** The current index. */
private int current;
+ /** Storage for the characters (may contain additional characters). */
public char[] array;
+
+ /** The number of characters in the segment. */
public int count;
+
+ /** The offset of the first character in the segment. */
public int offset;
+ /**
+ * Creates a new <code>Segment</code>.
+ */
public Segment()
{
// Nothing to do here.
}
+ /**
+ * Creates a new <code>Segment</code>.
+ *
+ * @param array the underlying character data.
+ * @param offset the offset of the first character in the segment.
+ * @param count the number of characters in the segment.
+ */
public Segment(char[] array, int offset, int count)
{
this.array = array;
@@ -60,6 +80,12 @@ public class Segment implements Cloneable, CharacterIterator
this.count = count;
}
+ /**
+ * Clones the segment (note that the underlying character array is not cloned,
+ * just the reference to it).
+ *
+ * @return A clone of the segment.
+ */
public Object clone()
{
try
@@ -72,6 +98,13 @@ public class Segment implements Cloneable, CharacterIterator
}
}
+ /**
+ * Returns the character at the current index. If the segment consists of
+ * zero characters, or the current index has passed the end of the
+ * characters in the segment, this method returns {@link #DONE}.
+ *
+ * @return The character at the current index.
+ */
public char current()
{
if (count == 0
@@ -81,6 +114,14 @@ public class Segment implements Cloneable, CharacterIterator
return array[current];
}
+ /**
+ * Sets the current index to the first character in the segment and returns
+ * that character. If the segment contains zero characters, this method
+ * returns {@link #DONE}.
+ *
+ * @return The first character in the segment, or {@link #DONE} if the
+ * segment contains zero characters.
+ */
public char first()
{
if (count == 0)
@@ -90,21 +131,46 @@ public class Segment implements Cloneable, CharacterIterator
return array[current];
}
+ /**
+ * Returns the index of the first character in the segment.
+ *
+ * @return The index of the first character.
+ */
public int getBeginIndex()
{
return offset;
}
+ /**
+ * Returns the end index for the segment (one position beyond the last
+ * character in the segment - note that this can be outside the range of the
+ * underlying character array).
+ *
+ * @return The end index for the segment.
+ */
public int getEndIndex()
{
return offset + count;
}
+ /**
+ * Returns the index of the current character in the segment.
+ *
+ * @return The index of the current character.
+ */
public int getIndex()
{
return current;
}
+ /**
+ * Sets the current index to point to the last character in the segment and
+ * returns that character. If the segment contains zero characters, this
+ * method returns {@link #DONE}.
+ *
+ * @return The last character in the segment, or {@link #DONE} if the
+ * segment contains zero characters.
+ */
public char last()
{
if (count == 0)
@@ -114,6 +180,17 @@ public class Segment implements Cloneable, CharacterIterator
return array[current];
}
+ /**
+ * Sets the current index to point to the next character in the segment and
+ * returns that character. If the next character position is past the end of
+ * the segment, the index is set to {@link #getEndIndex()} and the method
+ * returns {@link #DONE}. If the segment contains zero characters, this
+ * method returns {@link #DONE}.
+ *
+ * @return The next character in the segment or {@link #DONE} (if the next
+ * character position is past the end of the segment or if the
+ * segment contains zero characters).
+ */
public char next()
{
if (count == 0)
@@ -129,6 +206,16 @@ public class Segment implements Cloneable, CharacterIterator
return array[current];
}
+ /**
+ * Sets the current index to point to the previous character in the segment
+ * and returns that character. If the current index is equal to
+ * {@link #getBeginIndex()}, or if the segment contains zero characters, this
+ * method returns {@link #DONE}.
+ *
+ * @return The previous character in the segment or {@link #DONE} (if the
+ * current character position is at the beginning of the segment or
+ * if the segment contains zero characters).
+ */
public char previous()
{
if (count == 0
@@ -139,11 +226,26 @@ public class Segment implements Cloneable, CharacterIterator
return array[current];
}
+ /**
+ * Sets the current index and returns the character at that position (or
+ * {@link #DONE} if the index is equal to {@link #getEndIndex()}.
+ *
+ * @param position the current position.
+ *
+ * @return The character at the specified <code>position</code>, or
+ * {@link #DONE} if <code>position</code> is equal to
+ * {@link #getEndIndex()}.
+ *
+ * @throws IllegalArgumentException if <code>position</code> is not in the
+ * range {@link #getBeginIndex()} to {@link #getEndIndex()}.
+ */
public char setIndex(int position)
{
if (position < getBeginIndex()
|| position > getEndIndex())
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("position: " + position
+ + ", beginIndex: " + getBeginIndex()
+ + ", endIndex: " + getEndIndex());
current = position;
@@ -153,12 +255,23 @@ public class Segment implements Cloneable, CharacterIterator
return array[current];
}
+ /**
+ * Returns a <code>String</code> containing the same characters as this
+ * <code>Segment</code>.
+ *
+ * @return A <code>String</code> containing the same characters as this
+ * <code>Segment</code>.
+ */
public String toString()
{
return new String(array, offset, count);
}
/**
+ * Sets the partial return flag.
+ *
+ * @param p the new value of the flag.
+ *
* @since 1.4
*/
public void setPartialReturn(boolean p)
@@ -167,6 +280,9 @@ public class Segment implements Cloneable, CharacterIterator
}
/**
+ * Returns the partial return flag.
+ *
+ * @return The partial return flag.
* @since 1.4
*/
public boolean isPartialReturn()
diff --git a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
index 0c9f607b196..8dbcb0c6a14 100644
--- a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
+++ b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
@@ -1,5 +1,5 @@
/* SimpleAttributeSet.java --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,33 +42,67 @@ import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;
+/**
+ * A set of attributes.
+ */
public class SimpleAttributeSet
implements MutableAttributeSet, Serializable, Cloneable
{
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 8267656273837665219L;
+ /** An empty attribute set. */
public static final AttributeSet EMPTY = new SimpleAttributeSet();
+ /** Storage for the attributes. */
Hashtable tab;
+ /**
+ * Creates a new attribute set that is initially empty.
+ */
public SimpleAttributeSet()
{
- this(null);
+ tab = new Hashtable();
}
+ /**
+ * Creates a new <code>SimpleAttributeSet</code> with the same attributes
+ * and resolve parent as the specified set.
+ *
+ * @param a the attributes (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ */
public SimpleAttributeSet(AttributeSet a)
{
tab = new Hashtable();
- if (a != null)
- addAttributes(a);
+ addAttributes(a);
}
+ /**
+ * Adds an attribute with the given <code>name</code> and <code>value</code>
+ * to the set. If the set already contains an attribute with the given
+ * <code>name</code>, the attribute value is updated.
+ *
+ * @param name the attribute name (<code>null</code> not permitted).
+ * @param value the value (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
+ */
public void addAttribute(Object name, Object value)
{
tab.put(name, value);
}
+ /**
+ * Adds all the attributes from <code>attributes</code> to this set.
+ *
+ * @param attributes the set of attributes to add (<code>null</code> not
+ * permitted).
+ *
+ * @throws NullPointerException if <code>attributes</code> is
+ * <code>null</code>.
+ */
public void addAttributes(AttributeSet attributes)
{
Enumeration e = attributes.getAttributeNames();
@@ -80,6 +114,11 @@ public class SimpleAttributeSet
}
}
+ /**
+ * Returns a clone of the attribute set.
+ *
+ * @return A clone of the attribute set.
+ */
public Object clone()
{
SimpleAttributeSet s = new SimpleAttributeSet();
@@ -97,9 +136,18 @@ public class SimpleAttributeSet
*/
public boolean containsAttribute(Object name, Object value)
{
- return (tab.containsKey(name) && tab.get(name).equals(value)) ||
- (getResolveParent() != null && getResolveParent().
- containsAttribute(name, value));
+ if (value == null)
+ throw new NullPointerException("Null 'value' argument.");
+ if (tab.containsKey(name))
+ return tab.get(name).equals(value);
+ else
+ {
+ AttributeSet p = getResolveParent();
+ if (p != null)
+ return p.containsAttribute(name, value);
+ else
+ return false;
+ }
}
/**
@@ -115,6 +163,15 @@ public class SimpleAttributeSet
&& tab.get(name).equals(value);
}
+ /**
+ * Returns <code>true</code> of this <code>AttributeSet</code> contains all
+ * of the specified <code>attributes</code>.
+ *
+ * @param attributes the requested attributes
+ *
+ * @return <code>true</code> of this <code>AttributeSet</code> contains all
+ * of the specified <code>attributes</code>
+ */
public boolean containsAttributes(AttributeSet attributes)
{
Enumeration e = attributes.getAttributeNames();
@@ -128,11 +185,24 @@ public class SimpleAttributeSet
return true;
}
+ /**
+ * Creates and returns a copy of this <code>AttributeSet</code>.
+ *
+ * @return a copy of this <code>AttributeSet</code>
+ */
public AttributeSet copyAttributes()
{
return (AttributeSet) clone();
}
+ /**
+ * Checks this set for equality with an arbitrary object.
+ *
+ * @param obj the object (<code>null</code> permitted).
+ *
+ * @return <code>true</code> if this set is equal to <code>obj</code>, and
+ * <code>false</code> otherwise.
+ */
public boolean equals(Object obj)
{
return
@@ -140,44 +210,95 @@ public class SimpleAttributeSet
&& this.isEqual((AttributeSet) obj);
}
+ /**
+ * Returns the value of the specified attribute, or <code>null</code> if
+ * there is no attribute with that name. If the attribute is not defined
+ * directly in this set, the parent hierarchy (if there is one) will be
+ * used.
+ *
+ * @param name the attribute (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>name</code> is <code>null</code>.
+ */
public Object getAttribute(Object name)
{
Object val = tab.get(name);
if (val != null)
return val;
- Object p = getResolveParent();
- if (p != null && p instanceof AttributeSet)
- return (((AttributeSet)p).getAttribute(name));
+ AttributeSet p = getResolveParent();
+ if (p != null)
+ return p.getAttribute(name);
return null;
}
+ /**
+ * Returns the number of attributes stored in this set, plus 1 if a parent
+ * has been specified (the reference to the parent is stored as a special
+ * attribute). The attributes stored in the parent do NOT contribute
+ * to the count.
+ *
+ * @return The attribute count.
+ */
public int getAttributeCount()
{
return tab.size();
}
+ /**
+ * Returns an enumeration of the attribute names.
+ *
+ * @return An enumeration of the attribute names.
+ */
public Enumeration getAttributeNames()
{
return tab.keys();
}
+ /**
+ * Returns the resolving parent.
+ *
+ * @return The resolving parent (possibly <code>null</code>).
+ *
+ * @see #setResolveParent(AttributeSet)
+ */
public AttributeSet getResolveParent()
{
return (AttributeSet) tab.get(ResolveAttribute);
}
+ /**
+ * Returns a hash code for this instance.
+ *
+ * @return A hash code.
+ */
public int hashCode()
{
return tab.hashCode();
}
+ /**
+ * Returns <code>true</code> if the given attribute is defined in this set,
+ * and <code>false</code> otherwise. The parent attribute set is not
+ * checked.
+ *
+ * @param attrName the attribute name (<code>null</code> not permitted).
+ */
public boolean isDefined(Object attrName)
{
return tab.containsKey(attrName);
}
+ /**
+ * Returns <code>true</code> if the set contains no attributes, and
+ * <code>false</code> otherwise. Note that the resolving parent is
+ * stored as an attribute, so this method will return <code>false</code> if
+ * a resolving parent is set.
+ *
+ * @return <code>true</code> if the set contains no attributes, and
+ * <code>false</code> otherwise.
+ */
public boolean isEmpty()
{
return tab.isEmpty();
@@ -186,7 +307,13 @@ public class SimpleAttributeSet
/**
* Returns true if the given set has the same number of attributes
* as this set and <code>containsAttributes(attr)</code> returns
- * true.
+ * <code>true</code>.
+ *
+ * @param attr the attribute set (<code>null</code> not permitted).
+ *
+ * @return A boolean.
+ *
+ * @throws NullPointerException if <code>attr</code> is <code>null</code>.
*/
public boolean isEqual(AttributeSet attr)
{
@@ -194,6 +321,15 @@ public class SimpleAttributeSet
&& this.containsAttributes(attr);
}
+ /**
+ * Removes the attribute with the specified <code>name</code>, if this
+ * attribute is defined. This method will only remove an attribute from
+ * this set, not from the resolving parent.
+ *
+ * @param name the attribute name (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>name</code> is <code>null</code>.
+ */
public void removeAttribute(Object name)
{
tab.remove(name);
@@ -202,7 +338,12 @@ public class SimpleAttributeSet
/**
* Removes attributes from this set if they are found in the
* given set. Only attributes whose key AND value are removed.
- * Removes attributes only from this set, not from the resolving parent.
+ * Removes attributes only from this set, not from the resolving parent.
+ * Since the resolving parent is stored as an attribute, if
+ * <code>attributes</code> has the same resolving parent as this set, the
+ * parent will be removed from this set.
+ *
+ * @param attributes the attributes (<code>null</code> not permitted).
*/
public void removeAttributes(AttributeSet attributes)
{
@@ -216,6 +357,14 @@ public class SimpleAttributeSet
}
}
+ /**
+ * Removes the attributes listed in <code>names</code>.
+ *
+ * @param names the attribute names (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>names</code> is <code>null</code>
+ * or contains any <code>null</code> values.
+ */
public void removeAttributes(Enumeration names)
{
while (names.hasMoreElements())
@@ -224,11 +373,31 @@ public class SimpleAttributeSet
}
}
+ /**
+ * Sets the reolving parent for this set. When looking up an attribute, if
+ * it is not found in this set, then the resolving parent is also used for
+ * the lookup.
+ * <p>
+ * Note that the parent is stored as an attribute, and will contribute 1 to
+ * the count returned by {@link #getAttributeCount()}.
+ *
+ * @param parent the parent attribute set (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>parent</code> is <code>null</code>.
+ *
+ * @see #setResolveParent(AttributeSet)
+ */
public void setResolveParent(AttributeSet parent)
{
addAttribute(ResolveAttribute, parent);
}
-
+
+ /**
+ * Returns a string representation of this instance, typically used for
+ * debugging purposes.
+ *
+ * @return A string representation of this instance.
+ */
public String toString()
{
return tab.toString();
diff --git a/libjava/classpath/javax/swing/text/StringContent.java b/libjava/classpath/javax/swing/text/StringContent.java
index 7db377a1c9b..0a31505f3a6 100644
--- a/libjava/classpath/javax/swing/text/StringContent.java
+++ b/libjava/classpath/javax/swing/text/StringContent.java
@@ -1,5 +1,5 @@
/* StringContent.java --
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -54,7 +54,8 @@ import javax.swing.undo.UndoableEdit;
*
* <p>Do not use this class for large size.</p>
*/
-public final class StringContent implements AbstractDocument.Content, Serializable
+public final class StringContent
+ implements AbstractDocument.Content, Serializable
{
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 4755994433709540381L;
@@ -87,7 +88,8 @@ public final class StringContent implements AbstractDocument.Content, Serializab
try
{
StringContent.this.checkLocation(this.start, this.length);
- this.redoContent = new String(StringContent.this.content, this.start, this.length);
+ this.redoContent = new String(StringContent.this.content, this.start,
+ this.length);
StringContent.this.remove(this.start, this.length);
}
catch (BadLocationException b)
@@ -175,11 +177,20 @@ public final class StringContent implements AbstractDocument.Content, Serializab
}
}
+ /**
+ * Creates a new instance containing the string "\n".
+ */
public StringContent()
{
this(1);
}
+ /**
+ * Creates a new instance containing the string "\n".
+ *
+ * @param initialLength the initial length of the underlying character
+ * array used to store the content.
+ */
public StringContent(int initialLength)
{
super();
@@ -198,7 +209,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab
Iterator iter = this.positions.iterator();
while(iter.hasNext())
{
- Position p = (Position)iter.next();
+ Position p = (Position) iter.next();
if ((offset <= p.getOffset())
&& (p.getOffset() <= (offset + length)))
refPos.add(p);
@@ -206,6 +217,16 @@ public final class StringContent implements AbstractDocument.Content, Serializab
return refPos;
}
+ /**
+ * Creates a position reference for the character at the given offset. The
+ * position offset will be automatically updated when new characters are
+ * inserted into or removed from the content.
+ *
+ * @param offset the character offset.
+ *
+ * @throws BadLocationException if offset is outside the bounds of the
+ * content.
+ */
public Position createPosition(int offset) throws BadLocationException
{
if (offset < this.count || offset > this.count)
@@ -215,11 +236,27 @@ public final class StringContent implements AbstractDocument.Content, Serializab
return sp;
}
+ /**
+ * Returns the length of the string content, including the '\n' character at
+ * the end.
+ *
+ * @return The length of the string content.
+ */
public int length()
{
return this.count;
}
+ /**
+ * Inserts <code>str</code> at the given position and returns an
+ * {@link UndoableEdit} that enables undo/redo support.
+ *
+ * @param where the insertion point (must be less than
+ * <code>length()</code>).
+ * @param str the string to insert (<code>null</code> not permitted).
+ *
+ * @return An object that can undo the insertion.
+ */
public UndoableEdit insertString(int where, String str)
throws BadLocationException
{
@@ -235,13 +272,15 @@ public final class StringContent implements AbstractDocument.Content, Serializab
if (where > 0)
System.arraycopy(this.content, 0, temp, 0, where);
System.arraycopy(insert, 0, temp, where, insert.length);
- System.arraycopy(this.content, where, temp, (where + insert.length), (temp.length - where - insert.length));
+ System.arraycopy(this.content, where, temp, (where + insert.length),
+ (temp.length - where - insert.length));
if (this.content.length < temp.length)
this.content = new char[temp.length];
// Copy the result in the original char array.
System.arraycopy(temp, 0, this.content, 0, temp.length);
// Move all the positions.
- Vector refPos = getPositionsInRange(this.positions, where, temp.length - where);
+ Vector refPos = getPositionsInRange(this.positions, where,
+ temp.length - where);
Iterator iter = refPos.iterator();
while (iter.hasNext())
{
@@ -252,20 +291,35 @@ public final class StringContent implements AbstractDocument.Content, Serializab
return iundo;
}
+ /**
+ * Removes the specified range of characters and returns an
+ * {@link UndoableEdit} that enables undo/redo support.
+ *
+ * @param where the starting index.
+ * @param nitems the number of characters.
+ *
+ * @return An object that can undo the removal.
+ *
+ * @throws BadLocationException if the character range extends outside the
+ * bounds of the content OR includes the last character.
+ */
public UndoableEdit remove(int where, int nitems) throws BadLocationException
{
- checkLocation(where, nitems);
+ checkLocation(where, nitems + 1);
char[] temp = new char[(this.content.length - nitems)];
this.count = this.count - nitems;
- RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, nitems));
+ RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where,
+ nitems));
// Copy array.
System.arraycopy(this.content, 0, temp, 0, where);
- System.arraycopy(this.content, where + nitems, temp, where, this.content.length - where - nitems);
+ System.arraycopy(this.content, where + nitems, temp, where,
+ this.content.length - where - nitems);
this.content = new char[temp.length];
// Then copy the result in the original char array.
System.arraycopy(temp, 0, this.content, 0, this.content.length);
// Move all the positions.
- Vector refPos = getPositionsInRange(this.positions, where, this.content.length + nitems - where);
+ Vector refPos = getPositionsInRange(this.positions, where,
+ this.content.length + nitems - where);
Iterator iter = refPos.iterator();
while (iter.hasNext())
{
@@ -278,31 +332,75 @@ public final class StringContent implements AbstractDocument.Content, Serializab
return rundo;
}
+ /**
+ * Returns a new <code>String</code> containing the characters in the
+ * specified range.
+ *
+ * @param where the start index.
+ * @param len the number of characters.
+ *
+ * @return A string.
+ *
+ * @throws BadLocationException if the requested range of characters extends
+ * outside the bounds of the content.
+ */
public String getString(int where, int len) throws BadLocationException
{
checkLocation(where, len);
- return new String (this.content, where, len);
+ return new String(this.content, where, len);
}
- public void getChars(int where, int len, Segment txt) throws BadLocationException
+ /**
+ * Updates <code>txt</code> to contain a direct reference to the underlying
+ * character array.
+ *
+ * @param where the index of the first character.
+ * @param len the number of characters.
+ * @param txt a carrier for the return result (<code>null</code> not
+ * permitted).
+ *
+ * @throws BadLocationException if the requested character range is not
+ * within the bounds of the content.
+ * @throws NullPointerException if <code>txt</code> is <code>null</code>.
+ */
+ public void getChars(int where, int len, Segment txt)
+ throws BadLocationException
{
checkLocation(where, len);
- if (txt != null)
- {
- txt.array = this.content;
- txt.offset = where;
- txt.count = len;
- }
+ txt.array = this.content;
+ txt.offset = where;
+ txt.count = len;
}
- // This is package-private to avoid an accessor method.
+
+ /**
+ * @specnote This method is not very well specified and the positions vector
+ * is implementation specific. The undo positions are managed
+ * differently in this implementation, this method is only here
+ * for binary compatibility.
+ */
+ protected void updateUndoPositions(Vector positions)
+ {
+ // We do nothing here.
+ }
+
+ /**
+ * A utility method that checks the validity of the specified character
+ * range.
+ *
+ * @param where the first character in the range.
+ * @param len the number of characters in the range.
+ *
+ * @throws BadLocationException if the specified range is not within the
+ * bounds of the content.
+ */
void checkLocation(int where, int len) throws BadLocationException
{
if (where < 0)
throw new BadLocationException("Invalid location", 1);
else if (where > this.count)
throw new BadLocationException("Invalid location", this.count);
- else if ((where + len)>this.count)
+ else if ((where + len) > this.count)
throw new BadLocationException("Invalid range", this.count);
}
diff --git a/libjava/classpath/javax/swing/text/StyleConstants.java b/libjava/classpath/javax/swing/text/StyleConstants.java
index 598eaf621bc..c7906b8ad32 100644
--- a/libjava/classpath/javax/swing/text/StyleConstants.java
+++ b/libjava/classpath/javax/swing/text/StyleConstants.java
@@ -1,5 +1,5 @@
/* StyleConstants.java --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -43,45 +43,124 @@ import java.awt.Component;
import javax.swing.Icon;
+/**
+ * Represents standard attribute keys. This class also contains a set of
+ * useful static utility methods for querying and populating an
+ * {@link AttributeSet}.
+ *
+ * @since 1.2
+ */
public class StyleConstants
{
+ /**
+ * A value representing left alignment for the
+ * {@link ParagraphConstants#Alignment} attribute.
+ */
public static final int ALIGN_LEFT = 0;
+
+ /**
+ * A value representing center alignment for the
+ * {@link ParagraphConstants#Alignment} attribute.
+ */
public static final int ALIGN_CENTER = 1;
+
+ /**
+ * A value representing right alignment for the
+ * {@link ParagraphConstants#Alignment} attribute.
+ */
public static final int ALIGN_RIGHT = 2;
+
+ /**
+ * A value representing ful justification for the
+ * {@link ParagraphConstants#Alignment} attribute.
+ */
public static final int ALIGN_JUSTIFIED = 3;
+ /** An alias for {@link CharacterConstants#Background}. */
public static final Object Background = CharacterConstants.Background;
+
+ /** An alias for {@link CharacterConstants#BidiLevel}. */
public static final Object BidiLevel = CharacterConstants.BidiLevel;
+
+ /** An alias for {@link CharacterConstants#Bold}. */
public static final Object Bold = CharacterConstants.Bold;
- public static final Object ComponentAttribute = CharacterConstants.ComponentAttribute;
+
+ /** An alias for {@link CharacterConstants#ComponentAttribute}. */
+ public static final Object ComponentAttribute
+ = CharacterConstants.ComponentAttribute;
+
+ /** An alias for {@link CharacterConstants#Family}. */
public static final Object Family = CharacterConstants.Family;
+
+ /** An alias for {@link CharacterConstants#Family}. */
public static final Object FontFamily = CharacterConstants.Family;
+
+ /** An alias for {@link CharacterConstants#Size}. */
public static final Object FontSize = CharacterConstants.Size;
+
+ /** An alias for {@link CharacterConstants#Foreground}. */
public static final Object Foreground = CharacterConstants.Foreground;
+
+ /** An alias for {@link CharacterConstants#IconAttribute}. */
public static final Object IconAttribute = CharacterConstants.IconAttribute;
+
+ /** An alias for {@link CharacterConstants#Italic}. */
public static final Object Italic = CharacterConstants.Italic;
+
+ /** An alias for {@link CharacterConstants#Size}. */
public static final Object Size = CharacterConstants.Size;
+
+ /** An alias for {@link CharacterConstants#StrikeThrough}. */
public static final Object StrikeThrough = CharacterConstants.StrikeThrough;
+
+ /** An alias for {@link CharacterConstants#Subscript}. */
public static final Object Subscript = CharacterConstants.Subscript;
+
+ /** An alias for {@link CharacterConstants#Superscript}. */
public static final Object Superscript = CharacterConstants.Superscript;
+
+ /** An alias for {@link CharacterConstants#Underline}. */
public static final Object Underline = CharacterConstants.Underline;
+ /** An alias for {@link ParagraphConstants#Alignment}. */
public static final Object Alignment = ParagraphConstants.Alignment;
- public static final Object FirstLineIndent = ParagraphConstants.FirstLineIndent;
+
+ /** An alias for {@link ParagraphConstants#FirstLineIndent}. */
+ public static final Object FirstLineIndent
+ = ParagraphConstants.FirstLineIndent;
+
+ /** An alias for {@link ParagraphConstants#LeftIndent}. */
public static final Object LeftIndent = ParagraphConstants.LeftIndent;
+
+ /** An alias for {@link ParagraphConstants#LineSpacing}. */
public static final Object LineSpacing = ParagraphConstants.LineSpacing;
+
+ /** An alias for {@link ParagraphConstants#Orientation}. */
public static final Object Orientation = ParagraphConstants.Orientation;
+
+ /** An alias for {@link ParagraphConstants#RightIndent}. */
public static final Object RightIndent = ParagraphConstants.RightIndent;
+
+ /** An alias for {@link ParagraphConstants#SpaceAbove}. */
public static final Object SpaceAbove = ParagraphConstants.SpaceAbove;
+
+ /** An alias for {@link ParagraphConstants#SpaceBelow}. */
public static final Object SpaceBelow = ParagraphConstants.SpaceBelow;
+
+ /** An alias for {@link ParagraphConstants#TabSet}. */
public static final Object TabSet = ParagraphConstants.TabSet;
public static final String ComponentElementName = "component";
+
public static final String IconElementName = "icon";
- public static final Object ComposedTextAttribute = new StyleConstants("composed text");
+ public static final Object ComposedTextAttribute
+ = new StyleConstants("composed text");
+
public static final Object ModelAttribute = new StyleConstants("model");
+
public static final Object NameAttribute = new StyleConstants("name");
+
public static final Object ResolveAttribute = new StyleConstants("resolver");
String keyname;
@@ -93,279 +172,727 @@ public class StyleConstants
keyname = k;
}
+ /**
+ * Returns a string representation of the attribute key.
+ *
+ * @return A string representation of the attribute key.
+ */
public String toString()
{
return keyname;
}
+ /**
+ * Returns the alignment specified in the given attributes, or
+ * {@link #ALIGN_LEFT} if no alignment is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The alignment (typically one of {@link #ALIGN_LEFT},
+ * {@link #ALIGN_RIGHT}, {@link #ALIGN_CENTER} or
+ * {@link #ALIGN_JUSTIFIED}).
+ *
+ * @see #setAlignment(MutableAttributeSet, int)
+ */
public static int getAlignment(AttributeSet a)
{
- if (a.isDefined(Alignment))
- return ((Integer)a.getAttribute(Alignment)).intValue();
+ Integer i = (Integer) a.getAttribute(Alignment);
+ if (i != null)
+ return i.intValue();
else
return ALIGN_LEFT;
}
+ /**
+ * Returns the background color specified in the given attributes, or
+ * {@link Color#BLACK} if no background color is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The background color.
+ *
+ * @see #setBackground(MutableAttributeSet, Color)
+ */
public static Color getBackground(AttributeSet a)
{
- if (a.isDefined(Background))
- return (Color) a.getAttribute(Background);
+ Color c = (Color) a.getAttribute(Background);
+ if (c != null)
+ return c;
else
- return Color.WHITE;
+ return Color.BLACK;
}
-
+
+ /**
+ * Returns the bidi level specified in the given attributes, or
+ * <code>0</code> if no bidi level is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The bidi level.
+ *
+ * @see #setBidiLevel(MutableAttributeSet, int)
+ */
public static int getBidiLevel(AttributeSet a)
{
- if (a.isDefined(BidiLevel))
- return ((Integer)a.getAttribute(BidiLevel)).intValue();
+ Integer i = (Integer) a.getAttribute(BidiLevel);
+ if (i != null)
+ return i.intValue();
else
return 0;
}
+ /**
+ * Returns the component specified in the given attributes, or
+ * <code>null</code> if no component is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The component (possibly <code>null</code>).
+ *
+ * @see #setComponent(MutableAttributeSet, Component)
+ */
public static Component getComponent(AttributeSet a)
{
- if (a.isDefined(ComponentAttribute))
- return (Component) a.getAttribute(ComponentAttribute);
+ Component c = (Component) a.getAttribute(ComponentAttribute);
+ if (c != null)
+ return c;
else
- return (Component) null;
+ return null;
}
+ /**
+ * Returns the indentation specified in the given attributes, or
+ * <code>0.0f</code> if no indentation is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The indentation.
+ *
+ * @see #setFirstLineIndent(MutableAttributeSet, float)
+ */
public static float getFirstLineIndent(AttributeSet a)
{
- if (a.isDefined(FirstLineIndent))
- return ((Float)a.getAttribute(FirstLineIndent)).floatValue();
+ Float f = (Float) a.getAttribute(FirstLineIndent);
+ if (f != null)
+ return f.floatValue();
else
- return 0.f;
+ return 0.0f;
}
+ /**
+ * Returns the font family specified in the given attributes, or
+ * <code>Monospaced</code> if no font family is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The font family.
+ *
+ * @see #setFontFamily(MutableAttributeSet, String)
+ */
public static String getFontFamily(AttributeSet a)
{
- if (a.isDefined(FontFamily))
- return (String) a.getAttribute(FontFamily);
+ String ff = (String) a.getAttribute(FontFamily);
+ if (ff != null)
+ return ff;
else
return "Monospaced";
}
+ /**
+ * Returns the font size specified in the given attributes, or
+ * <code>12</code> if no font size is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The font size.
+ *
+ * @see #setFontSize(MutableAttributeSet, int)
+ */
public static int getFontSize(AttributeSet a)
{
- if (a.isDefined(FontSize))
- return ((Integer)a.getAttribute(FontSize)).intValue();
+ Integer i = (Integer) a.getAttribute(FontSize);
+ if (i != null)
+ return i.intValue();
else
return 12;
}
+ /**
+ * Returns the foreground color specified in the given attributes, or
+ * {@link Color#BLACK} if no foreground color is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The foreground color.
+ *
+ * @see #setForeground(MutableAttributeSet, Color)
+ */
public static Color getForeground(AttributeSet a)
{
- if (a.isDefined(Foreground))
- return (Color) a.getAttribute(Foreground);
+ Color c = (Color) a.getAttribute(Foreground);
+ if (c != null)
+ return c;
else
return Color.BLACK;
}
+ /**
+ * Returns the icon specified in the given attributes, or
+ * <code>null</code> if no icon is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The icon (possibly <code>null</code>).
+ *
+ * @see #setIcon(MutableAttributeSet, Icon)
+ */
public static Icon getIcon(AttributeSet a)
{
- if (a.isDefined(IconAttribute))
- return (Icon) a.getAttribute(IconAttribute);
- else
- return (Icon) null;
+ return (Icon) a.getAttribute(IconAttribute);
}
+ /**
+ * Returns the left indentation specified in the given attributes, or
+ * <code>0.0f</code> if no left indentation is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The left indentation.
+ *
+ * @see #setLeftIndent(MutableAttributeSet, float)
+ */
public static float getLeftIndent(AttributeSet a)
{
- if (a.isDefined(LeftIndent))
- return ((Float)a.getAttribute(LeftIndent)).floatValue();
+ Float f = (Float) a.getAttribute(LeftIndent);
+ if (f != null)
+ return f.floatValue();
else
- return 0.f;
+ return 0.0f;
}
+ /**
+ * Returns the line spacing specified in the given attributes, or
+ * <code>0.0f</code> if no line spacing is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The line spacing.
+ *
+ * @see #setLineSpacing(MutableAttributeSet, float)
+ */
public static float getLineSpacing(AttributeSet a)
{
- if (a.isDefined(LineSpacing))
- return ((Float)a.getAttribute(LineSpacing)).floatValue();
+ Float f = (Float) a.getAttribute(LineSpacing);
+ if (f != null)
+ return f.floatValue();
else
- return 0.f;
+ return 0.0f;
}
+ /**
+ * Returns the right indentation specified in the given attributes, or
+ * <code>0.0f</code> if no right indentation is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The right indentation.
+ *
+ * @see #setRightIndent(MutableAttributeSet, float)
+ */
public static float getRightIndent(AttributeSet a)
{
- if (a.isDefined(RightIndent))
- return ((Float)a.getAttribute(RightIndent)).floatValue();
+ Float f = (Float) a.getAttribute(RightIndent);
+ if (f != null)
+ return f.floatValue();
else
- return 0.f;
+ return 0.0f;
}
+ /**
+ * Returns the 'space above' specified in the given attributes, or
+ * <code>0.0f</code> if no 'space above' is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The 'space above'.
+ *
+ * @see #setSpaceAbove(MutableAttributeSet, float)
+ */
public static float getSpaceAbove(AttributeSet a)
{
- if (a.isDefined(SpaceAbove))
- return ((Float)a.getAttribute(SpaceAbove)).floatValue();
- else
- return 0.f;
+ Float f = (Float) a.getAttribute(SpaceAbove);
+ if (f != null)
+ return f.floatValue();
+ else
+ return 0.0f;
}
+ /**
+ * Returns the 'space below' specified in the given attributes, or
+ * <code>0.0f</code> if no 'space below' is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The 'space below'.
+ *
+ * @see #setSpaceBelow(MutableAttributeSet, float)
+ */
public static float getSpaceBelow(AttributeSet a)
{
- if (a.isDefined(SpaceBelow))
- return ((Float)a.getAttribute(SpaceBelow)).floatValue();
+ Float f = (Float) a.getAttribute(SpaceBelow);
+ if (f != null)
+ return f.floatValue();
else
- return 0.f;
+ return 0.0f;
}
+ /**
+ * Returns the tab set specified in the given attributes, or
+ * <code>null</code> if no tab set is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The tab set.
+ *
+ * @see #setTabSet(MutableAttributeSet, javax.swing.text.TabSet)
+ */
public static javax.swing.text.TabSet getTabSet(AttributeSet a)
{
- if (a.isDefined(StyleConstants.TabSet))
- return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet);
- else
- return (javax.swing.text.TabSet) null;
+ // I'm guessing that the fully qualified class name is to differentiate
+ // between the TabSet class and the TabSet (attribute) instance on some
+ // compiler...
+ return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet);
}
+ /**
+ * Returns the value of the bold flag in the given attributes, or
+ * <code>false</code> if no bold flag is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The bold flag.
+ *
+ * @see #setBold(MutableAttributeSet, boolean)
+ */
public static boolean isBold(AttributeSet a)
{
- if (a.isDefined(Bold))
- return ((Boolean) a.getAttribute(Bold)).booleanValue();
+ Boolean b = (Boolean) a.getAttribute(Bold);
+ if (b != null)
+ return b.booleanValue();
else
- return false;
+ return false;
}
+ /**
+ * Returns the value of the italic flag in the given attributes, or
+ * <code>false</code> if no italic flag is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The italic flag.
+ *
+ * @see #setItalic(MutableAttributeSet, boolean)
+ */
public static boolean isItalic(AttributeSet a)
{
- if (a.isDefined(Italic))
- return ((Boolean) a.getAttribute(Italic)).booleanValue();
+ Boolean b = (Boolean) a.getAttribute(Italic);
+ if (b != null)
+ return b.booleanValue();
else
- return false;
+ return false;
}
+ /**
+ * Returns the value of the strike-through flag in the given attributes, or
+ * <code>false</code> if no strike-through flag is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The strike-through flag.
+ *
+ * @see #setStrikeThrough(MutableAttributeSet, boolean)
+ */
public static boolean isStrikeThrough(AttributeSet a)
{
- if (a.isDefined(StrikeThrough))
- return ((Boolean) a.getAttribute(StrikeThrough)).booleanValue();
+ Boolean b = (Boolean) a.getAttribute(StrikeThrough);
+ if (b != null)
+ return b.booleanValue();
else
- return false;
+ return false;
}
+ /**
+ * Returns the value of the subscript flag in the given attributes, or
+ * <code>false</code> if no subscript flag is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The subscript flag.
+ *
+ * @see #setSubscript(MutableAttributeSet, boolean)
+ */
public static boolean isSubscript(AttributeSet a)
{
- if (a.isDefined(Subscript))
- return ((Boolean) a.getAttribute(Subscript)).booleanValue();
+ Boolean b = (Boolean) a.getAttribute(Subscript);
+ if (b != null)
+ return b.booleanValue();
else
- return false;
+ return false;
}
+ /**
+ * Returns the value of the superscript flag in the given attributes, or
+ * <code>false</code> if no superscript flag is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The superscript flag.
+ *
+ * @see #setSuperscript(MutableAttributeSet, boolean)
+ */
public static boolean isSuperscript(AttributeSet a)
{
- if (a.isDefined(Superscript))
- return ((Boolean) a.getAttribute(Superscript)).booleanValue();
- else
- return false;
+ Boolean b = (Boolean) a.getAttribute(Superscript);
+ if (b != null)
+ return b.booleanValue();
+ else
+ return false;
}
+ /**
+ * Returns the value of the underline flag in the given attributes, or
+ * <code>false</code> if no underline flag is specified.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ *
+ * @return The underline flag.
+ *
+ * @see #setUnderline(MutableAttributeSet, boolean)
+ */
public static boolean isUnderline(AttributeSet a)
{
- if (a.isDefined(Underline))
- return ((Boolean) a.getAttribute(Underline)).booleanValue();
+ Boolean b = (Boolean) a.getAttribute(Underline);
+ if (b != null)
+ return b.booleanValue();
else
- return false;
+ return false;
}
+ /**
+ * Adds an alignment attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param align the alignment (typically one of
+ * {@link StyleConstants#ALIGN_LEFT},
+ * {@link StyleConstants#ALIGN_RIGHT},
+ * {@link StyleConstants#ALIGN_CENTER} or
+ * {@link StyleConstants#ALIGN_JUSTIFIED}).
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getAlignment(AttributeSet)
+ */
public static void setAlignment(MutableAttributeSet a, int align)
{
a.addAttribute(Alignment, new Integer(align));
}
- public static void setBackground(MutableAttributeSet a, Color fg)
+ /**
+ * Adds a background attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param bg the background (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
+ *
+ * @see #getBackground(AttributeSet)
+ */
+ public static void setBackground(MutableAttributeSet a, Color bg)
{
- a.addAttribute(Background, fg);
+ a.addAttribute(Background, bg);
}
+ /**
+ * Adds a bidi-level attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param lev the level.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getBidiLevel(AttributeSet)
+ */
public static void setBidiLevel(MutableAttributeSet a, int lev)
{
a.addAttribute(BidiLevel, new Integer(lev));
}
+ /**
+ * Adds a bold attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param b the new value of the bold attribute.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #isBold(AttributeSet)
+ */
public static void setBold(MutableAttributeSet a, boolean b)
{
a.addAttribute(Bold, Boolean.valueOf(b));
}
+ /**
+ * Adds a component attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param c the component (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
+ *
+ * @see #getComponent(AttributeSet)
+ */
public static void setComponent(MutableAttributeSet a, Component c)
{
a.addAttribute(ComponentAttribute, c);
}
+ /**
+ * Adds a first line indentation attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param i the indentation.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getFirstLineIndent(AttributeSet)
+ */
public static void setFirstLineIndent(MutableAttributeSet a, float i)
{
a.addAttribute(FirstLineIndent, new Float(i));
}
+ /**
+ * Adds a font family attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param fam the font family name (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
+ *
+ * @see #getFontFamily(AttributeSet)
+ */
public static void setFontFamily(MutableAttributeSet a, String fam)
{
a.addAttribute(FontFamily, fam);
}
+ /**
+ * Adds a font size attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param s the font size (in points).
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getFontSize(AttributeSet)
+ */
public static void setFontSize(MutableAttributeSet a, int s)
{
a.addAttribute(FontSize, new Integer(s));
}
+ /**
+ * Adds a foreground color attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param fg the foreground color (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
+ *
+ * @see #getForeground(AttributeSet)
+ */
public static void setForeground(MutableAttributeSet a, Color fg)
{
a.addAttribute(Foreground, fg);
}
+ /**
+ * Adds an icon attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param c the icon (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
+ *
+ * @see #getIcon(AttributeSet)
+ */
public static void setIcon(MutableAttributeSet a, Icon c)
{
a.addAttribute(IconAttribute, c);
}
+ /**
+ * Adds an italic attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param b the new value of the italic attribute.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #isItalic(AttributeSet)
+ */
public static void setItalic(MutableAttributeSet a, boolean b)
{
a.addAttribute(Italic, Boolean.valueOf(b));
}
+ /**
+ * Adds a left indentation attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param i the indentation.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getLeftIndent(AttributeSet)
+ */
public static void setLeftIndent(MutableAttributeSet a, float i)
{
a.addAttribute(LeftIndent, new Float(i));
}
+ /**
+ * Adds a line spacing attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param i the line spacing.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getLineSpacing(AttributeSet)
+ */
public static void setLineSpacing(MutableAttributeSet a, float i)
{
a.addAttribute(LineSpacing, new Float(i));
}
+ /**
+ * Adds a right indentation attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param i the right indentation.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getRightIndent(AttributeSet)
+ */
public static void setRightIndent(MutableAttributeSet a, float i)
{
a.addAttribute(RightIndent, new Float(i));
}
+ /**
+ * Adds a 'space above' attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param i the space above attribute value.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getSpaceAbove(AttributeSet)
+ */
public static void setSpaceAbove(MutableAttributeSet a, float i)
{
a.addAttribute(SpaceAbove, new Float(i));
}
+ /**
+ * Adds a 'space below' attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param i the space below attribute value.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #getSpaceBelow(AttributeSet)
+ */
public static void setSpaceBelow(MutableAttributeSet a, float i)
{
a.addAttribute(SpaceBelow, new Float(i));
}
+ /**
+ * Adds a strike-through attribue to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param b the strike-through attribute value.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #isStrikeThrough(AttributeSet)
+ */
public static void setStrikeThrough(MutableAttributeSet a, boolean b)
{
a.addAttribute(StrikeThrough, Boolean.valueOf(b));
}
+ /**
+ * Adds a subscript attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param b the subscript attribute value.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #isSubscript(AttributeSet)
+ */
public static void setSubscript(MutableAttributeSet a, boolean b)
{
a.addAttribute(Subscript, Boolean.valueOf(b));
}
+ /**
+ * Adds a superscript attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param b the superscript attribute value.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #isSuperscript(AttributeSet)
+ */
public static void setSuperscript(MutableAttributeSet a, boolean b)
{
a.addAttribute(Superscript, Boolean.valueOf(b));
}
- public static void setTabSet(MutableAttributeSet a, javax.swing.text.TabSet tabs)
+ /**
+ * Adds a {@link TabSet} attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param tabs the tab set (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if either argument is <code>null</code>.
+ *
+ * @see #getTabSet(AttributeSet)
+ */
+ public static void setTabSet(MutableAttributeSet a,
+ javax.swing.text.TabSet tabs)
{
a.addAttribute(StyleConstants.TabSet, tabs);
}
+ /**
+ * Adds an underline attribute to the specified set.
+ *
+ * @param a the attribute set (<code>null</code> not permitted).
+ * @param b the underline attribute value.
+ *
+ * @throws NullPointerException if <code>a</code> is <code>null</code>.
+ *
+ * @see #isUnderline(AttributeSet)
+ */
public static void setUnderline(MutableAttributeSet a, boolean b)
{
a.addAttribute(Underline, Boolean.valueOf(b));
@@ -373,73 +900,173 @@ public class StyleConstants
// The remainder are so-called "typesafe enumerations" which
// alias subsets of the above constants.
+
+ /**
+ * A set of keys for attributes that apply to characters.
+ */
public static class CharacterConstants
extends StyleConstants
implements AttributeSet.CharacterAttribute
{
+ /**
+ * Private constructor prevents new instances being created.
+ *
+ * @param k the key name.
+ */
private CharacterConstants(String k)
{
super(k);
}
- public static Object Background = ColorConstants.Background;
- public static Object BidiLevel = new CharacterConstants("bidiLevel");
- public static Object Bold = FontConstants.Bold;
- public static Object ComponentAttribute = new CharacterConstants("component");
- public static Object Family = FontConstants.Family;
- public static Object Size = FontConstants.Size;
- public static Object Foreground = ColorConstants.Foreground;
- public static Object IconAttribute = new CharacterConstants("icon");
- public static Object Italic = FontConstants.Italic;
- public static Object StrikeThrough = new CharacterConstants("strikethrough");
- public static Object Subscript = new CharacterConstants("subscript");
- public static Object Superscript = new CharacterConstants("superscript");
- public static Object Underline = new CharacterConstants("underline");
+ /** An alias for {@link ColorConstants#Background}. */
+ public static final Object Background = ColorConstants.Background;
+
+ /** A key for the bidi level character attribute. */
+ public static final Object BidiLevel = new CharacterConstants("bidiLevel");
+
+ /** An alias for {@link FontConstants#Bold}. */
+ public static final Object Bold = FontConstants.Bold;
+
+ /** A key for the component character attribute. */
+ public static final Object ComponentAttribute
+ = new CharacterConstants("component");
+
+ /** An alias for {@link FontConstants#Family}. */
+ public static final Object Family = FontConstants.Family;
+
+ /** An alias for {@link FontConstants#Size}. */
+ public static final Object Size = FontConstants.Size;
+
+ /** An alias for {@link ColorConstants#Foreground}. */
+ public static final Object Foreground = ColorConstants.Foreground;
+
+ /** A key for the icon character attribute. */
+ public static final Object IconAttribute = new CharacterConstants("icon");
+
+ /** A key for the italic character attribute. */
+ public static final Object Italic = FontConstants.Italic;
+
+ /** A key for the strike through character attribute. */
+ public static final Object StrikeThrough
+ = new CharacterConstants("strikethrough");
+
+ /** A key for the subscript character attribute. */
+ public static final Object Subscript = new CharacterConstants("subscript");
+
+ /** A key for the superscript character attribute. */
+ public static final Object Superscript
+ = new CharacterConstants("superscript");
+
+ /** A key for the underline character attribute. */
+ public static final Object Underline = new CharacterConstants("underline");
+
}
+ /**
+ * A set of keys for attributes that relate to colors.
+ */
public static class ColorConstants
extends StyleConstants
implements AttributeSet.ColorAttribute, AttributeSet.CharacterAttribute
{
+ /**
+ * Private constructor prevents new instances being created.
+ *
+ * @param k the key name.
+ */
private ColorConstants(String k)
{
super(k);
}
- public static Object Foreground = new ColorConstants("foreground");
- public static Object Background = new ColorConstants("background");
+
+ /** A key for the foreground color attribute. */
+ public static final Object Foreground = new ColorConstants("foreground");
+
+ /** A key for the background color attribute. */
+ public static final Object Background = new ColorConstants("background");
}
+ /**
+ * A set of keys for attributes that apply to fonts.
+ */
public static class FontConstants
extends StyleConstants
implements AttributeSet.FontAttribute, AttributeSet.CharacterAttribute
{
+ /**
+ * Private constructor prevents new instances being created.
+ *
+ * @param k the key name.
+ */
private FontConstants(String k)
{
super(k);
}
- public static Object Bold = new FontConstants("bold");
- public static Object Family = new FontConstants("family");
- public static Object Italic = new FontConstants("italic");
- public static Object Size = new FontConstants("size");
+
+ /** A key for the bold font attribute. */
+ public static final Object Bold = new FontConstants("bold");
+
+ /** A key for the family font attribute. */
+ public static final Object Family = new FontConstants("family");
+
+ /** A key for the italic font attribute. */
+ public static final Object Italic = new FontConstants("italic");
+
+ /** A key for the size font attribute. */
+ public static final Object Size = new FontConstants("size");
}
+ /**
+ * A set of keys for attributes that apply to paragraphs.
+ */
public static class ParagraphConstants
extends StyleConstants
implements AttributeSet.ParagraphAttribute
{
+ /**
+ * Private constructor prevents new instances being created.
+ *
+ * @param k the key name.
+ */
private ParagraphConstants(String k)
{
super(k);
}
- public static Object Alignment = new ParagraphConstants("Alignment");
- public static Object FirstLineIndent = new ParagraphConstants("FirstLineIndent");
- public static Object LeftIndent = new ParagraphConstants("LeftIndent");
- public static Object LineSpacing = new ParagraphConstants("LineSpacing");
- public static Object Orientation = new ParagraphConstants("Orientation");
- public static Object RightIndent = new ParagraphConstants("RightIndent");
- public static Object SpaceAbove = new ParagraphConstants("SpaceAbove");
- public static Object SpaceBelow = new ParagraphConstants("SpaceBelow");
- public static Object TabSet = new ParagraphConstants("TabSet");
+
+ /** A key for the alignment paragraph attribute. */
+ public static final Object Alignment = new ParagraphConstants("Alignment");
+
+ /** A key for the first line indentation paragraph attribute. */
+ public static final Object FirstLineIndent
+ = new ParagraphConstants("FirstLineIndent");
+
+ /** A key for the left indentation paragraph attribute. */
+ public static final Object LeftIndent
+ = new ParagraphConstants("LeftIndent");
+
+ /** A key for the line spacing paragraph attribute. */
+ public static final Object LineSpacing
+ = new ParagraphConstants("LineSpacing");
+
+ /** A key for the orientation paragraph attribute. */
+ public static final Object Orientation
+ = new ParagraphConstants("Orientation");
+
+ /** A key for the right indentation paragraph attribute. */
+ public static final Object RightIndent
+ = new ParagraphConstants("RightIndent");
+
+ /** A key for the 'space above' paragraph attribute. */
+ public static final Object SpaceAbove
+ = new ParagraphConstants("SpaceAbove");
+
+ /** A key for the 'space below' paragraph attribute. */
+ public static final Object SpaceBelow
+ = new ParagraphConstants("SpaceBelow");
+
+ /** A key for the tabset paragraph attribute. */
+ public static final Object TabSet = new ParagraphConstants("TabSet");
+
}
}
diff --git a/libjava/classpath/javax/swing/text/StyleContext.java b/libjava/classpath/javax/swing/text/StyleContext.java
index dabc0ba9cd0..e2643a2aacd 100644
--- a/libjava/classpath/javax/swing/text/StyleContext.java
+++ b/libjava/classpath/javax/swing/text/StyleContext.java
@@ -48,6 +48,7 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.EventListener;
+import java.util.HashSet;
import java.util.Hashtable;
import javax.swing.event.ChangeEvent;
@@ -370,7 +371,7 @@ public class StyleContext
{
StringBuffer sb = new StringBuffer();
sb.append("[StyleContext.SmallattributeSet:");
- for (int i = 0; i < attrs.length; ++i)
+ for (int i = 0; i < attrs.length - 1; ++i)
{
sb.append(" (");
sb.append(attrs[i].toString());
@@ -406,7 +407,12 @@ public class StyleContext
static StyleContext defaultStyleContext = new StyleContext();
static final int compressionThreshold = 9;
-
+
+ /**
+ * These attribute keys are handled specially in serialization.
+ */
+ private static HashSet staticAttributeKeys = new HashSet();
+
EventListenerList listenerList;
Hashtable styleTable;
@@ -737,4 +743,19 @@ public class StyleContext
{
throw new InternalError("not implemented");
}
+
+ /**
+ * Registers an attribute key as a well-known keys. When an attribute with
+ * such a key is written to a stream,, a special syntax is used so that it
+ * can be recognized when it is read back in. All attribute keys defined
+ * in <code>StyleContext</code> are registered as static keys. If you define
+ * additional attribute keys that you want to exist as nonreplicated objects,
+ * then you should register them using this method.
+ *
+ * @param key the key to register as static attribute key
+ */
+ public static void registerStaticAttributeKey(Object key)
+ {
+ staticAttributeKeys.add(key);
+ }
}
diff --git a/libjava/classpath/javax/swing/text/TableView.java b/libjava/classpath/javax/swing/text/TableView.java
index d3113b82be2..2dcb9ebf7b3 100644
--- a/libjava/classpath/javax/swing/text/TableView.java
+++ b/libjava/classpath/javax/swing/text/TableView.java
@@ -54,7 +54,7 @@ import javax.swing.event.DocumentEvent;
*
* @author Roman Kennke (kennke@aicas.com)
*/
-public class TableView
+public abstract class TableView
extends BoxView
{
@@ -90,6 +90,18 @@ public class TableView
public void replace(int offset, int length, View[] views)
{
super.replace(offset, length, views);
+ int viewCount = getViewCount();
+ if (columnRequirements == null
+ || viewCount > columnRequirements.length)
+ {
+ columnRequirements = new SizeRequirements[viewCount];
+ for (int i = 0; i < columnRequirements.length; i++)
+ columnRequirements[i] = new SizeRequirements();
+ }
+ if (columnOffsets == null || columnOffsets.length < viewCount)
+ columnOffsets = new int[viewCount];
+ if (columnSpans == null || columnSpans.length < viewCount)
+ columnSpans = new int[viewCount];
layoutChanged(X_AXIS);
}
@@ -108,8 +120,6 @@ public class TableView
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
int[] spans)
{
- // TODO: Maybe prepare columnSpans and columnOffsets.
-
// Some sanity checks. If these preconditions are not met, then the
// following code will not work. Also, there must be something
// seriously wrong then.
@@ -140,7 +150,7 @@ public class TableView
{
// FIXME: Figure out how to fetch the row heights from the TableView's
// element.
- super.layoutMajorAxis(targetSpan, axis, offsets, spans);
+ super.layoutMinorAxis(targetSpan, axis, offsets, spans);
}
/**
@@ -303,7 +313,7 @@ public class TableView
/**
* The size requirements of the columns.
*/
- private SizeRequirements[] columnRequirements;
+ SizeRequirements[] columnRequirements = new SizeRequirements[0];
/**
* Creates a new instance of <code>TableView</code>.
@@ -313,15 +323,6 @@ public class TableView
public TableView(Element el)
{
super(el, Y_AXIS);
- int numChildren = el.getElementCount();
- View[] rows = new View[numChildren];
- for (int i = 0; i < numChildren; ++i)
- {
- Element rowEl = el.getElement(i);
- TableRow rowView = createTableRow(rowEl);
- rows[i] = rowView;
- }
- replace(0, 0, rows);
}
/**
@@ -385,7 +386,10 @@ public class TableView
protected void layoutColumns(int targetSpan, int[] offsets, int spans[],
SizeRequirements[] reqs)
{
- // TODO: Figure out what exactly to do here.
+ updateColumnRequirements();
+ SizeRequirements r = calculateMinorAxisRequirements(X_AXIS, null);
+ SizeRequirements.calculateTiledPositions(targetSpan, r, columnRequirements,
+ offsets, spans);
}
/**
@@ -462,4 +466,26 @@ public class TableView
// and look for a range that contains the given position.
return super.getViewAtPosition(pos, a);
}
+
+ /**
+ * Updates the column requirements.
+ */
+ private void updateColumnRequirements()
+ {
+ int rowCount = getViewCount();
+ for (int r = 0; r < rowCount; ++r)
+ {
+ TableRow row = (TableRow) getView(r);
+ int columnCount = row.getViewCount();
+ for (int c = 0; c < columnCount; ++c)
+ {
+ View cell = row.getView(c);
+ SizeRequirements cr = columnRequirements[c];
+ cr.minimum = Math.max(cr.minimum, (int) cell.getMinimumSpan(X_AXIS));
+ cr.preferred = Math.max(cr.preferred,
+ (int) cell.getPreferredSpan(X_AXIS));
+ cr.maximum = Math.max(cr.maximum, (int) cell.getMaximumSpan(X_AXIS));
+ }
+ }
+ }
}
diff --git a/libjava/classpath/javax/swing/text/Utilities.java b/libjava/classpath/javax/swing/text/Utilities.java
index 1adc8ff87e9..d109a4a950f 100644
--- a/libjava/classpath/javax/swing/text/Utilities.java
+++ b/libjava/classpath/javax/swing/text/Utilities.java
@@ -41,12 +41,8 @@ package javax.swing.text;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
-import java.awt.Rectangle;
import java.text.BreakIterator;
-import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
-
/**
* A set of utilities to deal with text. This is used by several other classes
* inside this package.
@@ -73,6 +69,10 @@ public class Utilities
* are taken into account. Tabs are expanded using the
* specified {@link TabExpander}.
*
+ *
+ * The X and Y coordinates denote the start of the <em>baseline</em> where
+ * the text should be drawn.
+ *
* @param s the text fragment to be drawn.
* @param x the x position for drawing.
* @param y the y position for drawing.
@@ -88,15 +88,14 @@ public class Utilities
// This buffers the chars to be drawn.
char[] buffer = s.array;
-
- // The current x and y pixel coordinates.
- int pixelX = x;
- int pixelY = y;
-
// The font metrics of the current selected font.
FontMetrics metrics = g.getFontMetrics();
int ascent = metrics.getAscent();
+ // The current x and y pixel coordinates.
+ int pixelX = x;
+ int pixelY = y - ascent;
+
int pixelWidth = 0;
int pos = s.offset;
int len = 0;
@@ -238,9 +237,10 @@ public class Utilities
int pos;
int currentX = x0;
- for (pos = p0; pos < s.count; pos++)
+ for (pos = 0; pos < s.count; pos++)
{
char nextChar = s.array[s.offset+pos];
+
if (nextChar == 0)
{
if (! round)
@@ -256,6 +256,7 @@ public class Utilities
else
currentX = (int) te.nextTabStop(currentX, pos);
}
+
if (currentX > x)
{
if (! round)
@@ -263,7 +264,8 @@ public class Utilities
break;
}
}
- return pos;
+
+ return pos + p0;
}
/**
@@ -510,10 +512,10 @@ public class Utilities
{
int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset);
BreakIterator breaker = BreakIterator.getWordInstance();
- breaker.setText(s.toString());
-
+ breaker.setText(s);
+
// If mark is equal to the end of the string, just use that position
- if (mark == s.count)
+ if (mark == s.count + s.offset)
return mark;
// Try to find a word boundary previous to the mark at which we
@@ -571,15 +573,29 @@ public class Utilities
public static final int getPositionAbove(JTextComponent c, int offset, int x)
throws BadLocationException
{
- View rootView = c.getUI().getRootView(c);
- Rectangle r = c.modelToView(offset);
- int offs = c.viewToModel(new Point(x, r.y));
- int pos = rootView.getNextVisualPositionFrom(offs,
- Position.Bias.Forward,
- SwingUtilities.calculateInnerArea(c, null),
- SwingConstants.NORTH,
- new Position.Bias[1]);
- return pos;
+ int offs = getRowStart(c, offset);
+
+ if(offs == -1)
+ return -1;
+
+ // Effectively calculates the y value of the previous line.
+ Point pt = c.modelToView(offs-1).getLocation();
+
+ pt.x = x;
+
+ // Calculate a simple fitting offset.
+ offs = c.viewToModel(pt);
+
+ // Find out the real x positions of the calculated character and its
+ // neighbour.
+ int offsX = c.modelToView(offs).getLocation().x;
+ int offsXNext = c.modelToView(offs+1).getLocation().x;
+
+ // Chose the one which is nearer to us and return its offset.
+ if (Math.abs(offsX-x) <= Math.abs(offsXNext-x))
+ return offs;
+ else
+ return offs+1;
}
/**
@@ -598,14 +614,31 @@ public class Utilities
public static final int getPositionBelow(JTextComponent c, int offset, int x)
throws BadLocationException
{
- View rootView = c.getUI().getRootView(c);
- Rectangle r = c.modelToView(offset);
- int offs = c.viewToModel(new Point(x, r.y));
- int pos = rootView.getNextVisualPositionFrom(offs,
- Position.Bias.Forward,
- SwingUtilities.calculateInnerArea(c, null),
- SwingConstants.SOUTH,
- new Position.Bias[1]);
- return pos;
- }
+ int offs = getRowEnd(c, offset);
+
+ if(offs == -1)
+ return -1;
+
+ // Effectively calculates the y value of the previous line.
+ Point pt = c.modelToView(offs+1).getLocation();
+
+ pt.x = x;
+
+ // Calculate a simple fitting offset.
+ offs = c.viewToModel(pt);
+
+ if (offs == c.getDocument().getLength())
+ return offs;
+
+ // Find out the real x positions of the calculated character and its
+ // neighbour.
+ int offsX = c.modelToView(offs).getLocation().x;
+ int offsXNext = c.modelToView(offs+1).getLocation().x;
+
+ // Chose the one which is nearer to us and return its offset.
+ if (Math.abs(offsX-x) <= Math.abs(offsXNext-x))
+ return offs;
+ else
+ return offs+1;
+ }
}
diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java
index b835842bc0e..2feaf29a4f9 100644
--- a/libjava/classpath/javax/swing/text/View.java
+++ b/libjava/classpath/javax/swing/text/View.java
@@ -44,6 +44,7 @@ import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
public abstract class View implements SwingConstants
@@ -72,8 +73,29 @@ public abstract class View implements SwingConstants
public abstract void paint(Graphics g, Shape s);
+ /**
+ * Sets the parent for this view. This is the first method that is beeing
+ * called on a view to setup the view hierarchy. This is also the last method
+ * beeing called when the view is disconnected from the view hierarchy, in
+ * this case <code>parent</code> is null.
+ *
+ * If <code>parent</code> is <code>null</code>, a call to this method also
+ * calls <code>setParent</code> on the children, thus disconnecting them from
+ * the view hierarchy. That means that super must be called when this method
+ * is overridden.
+ *
+ * @param parent the parent to set, <code>null</code> when this view is
+ * beeing disconnected from the view hierarchy
+ */
public void setParent(View parent)
{
+ if (parent == null)
+ {
+ int numChildren = getViewCount();
+ for (int i = 0; i < numChildren; i++)
+ getView(i).setParent(null);
+ }
+
this.parent = parent;
}
@@ -101,27 +123,65 @@ public abstract class View implements SwingConstants
return elt;
}
+ /**
+ * Returns the preferred span along the specified axis. Normally the view is
+ * rendered with the span returned here if that is possible.
+ *
+ * @param axis the axis
+ *
+ * @return the preferred span along the specified axis
+ */
public abstract float getPreferredSpan(int axis);
+ /**
+ * Returns the resize weight of this view. A value of <code>0</code> or less
+ * means this view is not resizeable. Positive values make the view
+ * resizeable. The default implementation returns <code>0</code>
+ * unconditionally.
+ *
+ * @param axis the axis
+ *
+ * @return the resizability of this view along the specified axis
+ */
public int getResizeWeight(int axis)
{
return 0;
}
+ /**
+ * Returns the maximum span along the specified axis. The default
+ * implementation will forward to
+ * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)}
+ * returns a value > 0, in which case this returns {@link Integer#MIN_VALUE}.
+ *
+ * @param axis the axis
+ *
+ * @return the maximum span along the specified axis
+ */
public float getMaximumSpan(int axis)
{
+ float max = Integer.MAX_VALUE;
if (getResizeWeight(axis) <= 0)
- return getPreferredSpan(axis);
-
- return Integer.MAX_VALUE;
+ max = getPreferredSpan(axis);
+ return max;
}
+ /**
+ * Returns the minimum span along the specified axis. The default
+ * implementation will forward to
+ * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)}
+ * returns a value > 0, in which case this returns <code>0</code>.
+ *
+ * @param axis the axis
+ *
+ * @return the minimum span along the specified axis
+ */
public float getMinimumSpan(int axis)
{
+ float min = 0;
if (getResizeWeight(axis) <= 0)
- return getPreferredSpan(axis);
-
- return Integer.MAX_VALUE;
+ min = getPreferredSpan(axis);
+ return min;
}
public void setSize(float width, float height)
@@ -129,6 +189,20 @@ public abstract class View implements SwingConstants
// The default implementation does nothing.
}
+ /**
+ * Returns the alignment of this view along the baseline of the parent view.
+ * An alignment of <code>0.0</code> will align this view with the left edge
+ * along the baseline, an alignment of <code>0.5</code> will align it
+ * centered to the baseline, an alignment of <code>1.0</code> will align
+ * the right edge along the baseline.
+ *
+ * The default implementation returns 0.5 unconditionally.
+ *
+ * @param axis the axis
+ *
+ * @return the alignment of this view along the parents baseline for the
+ * specified axis
+ */
public float getAlignment(int axis)
{
return 0.5f;
@@ -160,6 +234,15 @@ public abstract class View implements SwingConstants
return parent != null ? parent.getViewFactory() : null;
}
+ /**
+ * Replaces a couple of child views with new child views. If
+ * <code>length == 0</code> then this is a simple insertion, if
+ * <code>views == null</code> this only removes some child views.
+ *
+ * @param offset the offset at which to replace
+ * @param length the number of child views to be removed
+ * @param views the new views to be inserted, may be <code>null</code>
+ */
public void replace(int offset, int length, View[] views)
{
// Default implementation does nothing.
@@ -392,6 +475,10 @@ public abstract class View implements SwingConstants
* of the change to the model. This calles {@link #forwardUpdateToView}
* for each View that must be forwarded to.
*
+ * If <code>ec</code> is not <code>null</code> (this means there have been
+ * structural changes to the element that this view is responsible for) this
+ * method should recognize this and don't notify newly added child views.
+ *
* @param ec the ElementChange describing the element changes (may be
* <code>null</code> if there were no changes)
* @param ev the DocumentEvent describing the changes to the model
@@ -404,10 +491,31 @@ public abstract class View implements SwingConstants
DocumentEvent ev, Shape shape, ViewFactory vf)
{
int count = getViewCount();
- for (int i = 0; i < count; i++)
+ if (count > 0)
{
- View child = getView(i);
- forwardUpdateToView(child, ev, shape, vf);
+ int startOffset = ev.getOffset();
+ int endOffset = startOffset + ev.getLength();
+ int startIndex = getViewIndex(startOffset, Position.Bias.Backward);
+ int endIndex = getViewIndex(endOffset, Position.Bias.Forward);
+ int index = -1;
+ int addLength = -1;
+ if (ec != null)
+ {
+ index = ec.getIndex();
+ addLength = ec.getChildrenAdded().length;
+ }
+
+ if (startIndex >= 0 && endIndex >= 0)
+ {
+ for (int i = startIndex; i <= endIndex; i++)
+ {
+ // Skip newly added child views.
+ if (index >= 0 && i >= index && i < (index+addLength))
+ continue;
+ View child = getView(i);
+ forwardUpdateToView(child, ev, shape, vf);
+ }
+ }
}
}
@@ -503,9 +611,9 @@ public abstract class View implements SwingConstants
if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward)
throw new IllegalArgumentException
("b2 must be either Position.Bias.Forward or Position.Bias.Backward");
- Shape s1 = modelToView(p1, a, b1);
- Shape s2 = modelToView(p2, a, b2);
- return s1.getBounds().union(s2.getBounds());
+ Rectangle s1 = (Rectangle) modelToView(p1, a, b1);
+ Rectangle s2 = (Rectangle) modelToView(p2, a, b2);
+ return SwingUtilities.computeUnion(s1.x, s1.y, s1.width, s1.height, s2);
}
/**
@@ -570,7 +678,7 @@ public abstract class View implements SwingConstants
* Dumps the complete View hierarchy. This method can be used for debugging
* purposes.
*/
- void dump()
+ protected void dump()
{
// Climb up the hierarchy to the parent.
View parent = getParent();
@@ -590,7 +698,7 @@ public abstract class View implements SwingConstants
{
for (int i = 0; i < indent; ++i)
System.out.print('.');
- System.out.println(this);
+ System.out.println(this + "(" + getStartOffset() + "," + getEndOffset() + ": " + getElement());
int count = getViewCount();
for (int i = 0; i < count; ++i)
diff --git a/libjava/classpath/javax/swing/text/WrappedPlainView.java b/libjava/classpath/javax/swing/text/WrappedPlainView.java
index baba343c5bf..e2790a05ca0 100644
--- a/libjava/classpath/javax/swing/text/WrappedPlainView.java
+++ b/libjava/classpath/javax/swing/text/WrappedPlainView.java
@@ -270,8 +270,7 @@ public class WrappedPlainView extends BoxView implements TabExpander
protected int calculateBreakPosition(int p0, int p1)
{
Container c = getContainer();
- Rectangle alloc = c.isValid() ? c.getBounds()
- : new Rectangle(c.getPreferredSize());
+ Rectangle alloc = new Rectangle(0, 0, getWidth(), getHeight());
updateMetrics();
try
{
diff --git a/libjava/classpath/javax/swing/text/html/FormView.java b/libjava/classpath/javax/swing/text/html/FormView.java
new file mode 100644
index 00000000000..b85c6943404
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/FormView.java
@@ -0,0 +1,230 @@
+/* FormView.java -- A view for a variety of HTML form elements
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JPasswordField;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.UIManager;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+
+/**
+ * A View that renders HTML form elements like buttons and input fields.
+ * This is implemented as a {@link ComponentView} that creates different Swing
+ * component depending on the type and setting of the different form elements.
+ *
+ * Namely, this view creates the following components:
+ * <table>
+ * <tr><th>Element type</th><th>Swing component</th></tr>
+ * <tr><td>input, button</td><td>JButton</td></tr>
+ * <tr><td>input, checkbox</td><td>JButton</td></tr>
+ * <tr><td>input, image</td><td>JButton</td></tr>
+ * <tr><td>input, password</td><td>JButton</td></tr>
+ * <tr><td>input, radio</td><td>JButton</td></tr>
+ * <tr><td>input, reset</td><td>JButton</td></tr>
+ * <tr><td>input, submit</td><td>JButton</td></tr>
+ * <tr><td>input, text</td><td>JButton</td></tr>
+ * <tr><td>select, size > 1 or with multiple attribute</td>
+ * <td>JList in JScrollPane</td></tr>
+ * <tr><td>select, size unspecified or == 1</td><td>JComboBox</td></tr>
+ * <tr><td>textarea, text</td><td>JTextArea in JScrollPane</td></tr>
+ * <tr><td>input, file</td><td>JTextField</td></tr>
+ * </table>
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class FormView
+ extends ComponentView
+ implements ActionListener
+{
+
+ /**
+ * If the value attribute of an <code>&lt;input type=&quot;submit&quot;&gt>
+ * tag is not specified, then this string is used.
+ *
+ * @deprecated As of JDK1.3 the value is fetched from the UIManager property
+ * <code>FormView.submitButtonText</code>.
+ */
+ public static final String SUBMIT =
+ UIManager.getString("FormView.submitButtonText");
+
+ /**
+ * If the value attribute of an <code>&lt;input type=&quot;reset&quot;&gt>
+ * tag is not specified, then this string is used.
+ *
+ * @deprecated As of JDK1.3 the value is fetched from the UIManager property
+ * <code>FormView.resetButtonText</code>.
+ */
+ public static final String RESET =
+ UIManager.getString("FormView.resetButtonText");
+
+ /**
+ * Creates a new <code>FormView</code>.
+ *
+ * @param el the element that is displayed by this view.
+ */
+ public FormView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Creates the correct AWT component for rendering the form element.
+ */
+ protected Component createComponent()
+ {
+ Component comp = null;
+ Element el = getElement();
+ Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute);
+ if (tag.equals(HTML.Tag.INPUT))
+ {
+ AttributeSet atts = el.getAttributes();
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ if (type.equals("button"))
+ comp = new JButton(value);
+ else if (type.equals("checkbox"))
+ comp = new JCheckBox(value);
+ else if (type.equals("image"))
+ comp = new JButton(value); // FIXME: Find out how to fetch the image.
+ else if (type.equals("password"))
+ comp = new JPasswordField(value);
+ else if (type.equals("radio"))
+ comp = new JRadioButton(value);
+ else if (type.equals("reset"))
+ {
+ if (value == null || value.equals(""))
+ value = RESET;
+ comp = new JButton(value);
+ }
+ else if (type.equals("submit"))
+ {
+ if (value == null || value.equals(""))
+ value = SUBMIT;
+ comp = new JButton(value);
+ }
+ else if (type.equals("text"))
+ comp = new JTextField(value);
+
+ }
+ // FIXME: Implement the remaining components.
+ return comp;
+ }
+
+ /**
+ * Determines the maximum span for this view on the specified axis.
+ *
+ * @param axis the axis along which to determine the span
+ *
+ * @return the maximum span for this view on the specified axis
+ *
+ * @throws IllegalArgumentException if the axis is invalid
+ */
+ public float getMaximumSpan(int axis)
+ {
+ // FIXME: The specs say that for some components the maximum span == the
+ // preferred span of the component. This should be figured out and
+ // implemented accordingly.
+ float span;
+ if (axis == X_AXIS)
+ span = getComponent().getMaximumSize().width;
+ else if (axis == Y_AXIS)
+ span = getComponent().getMaximumSize().height;
+ else
+ throw new IllegalArgumentException("Invalid axis parameter");
+ return span;
+ }
+
+ /**
+ * Processes an action from the Swing component.
+ *
+ * If the action comes from a submit button, the form is submitted by calling
+ * {@link #submitData}. In the case of a reset button, the form is reset to
+ * the original state. If the action comes from a password or text field,
+ * then the input focus is transferred to the next input element in the form,
+ * unless this text/password field is the last one, in which case the form
+ * is submitted.
+ *
+ * @param ev the action event
+ */
+ public void actionPerformed(ActionEvent ev)
+ {
+ Element el = getElement();
+ Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute);
+ if (tag.equals(HTML.Tag.INPUT))
+ {
+ AttributeSet atts = el.getAttributes();
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ if (type.equals("submit"))
+ submitData(""); // FIXME: How to fetch the actual form data?
+ }
+ // FIXME: Implement the remaining actions.
+ }
+
+ /**
+ * Submits the form data. A separate thread is created to do the
+ * transmission.
+ *
+ * @param data the form data
+ */
+ protected void submitData(String data)
+ {
+ // FIXME: Implement this.
+ }
+
+ /**
+ * Submits the form data in response to a click on a
+ * <code>&lt;input type=&quot;image&quot;&gt;</code> element.
+ *
+ * @param imageData the mouse click coordinates
+ */
+ protected void imageSubmit(String imageData)
+ {
+ // FIXME: Implement this.
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTML.java b/libjava/classpath/javax/swing/text/html/HTML.java
index 0b758d2b873..2b521cd22b4 100644
--- a/libjava/classpath/javax/swing/text/html/HTML.java
+++ b/libjava/classpath/javax/swing/text/html/HTML.java
@@ -57,8 +57,7 @@ public class HTML
/**
* Represents a HTML attribute.
*/
- public static class Attribute
- implements Serializable
+ public static final class Attribute
{
/**
* The action attribute
@@ -464,47 +463,18 @@ public class HTML
* The width attribute
*/
public static final Attribute WIDTH = new Attribute("width");
- private final String name;
-
- /**
- * Creates the attribute with the given name.
- */
- protected Attribute(String a_name)
- {
- name = a_name;
- }
-
- /**
- * Calls compareTo on the tag names (Strings)
- */
- public int compareTo(Object other)
- {
- return name.compareTo(((Attribute) other).name);
- }
/**
- * The attributes are equal if the names are equal
- * (ignoring case)
+ * The attribute name.
*/
- public boolean equals(Object other)
- {
- if (other == this)
- return true;
-
- if (!(other instanceof Attribute))
- return false;
-
- Attribute that = (Attribute) other;
-
- return that.name.equalsIgnoreCase(name);
- }
+ private final String name;
/**
- * Returns the hash code which corresponds to the string for this tag.
+ * Creates the attribute with the given name.
*/
- public int hashCode()
+ private Attribute(String a_name)
{
- return name == null ? 0 : name.hashCode();
+ name = a_name;
}
/**
@@ -559,7 +529,6 @@ public class HTML
* Represents a HTML tag.
*/
public static class Tag
- implements Comparable, Serializable
{
/**
* The &lt;a&gt; tag
@@ -1047,42 +1016,6 @@ public class HTML
}
/**
- * Calls compareTo on the tag names (Strings)
- */
- public int compareTo(Object other)
- {
- return name.compareTo(((Tag) other).name);
- }
-
- /**
- * The tags are equal if the names are equal (ignoring case).
- */
- public boolean equals(Object other)
- {
- if (other == this)
- {
- return true;
- }
-
- if (!(other instanceof Tag))
- {
- return false;
- }
-
- Tag that = (Tag) other;
-
- return that.name.equalsIgnoreCase(name);
- }
-
- /**
- * Returns the hash code which corresponds to the string for this tag.
- */
- public int hashCode()
- {
- return name == null ? 0 : name.hashCode();
- }
-
- /**
* Returns the tag name. The names of the built-in tags are always
* returned in lowercase.
*/
diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
index 5b2452b32f6..2a96953ee91 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
@@ -38,10 +38,8 @@ exception statement from your version. */
package javax.swing.text.html;
-import java.net.URL;
-
import java.io.IOException;
-
+import java.net.URL;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;
@@ -131,16 +129,17 @@ public class HTMLDocument extends DefaultStyledDocument
}
/**
- * Replaces the contents of the document with the given element specifications.
- * This is called before insert if the loading is done in bursts. This is the
- * only method called if loading the document entirely in one burst.
+ * Replaces the contents of the document with the given element
+ * specifications. This is called before insert if the loading is done
+ * in bursts. This is the only method called if loading the document
+ * entirely in one burst.
*
* @param data - the date that replaces the content of the document
*/
protected void create(DefaultStyledDocument.ElementSpec[] data)
{
- // FIXME: Not implemented
- System.out.println("create not implemented");
+ // Once the super behaviour is properly implemented it should be sufficient
+ // to simply call super.create(data).
super.create(data);
}
@@ -149,11 +148,35 @@ public class HTMLDocument extends DefaultStyledDocument
*
* @return the new default root
*/
- protected AbstractDocument.AbstractElement createDefaultRoot()
+ protected AbstractElement createDefaultRoot()
{
- // FIXME: Not implemented
- System.out.println("createDefaultRoot not implemented");
- return super.createDefaultRoot();
+ AbstractDocument.AttributeContext ctx = getAttributeContext();
+
+ // Create html element.
+ AttributeSet atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.HTML);
+ BranchElement html = (BranchElement) createBranchElement(null, atts);
+
+ // Create body element.
+ atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.BODY);
+ BranchElement body = (BranchElement) createBranchElement(html, atts);
+ html.replace(0, 0, new Element[] { body });
+
+ // Create p element.
+ atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.P);
+ BranchElement p = (BranchElement) createBranchElement(body, atts);
+ body.replace(0, 0, new Element[] { p });
+
+ // Create an empty leaf element.
+ atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute,
+ HTML.Tag.CONTENT);
+ Element leaf = createLeafElement(p, atts, 0, 1);
+ p.replace(0, 0, new Element[]{ leaf });
+
+ return html;
}
/**
@@ -165,28 +188,29 @@ public class HTMLDocument extends DefaultStyledDocument
* @param a - the attributes for the element
* @param p0 - the beginning of the range >= 0
* @param p1 - the end of the range >= p0
+ *
* @return the new element
*/
protected Element createLeafElement(Element parent, AttributeSet a, int p0,
int p1)
{
- // FIXME: Not implemented
- System.out.println("createLeafElement not implemented");
- return super.createLeafElement(parent, a, p0, p1);
+ RunElement el = new RunElement(parent, a, p0, p1);
+ el.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT);
+ return new RunElement(parent, a, p0, p1);
}
- /** This method returns an HTMLDocument.BlockElement object representing the
+ /**
+ * This method returns an HTMLDocument.BlockElement object representing the
* attribute set a and attached to parent.
*
* @param parent - the parent element
* @param a - the attributes for the element
+ *
* @return the new element
*/
protected Element createBranchElement(Element parent, AttributeSet a)
{
- // FIXME: Not implemented
- System.out.println("createBranchElement not implemented");
- return super.createBranchElement(parent, a);
+ return new BlockElement(parent, a);
}
/**
@@ -204,9 +228,9 @@ public class HTMLDocument extends DefaultStyledDocument
*/
protected void insert(int offset, DefaultStyledDocument.ElementSpec[] data)
throws BadLocationException
- {
- super.insert(offset, data);
- }
+ {
+ super.insert(offset, data);
+ }
/**
* Updates document structure as a result of text insertion. This will happen
@@ -451,7 +475,7 @@ public class HTMLDocument extends DefaultStyledDocument
{
public BlockElement (Element parent, AttributeSet a)
{
- super (parent, a);
+ super(parent, a);
}
/**
@@ -470,10 +494,14 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public String getName()
{
- return (String) getAttribute(StyleConstants.NameAttribute);
+ Object tag = getAttribute(StyleConstants.NameAttribute);
+ String name = null;
+ if (tag != null)
+ name = tag.toString();
+ return name;
}
}
-
+
/**
* RunElement represents a section of text that has a set of
* HTML character level attributes assigned to it.
@@ -502,7 +530,11 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public String getName()
{
- return (String) getAttribute(StyleConstants.NameAttribute);
+ Object tag = getAttribute(StyleConstants.NameAttribute);
+ String name = null;
+ if (tag != null)
+ name = tag.toString();
+ return name;
}
/**
@@ -531,7 +563,13 @@ public class HTMLDocument extends DefaultStyledDocument
/** A stack for character attribute sets **/
Stack charAttrStack = new Stack();
-
+
+ /**
+ * The parse stack. This stack holds HTML.Tag objects that reflect the
+ * current position in the parsing process.
+ */
+ private Stack parseStack = new Stack();
+
/** A mapping between HTML.Tag objects and the actions that handle them **/
HashMap tagToAction;
@@ -699,8 +737,8 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void start(HTML.Tag t, MutableAttributeSet a)
{
- // FIXME: Implement.
- print ("ParagraphAction.start not implemented");
+ // FIXME: What else must be done here?
+ blockOpen(t, a);
}
/**
@@ -709,8 +747,8 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void end(HTML.Tag t)
{
- // FIXME: Implement.
- print ("ParagraphAction.end not implemented");
+ // FIXME: What else must be done here?
+ blockClose(t);
}
}
@@ -1102,7 +1140,11 @@ public class HTMLDocument extends DefaultStyledDocument
elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()];
parseBuffer.copyInto(elements);
parseBuffer.removeAllElements();
- insert(offset, elements);
+ if (offset == 0)
+ create(elements);
+ else
+ insert(offset, elements);
+
offset += HTMLDocument.this.getLength() - offset;
}
@@ -1250,12 +1292,27 @@ public class HTMLDocument extends DefaultStyledDocument
{
printBuffer();
DefaultStyledDocument.ElementSpec element;
- element = new DefaultStyledDocument.ElementSpec(attr.copyAttributes(),
- DefaultStyledDocument.ElementSpec.StartTagType);
+
+ // If the previous tag is content and the parent is p-implied, then
+ // we must also close the p-implied.
+ if (parseStack.size() > 0 && parseStack.peek() == HTML.Tag.IMPLIED)
+ {
+ element = new DefaultStyledDocument.ElementSpec(null,
+ DefaultStyledDocument.ElementSpec.EndTagType);
+ parseBuffer.addElement(element);
+ parseStack.pop();
+ }
+
+ parseStack.push(t);
+ AbstractDocument.AttributeContext ctx = getAttributeContext();
+ AttributeSet copy = attr.copyAttributes();
+ copy = ctx.addAttribute(copy, StyleConstants.NameAttribute, t);
+ element = new DefaultStyledDocument.ElementSpec(copy,
+ DefaultStyledDocument.ElementSpec.StartTagType);
parseBuffer.addElement(element);
printBuffer();
}
-
+
/**
* Instructs the parse buffer to close the block element associated with
* the given HTML.Tag
@@ -1266,10 +1323,40 @@ public class HTMLDocument extends DefaultStyledDocument
{
printBuffer();
DefaultStyledDocument.ElementSpec element;
+
+ // If the previous tag is a start tag then we insert a synthetic
+ // content tag.
+ DefaultStyledDocument.ElementSpec prev;
+ prev = (DefaultStyledDocument.ElementSpec)
+ parseBuffer.get(parseBuffer.size() - 1);
+ if (prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
+ {
+ AbstractDocument.AttributeContext ctx = getAttributeContext();
+ AttributeSet attributes = ctx.getEmptySet();
+ attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
+ HTML.Tag.CONTENT);
+ element = new DefaultStyledDocument.ElementSpec(attributes,
+ DefaultStyledDocument.ElementSpec.ContentType,
+ new char[0], 0, 0);
+ parseBuffer.add(element);
+ }
+ // If the previous tag is content and the parent is p-implied, then
+ // we must also close the p-implied.
+ else if (parseStack.peek() == HTML.Tag.IMPLIED)
+ {
+ element = new DefaultStyledDocument.ElementSpec(null,
+ DefaultStyledDocument.ElementSpec.EndTagType);
+ parseBuffer.addElement(element);
+ if (parseStack.size() > 0)
+ parseStack.pop();
+ }
+
element = new DefaultStyledDocument.ElementSpec(null,
DefaultStyledDocument.ElementSpec.EndTagType);
parseBuffer.addElement(element);
printBuffer();
+ if (parseStack.size() > 0)
+ parseStack.pop();
}
/**
@@ -1298,16 +1385,42 @@ public class HTMLDocument extends DefaultStyledDocument
protected void addContent(char[] data, int offs, int length,
boolean generateImpliedPIfNecessary)
{
+ AbstractDocument.AttributeContext ctx = getAttributeContext();
+ DefaultStyledDocument.ElementSpec element;
+ AttributeSet attributes = null;
+
+ // Content must always be embedded inside a paragraph element,
+ // so we create this if the previous element is not one of
+ // <p>, <h1> .. <h6>.
+ boolean createImpliedParagraph = false;
+ HTML.Tag parent = (HTML.Tag) parseStack.peek();
+ if (parent != HTML.Tag.P && parent != HTML.Tag.H1
+ && parent != HTML.Tag.H2
+ && parent != HTML.Tag.H3 && parent != HTML.Tag.H4
+ && parent != HTML.Tag.H5 && parent != HTML.Tag.H6
+ && parent != HTML.Tag.TD)
+ {
+ attributes = ctx.getEmptySet();
+ attributes = ctx.addAttribute(attributes,
+ StyleConstants.NameAttribute,
+ HTML.Tag.IMPLIED);
+ element = new DefaultStyledDocument.ElementSpec(attributes,
+ DefaultStyledDocument.ElementSpec.StartTagType);
+ parseBuffer.add(element);
+ parseStack.push(HTML.Tag.IMPLIED);
+ }
+
// Copy the attribute set, don't use the same object because
// it may change
- AttributeSet attributes = null;
if (charAttr != null)
attributes = charAttr.copyAttributes();
-
- DefaultStyledDocument.ElementSpec element;
+ else
+ attributes = ctx.getEmptySet();
+ attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
+ HTML.Tag.CONTENT);
element = new DefaultStyledDocument.ElementSpec(attributes,
- DefaultStyledDocument.ElementSpec.ContentType,
- data, offs, length);
+ DefaultStyledDocument.ElementSpec.ContentType,
+ data, offs, length);
printBuffer();
// Add the element to the buffer
diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
index 1ef9768c923..2d5d1eb79da 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
@@ -56,17 +56,11 @@ import javax.accessibility.AccessibleContext;
import javax.swing.Action;
import javax.swing.JEditorPane;
-import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
-import javax.swing.text.BoxView;
-import javax.swing.text.ComponentView;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.Element;
-import javax.swing.text.IconView;
-import javax.swing.text.LabelView;
import javax.swing.text.MutableAttributeSet;
-import javax.swing.text.ParagraphView;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledEditorKit;
@@ -532,8 +526,8 @@ public class HTMLEditorKit
public View create(Element element)
{
View view = null;
- Object attr = element.getAttributes().getAttribute(
- StyleConstants.NameAttribute);
+ Object attr =
+ element.getAttributes().getAttribute(StyleConstants.NameAttribute);
if (attr instanceof HTML.Tag)
{
HTML.Tag tag = (HTML.Tag) attr;
@@ -553,8 +547,16 @@ public class HTMLEditorKit
view = new BlockView(element, View.Y_AXIS);
// FIXME: Uncomment when the views have been implemented
- /* else if (tag.equals(HTML.Tag.CONTENT))
- view = new InlineView(element);
+ else if (tag.equals(HTML.Tag.CONTENT))
+ view = new InlineView(element);
+ else if (tag == HTML.Tag.HEAD)
+ view = new NullView(element);
+ else if (tag.equals(HTML.Tag.TABLE))
+ view = new HTMLTableView(element);
+ else if (tag.equals(HTML.Tag.TD))
+ view = new ParagraphView(element);
+
+ /*
else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR)
|| tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
view = new ListView(element);
@@ -564,8 +566,6 @@ public class HTMLEditorKit
view = new HRuleView(element);
else if (tag.equals(HTML.Tag.BR))
view = new BRView(element);
- else if (tag.equals(HTML.Tag.TABLE))
- view = new TableView(element);
else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
|| tag.equals(HTML.Tag.TEXTAREA))
view = new FormView(element);
@@ -575,21 +575,11 @@ public class HTMLEditorKit
view = new FrameSetView(element);
else if (tag.equals(HTML.Tag.FRAME))
view = new FrameView(element); */
- }
-
+ }
if (view == null)
{
- String name = element.getName();
- if (name.equals(AbstractDocument.ContentElementName))
- view = new LabelView(element);
- else if (name.equals(AbstractDocument.ParagraphElementName))
- view = new ParagraphView(element);
- else if (name.equals(AbstractDocument.SectionElementName))
- view = new BoxView(element, View.Y_AXIS);
- else if (name.equals(StyleConstants.ComponentElementName))
- view = new ComponentView(element);
- else if (name.equals(StyleConstants.IconElementName))
- view = new IconView(element);
+ System.err.println("missing tag->view mapping for: " + element);
+ view = new NullView(element);
}
return view;
}
@@ -958,7 +948,8 @@ public class HTMLEditorKit
throw new IOException("Parser is null.");
HTMLDocument hd = ((HTMLDocument) doc);
- hd.setBase(editorPane.getPage());
+ if (editorPane != null)
+ hd.setBase(editorPane.getPage());
ParserCallback pc = hd.getReader(pos);
// FIXME: What should ignoreCharSet be set to?
diff --git a/libjava/classpath/javax/swing/text/html/HTMLTableView.java b/libjava/classpath/javax/swing/text/html/HTMLTableView.java
new file mode 100644
index 00000000000..cac44d8dc27
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HTMLTableView.java
@@ -0,0 +1,82 @@
+/* HTMLTableView.java -- A table view for HTML tables
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import javax.swing.text.Element;
+import javax.swing.text.TableView;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * A conrete implementation of TableView that renders HTML tables.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+class HTMLTableView
+ extends TableView
+{
+
+ /**
+ * Creates a new HTMLTableView for the specified element.
+ *
+ * @param el the element for the table view
+ */
+ public HTMLTableView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Loads the children of the Table. This completely bypasses the ViewFactory
+ * and creates instances of TableRow instead.
+ *
+ * @param vf ignored
+ */
+ protected void loadChildren(ViewFactory vf)
+ {
+ Element el = getElement();
+ int numChildren = el.getElementCount();
+ View[] rows = new View[numChildren];
+ for (int i = 0; i < numChildren; ++i)
+ {
+ rows[i] = createTableRow(el.getElement(i));
+ }
+ replace(0, getViewCount(), rows);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/InlineView.java b/libjava/classpath/javax/swing/text/html/InlineView.java
new file mode 100644
index 00000000000..77ec86e8263
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/InlineView.java
@@ -0,0 +1,166 @@
+/* InlineView.java -- Renders HTML content
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Shape;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.LabelView;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * Renders HTML content (identified by {@link HTML.Tag#CONTENT}). This is
+ * basically a {@link LabelView} that is adjusted to understand styles defined
+ * by stylesheets.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class InlineView
+ extends LabelView
+{
+
+ /**
+ * Creates a new <code>InlineView</code> that renders the specified element.
+ *
+ * @param element the element for this view
+ */
+ public InlineView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Receives notification that something was inserted into the document in
+ * a location that this view is responsible for.
+ *
+ * @param e the document event
+ * @param a the current allocation of this view
+ * @param f the view factory for creating new views
+ *
+ * @since 1.5
+ */
+ public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ // FIXME: What to do here?
+ super.insertUpdate(e, a, f);
+ }
+
+ /**
+ * Receives notification that something was removed from the document in
+ * a location that this view is responsible for.
+ *
+ * @param e the document event
+ * @param a the current allocation of this view
+ * @param f the view factory for creating new views
+ *
+ * @since 1.5
+ */
+ public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ // FIXME: What to do here?
+ super.removeUpdate(e, a, f);
+ }
+
+ /**
+ * Receives notification that attributes have changed in the document in
+ * a location that this view is responsible for. This calls
+ * {@link #setPropertiesFromAttributes}.
+ *
+ * @param e the document event
+ * @param a the current allocation of this view
+ * @param f the view factory for creating new views
+ *
+ * @since 1.5
+ */
+ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ super.changedUpdate(e, a, f);
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Returns the attributes that are used for rendering. This is implemented
+ * to multiplex the attributes specified in the model with a stylesheet.
+ *
+ * @return the attributes that are used for rendering
+ */
+ public AttributeSet getAttributes()
+ {
+ // FIXME: Implement this.
+ return super.getAttributes();
+ }
+
+
+ public int getBreakWeight(int axis, float pos, float len)
+ {
+ // FIXME: Implement this.
+ return super.getBreakWeight(axis, pos, len);
+ }
+
+ public View breakView(int axis, int offset, float pos, float len)
+ {
+ // FIXME: Implement this.
+ return super.breakView(axis, offset, pos, len);
+ }
+
+ protected void setPropertiesFromAttributes()
+ {
+ // FIXME: Implement this.
+ super.setPropertiesFromAttributes();
+ }
+
+ /**
+ * Returns the stylesheet used by this view. This returns the stylesheet
+ * of the <code>HTMLDocument</code> that is rendered by this view.
+ *
+ * @return the stylesheet used by this view
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document doc = getDocument();
+ StyleSheet styleSheet = null;
+ if (doc instanceof HTMLDocument)
+ styleSheet = ((HTMLDocument) doc).getStyleSheet();
+ return styleSheet;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/NullView.java b/libjava/classpath/javax/swing/text/html/NullView.java
new file mode 100644
index 00000000000..4b66c5ad87e
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/NullView.java
@@ -0,0 +1,102 @@
+/* NullView.java -- A dummy view that renders nothing
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Graphics;
+import java.awt.Shape;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.Position.Bias;
+
+/**
+ * A dummy view that renders nothing. This is used for invisible HTML elements
+ * like <head>.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class NullView
+ extends View
+{
+
+ /**
+ * Creates a new NullView.
+ *
+ * @param elem the element
+ */
+ public NullView(Element elem)
+ {
+ super(elem);
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void paint(Graphics g, Shape s)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Returns zero for both directions.
+ */
+ public float getPreferredSpan(int axis)
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the allocation of this view, which should be empty anyway.
+ */
+ public Shape modelToView(int pos, Shape a, Bias b)
+ throws BadLocationException
+ {
+ return a;
+ }
+
+ /**
+ * Returns the start offset of the element.
+ */
+ public int viewToModel(float x, float y, Shape a, Bias[] b)
+ {
+ return getElement().getStartOffset();
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/ObjectView.java b/libjava/classpath/javax/swing/text/html/ObjectView.java
new file mode 100644
index 00000000000..d6a77c06aad
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ObjectView.java
@@ -0,0 +1,110 @@
+/* ObjectView.java -- A view for HTML object tags
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Component;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+
+/**
+ * A view for HTML <code>&lt;object&gt;</code> tags.
+ *
+ * This is a {@link ComponentView} that creates special components depending
+ * on the object specification. If the object tag has a classid attribute, then
+ * this view will try to load the class specified by this attribute using the
+ * classloader that loaded the associated document. If the class could be
+ * loaded, an instance is created and the type narrowed to {@link Component}.
+ *
+ * It is also possible to set bean properties on the created component using
+ * nested <code>&lt;param&gt;</code> tags. For example:
+ * <pre>
+ * <object classid="javax.swing.JLabel">
+ * <param name="text" value="sample text">
+ * </object>
+ * </pre>
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class ObjectView extends ComponentView
+{
+
+ /**
+ * Creates a new <code>ObjectView</code>.
+ *
+ * @param el the element for which to create a view
+ */
+ public ObjectView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Creates a component based on the specification in the element of this
+ * view. See the class description for details.
+ */
+ protected Component createComponent()
+ {
+ Component comp = null;
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ String classId = (String) atts.getAttribute("classid");
+ try
+ {
+ Class objectClass = Class.forName(classId);
+ Object instance = objectClass.newInstance();
+ comp = (Component) instance;
+ }
+ catch (ClassNotFoundException ex)
+ {
+ // Ignored.
+ }
+ catch (IllegalAccessException ex)
+ {
+ // Ignored.
+ }
+ catch (InstantiationException ex)
+ {
+ // Ignored.
+ }
+ // FIXME: Handle param tags and set bean properties accordingly.
+ return comp;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/Option.java b/libjava/classpath/javax/swing/text/html/Option.java
new file mode 100644
index 00000000000..1def51b2f59
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/Option.java
@@ -0,0 +1,157 @@
+/* Option.java -- Value class for <option> list model elements
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import javax.swing.text.AttributeSet;
+
+/**
+ * Value class for the combobox model that renders <code>&lt;option&gt;</code>
+ * elements.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class Option
+{
+
+ /**
+ * The attributes of the <option> tag.
+ */
+ private AttributeSet attributes;
+
+ /**
+ * The label.
+ */
+ private String label;
+
+ /**
+ * The selected state of this label.
+ */
+ private boolean selected;
+
+ /**
+ * Creates a new <code>Option</code> instance that uses the specified
+ * tag attributes.
+ *
+ * @param attr the attributes to use
+ */
+ public Option(AttributeSet attr)
+ {
+ attributes = attr;
+ label = null;
+ selected = false;
+ // FIXME: Probably initialize something using the attributes.
+ }
+
+ /**
+ * Sets the label to use for this <code>&lt;option&gt;</code> tag.
+ *
+ * @param l the label to set
+ */
+ public void setLabel(String l)
+ {
+ label = l;
+ }
+
+ /**
+ * Returns the label of this <code>&lt;option&gt;</code> tag.
+ *
+ * @return the label of this <code>&lt;option&gt;</code> tag
+ */
+ public String getLabel()
+ {
+ return label;
+ }
+
+ /**
+ * Returns the attributes used to render this <code>&lt;option&gt;</code>
+ * tag.
+ *
+ * @return the attributes used to render this <code>&lt;option&gt;</code> tag
+ */
+ public AttributeSet getAttributes()
+ {
+ return attributes;
+ }
+
+ /**
+ * Returns a string representation of this <code>&lt;option&gt;</code> tag.
+ * This returns the <code>label</code> property.
+ *
+ * @return a string representation of this <code>&lt;option&gt;</code> tag
+ */
+ public String toString()
+ {
+ return label;
+ }
+
+ /**
+ * Sets the selected state of this <code>&lt;option&gt;</code> tag.
+ *
+ * @param s the selected state to set
+ */
+ protected void setSelection(boolean s)
+ {
+ selected = s;
+ }
+
+ /**
+ * Returns <code>true</code> when this option is selected, <code>false</code>
+ * otherwise.
+ *
+ * @return <code>true</code> when this option is selected, <code>false</code>
+ * otherwise
+ */
+ public boolean isSelected()
+ {
+ return selected;
+ }
+
+ /**
+ * Returns the string associated with the <code>value</code> attribute or
+ * the label, if no such attribute is specified.
+ *
+ * @return the string associated with the <code>value</code> attribute or
+ * the label, if no such attribute is specified
+ */
+ public String getValue()
+ {
+ // FIXME: Return some attribute here if specified.
+ return label;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/ParagraphView.java b/libjava/classpath/javax/swing/text/html/ParagraphView.java
new file mode 100644
index 00000000000..2339f4e661d
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ParagraphView.java
@@ -0,0 +1,209 @@
+/* ParagraphView.java -- Renders a paragraph in HTML
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Graphics;
+import java.awt.Shape;
+
+import javax.swing.SizeRequirements;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+
+/**
+ * Renders a paragraph in HTML. This is a subclass of
+ * {@link javax.swing.text.ParagraphView} with some adjustments for
+ * understanding stylesheets.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class ParagraphView
+ extends javax.swing.text.ParagraphView
+{
+
+ /**
+ * Creates a new ParagraphView for the specified element.
+ *
+ * @param element the element
+ */
+ public ParagraphView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Sets the parent of this view. This is implemented to call the parent
+ * functionality and then trigger {@link #setPropertiesFromAttributes} in
+ * order to load the stylesheet attributes.
+ *
+ * @param parent the parent view to set
+ */
+ public void setParent(View parent)
+ {
+ super.setParent(parent);
+ if (parent != null)
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Returns the attributes used by this view. This is implemented to multiplex
+ * the attributes of the model with the attributes of the stylesheet.
+ */
+ public AttributeSet getAttributes()
+ {
+ // FIXME: Implement this multiplexing thing.
+ return super.getAttributes();
+ }
+
+ /**
+ * Loads the visual properties of the ParagraphView from the element's
+ * attributes and the stylesheet of the HTML document.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ // FIXME: Implement this.
+ }
+
+ /**
+ * Returns the stylesheet used by this view.
+ *
+ * @return the stylesheet used by this view
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document doc = getDocument();
+ StyleSheet styleSheet = null;
+ if (doc instanceof HTMLDocument)
+ styleSheet = ((HTMLDocument) doc).getStyleSheet();
+ return styleSheet;
+ }
+
+ /**
+ * Calculates the minor axis requirements of this view. This is implemented
+ * to return the super class'es requirements and modifies the minimumSpan
+ * slightly so that it is not smaller than the length of the longest word.
+ *
+ * @param axis the axis
+ * @param r the SizeRequirements object to be used as return parameter;
+ * if <code>null</code> a new one will be created
+ *
+ * @return the requirements along the minor layout axis
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ // FIXME: Implement the above specified behaviour.
+ return super.calculateMinorAxisRequirements(axis, r);
+ }
+
+ /**
+ * Determines if this view is visible or not. If none of the children is
+ * visible and the only visible child is the break that ends the paragraph,
+ * this paragraph is not considered to be visible.
+ *
+ * @return the visibility of this paragraph
+ */
+ public boolean isVisible()
+ {
+ // FIXME: Implement the above specified behaviour.
+ return super.isVisible();
+ }
+
+ /**
+ * Paints this view. This delegates to the superclass after the coordinates
+ * have been updated for tab calculations.
+ *
+ * @param g the graphics object
+ * @param a the current allocation of this view
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ // FIXME: Implement the above specified behaviour.
+ super.paint(g, a);
+ }
+
+ /**
+ * Returns the preferred span of this view. If this view is not visible,
+ * we return <code>0</code>, otherwise the super class is called.
+ *
+ * @param axis the axis
+ *
+ * @return the preferred span of this view
+ */
+ public float getPreferredSpan(int axis)
+ {
+ float span = 0;
+ if (isVisible())
+ span = super.getPreferredSpan(axis);
+ return span;
+ }
+
+ /**
+ * Returns the minimum span of this view. If this view is not visible,
+ * we return <code>0</code>, otherwise the super class is called.
+ *
+ * @param axis the axis
+ *
+ * @return the minimum span of this view
+ */
+ public float getMinimumSpan(int axis)
+ {
+ float span = 0;
+ if (isVisible())
+ span = super.getMinimumSpan(axis);
+ return span;
+ }
+
+ /**
+ * Returns the maximum span of this view. If this view is not visible,
+ * we return <code>0</code>, otherwise the super class is called.
+ *
+ * @param axis the axis
+ *
+ * @return the maximum span of this view
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float span = 0;
+ if (isVisible())
+ span = super.getMaximumSpan(axis);
+ return span;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/package.html b/libjava/classpath/javax/swing/text/package.html
index 50043b6c4e8..5db555d8898 100644
--- a/libjava/classpath/javax/swing/text/package.html
+++ b/libjava/classpath/javax/swing/text/package.html
@@ -40,7 +40,7 @@ exception statement from your version. -->
<head><title>GNU Classpath - javax.swing.text</title></head>
<body>
-<p></p>
-
+<p>Provides core text classes and interfaces representing models and views
+used by the text components for display and editing of text.</p>
</body>
</html>
diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java
index ae8b99c2fe5..e28c9261bab 100644
--- a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java
+++ b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java
@@ -45,7 +45,6 @@ import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
-import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -60,26 +59,52 @@ import javax.swing.Icon;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
-import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
import javax.swing.event.EventListenerList;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
/**
- * DefaultTreeCellEditor
+ * Participates in the tree cell editing.
+ *
* @author Andrew Selkirk
+ * @author Audrius Meskauskas
*/
public class DefaultTreeCellEditor
implements ActionListener, TreeCellEditor, TreeSelectionListener
{
/**
- * EditorContainer
+ * The gap between the icon and editing component during editing.
+ */
+ static int ICON_TEXT_GAP = 3;
+
+ /**
+ * The left margin of the editing container (the gap between the tree and
+ * the editing component of the editing icon.
+ */
+ static int TREE_ICON_GAP = ICON_TEXT_GAP;
+
+ /**
+ * The number of the fast mouse clicks, required to start the editing
+ * session.
+ */
+ static int CLICK_COUNT_TO_START = 3;
+
+ /**
+ * This container that appears on the tree during editing session.
+ * It contains the editing component displays various other editor -
+ * specific parts like editing icon.
*/
public class EditorContainer extends Container
{
+ /**
+ * Use v 1.5 serial version UID for interoperability.
+ */
+ static final long serialVersionUID = 6470339600449699810L;
+
/**
* Creates an <code>EditorContainer</code> object.
*/
@@ -96,17 +121,11 @@ public class DefaultTreeCellEditor
{
// Do nothing here.
}
-
- /**
- * Returns the preferred size for the Container.
- *
- * @return Dimension of EditorContainer
- */
- public Dimension getPreferredSize()
+
+ public void setBounds(Rectangle bounds)
{
- Dimension containerSize = super.getPreferredSize();
- containerSize.width += DefaultTreeCellEditor.this.offset;
- return containerSize;
+ super.setBounds(bounds);
+ doLayout();
}
/**
@@ -118,63 +137,68 @@ public class DefaultTreeCellEditor
*/
public void paint(Graphics g)
{
- Rectangle tr = tree.getPathBounds(lastPath);
- if (tr != null)
+ if (editingIcon != null)
{
- Insets i = ((DefaultTextField) editingComponent).getBorder()
- .getBorderInsets(this);
- int textIconGap = 3;
- tr.x -= i.left;
-
- // paints icon
- if (editingIcon != null)
- {
- editingIcon.paintIcon(this, g, tr.x - editingIcon.
- getIconWidth()/2, tr.y + i.top + i.bottom);
- tr.x += editingIcon.getIconWidth()/2 + textIconGap;
- }
-
- tr.width += offset;
-
- // paint background
- g.translate(tr.x, tr.y);
- editingComponent.setSize(new Dimension(tr.width, tr.height));
- editingComponent.paint(g);
- g.translate(-tr.x, -tr.y);
+ // From the previous version, the left margin is taken as half
+ // of the icon width.
+ editingIcon.paintIcon(this, g, TREE_ICON_GAP, 0);
}
super.paint(g);
}
/**
- * Lays out this Container. If editing, the editor will be placed at offset
- * in the x direction and 0 for y.
+ * Lays out this Container, moving the editor component to the left
+ * (leaving place for the icon).
*/
public void doLayout()
{
- if (DefaultTreeCellEditor.this.tree.isEditing())
- setLocation(offset, 0);
- super.doLayout();
+ // The offset of the editing component.
+ int eOffset;
+
+ // Move the component to the left, leaving room for the editing icon:
+ if (editingIcon != null)
+ eOffset = TREE_ICON_GAP + editingIcon.getIconWidth() + ICON_TEXT_GAP;
+ else
+ eOffset = 0;
+
+ Rectangle bounds = getBounds();
+ Component c = getComponent(0);
+ c.setLocation(eOffset, 0);
+
+ // Span the editing component near over all window width.
+ c.setSize(bounds.width - eOffset - TREE_ICON_GAP, bounds.height);
+ /*
+ * @specnote the Sun sets some more narrow editing component width (it is
+ * not documented how does it is calculated). However as our text field is
+ * still not able to auto - scroll horizontally, replicating such strategy
+ * would prevent adding extra characters to the text being edited.
+ */
}
}
/**
- * DefaultTextField
+ * The default text field, used in the editing sessions.
*/
public class DefaultTextField extends JTextField
{
+ /**
+ * Use v 1.5 serial version UID for interoperability.
+ */
+ static final long serialVersionUID = -6629304544265300143L;
+
/**
- * border
+ * The border of the text field.
*/
protected Border border;
/**
* Creates a <code>DefaultTextField</code> object.
*
- * @param border the border to use
+ * @param aBorder the border to use
*/
- public DefaultTextField(Border border)
+ public DefaultTextField(Border aBorder)
{
- this.border = border;
+ border = aBorder;
}
/**
@@ -228,6 +252,31 @@ public class DefaultTreeCellEditor
return renderer.getPreferredSize();
}
}
+
+ /**
+ * Listens for the events from the realEditor.
+ */
+ class RealEditorListener implements CellEditorListener
+ {
+ /**
+ * The method is called when the editing has been cancelled.
+ * @param event unused
+ */
+ public void editingCanceled(ChangeEvent event)
+ {
+ cancelCellEditing();
+ }
+
+ /**
+ * The method is called after completing the editing session.
+ *
+ * @param event unused
+ */
+ public void editingStopped(ChangeEvent event)
+ {
+ stopCellEditing();
+ }
+ }
private EventListenerList listenerList = new EventListenerList();
@@ -334,6 +383,9 @@ public class DefaultTreeCellEditor
if (editor == null)
editor = createTreeCellEditor();
+ else
+ editor.addCellEditorListener(new RealEditorListener());
+
realEditor = editor;
lastPath = tree.getLeadSelectionPath();
@@ -342,7 +394,6 @@ public class DefaultTreeCellEditor
setFont(UIManager.getFont("Tree.font"));
setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor"));
editingIcon = renderer.getIcon();
- timer = new javax.swing.Timer(1200, this);
}
/**
@@ -371,7 +422,7 @@ public class DefaultTreeCellEditor
else
renderer.setIcon(renderer.getClosedIcon());
editingIcon = renderer.getIcon();
-
+
editingComponent = getTreeCellEditorComponent(tree, val, true,
expanded, isLeaf, lastRow);
}
@@ -470,20 +521,21 @@ public class DefaultTreeCellEditor
boolean leaf, int row)
{
if (realEditor == null)
- createTreeCellEditor();
+ realEditor = createTreeCellEditor();
return realEditor.getTreeCellEditorComponent(tree, value, isSelected,
expanded, leaf, row);
}
/**
- * Returns the value currently being edited.
+ * Returns the value currently being edited (requests it from the
+ * {@link realEditor}.
*
* @return the value currently being edited
*/
public Object getCellEditorValue()
{
- return editingComponent;
+ return realEditor.getCellEditorValue();
}
/**
@@ -503,12 +555,6 @@ public class DefaultTreeCellEditor
prepareForEditing();
return true;
}
-
- // Cell may not be currently editable, but may need to start timer.
- if (shouldStartEditingTimer(event))
- startEditingTimer();
- else if (timer.isRunning())
- timer.stop();
return false;
}
@@ -532,9 +578,11 @@ public class DefaultTreeCellEditor
*/
public boolean stopCellEditing()
{
- if (editingComponent != null && realEditor.stopCellEditing())
+ if (editingComponent != null)
{
- timer.stop();
+ stopEditingTimer();
+ tree.stopEditing();
+ editingComponent = null;
return true;
}
return false;
@@ -548,15 +596,26 @@ public class DefaultTreeCellEditor
{
if (editingComponent != null)
{
- timer.stop();
- realEditor.cancelCellEditing();
+ tree.cancelEditing();
+ editingComponent = null;
}
+ stopEditingTimer();
+ }
+
+ /**
+ * Stop the editing timer, if it is installed and running.
+ */
+ private void stopEditingTimer()
+ {
+ if (timer != null && timer.isRunning())
+ timer.stop();
}
/**
* Adds a <code>CellEditorListener</code> object to this editor.
- *
- * @param listener the listener to add
+ *
+ * @param listener
+ * the listener to add
*/
public void addCellEditorListener(CellEditorListener listener)
{
@@ -595,21 +654,16 @@ public class DefaultTreeCellEditor
tPath = lastPath;
lastPath = e.getNewLeadSelectionPath();
lastRow = tree.getRowForPath(lastPath);
- configureEditingComponent(tree, renderer, realEditor);
+ stopCellEditing();
}
/**
- * Messaged when the timer fires, this will start the editing session.
+ * Messaged when the timer fires.
*
* @param e the event that characterizes the action.
*/
public void actionPerformed(ActionEvent e)
{
- if (lastPath != null && tPath != null && tPath.equals(lastPath))
- {
- tree.startEditingAtPath(lastPath);
- timer.stop();
- }
}
/**
@@ -639,13 +693,11 @@ public class DefaultTreeCellEditor
}
/**
- * Starts the editing timer.
+ * Starts the editing timer (if one installed).
*/
protected void startEditingTimer()
{
- if (timer == null)
- timer = new javax.swing.Timer(1200, this);
- if (!timer.isRunning())
+ if (timer != null)
timer.start();
}
@@ -713,6 +765,7 @@ public class DefaultTreeCellEditor
*/
protected void prepareForEditing()
{
+ editingContainer.removeAll();
editingContainer.add(editingComponent);
}
@@ -734,8 +787,11 @@ public class DefaultTreeCellEditor
*/
protected TreeCellEditor createTreeCellEditor()
{
- realEditor = new DefaultCellEditor(new DefaultTreeCellEditor.DefaultTextField(
+ DefaultCellEditor editor = new DefaultCellEditor(new DefaultTreeCellEditor.DefaultTextField(
UIManager.getBorder("Tree.selectionBorder")));
- return realEditor;
+ editor.addCellEditorListener(new RealEditorListener());
+ editor.setClickCountToStart(CLICK_COUNT_TO_START);
+ realEditor = editor;
+ return editor;
}
}
diff --git a/libjava/classpath/javax/swing/undo/StateEdit.java b/libjava/classpath/javax/swing/undo/StateEdit.java
index 80e4e33ec29..326abea1f4e 100644
--- a/libjava/classpath/javax/swing/undo/StateEdit.java
+++ b/libjava/classpath/javax/swing/undo/StateEdit.java
@@ -104,9 +104,11 @@ public class StateEdit
* System (RCS). This certainly should not be part of the API
* specification. But in order to be API-compatible with
* Sun&#x2019;s reference implementation, GNU Classpath also has to
- * provide this field. However, we do not try to match its value.
+ * provide this field and match its value. The value used here has
+ * been in every JDK release at least from 1.2 to 1.5.
*/
- protected static final String RCSID = "";
+ protected static final String RCSID = "$" +
+ "Id: StateEdit.java,v 1.6 1997/10/01 20:05:51 sandipc Exp $";
/**
diff --git a/libjava/classpath/javax/swing/undo/StateEditable.java b/libjava/classpath/javax/swing/undo/StateEditable.java
index 9a7fb09545d..bec396e1e20 100644
--- a/libjava/classpath/javax/swing/undo/StateEditable.java
+++ b/libjava/classpath/javax/swing/undo/StateEditable.java
@@ -78,9 +78,11 @@ public interface StateEditable
* System (RCS). This certainly should not be part of the API
* specification. But in order to be API-compatible with
* Sun&#x2019;s reference implementation, GNU Classpath also has to
- * provide this field. However, we do not try to match its value.
+ * provide this field and match its value. The value used here has
+ * been in every JDK release at least from 1.2 to 1.5.
*/
- String RCSID = "";
+ String RCSID = "$" +
+ "Id: StateEditable.java,v 1.2 1997/09/08 19:39:08 marklin Exp $";
/**