summaryrefslogtreecommitdiff
path: root/javax/swing
diff options
context:
space:
mode:
Diffstat (limited to 'javax/swing')
-rw-r--r--javax/swing/AbstractAction.java6
-rw-r--r--javax/swing/BoxLayout.java11
-rw-r--r--javax/swing/JComponent.java19
-rw-r--r--javax/swing/JEditorPane.java139
-rw-r--r--javax/swing/JFileChooser.java10
-rw-r--r--javax/swing/JFormattedTextField.java427
-rw-r--r--javax/swing/JInternalFrame.java1
-rw-r--r--javax/swing/JLayeredPane.java7
-rw-r--r--javax/swing/JList.java14
-rw-r--r--javax/swing/JMenuItem.java12
-rw-r--r--javax/swing/JProgressBar.java3
-rw-r--r--javax/swing/JTable.java81
-rw-r--r--javax/swing/JTextArea.java6
-rw-r--r--javax/swing/JTextPane.java41
-rw-r--r--javax/swing/JTree.java1
-rw-r--r--javax/swing/JViewport.java8
-rw-r--r--javax/swing/LookAndFeel.java4
-rw-r--r--javax/swing/Popup.java3
-rw-r--r--javax/swing/RepaintManager.java9
-rw-r--r--javax/swing/SwingUtilities.java26
-rw-r--r--javax/swing/TransferHandler.java43
-rw-r--r--javax/swing/UIDefaults.java9
-rw-r--r--javax/swing/ViewportLayout.java26
-rw-r--r--javax/swing/event/EventListenerList.java2
-rw-r--r--javax/swing/plaf/basic/BasicComboBoxUI.java14
-rw-r--r--javax/swing/plaf/basic/BasicComboPopup.java1
-rw-r--r--javax/swing/plaf/basic/BasicFileChooserUI.java107
-rw-r--r--javax/swing/plaf/basic/BasicHTML.java154
-rw-r--r--javax/swing/plaf/basic/BasicListUI.java233
-rw-r--r--javax/swing/plaf/basic/BasicLookAndFeel.java850
-rw-r--r--javax/swing/plaf/basic/BasicMenuItemUI.java30
-rw-r--r--javax/swing/plaf/basic/BasicScrollPaneUI.java3
-rw-r--r--javax/swing/plaf/basic/BasicTabbedPaneUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicTextUI.java103
-rw-r--r--javax/swing/plaf/basic/BasicTreeUI.java533
-rw-r--r--javax/swing/plaf/metal/MetalFileChooserUI.java819
-rw-r--r--javax/swing/plaf/metal/MetalLookAndFeel.java211
-rw-r--r--javax/swing/plaf/metal/MetalRadioButtonUI.java2
-rw-r--r--javax/swing/plaf/metal/MetalSplitPaneDivider.java6
-rw-r--r--javax/swing/text/AbstractDocument.java24
-rw-r--r--javax/swing/text/DefaultCaret.java7
-rw-r--r--javax/swing/text/DefaultEditorKit.java51
-rw-r--r--javax/swing/text/DefaultFormatter.java2
-rw-r--r--javax/swing/text/DefaultFormatterFactory.java280
-rw-r--r--javax/swing/text/DefaultStyledDocument.java602
-rw-r--r--javax/swing/text/GapContent.java6
-rw-r--r--javax/swing/text/InternationalFormatter.java2
-rw-r--r--javax/swing/text/JTextComponent.java49
-rw-r--r--javax/swing/text/StyleContext.java5
-rw-r--r--javax/swing/text/StyledEditorKit.java33
-rw-r--r--javax/swing/text/TableView.java465
-rw-r--r--javax/swing/text/View.java8
-rw-r--r--javax/swing/text/html/BlockView.java301
-rw-r--r--javax/swing/text/html/CSS.java3
-rw-r--r--javax/swing/text/html/CSSParser.java568
-rw-r--r--javax/swing/text/html/HTMLDocument.java1337
-rw-r--r--javax/swing/text/html/HTMLEditorKit.java944
-rw-r--r--javax/swing/text/html/StyleSheet.java937
-rw-r--r--javax/swing/text/html/default.css378
-rw-r--r--javax/swing/tree/DefaultTreeModel.java6
-rw-r--r--javax/swing/tree/DefaultTreeSelectionModel.java2
61 files changed, 8643 insertions, 1345 deletions
diff --git a/javax/swing/AbstractAction.java b/javax/swing/AbstractAction.java
index da65bdd1d..bd3167e1e 100644
--- a/javax/swing/AbstractAction.java
+++ b/javax/swing/AbstractAction.java
@@ -79,7 +79,7 @@ public abstract class AbstractAction
*/
public AbstractAction()
{
- this(""); // TODO: default name
+ this(null);
}
/**
@@ -90,7 +90,7 @@ public abstract class AbstractAction
*/
public AbstractAction(String name)
{
- this(name, null); // TODO: default icon??
+ this(name, null);
}
/**
@@ -174,7 +174,7 @@ public abstract class AbstractAction
public void putValue(String key, Object value)
{
Object old = getValue(key);
- if (old != value)
+ if (old == null || !old.equals(value))
{
store.put(key, value);
firePropertyChange(key, old, value);
diff --git a/javax/swing/BoxLayout.java b/javax/swing/BoxLayout.java
index ebc0b4c21..408dea934 100644
--- a/javax/swing/BoxLayout.java
+++ b/javax/swing/BoxLayout.java
@@ -335,8 +335,15 @@ public class BoxLayout implements LayoutManager2, Serializable
checkTotalRequirements();
Insets i = container.getInsets();
- return new Dimension(xTotal.maximum + i.left + i.right,
- yTotal.maximum + i.top + i.bottom);
+ int xDim = xTotal.maximum + i.left + i.right;
+ int yDim = yTotal.maximum + i.top + i.bottom;
+
+ // Check for overflow
+ if (xDim < xTotal.maximum)
+ xDim = Integer.MAX_VALUE;
+ if (yDim < yTotal.maximum)
+ yDim = Integer.MAX_VALUE;
+ return new Dimension(xDim, yDim);
}
}
diff --git a/javax/swing/JComponent.java b/javax/swing/JComponent.java
index 6f9c9dcf8..b1ad855f2 100644
--- a/javax/swing/JComponent.java
+++ b/javax/swing/JComponent.java
@@ -45,7 +45,6 @@ import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
-import java.awt.FlowLayout;
import java.awt.FocusTraversalPolicy;
import java.awt.Font;
import java.awt.Graphics;
@@ -621,7 +620,6 @@ public abstract class JComponent extends Container implements Serializable
public JComponent()
{
super();
- super.setLayout(new FlowLayout());
setDropTarget(new DropTarget());
defaultLocale = Locale.getDefault();
debugGraphicsOptions = DebugGraphics.NONE_OPTION;
@@ -1296,7 +1294,7 @@ public abstract class JComponent extends Container implements Serializable
{
Dimension prefSize = null;
if (preferredSize != null)
- prefSize = preferredSize;
+ prefSize = new Dimension(preferredSize);
else if (ui != null)
{
@@ -1307,12 +1305,7 @@ public abstract class JComponent extends Container implements Serializable
if (prefSize == null)
prefSize = super.getPreferredSize();
- // make sure that prefSize is not smaller than minSize
- if (minimumSize != null && prefSize != null
- && (minimumSize.width > prefSize.width
- || minimumSize.height > prefSize.height))
- prefSize = new Dimension(Math.max(minimumSize.width, prefSize.width),
- Math.max(minimumSize.height, prefSize.height));
+
return prefSize;
}
@@ -2740,7 +2733,7 @@ public abstract class JComponent extends Container implements Serializable
*/
public void updateUI()
{
- System.out.println("update UI not overwritten in class: " + this);
+ // Nothing to do here.
}
public static Locale getDefaultLocale()
@@ -3271,7 +3264,7 @@ public abstract class JComponent extends Container implements Serializable
Rectangle target = SwingUtilities.convertRectangle(found,
currentClip,
newParent);
- if (target.contains(parRect) || target.intersects(parRect))
+ if (! target.intersection(parRect).equals(target))
{
found = newParent;
currentClip = target;
@@ -3287,10 +3280,12 @@ public abstract class JComponent extends Container implements Serializable
boolean skip = true;
for (int i = children.length - 1; i >= 0; i--)
{
+ boolean nextSkip = skip;
if (children[i] == parent)
- skip = false;
+ 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
diff --git a/javax/swing/JEditorPane.java b/javax/swing/JEditorPane.java
index 6e99a9595..3560ffd57 100644
--- a/javax/swing/JEditorPane.java
+++ b/javax/swing/JEditorPane.java
@@ -43,8 +43,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.HashMap;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleHyperlink;
@@ -88,6 +90,7 @@ import javax.swing.text.html.HTMLEditorKit;
*
* @author original author unknown
* @author Roman Kennke (roman@kennke.org)
+ * @author Anthony Balkissoon abalkiss at redhat dot com
*/
public class JEditorPane extends JTextComponent
{
@@ -507,9 +510,16 @@ public class JEditorPane extends JTextComponent
private EditorKit editorKit;
boolean focus_root;
+
+ // A mapping between content types and registered EditorKit types
+ static HashMap registerMap;
+
+ // A mapping between content types and used EditorKits
+ HashMap editorMap;
public JEditorPane()
{
+ init();
setEditorKit(createDefaultEditorKit());
}
@@ -520,24 +530,69 @@ public class JEditorPane extends JTextComponent
public JEditorPane(String type, String text)
{
+ init();
setEditorKit(createEditorKitForContentType(type));
setText(text);
}
public JEditorPane(URL url) throws IOException
{
- this();
+ init ();
+ setEditorKit (createEditorKitForContentType("text/html"));;
setPage(url);
}
+
+ /**
+ * Called by the constructors to set up the default bindings for content
+ * types and EditorKits.
+ */
+ void init()
+ {
+ editorMap = new HashMap();
+ registerMap = new HashMap();
+ registerEditorKitForContentType("application/rtf",
+ "javax.swing.text.rtf.RTFEditorKit");
+ registerEditorKitForContentType("text/plain",
+ "javax.swing.JEditorPane$PlainEditorKit");
+ registerEditorKitForContentType("text/html",
+ "javax.swing.text.html.HTMLEditorKit");
+ registerEditorKitForContentType("text/rtf",
+ "javax.swing.text.rtf.RTFEditorKit");
+ }
protected EditorKit createDefaultEditorKit()
{
return new PlainEditorKit();
}
+ /**
+ * Creates and returns an EditorKit that is appropriate for the given
+ * content type. This is created using the default recognized types
+ * plus any EditorKit types that have been registered.
+ *
+ * @see #registerEditorKitForContentType(String, String)
+ * @see #registerEditorKitForContentType(String, String, ClassLoader)
+ * @param type the content type
+ * @return an EditorKit for use with the given content type
+ */
public static EditorKit createEditorKitForContentType(String type)
{
- return new PlainEditorKit();
+ // TODO: Have to handle the case where a ClassLoader was specified
+ // when the EditorKit was registered
+ EditorKit e = null;
+ String className = (String)registerMap.get(type);
+ if (className != null)
+ {
+ try
+ {
+ e = (EditorKit) Class.forName(className).newInstance();
+ }
+ catch (Exception e2)
+ {
+ // TODO: Not sure what to do here.
+ }
+ }
+ return e;
}
/**
@@ -586,14 +641,44 @@ public class JEditorPane extends JTextComponent
return editorKit;
}
+ /**
+ * Returns the class name of the EditorKit associated with the given
+ * content type.
+ *
+ * @since 1.3
+ * @param type the content type
+ * @return the class name of the EditorKit associated with this content type
+ */
public static String getEditorKitClassNameForContentType(String type)
{
- return "text/plain";
+ return (String) registerMap.get(type);
}
+ /**
+ * Returns the EditorKit to use for the given content type. If an
+ * EditorKit has been explicitly set via
+ * <code>setEditorKitForContentType</code>
+ * then it will be returned. Otherwise an attempt will be made to create
+ * an EditorKit from the default recognzied content types or any
+ * EditorKits that have been registered. If none can be created, a
+ * PlainEditorKit is created.
+ *
+ * @see #registerEditorKitForContentType(String, String)
+ * @see #registerEditorKitForContentType(String, String, ClassLoader)
+ * @param type the content type
+ * @return an appropriate EditorKit for the given content type
+ */
public EditorKit getEditorKitForContentType(String type)
{
- return editorKit;
+ // First check if an EditorKit has been explicitly set.
+ EditorKit e = (EditorKit) editorMap.get(type);
+ // Then check to see if we can create one.
+ if (e == null)
+ e = createEditorKitForContentType(type);
+ // Otherwise default to PlainEditorKit.
+ if (e == null)
+ e = new PlainEditorKit();
+ return e;
}
/**
@@ -677,12 +762,17 @@ public class JEditorPane extends JTextComponent
}
/**
- * Establishes the default bindings of type to classname.
+ * Establishes a binding between type and classname. This enables
+ * us to create an EditorKit later for the given content type.
+ *
+ * @param type the content type
+ * @param classname the name of the class that is associated with this
+ * content type
*/
public static void registerEditorKitForContentType(String type,
String classname)
{
- // TODO: Implement this properly.
+ registerMap.put(type, classname);
}
/**
@@ -702,6 +792,7 @@ public class JEditorPane extends JTextComponent
public void replaceSelection(String content)
{
// TODO: Implement this properly.
+ super.replaceSelection(content);
}
/**
@@ -749,9 +840,14 @@ public class JEditorPane extends JTextComponent
accessibleContext = null;
}
+ /**
+ * Explicitly sets an EditorKit to be used for the given content type.
+ * @param type the content type
+ * @param k the EditorKit to use for the given content type
+ */
public void setEditorKitForContentType(String type, EditorKit k)
{
- // FIXME: editorKitCache.put(type, kit);
+ editorMap.put(type, k);
}
/**
@@ -781,9 +877,36 @@ public class JEditorPane extends JTextComponent
}
}
+ /**
+ * Sets the text of the JEditorPane. The argument <code>t</code>
+ * is expected to be in the format of the current EditorKit. This removes
+ * the content of the current document and uses the EditorKit to read in the
+ * new text. This allows the EditorKit to handle the String rather than just
+ * inserting in plain text.
+ *
+ * @param t the text to display in this JEditorPane
+ */
public void setText(String t)
{
- super.setText(t);
+ try
+ {
+ // Remove the current content.
+ Document doc = getDocument();
+ doc.remove(0, doc.getLength());
+ if (t == null || t == "")
+ return;
+
+ // Let the EditorKit read the text into the Document.
+ getEditorKit().read(new StringReader(t), doc, 0);
+ }
+ catch (BadLocationException ble)
+ {
+ // TODO: Don't know what to do here.
+ }
+ catch (IOException ioe)
+ {
+ // TODO: Don't know what to do here.
+ }
}
/**
diff --git a/javax/swing/JFileChooser.java b/javax/swing/JFileChooser.java
index fcd0aff65..3a9d6a01f 100644
--- a/javax/swing/JFileChooser.java
+++ b/javax/swing/JFileChooser.java
@@ -40,6 +40,7 @@ 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;
@@ -657,7 +658,8 @@ public class JFileChooser extends JComponent implements Accessible
retval = ERROR_OPTION;
- d.pack();
+ Insets i = d.getInsets();
+ d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height);
d.show();
return retval;
}
@@ -681,7 +683,8 @@ public class JFileChooser extends JComponent implements Accessible
retval = ERROR_OPTION;
- d.pack();
+ Insets i = d.getInsets();
+ d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height);
d.show();
return retval;
}
@@ -707,7 +710,8 @@ public class JFileChooser extends JComponent implements Accessible
retval = ERROR_OPTION;
- d.pack();
+ Insets i = d.getInsets();
+ d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height);
d.show();
return retval;
}
diff --git a/javax/swing/JFormattedTextField.java b/javax/swing/JFormattedTextField.java
index 9890df200..761955d6d 100644
--- a/javax/swing/JFormattedTextField.java
+++ b/javax/swing/JFormattedTextField.java
@@ -40,15 +40,21 @@ package javax.swing;
import java.awt.event.FocusEvent;
import java.io.Serializable;
+import java.text.DateFormat;
import java.text.Format;
+import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Date;
+import javax.swing.text.AbstractDocument;
import javax.swing.text.DateFormatter;
import javax.swing.text.DefaultFormatter;
+import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
+import javax.swing.text.InternationalFormatter;
import javax.swing.text.NavigationFilter;
+import javax.swing.text.NumberFormatter;
/**
* A text field that makes use of a formatter to display and edit a specific
@@ -62,6 +68,7 @@ import javax.swing.text.NavigationFilter;
* formatting of the value of the JFormattedTextField.
*
* @author Michael Koch
+ * @author Anthony Balkissoon abalkiss at redhat dot com
*
* @since 1.4
*/
@@ -85,58 +92,184 @@ public class JFormattedTextField extends JTextField
//Do nothing here.
}
+ /**
+ * Clones the AbstractFormatter and removes the association to any
+ * particular JFormattedTextField.
+ *
+ * @return a clone of this formatter with no association to any particular
+ * JFormattedTextField
+ * @throws CloneNotSupportedException if the Object's class doesn't support
+ * the {@link Cloneable} interface
+ */
protected Object clone ()
throws CloneNotSupportedException
{
- throw new InternalError ("not implemented");
+ // Clone this formatter.
+ AbstractFormatter newFormatter = (AbstractFormatter)super.clone();
+
+ // And remove the association to the JFormattedTextField.
+ newFormatter.textField = null;
+ return newFormatter;
}
+ /**
+ * Returns a custom set of Actions that this formatter supports. Should
+ * be subclassed by formatters that have a custom set of Actions.
+ *
+ * @return <code>null</code>. Should be subclassed by formatters that want
+ * to install custom Actions on the JFormattedTextField.
+ */
protected Action[] getActions ()
{
- return textField.getActions();
+ return null;
}
+ /**
+ * Gets the DocumentFilter for this formatter. Should be subclassed
+ * by formatters wishing to install a filter that oversees Document
+ * mutations.
+ *
+ * @return <code>null</code>. Should be subclassed by formatters
+ * that want to restrict Document mutations.
+ */
protected DocumentFilter getDocumentFilter ()
{
- throw new InternalError ("not implemented");
+ // Subclasses should override this if they want to install a
+ // DocumentFilter.
+ return null;
}
+ /**
+ * Returns the JFormattedTextField on which this formatter is
+ * currently installed.
+ *
+ * @return the JFormattedTextField on which this formatter is currently
+ * installed
+ */
protected JFormattedTextField getFormattedTextField ()
{
return textField;
}
+ /**
+ * Gets the NavigationFilter for this formatter. Should be subclassed
+ * by formatters (such as {@link DefaultFormatter}) that wish to
+ * restrict where the cursor can be placed within the text field.
+ *
+ * @return <code>null</code>. Subclassed by formatters that want to restrict
+ * cursor location within the JFormattedTextField.
+ */
protected NavigationFilter getNavigationFilter ()
{
- return textField.getNavigationFilter();
+ // This should be subclassed if the formatter wants to install
+ // a NavigationFilter on the JFormattedTextField.
+ return null;
}
+ /**
+ * Installs this formatter on the specified JFormattedTextField. This
+ * converts the current value to a displayable String and displays it,
+ * and installs formatter specific Actions from <code>getActions</code>.
+ * It also installs a DocumentFilter and NavigationFilter on the
+ * JFormattedTextField.
+ * <p>
+ * If there is a <code>ParseException</code> this sets the text to an
+ * empty String and marks the text field in an invalid state.
+ *
+ * @param textField the JFormattedTextField on which to install this
+ * formatter
+ */
public void install(JFormattedTextField textField)
{
+ // Uninstall the current textfield.
if (this.textField != null)
- uninstall();
+ uninstall();
this.textField = textField;
+
+ // Install some state on the text field, including display text,
+ // DocumentFilter, NavigationFilter, and formatter specific Actions.
+ if (textField != null)
+ {
+ try
+ {
+ // Set the text of the field.
+ textField.setText(valueToString(textField.getValue()));
+ Document doc = textField.getDocument();
+
+ // Set the DocumentFilter for the field's Document.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument)doc).setDocumentFilter(getDocumentFilter());
+
+ // Set the NavigationFilter.
+ textField.setNavigationFilter(getNavigationFilter());
+
+ // Set the Formatter Actions
+ // FIXME: Have to add the actions from getActions()
+ }
+ catch (ParseException pe)
+ {
+ // Set the text to an empty String and mark the field as invalid.
+ textField.setText("");
+ setEditValid(false);
+ }
+ }
}
+ /**
+ * Clears the state installed on the JFormattedTextField by the formatter.
+ * This resets the DocumentFilter, NavigationFilter, and any additional
+ * Actions (returned by <code>getActions()</code>).
+ */
public void uninstall ()
{
+ // Set the DocumentFilter for the field's Document.
+ Document doc = textField.getDocument();
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument)doc).setDocumentFilter(null);
+ textField.setNavigationFilter(null);
+ // FIXME: Have to remove the Actions from getActions()
this.textField = null;
}
+ /**
+ * Invoke this method when invalid values are entered. This forwards the
+ * call to the JFormattedTextField.
+ */
protected void invalidEdit ()
{
textField.invalidEdit();
}
+ /**
+ * This method updates the <code>editValid</code> property of
+ * JFormattedTextField.
+ *
+ * @param valid the new state for the <code>editValid</code> property
+ */
protected void setEditValid (boolean valid)
{
textField.editValid = valid;
}
+ /**
+ * Parses <code>text</code> to return a corresponding Object.
+ *
+ * @param text the String to parse
+ * @return an Object that <code>text</code> represented
+ * @throws ParseException if there is an error in the conversion
+ */
public abstract Object stringToValue (String text)
throws ParseException;
+ /**
+ * Returns a String to be displayed, based on the Object
+ * <code>value</code>.
+ *
+ * @param value the Object from which to generate a String
+ * @return a String to be displayed
+ * @throws ParseException if there is an error in the conversion
+ */
public abstract String valueToString (Object value)
throws ParseException;
}
@@ -155,88 +288,177 @@ public class JFormattedTextField extends JTextField
public abstract AbstractFormatter getFormatter (JFormattedTextField tf);
}
- static class FormatterFactoryWrapper extends AbstractFormatterFactory
- {
- AbstractFormatter formatter;
-
- public FormatterFactoryWrapper(AbstractFormatter formatter)
- {
- this.formatter = formatter;
- }
-
- public AbstractFormatter getFormatter(JFormattedTextField tf)
- {
- return formatter;
- }
- }
-
+ /** The possible focusLostBehavior options **/
public static final int COMMIT = 0;
public static final int COMMIT_OR_REVERT = 1;
public static final int REVERT = 2;
public static final int PERSIST = 3;
+ /** The most recent valid and committed value **/
private Object value;
+
+ /** The behaviour for when this text field loses focus **/
private int focusLostBehavior = COMMIT_OR_REVERT;
+
+ /** The formatter factory currently being used **/
private AbstractFormatterFactory formatterFactory;
+
+ /** The formatter currently being used **/
+ private AbstractFormatter formatter;
+
// Package-private to avoid an accessor method.
boolean editValid = true;
+ /**
+ * Creates a JFormattedTextField with no formatter factory.
+ * <code>setValue</code> or <code>setFormatterFactory</code> will
+ * properly configure this text field to edit a particular type
+ * of value.
+ */
public JFormattedTextField ()
{
this((AbstractFormatterFactory) null, null);
}
+ /**
+ * Creates a JFormattedTextField that can handle the specified Format.
+ * An appopriate AbstractFormatter and AbstractFormatterFactory will
+ * be created for the specified Format.
+ *
+ * @param format the Format that this JFormattedTextField should be able
+ * to handle
+ */
public JFormattedTextField (Format format)
{
- throw new InternalError ("not implemented");
+ this ();
+ setFormatterFactory(getAppropriateFormatterFactory(format));
}
+ /**
+ * Creates a JFormattedTextField with the specified formatter. This will
+ * create a {@link DefaultFormatterFactory} with this formatter as the default
+ * formatter.
+ *
+ * @param formatter the formatter to use for this JFormattedTextField
+ */
public JFormattedTextField (AbstractFormatter formatter)
{
- this(new FormatterFactoryWrapper(formatter), null);
+ this(new DefaultFormatterFactory (formatter));
}
+ /**
+ * Creates a JFormattedTextField with the specified formatter factory.
+ *
+ * @param factory the formatter factory to use for this JFormattedTextField
+ */
public JFormattedTextField (AbstractFormatterFactory factory)
{
- this(factory, null);
+ setFormatterFactory(factory);
}
+ /**
+ * Creates a JFormattedTextField with the specified formatter factory and
+ * initial value.
+ *
+ * @param factory the initial formatter factory for this JFormattedTextField
+ * @param value the initial value for the text field
+ */
public JFormattedTextField (AbstractFormatterFactory factory, Object value)
- {
- this.formatterFactory = factory;
- this.value = value;
+ {
+ setFormatterFactory(factory);
+ setValue(value);
}
+ /**
+ * Creates a JFormattedTextField with the specified value. This creates a
+ * formatter and formatterFactory that are appropriate for the value.
+ *
+ * @param value the initial value for this JFormattedTextField
+ */
public JFormattedTextField (Object value)
{
- this.value = value;
+ setValue(value);
+ }
+
+ /**
+ * Returns an AbstractFormatterFactory that will give an appropriate
+ * AbstractFormatter for the given Format.
+ * @param format the Format to match with an AbstractFormatter.
+ * @return a DefaultFormatterFactory whose defaultFormatter is appropriate
+ * for the given Format.
+ */
+ private AbstractFormatterFactory getAppropriateFormatterFactory (Format format)
+ {
+ AbstractFormatter newFormatter;
+ if (format instanceof DateFormat)
+ newFormatter = new DateFormatter((DateFormat)format);
+ else if (format instanceof NumberFormat)
+ newFormatter = new NumberFormatter ((NumberFormat)format);
+ else
+ newFormatter = new InternationalFormatter(format);
+
+ return new DefaultFormatterFactory(newFormatter);
}
+ /**
+ * Forces the current value from the editor to be set as the current
+ * value. If there is no current formatted this has no effect.
+ *
+ * @throws ParseException if the formatter cannot format the current value
+ */
public void commitEdit ()
throws ParseException
{
- throw new InternalError ("not implemented");
+ if (formatter == null)
+ return;
+ // Note: this code is a lot like setValue except that we don't want
+ // to create a new formatter.
+ Object oldValue = this.value;
+
+ this.value = formatter.stringToValue(getText());;
+ editValid = true;
+
+ firePropertyChange("value", oldValue, this.value);
}
+ /**
+ * Gets the command list supplied by the UI augmented by the specific
+ * Actions for JFormattedTextField.
+ *
+ * @return an array of Actions that this text field supports
+ */
public Action[] getActions ()
{
// FIXME: Add JFormattedTextField specific actions
+ // These are related to committing or cancelling edits.
return super.getActions();
}
+ /**
+ * Returns the behaviour of this JFormattedTextField upon losing focus. This
+ * is one of <code>COMMIT</code>, <code>COMMIT_OR_REVERT</code>,
+ * <code>PERSIST</code>, or <code>REVERT</code>.
+ * @return the behaviour upon losing focus
+ */
public int getFocusLostBehavior()
{
return focusLostBehavior;
}
+ /**
+ * Returns the current formatter used for this JFormattedTextField.
+ * @return the current formatter used for this JFormattedTextField
+ */
public AbstractFormatter getFormatter ()
{
- if (formatterFactory == null)
- return null;
-
- return formatterFactory.getFormatter(this);
+ return formatter;
}
-
+
+ /**
+ * Returns the factory currently used to generate formatters for this
+ * JFormattedTextField.
+ * @return the factory currently used to generate formatters
+ */
public AbstractFormatterFactory getFormatterFactory ()
{
return formatterFactory;
@@ -247,31 +469,61 @@ public class JFormattedTextField extends JTextField
return "FormattedTextFieldUI";
}
+ /**
+ * Returns the last valid value. This may not be the value currently shown
+ * in the text field depending on whether or not the formatter commits on
+ * valid edits and allows invalid input to be temporarily displayed.
+ * @return the last committed valid value
+ */
public Object getValue ()
{
return value;
}
+ /**
+ * This method is used to provide feedback to the user when an invalid value
+ * is input during editing.
+ */
protected void invalidEdit ()
{
UIManager.getLookAndFeel().provideErrorFeedback(this);
}
+ /**
+ * Returns true if the current value being edited is valid. This property is
+ * managed by the current formatted.
+ * @return true if the value being edited is valid.
+ */
public boolean isEditValid ()
{
return editValid;
}
+ /**
+ * Processes focus events. This is overridden because we may want to
+ * change the formatted depending on whether or not this field has
+ * focus.
+ *
+ * @param evt the FocusEvent
+ */
protected void processFocusEvent (FocusEvent evt)
{
- // it's safe to simply call super for now, until it gets clear
- // what this method is supposed to do
- // throw new InternalError ("not implemented");
super.processFocusEvent(evt);
+ // Let the formatterFactory change the formatter for this text field
+ // based on whether or not it has focus.
+ setFormatter (formatterFactory.getFormatter(this));
}
-
+
+ /**
+ * Associates this JFormattedTextField with a Document and propagates
+ * a PropertyChange event to each listener.
+ *
+ * @param newDocument the Document to associate with this text field
+ */
public void setDocument(Document newDocument)
{
+ // FIXME: This method should do more than this. Must do some handling
+ // of the DocumentListeners.
Document oldDocument = getDocument();
if (oldDocument == newDocument)
@@ -280,6 +532,16 @@ public class JFormattedTextField extends JTextField
super.setDocument(newDocument);
}
+ /**
+ * Sets the behaviour of this JFormattedTextField upon losing focus.
+ * This must be <code>COMMIT</code>, <code>COMMIT_OR_REVERT</code>,
+ * <code>PERSIST</code>, or <code>REVERT</code> or an
+ * IllegalArgumentException will be thrown.
+ *
+ * @param behavior
+ * @throws IllegalArgumentException if <code>behaviour</code> is not
+ * one of the above
+ */
public void setFocusLostBehavior(int behavior)
{
if (behavior != COMMIT
@@ -291,20 +553,38 @@ public class JFormattedTextField extends JTextField
this.focusLostBehavior = behavior;
}
+ /**
+ * Sets the formatter for this JFormattedTextField. Normally the formatter
+ * factory will take care of this, or calls to setValue will also make sure
+ * that the formatter is set appropriately.
+ *
+ * @param formatter the AbstractFormatter to use for formatting the value for
+ * this JFormattedTextField
+ */
protected void setFormatter (AbstractFormatter formatter)
{
AbstractFormatter oldFormatter = null;
- if (formatterFactory != null)
- oldFormatter = formatterFactory.getFormatter(this);
+ oldFormatter = this.formatter;
- if (oldFormatter == formatter)
- return;
+ if (oldFormatter != null)
+ oldFormatter.uninstall();
+
+ this.formatter = formatter;
+
+ if (formatter != null)
+ formatter.install(this);
- setFormatterFactory(new FormatterFactoryWrapper(formatter));
firePropertyChange("formatter", oldFormatter, formatter);
}
+ /**
+ * Sets the factory from which this JFormattedTextField should obtain
+ * its formatters.
+ *
+ * @param factory the AbstractFormatterFactory that will be used to generate
+ * formatters for this JFormattedTextField
+ */
public void setFormatterFactory (AbstractFormatterFactory factory)
{
if (formatterFactory == factory)
@@ -313,55 +593,56 @@ public class JFormattedTextField extends JTextField
AbstractFormatterFactory oldFactory = formatterFactory;
formatterFactory = factory;
firePropertyChange("formatterFactory", oldFactory, factory);
+
+ // Now set the formatter according to our new factory.
+ if (formatterFactory != null)
+ setFormatter(formatterFactory.getFormatter(this));
+ else
+ setFormatter(null);
}
+ /**
+ * Sets the value that will be formatted and displayed.
+ *
+ * @param newValue the value to be formatted and displayed
+ */
public void setValue (Object newValue)
{
if (value == newValue)
return;
- // format value
- AbstractFormatter formatter = createFormatter(newValue);
- try
- {
- setText(formatter.valueToString(newValue));
- }
- catch (ParseException ex)
- {
- // TODO: what should we do with this?
- }
-
Object oldValue = value;
value = newValue;
+
+ // If there is no formatterFactory then make one.
+ if (formatterFactory == null)
+ setFormatterFactory(createFormatterFactory(newValue));
+
+ // Set the formatter appropriately. This is because there may be a new
+ // formatterFactory from the line above, or we may want a new formatter
+ // depending on the type of newValue (or if newValue is null).
+ setFormatter (formatterFactory.getFormatter(this));
firePropertyChange("value", oldValue, newValue);
}
/**
- * A helper method that attempts to create a formatter that is suitable
- * to format objects of the type like <code>value</code>.
+ * A helper method that attempts to create a formatter factory that is
+ * suitable to format objects of the type like <code>value</code>.
*
- * If <code>formatterFactory</code> is not null and the returned formatter
- * is also not <code>null</code> then this formatter is used. Otherwise we
- * try to create one based on the type of <code>value</code>.
+ * @param value an object which should be formatted by the formatter factory.
*
- * @param value an object which should be formatted by the formatter
- *
- * @return a formatter able to format objects of the class of
+ * @return a formatter factory able to format objects of the class of
* <code>value</code>
*/
- AbstractFormatter createFormatter(Object value)
+ AbstractFormatterFactory createFormatterFactory(Object value)
{
AbstractFormatter formatter = null;
- if (formatterFactory != null
- && formatterFactory.getFormatter(this) != null)
- formatter = formatterFactory.getFormatter(this);
- else
- {
- if (value instanceof Date)
- formatter = new DateFormatter();
- else
- formatter = new DefaultFormatter();
- }
- return formatter;
+ if (value instanceof Date)
+ formatter = new DateFormatter();
+ else if (value instanceof Number)
+ formatter = new NumberFormatter();
+ else
+ formatter = new DefaultFormatter();
+ return new DefaultFormatterFactory(formatter);
}
}
diff --git a/javax/swing/JInternalFrame.java b/javax/swing/JInternalFrame.java
index 479294b13..948988c24 100644
--- a/javax/swing/JInternalFrame.java
+++ b/javax/swing/JInternalFrame.java
@@ -1628,7 +1628,6 @@ public class JInternalFrame extends JComponent implements Accessible,
{
if (! isVisible())
{
- moveToFront();
super.show();
JDesktopPane pane = getDesktopPane();
diff --git a/javax/swing/JLayeredPane.java b/javax/swing/JLayeredPane.java
index 31222778a..b087637b1 100644
--- a/javax/swing/JLayeredPane.java
+++ b/javax/swing/JLayeredPane.java
@@ -436,7 +436,12 @@ public class JLayeredPane extends JComponent implements Accessible
// should have found it
throw new IllegalArgumentException();
- super.swapComponents (curr, targ);
+ if (curr == 0)
+ super.swapComponents(curr, targ);
+ else
+ while (curr > 0)
+ super.swapComponents (curr, --curr);
+
revalidate();
repaint();
}
diff --git a/javax/swing/JList.java b/javax/swing/JList.java
index c089aae10..df2f3f668 100644
--- a/javax/swing/JList.java
+++ b/javax/swing/JList.java
@@ -1070,15 +1070,16 @@ public class JList extends JComponent implements Accessible, Scrollable
layoutOrientation = VERTICAL;
opaque = true;
valueIsAdjusting = false;
- visibleRowCount = 8;
+ visibleRowCount = 7;
cellRenderer = new DefaultListCellRenderer();
listListener = new ListListener();
setModel(new DefaultListModel());
setSelectionModel(createSelectionModel());
- setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
+ setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ setLayout(null);
+
updateUI();
}
@@ -1256,14 +1257,17 @@ public class JList extends JComponent implements Accessible, Scrollable
*
* @param a A number in the half-open range <code>[0, x)</code> where
* <code>x = getModel.getSize()</code>, indicating the index of an
- * element in the list to select.
+ * element in the list to select. When &lt; 0 the selection is cleared.
*
* @see #setSelectionMode
* @see #selectionModel
*/
public void setSelectedIndex(int a)
{
- selectionModel.setSelectionInterval(a, a);
+ if (a < 0)
+ selectionModel.clearSelection();
+ else
+ selectionModel.setSelectionInterval(a, a);
}
/**
diff --git a/javax/swing/JMenuItem.java b/javax/swing/JMenuItem.java
index c87a4dc2b..c3c10d6ef 100644
--- a/javax/swing/JMenuItem.java
+++ b/javax/swing/JMenuItem.java
@@ -117,6 +117,13 @@ public class JMenuItem extends AbstractButton implements Accessible,
super();
super.setAction(action);
init(null, null);
+ if (action != null)
+ {
+ setName((String) action.getValue(Action.NAME));
+ setAccelerator((KeyStroke) action.getValue(Action.ACCELERATOR_KEY));
+ setMnemonic(((Integer) action.getValue(Action.MNEMONIC_KEY)).intValue());
+ setActionCommand((String) action.getValue(Action.ACTION_COMMAND_KEY));
+ }
}
/**
@@ -273,8 +280,9 @@ public class JMenuItem extends AbstractButton implements Accessible,
if (! (this instanceof JMenu) && action != null)
{
setAccelerator((KeyStroke) (action.getValue(Action.ACCELERATOR_KEY)));
- super.registerKeyboardAction(action, accelerator,
- JComponent.WHEN_IN_FOCUSED_WINDOW);
+ if (accelerator != null)
+ super.registerKeyboardAction(action, accelerator,
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
}
}
diff --git a/javax/swing/JProgressBar.java b/javax/swing/JProgressBar.java
index 0de9115dc..abca3e7ae 100644
--- a/javax/swing/JProgressBar.java
+++ b/javax/swing/JProgressBar.java
@@ -262,7 +262,8 @@ public class JProgressBar extends JComponent implements SwingConstants,
{
this.model = model;
changeListener = createChangeListener();
- model.addChangeListener(changeListener);
+ if (model != null)
+ model.addChangeListener(changeListener);
updateUI();
}
diff --git a/javax/swing/JTable.java b/javax/swing/JTable.java
index 14f00e654..fe456cee4 100644
--- a/javax/swing/JTable.java
+++ b/javax/swing/JTable.java
@@ -927,7 +927,47 @@ public class JTable
// TODO Auto-generated method stub
return null;
}
-
+
+ /**
+ * Returns the accessible row at the specified index.
+ *
+ * @param index the index for which to query the row
+ *
+ * @return the row number at the specified table index
+ */
+ public int getAccessibleRowAtIndex(int index)
+ {
+ // TODO: Back this up by a Mauve test and update API docs accordingly.
+ return index / getColumnCount();
+ }
+
+ /**
+ * Returns the accessible column at the specified index.
+ *
+ * @param index the index for which to query the column
+ *
+ * @return the column number at the specified table index
+ */
+ public int getAccessibleColumnAtIndex(int index)
+ {
+ // TODO: Back this up by a Mauve test and update API docs accordingly.
+ return index % getColumnCount();
+ }
+
+ /**
+ * Returns the accessible child index at the specified column and row.
+ *
+ * @param row the row
+ * @param column the column
+ *
+ * @return the index of the accessible child at the specified row and
+ * column
+ */
+ public int getAccessibleIndexAt(int row, int column)
+ {
+ // TODO: Back this up by a Mauve test and update API docs accordingly.
+ return row * getColumnCount() + column;
+ }
}
/**
* Handles property changes from the <code>TableColumn</code>s of this
@@ -1464,6 +1504,12 @@ public class JTable
new TableColumnPropertyChangeHandler();
/**
+ * Whether cell editors should receive keyboard focus when the table is
+ * activated.
+ */
+ private boolean surrendersFocusOnKeystroke = false;
+
+ /**
* Creates a new <code>JTable</code> instance.
*/
public JTable ()
@@ -3281,4 +3327,37 @@ public class JTable
revalidate();
repaint();
}
+
+ /**
+ * Sets whether cell editors of this table should receive keyboard focus
+ * when the editor is activated by a keystroke. The default setting is
+ * <code>false</code> which means that the table should keep the keyboard
+ * focus until the cell is selected by a mouse click.
+ *
+ * @param value the value to set
+ *
+ * @since 1.4
+ */
+ public void setSurrendersFocusOnKeystroke(boolean value)
+ {
+ // 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
+ * <code>false</code> which means that the table should keep the keyboard
+ * focus until the cell is selected by a mouse click.
+ *
+ * @return whether cell editors of this table should receive keyboard focus
+ * when the editor is activated by a keystroke
+ *
+ * @since 1.4
+ */
+ public boolean getSurrendersFocusOnKeystroke()
+ {
+ // TODO: Implement functionality of this property (in UI impl).
+ return surrendersFocusOnKeystroke;
+ }
}
diff --git a/javax/swing/JTextArea.java b/javax/swing/JTextArea.java
index 2fa185b62..9b50febe3 100644
--- a/javax/swing/JTextArea.java
+++ b/javax/swing/JTextArea.java
@@ -217,7 +217,11 @@ public class JTextArea extends JTextComponent
public JTextArea(Document doc, String text, int rows, int columns)
{
setDocument(doc == null ? createDefaultModel() : doc);
- setText(text);
+ // Only explicitly setText() when there is actual text since
+ // setText() might be overridden and not expected to be called
+ // from the constructor (as in JEdit).
+ if (text != null)
+ setText(text);
setRows(rows);
setColumns(columns);
}
diff --git a/javax/swing/JTextPane.java b/javax/swing/JTextPane.java
index a2aebd4ca..7c95d7682 100644
--- a/javax/swing/JTextPane.java
+++ b/javax/swing/JTextPane.java
@@ -40,6 +40,7 @@ package javax.swing;
import java.awt.Component;
+import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
@@ -151,38 +152,34 @@ public class JTextPane
{
Caret caret = getCaret();
StyledDocument doc = getStyledDocument();
+ AttributeSet a = getInputAttributes().copyAttributes();
+ if (doc == null)
+ return;
int dot = caret.getDot();
int mark = caret.getMark();
- // If content is empty delete selection.
- if (content == null)
- {
- caret.setDot(dot);
- return;
- }
+ int p0 = Math.min (dot, mark);
+ int p1 = Math.max (dot, mark);
try
{
- int start = getSelectionStart();
- int end = getSelectionEnd();
- int contentLength = content.length();
-
- // Remove selected text.
- if (dot != mark)
- doc.remove(start, end - start);
-
- // Insert new text.
- doc.insertString(start, content, null);
- // Set attributes for inserted text
- doc.setCharacterAttributes(start, contentLength, getInputAttributes(),
- true);
-
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument)doc).replace(p0, p1 - p0, content, a);
+ else
+ {
+ // Remove selected text.
+ if (dot != mark)
+ doc.remove(p0, p1 - p0);
+ // Insert new text.
+ if (content != null && content.length() > 0)
+ doc.insertString(p0, content, a);
+ }
}
catch (BadLocationException e)
{
- throw new AssertionError
- ("No BadLocationException should be thrown here");
+ throw new AssertionError
+ ("No BadLocationException should be thrown here");
}
}
diff --git a/javax/swing/JTree.java b/javax/swing/JTree.java
index bd71035dd..d566f5351 100644
--- a/javax/swing/JTree.java
+++ b/javax/swing/JTree.java
@@ -1481,6 +1481,7 @@ public class JTree extends JComponent implements Scrollable, Accessible
setRootVisible(true);
setModel(model);
setSelectionModel(new EmptySelectionModel());
+ selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
}
/**
diff --git a/javax/swing/JViewport.java b/javax/swing/JViewport.java
index 285a7bf59..3a1632730 100644
--- a/javax/swing/JViewport.java
+++ b/javax/swing/JViewport.java
@@ -424,8 +424,9 @@ public class JViewport extends JComponent implements Accessible
public void setView(Component v)
{
- if (viewListener != null)
- getView().removeComponentListener(viewListener);
+ Component currView = getView();
+ if (viewListener != null && currView != null)
+ currView.removeComponentListener(viewListener);
if (v != null)
{
@@ -786,6 +787,9 @@ public class JViewport extends JComponent implements Accessible
*/
void paintSimple(Graphics g)
{
+ // We need to call this to properly clear the background.
+ paintComponent(g);
+
Point pos = getViewPosition();
Component view = getView();
boolean translated = false;
diff --git a/javax/swing/LookAndFeel.java b/javax/swing/LookAndFeel.java
index 74dff9dba..da57e561b 100644
--- a/javax/swing/LookAndFeel.java
+++ b/javax/swing/LookAndFeel.java
@@ -300,11 +300,11 @@ public abstract class LookAndFeel
/**
* Returns a string that displays and identifies this object's properties.
*
- * @return the string "LookAndFeel"
+ * @return string containing the description and class name.
*/
public String toString()
{
- return "LookAndFeel";
+ return getDescription() + " " + getClass().getName();
}
/**
diff --git a/javax/swing/Popup.java b/javax/swing/Popup.java
index cbb243e28..203ee3c9b 100644
--- a/javax/swing/Popup.java
+++ b/javax/swing/Popup.java
@@ -41,6 +41,7 @@ package javax.swing;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Point;
+import java.awt.Rectangle;
/**
@@ -291,7 +292,9 @@ public class Popup
*/
public void hide()
{
+ Rectangle bounds = panel.getBounds();
layeredPane.remove(panel);
+ layeredPane.repaint(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
}
diff --git a/javax/swing/RepaintManager.java b/javax/swing/RepaintManager.java
index 022122b87..385fe7925 100644
--- a/javax/swing/RepaintManager.java
+++ b/javax/swing/RepaintManager.java
@@ -534,7 +534,14 @@ public class RepaintManager
}
for (Iterator i = workInvalidComponents.iterator(); i.hasNext(); )
{
- JComponent comp = (JComponent) i.next();
+ 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.
if (! (comp.isVisible() && comp.isShowing()))
continue;
comp.validate();
diff --git a/javax/swing/SwingUtilities.java b/javax/swing/SwingUtilities.java
index 2d737eeb5..f50f26b63 100644
--- a/javax/swing/SwingUtilities.java
+++ b/javax/swing/SwingUtilities.java
@@ -1395,4 +1395,30 @@ public class SwingUtilities
else
return null;
}
+
+ /**
+ * Processes key bindings for the component that is associated with the
+ * key event. Note that this method does not make sense for
+ * JComponent-derived components, except when
+ * {@link JComponent#processKeyEvent(KeyEvent)} is overridden and super is
+ * not called.
+ *
+ * This method searches through the component hierarchy of the component's
+ * top-level container to find a <code>JComponent</code> that has a binding
+ * for the key event in the WHEN_IN_FOCUSED_WINDOW scope.
+ *
+ * @param ev the key event
+ *
+ * @return <code>true</code> if a binding has been found and processed,
+ * <code>false</code> otherwise
+ *
+ * @since 1.4
+ */
+ public static boolean processKeyBindings(KeyEvent ev)
+ {
+ Component c = ev.getComponent();
+ KeyStroke s = KeyStroke.getKeyStrokeForEvent(ev);
+ KeyboardManager km = KeyboardManager.getManager();
+ return km.processKeyStroke(c, s, ev);
+ }
}
diff --git a/javax/swing/TransferHandler.java b/javax/swing/TransferHandler.java
index 486411092..6115043ed 100644
--- a/javax/swing/TransferHandler.java
+++ b/javax/swing/TransferHandler.java
@@ -1,5 +1,5 @@
/* TransferHandler.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -43,6 +43,7 @@ import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
+import java.awt.Toolkit;
import java.io.Serializable;
public class TransferHandler implements Serializable
@@ -62,6 +63,13 @@ public class TransferHandler implements Serializable
TransferHandler transferHandler = component.getTransferHandler();
Clipboard clipboard = getClipboard(component);
+ if (clipboard == null)
+ {
+ // Access denied!
+ Toolkit.getDefaultToolkit().beep();
+ return;
+ }
+
if (command.equals(COMMAND_COPY))
transferHandler.exportToClipboard(component, clipboard, COPY);
else if (command.equals(COMMAND_CUT))
@@ -76,8 +84,8 @@ public class TransferHandler implements Serializable
}
/**
- * Get the system cliboard. If not available, create and return the VM-local
- * clipboard.
+ * Get the system cliboard or null if the caller isn't allowed to
+ * access the system clipboard.
*
* @param component a component, used to get the toolkit.
* @return the clipboard
@@ -85,22 +93,13 @@ public class TransferHandler implements Serializable
private static Clipboard getClipboard(JComponent component)
{
try
- {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkSystemClipboardAccess();
-
- // We may access the system clipboard.
- return component.getToolkit().getSystemClipboard();
- }
- catch (Exception e)
- {
- // We may not access system clipboard.
- // Create VM-local clipboard if none exists yet.
- if (clipboard == null)
- clipboard = new Clipboard("Clipboard");
- return clipboard;
- }
+ {
+ return component.getToolkit().getSystemClipboard();
+ }
+ catch (SecurityException se)
+ {
+ return null;
+ }
}
}
@@ -119,12 +118,6 @@ public class TransferHandler implements Serializable
private static Action cutAction = new TransferAction(COMMAND_CUT);
private static Action pasteAction = new TransferAction(COMMAND_PASTE);
- /**
- * Clipboard if system clipboard may not be used.
- * Package-private to avoid an accessor method.
- */
- static Clipboard clipboard;
-
private int sourceActions;
private Icon visualRepresentation;
diff --git a/javax/swing/UIDefaults.java b/javax/swing/UIDefaults.java
index 19283aed8..e627be785 100644
--- a/javax/swing/UIDefaults.java
+++ b/javax/swing/UIDefaults.java
@@ -54,6 +54,7 @@ import java.util.ResourceBundle;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.InputMapUIResource;
/**
* UIDefaults is a database where all settings and interface bindings are
@@ -95,10 +96,14 @@ public class UIDefaults extends Hashtable<Object, Object>
}
public Object createValue(UIDefaults table)
{
- InputMap im = new InputMap ();
+ InputMapUIResource im = new InputMapUIResource ();
for (int i = 0; 2*i+1 < bind.length; ++i)
{
- im.put (KeyStroke.getKeyStroke ((String) bind[2*i]),
+ Object curr = bind[2*i];
+ if (curr instanceof KeyStroke)
+ im.put((KeyStroke) curr, bind[2*i+1]);
+ else
+ im.put(KeyStroke.getKeyStroke((String) curr),
bind[2*i+1]);
}
return im;
diff --git a/javax/swing/ViewportLayout.java b/javax/swing/ViewportLayout.java
index 884f7cb27..54935a89f 100644
--- a/javax/swing/ViewportLayout.java
+++ b/javax/swing/ViewportLayout.java
@@ -143,32 +143,32 @@ public class ViewportLayout implements LayoutManager, Serializable
Dimension viewMinimum = view.getMinimumSize();
Point portLowerRight = new Point(portBounds.x + portBounds.width,
portBounds.y + portBounds.height);
-
+
// vertical implementation of the above rules
+ if ((! (view instanceof Scrollable)
+ || ((Scrollable) view).getScrollableTracksViewportHeight())
+ && viewPref.height < portBounds.height)
+ viewPref.height = portBounds.height;
+
if (portBounds.height >= viewMinimum.height)
- {
- portBounds.y = 0;
- if ( !(view instanceof Scrollable) || ((Scrollable)view).getScrollableTracksViewportHeight())
- viewPref.height = portBounds.height;
- }
+ portBounds.y = 0;
else
{
- viewPref.height = viewMinimum.height;
int overextension = portLowerRight.y - viewPref.height;
if (overextension > 0)
portBounds.y -= overextension;
}
// horizontal implementation of the above rules
+ if ((! (view instanceof Scrollable)
+ || ((Scrollable) view).getScrollableTracksViewportWidth())
+ && viewPref.width < portBounds.width)
+ viewPref.width = portBounds.width;
+
if (portBounds.width >= viewMinimum.width)
- {
- portBounds.x = 0;
- if ( !(view instanceof Scrollable) || ((Scrollable)view).getScrollableTracksViewportWidth())
- viewPref.width = portBounds.width;
- }
+ portBounds.x = 0;
else
{
- viewPref.width = viewMinimum.width;
int overextension = portLowerRight.x - viewPref.width;
if (overextension > 0)
portBounds.x -= overextension;
diff --git a/javax/swing/event/EventListenerList.java b/javax/swing/event/EventListenerList.java
index 111e4bca4..332aeba95 100644
--- a/javax/swing/event/EventListenerList.java
+++ b/javax/swing/event/EventListenerList.java
@@ -228,7 +228,7 @@ public class EventListenerList
count = getListenerCount(c);
result = (EventListener[]) Array.newInstance(c, count);
f = 0;
- for (int i = 0; i < listenerList.length; i += 2)
+ for (int i = listenerList.length - 2; i >= 0; i -= 2)
if (listenerList[i] == c)
result[f++] = (EventListener) listenerList[i + 1];
diff --git a/javax/swing/plaf/basic/BasicComboBoxUI.java b/javax/swing/plaf/basic/BasicComboBoxUI.java
index 78ceccb05..288a8d89f 100644
--- a/javax/swing/plaf/basic/BasicComboBoxUI.java
+++ b/javax/swing/plaf/basic/BasicComboBoxUI.java
@@ -294,8 +294,7 @@ public class BasicComboBoxUI extends ComboBoxUI
comboBox.addPropertyChangeListener(propertyChangeListener);
focusListener = createFocusListener();
- comboBox.addFocusListener(focusListener);
- listBox.addFocusListener(focusListener);
+ editor.addFocusListener(focusListener);
itemListener = createItemListener();
comboBox.addItemListener(itemListener);
@@ -572,6 +571,7 @@ public class BasicComboBoxUI extends ComboBoxUI
{
arrowButton.setEnabled(comboBox.isEnabled());
arrowButton.setFont(comboBox.getFont());
+ arrowButton.setFocusable(false);
}
/**
@@ -624,12 +624,14 @@ public class BasicComboBoxUI extends ComboBoxUI
public void setPopupVisible(JComboBox c, boolean v)
{
if (v)
- {
- popup.show();
- popup.getList().requestFocus();
- }
+ popup.show();
else
popup.hide();
+
+ if (comboBox.isEditable())
+ editor.requestFocus();
+ else
+ comboBox.requestFocus();
}
/**
diff --git a/javax/swing/plaf/basic/BasicComboPopup.java b/javax/swing/plaf/basic/BasicComboPopup.java
index 73979bb89..08dab7f9f 100644
--- a/javax/swing/plaf/basic/BasicComboPopup.java
+++ b/javax/swing/plaf/basic/BasicComboPopup.java
@@ -442,6 +442,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
{
list.setModel(comboBox.getModel());
list.setVisibleRowCount(comboBox.getMaximumRowCount());
+ list.setFocusable(false);
installListListeners();
}
diff --git a/javax/swing/plaf/basic/BasicFileChooserUI.java b/javax/swing/plaf/basic/BasicFileChooserUI.java
index 198529a99..105319f7d 100644
--- a/javax/swing/plaf/basic/BasicFileChooserUI.java
+++ b/javax/swing/plaf/basic/BasicFileChooserUI.java
@@ -37,8 +37,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import java.awt.Color;
-import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
@@ -58,14 +56,10 @@ import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
-import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
-import javax.swing.ListCellRenderer;
-import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
-import javax.swing.Timer;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
@@ -143,17 +137,22 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public void actionPerformed(ActionEvent e)
{
- Object obj = new String(parentPath + getFileName());
+ Object obj = null;
+ if (parentPath != null)
+ obj = new String(parentPath + getFileName());
+ else
+ obj = filechooser.getSelectedFile();
if (obj != null)
{
- File f = filechooser.getFileSystemView().createFileObject(
- obj.toString());
- if (filechooser.isTraversable(f)
- && filechooser.isDirectorySelectionEnabled())
- filechooser.setCurrentDirectory(f);
+ File f = filechooser.getFileSystemView().createFileObject(obj.toString());
+ File currSelected = filechooser.getSelectedFile();
+ if (filechooser.isTraversable(f))
+ {
+ filechooser.setCurrentDirectory(currSelected);
+ filechooser.rescanCurrentDirectory();
+ }
else
{
- filechooser.setSelectedFile(f);
filechooser.approveSelection();
closeDialog();
}
@@ -306,6 +305,8 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public void actionPerformed(ActionEvent e)
{
+ filechooser.setSelectedFile(null);
+ filechooser.setSelectedFiles(null);
filechooser.cancelSelection();
closeDialog();
}
@@ -373,11 +374,12 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public void mouseClicked(MouseEvent e)
{
- if (list.getSelectedValue() == null)
+ Object p = list.getSelectedValue();
+ if (p == null)
return;
FileSystemView fsv = filechooser.getFileSystemView();
- if (e.getClickCount() >= 2 &&
- list.getSelectedValue().toString().equals(lastSelected.toString()))
+ if (e.getClickCount() >= 2 && lastSelected != null &&
+ p.toString().equals(lastSelected.toString()))
{
File f = fsv.createFileObject(lastSelected.toString());
if (filechooser.isTraversable(f))
@@ -394,8 +396,19 @@ public class BasicFileChooserUI extends FileChooserUI
}
else
{
- String path = list.getSelectedValue().toString();
+ String path = p.toString();
File f = fsv.createFileObject(path);
+ filechooser.setSelectedFile(f);
+
+ if (filechooser.isMultiSelectionEnabled())
+ {
+ int[] inds = list.getSelectedIndices();
+ File[] allFiles = new File[inds.length];
+ for (int i = 0; i < inds.length; i++)
+ allFiles[i] = (File) list.getModel().getElementAt(inds[i]);
+ filechooser.setSelectedFiles(allFiles);
+ }
+
if (filechooser.isTraversable(f))
{
setDirectorySelected(true);
@@ -408,7 +421,11 @@ public class BasicFileChooserUI extends FileChooserUI
}
lastSelected = path;
parentPath = path.substring(0, path.lastIndexOf("/") + 1);
- setFileName(path.substring(path.lastIndexOf("/") + 1));
+ if (f.isFile())
+ setFileName(path.substring(path.lastIndexOf("/") + 1));
+ else if (filechooser.getFileSelectionMode() ==
+ JFileChooser.DIRECTORIES_ONLY)
+ setFileName(path);
}
}
@@ -652,7 +669,7 @@ public class BasicFileChooserUI extends FileChooserUI
JButton accept;
/** An optional accessory panel. */
- JPanel accessoryPanel;
+ JPanel accessoryPanel = new JPanel();
/** A property change listener. */
PropertyChangeListener propertyChangeListener;
@@ -722,46 +739,6 @@ public class BasicFileChooserUI extends FileChooserUI
private UpdateAction updateAction;
// -- end private --
- private class ListLabelRenderer extends JLabel implements ListCellRenderer
- {
- /** DOCUMENT ME! */
- final Color selected = new Color(153, 204, 255);
-
- /**
- * Creates a new ListLabelRenderer object.
- */
- public ListLabelRenderer()
- {
- super();
- setOpaque(true);
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param list DOCUMENT ME!
- * @param value DOCUMENT ME!
- * @param index DOCUMENT ME!
- * @param isSelected DOCUMENT ME!
- * @param cellHasFocus DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public Component getListCellRendererComponent(JList list, Object value,
- int index,
- boolean isSelected,
- boolean cellHasFocus)
- {
- setHorizontalAlignment(SwingConstants.LEFT);
- File file = (File) value;
- setText(filechooser.getName(file));
- setIcon(filechooser.getIcon(file));
- setBackground(isSelected ? selected : Color.WHITE);
- setForeground(Color.BLACK);
-
- return this;
- }
- }
/**
* Closes the dialog.
@@ -972,28 +949,28 @@ public class BasicFileChooserUI extends FileChooserUI
acceptAllFileFilterText = defaults.getString("FileChooser.acceptAllFileFilterText");
cancelButtonText = "Cancel";
cancelButtonToolTipText = "Abort file chooser dialog";
- cancelButtonMnemonic = defaults.getInt("FileChooser.cancelButtonMnemonic");
+ cancelButtonMnemonic = new Integer((String) UIManager.get("FileChooser.cancelButtonMnemonic")).intValue();
directoryOpenButtonText = "Open";
directoryOpenButtonToolTipText = "Open selected directory";
directoryOpenButtonMnemonic
- = defaults.getInt("FileChooser.directoryOpenButtonMnemonic");
+ = new Integer((String) UIManager.get("FileChooser.directoryOpenButtonMnemonic")).intValue();
helpButtonText = "Help";
helpButtonToolTipText = "FileChooser help";
- helpButtonMnemonic = defaults.getInt("FileChooser.helpButtonMnemonic");
+ helpButtonMnemonic = new Integer((String) UIManager.get("FileChooser.helpButtonMnemonic")).intValue();
openButtonText = "Open";
openButtonToolTipText = "Open selected file";
- openButtonMnemonic = defaults.getInt("FileChooser.openButtonMnemonic");
+ openButtonMnemonic = new Integer((String) UIManager.get("FileChooser.openButtonMnemonic")).intValue();
saveButtonText = "Save";
saveButtonToolTipText = "Save selected file";
- saveButtonMnemonic = UIManager.getInt("FileChooser.saveButtonMnemonic");
+ saveButtonMnemonic = new Integer((String) UIManager.get("FileChooser.saveButtonMnemonic")).intValue();
updateButtonText = "Update";
updateButtonToolTipText = "Update directory listing";
- updateButtonMnemonic = defaults.getInt("FileChooser.updateButtonMnemonic");
+ updateButtonMnemonic = new Integer((String) UIManager.get("FileChooser.updateButtonMnemonic")).intValue();
}
/**
diff --git a/javax/swing/plaf/basic/BasicHTML.java b/javax/swing/plaf/basic/BasicHTML.java
new file mode 100644
index 000000000..b9891e144
--- /dev/null
+++ b/javax/swing/plaf/basic/BasicHTML.java
@@ -0,0 +1,154 @@
+/* BasicHTML.java -- Provides HTML support to ComponentUI implementations
+ 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.basic;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.swing.JComponent;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+
+/**
+ * Provides support for HTML rendering to {@link javax.swing.plaf.ComponentUI}
+ * implementations.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class BasicHTML
+{
+
+ /**
+ * The key that is used to store a HTML view in a JComponent's client
+ * properties.
+ */
+ public static final String propertyKey = "html";
+
+ /**
+ * The key that is used to store the document base in a JComponent's client
+ * properties. The document base is used to resolve relative references
+ * in HTML.
+ */
+ public static final String documentBaseKey = "html.base";
+
+ /**
+ * Creates a new instance of BasicHTML. This should not be necessary since
+ * all methods in this class are static.
+ */
+ public BasicHTML()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Creates a {@link View} instance that can be used by the component
+ * <code>c</code> to render the HTML string <code>html</code>.
+ *
+ * @param c the component that needs to render the HTML string
+ * @param html the HTML string to be rendered
+ *
+ * @return a view that can render the HTML string
+ */
+ public static View createHTMLView(JComponent c, String html)
+ {
+ // TODO: This might be wrong. Lets see if it turns out good when
+ // the javax.swing.text.html package is in a good shape.
+ HTMLDocument doc = new HTMLDocument();
+ HTMLEditorKit kit = new HTMLEditorKit();
+ StringReader reader = new StringReader(html);
+ try
+ {
+ kit.read(reader, doc, 0);
+ }
+ catch (IOException ex)
+ {
+ AssertionError err = new AssertionError("unexpected IOException");
+ err.initCause(ex);
+ throw err;
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError err =
+ new AssertionError("unexpected BadLocationException");
+ err.initCause(ex);
+ throw err;
+ }
+ ViewFactory vf = kit.getViewFactory();
+ Element root = doc.getDefaultRootElement();
+ View view = vf.create(root);
+ return view;
+ }
+
+ /**
+ * Returns <code>true</code> if <code>s</code> is HTML, <code>false</code>
+ * otherwise.
+ *
+ * @param s the string to test
+ *
+ * @return <code>true</code> if <code>s</code> is HTML, <code>false</code>
+ * otherwise
+ */
+ public static boolean isHTMLString(String s)
+ {
+ // We consider a string to be HTML if it contains both the '<' and '>'
+ // character at least once.
+ return 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}
+ * implementations that are shared between it's components.
+ *
+ * @param c the component to update the renderer for
+ * @param text the string to be rendered
+ */
+ public static void updateRenderer(JComponent c, String text)
+ {
+ if (isHTMLString(text))
+ c.putClientProperty(propertyKey, createHTMLView(c, text));
+ else
+ c.putClientProperty(propertyKey, null);
+ }
+}
diff --git a/javax/swing/plaf/basic/BasicListUI.java b/javax/swing/plaf/basic/BasicListUI.java
index 7a6319274..593e7780f 100644
--- a/javax/swing/plaf/basic/BasicListUI.java
+++ b/javax/swing/plaf/basic/BasicListUI.java
@@ -41,13 +41,11 @@ package javax.swing.plaf.basic;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
@@ -61,7 +59,6 @@ import javax.swing.DefaultListSelectionModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JList;
-import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
@@ -87,21 +84,6 @@ public class BasicListUI extends ListUI
{
/**
- * A helper class which listens for {@link ComponentEvent}s from
- * the JList.
- */
- private class ComponentHandler extends ComponentAdapter {
-
- /**
- * Called when the component is hidden. Invalidates the internal
- * layout.
- */
- public void componentResized(ComponentEvent ev) {
- BasicListUI.this.damageLayout();
- }
- }
-
- /**
* A helper class which listens for {@link FocusEvent}s
* from the JList.
*/
@@ -153,7 +135,7 @@ public class BasicListUI extends ListUI
*/
public void contentsChanged(ListDataEvent e)
{
- BasicListUI.this.damageLayout();
+ list.revalidate();
}
/**
@@ -163,7 +145,7 @@ public class BasicListUI extends ListUI
*/
public void intervalAdded(ListDataEvent e)
{
- BasicListUI.this.damageLayout();
+ list.revalidate();
}
/**
@@ -173,7 +155,7 @@ public class BasicListUI extends ListUI
*/
public void intervalRemoved(ListDataEvent e)
{
- BasicListUI.this.damageLayout();
+ list.revalidate();
}
}
@@ -569,20 +551,19 @@ public class BasicListUI extends ListUI
}
// Update the updateLayoutStateNeeded flag.
if (e.getPropertyName().equals("model"))
- updateLayoutStateNeeded += modelChanged;
+ updateLayoutStateNeeded |= modelChanged;
else if (e.getPropertyName().equals("selectionModel"))
- updateLayoutStateNeeded += selectionModelChanged;
+ updateLayoutStateNeeded |= selectionModelChanged;
else if (e.getPropertyName().equals("font"))
- updateLayoutStateNeeded += fontChanged;
+ updateLayoutStateNeeded |= fontChanged;
else if (e.getPropertyName().equals("fixedCellWidth"))
- updateLayoutStateNeeded += fixedCellWidthChanged;
+ updateLayoutStateNeeded |= fixedCellWidthChanged;
else if (e.getPropertyName().equals("fixedCellHeight"))
- updateLayoutStateNeeded += fixedCellHeightChanged;
+ updateLayoutStateNeeded |= fixedCellHeightChanged;
else if (e.getPropertyName().equals("prototypeCellValue"))
- updateLayoutStateNeeded += prototypeCellValueChanged;
+ updateLayoutStateNeeded |= prototypeCellValueChanged;
else if (e.getPropertyName().equals("cellRenderer"))
- updateLayoutStateNeeded += cellRendererChanged;
- BasicListUI.this.damageLayout();
+ updateLayoutStateNeeded |= cellRendererChanged;
}
}
@@ -648,11 +629,6 @@ public class BasicListUI extends ListUI
/** The property change listener listening to the list. */
protected PropertyChangeListener propertyChangeListener;
-
- /** The component listener that receives notification for resizing the
- * JList component.*/
- private ComponentListener componentListener;
-
/** Saved reference to the list this UI was created for. */
protected JList list;
@@ -745,13 +721,12 @@ public class BasicListUI extends ListUI
int maxIndex = Math.max(index1, index2);
Point loc = indexToLocation(list, minIndex);
Rectangle bounds = new Rectangle(loc.x, loc.y, cellWidth,
- getRowHeight(minIndex));
-
+ getCellHeight(minIndex));
for (int i = minIndex + 1; i <= maxIndex; i++)
{
Point hiLoc = indexToLocation(list, i);
Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, cellWidth,
- getRowHeight(i));
+ getCellHeight(i));
bounds = bounds.union(hibounds);
}
@@ -759,6 +734,29 @@ public class BasicListUI extends ListUI
}
/**
+ * Calculates the maximum cell height.
+ *
+ * @param index the index of the cell
+ *
+ * @return the maximum cell height
+ */
+ private int getCellHeight(int index)
+ {
+ int height = cellHeight;
+ if (height <= 0)
+ {
+ if (list.getLayoutOrientation() == JList.VERTICAL)
+ height = getRowHeight(index);
+ else
+ {
+ for (int j = 0; j < cellHeights.length; j++)
+ height = Math.max(height, cellHeights[j]);
+ }
+ }
+ return height;
+ }
+
+ /**
* Calculate the Y coordinate of the upper edge of a particular row,
* considering the Y coordinate <code>0</code> to occur at the top of the
* list.
@@ -811,7 +809,7 @@ public class BasicListUI extends ListUI
// Update the layout if necessary.
maybeUpdateLayoutState();
- int index = list.getModel().getSize() - 1;;
+ int index = list.getModel().getSize() - 1;
// If a fixed cell height is set, then we can work more efficient.
if (cellHeight > 0)
@@ -891,18 +889,6 @@ public class BasicListUI extends ListUI
}
/**
- * Marks the current layout as damaged and requests revalidation from the
- * JList.
- * This is package-private to avoid an accessor method.
- *
- * @see #updateLayoutStateNeeded
- */
- void damageLayout()
- {
- updateLayoutStateNeeded = 1;
- }
-
- /**
* Calls {@link #updateLayoutState} if {@link #updateLayoutStateNeeded}
* is nonzero, then resets {@link #updateLayoutStateNeeded} to zero.
*/
@@ -975,12 +961,6 @@ public class BasicListUI extends ListUI
if (propertyChangeListener == null)
propertyChangeListener = createPropertyChangeListener();
list.addPropertyChangeListener(propertyChangeListener);
-
- // FIXME: Are these two really needed? At least they are not documented.
- //keyListener = new KeyHandler();
- componentListener = new ComponentHandler();
- list.addComponentListener(componentListener);
- //list.addKeyListener(keyListener);
}
/**
@@ -992,7 +972,6 @@ public class BasicListUI extends ListUI
list.getModel().removeListDataListener(listDataListener);
list.removeListSelectionListener(listSelectionListener);
list.removeMouseListener(mouseInputListener);
- //list.removeKeyListener(keyListener);
list.removeMouseMotionListener(mouseInputListener);
list.removePropertyChangeListener(propertyChangeListener);
}
@@ -1080,33 +1059,62 @@ public class BasicListUI extends ListUI
*/
public Dimension getPreferredSize(JComponent c)
{
+ maybeUpdateLayoutState();
int size = list.getModel().getSize();
- if (size == 0)
- return new Dimension(0, 0);
int visibleRows = list.getVisibleRowCount();
int layoutOrientation = list.getLayoutOrientation();
- Rectangle bounds = getCellBounds(list, 0, list.getModel().getSize() - 1);
- Dimension retVal = bounds.getSize();
- Component parent = list.getParent();
- if ((visibleRows == -1) && (parent instanceof JViewport))
- {
- JViewport viewport = (JViewport) parent;
- if (layoutOrientation == JList.HORIZONTAL_WRAP)
+ int h;
+ int w;
+ int maxCellHeight = cellHeight;
+ if (maxCellHeight <= 0)
+ {
+ for (int i = 0; i < cellHeights.length; i++)
+ maxCellHeight = Math.max(maxCellHeight, cellHeights[i]);
+ }
+ if (layoutOrientation == JList.HORIZONTAL_WRAP)
+ {
+ if (visibleRows > 0)
{
- int h = viewport.getSize().height;
- int cellsPerCol = h / cellHeight;
- int w = size / cellsPerCol * cellWidth;
- retVal = new Dimension(w, h);
+ // We cast to double here to force double divisions.
+ double modelSize = size;
+ int neededColumns = (int) Math.ceil(modelSize / visibleRows);
+ int adjustedRows = (int) Math.ceil(modelSize / neededColumns);
+ h = maxCellHeight * adjustedRows;
+ w = cellWidth * neededColumns;
}
- else if (layoutOrientation == JList.VERTICAL_WRAP)
+ else
{
- int w = viewport.getSize().width;
- int cellsPerRow = Math.max(w / cellWidth, 1);
- int h = size / cellsPerRow * cellHeight;
- retVal = new Dimension(w, h);
+ int neededColumns = Math.min(1, list.getWidth() / cellWidth);
+ h = size / neededColumns * maxCellHeight;
+ w = neededColumns * cellWidth;
}
}
+ else if (layoutOrientation == JList.VERTICAL_WRAP)
+ {
+ if (visibleRows > 0)
+ h = visibleRows * maxCellHeight;
+ else
+ h = Math.max(list.getHeight(), maxCellHeight);
+ int neededColumns = h / maxCellHeight;
+ w = cellWidth * neededColumns;
+ }
+ else
+ {
+ if (list.getFixedCellWidth() > 0)
+ w = list.getFixedCellWidth();
+ else
+ w = cellWidth;
+ if (list.getFixedCellHeight() > 0)
+ // FIXME: We need to add some cellVerticalMargins here, according
+ // to the specs.
+ h = list.getFixedCellHeight() * size;
+ else
+ h = maxCellHeight * size;
+ }
+ Insets insets = list.getInsets();
+ Dimension retVal = new Dimension(w + insets.left + insets.right,
+ h + insets.top + insets.bottom);
return retVal;
}
@@ -1155,9 +1163,9 @@ public class BasicListUI extends ListUI
int lead = sel.getLeadSelectionIndex();
Rectangle clip = g.getClipBounds();
- int startIndex = list.locationToIndex(new Point(clip.x, clip.y));
- int endIndex = list.locationToIndex(new Point(clip.x + clip.width,
- clip.y + clip.height));
+ int startIndex = locationToIndex(list, new Point(clip.x, clip.y));
+ int endIndex = locationToIndex(list, new Point(clip.x + clip.width,
+ clip.y + clip.height));
for (int row = startIndex; row <= endIndex; ++row)
{
@@ -1172,13 +1180,13 @@ public class BasicListUI extends ListUI
* location lies outside the bounds of the list, the greatest index in the
* list model is returned.
*
- * @param list the list which on which the computation is based on
+ * @param l the list which on which the computation is based on
* @param location the coordinates
*
* @return the index of the list item that is located at the given
* coordinates or <code>-1</code> if the list model is empty
*/
- public int locationToIndex(JList list, Point location)
+ public int locationToIndex(JList l, Point location)
{
int layoutOrientation = list.getLayoutOrientation();
int index = -1;
@@ -1189,52 +1197,34 @@ public class BasicListUI extends ListUI
break;
case JList.HORIZONTAL_WRAP:
// determine visible rows and cells per row
- int visibleRows = list.getVisibleRowCount();
+ int maxCellHeight = getCellHeight(0);
+ int visibleRows = list.getHeight() / maxCellHeight;
int cellsPerRow = -1;
int numberOfItems = list.getModel().getSize();
- Dimension listDim = list.getSize();
- if (visibleRows <= 0)
- {
- try
- {
- cellsPerRow = listDim.width / cellWidth;
- }
- catch (ArithmeticException ex)
- {
- cellsPerRow = 1;
- }
- }
- else
- {
- cellsPerRow = numberOfItems / visibleRows + 1;
- }
+ cellsPerRow = numberOfItems / visibleRows + 1;
// determine index for the given location
int cellsPerColumn = numberOfItems / cellsPerRow + 1;
int gridX = Math.min(location.x / cellWidth, cellsPerRow - 1);
- int gridY = Math.min(location.y / cellHeight, cellsPerColumn);
+ int gridY = Math.min(location.y / maxCellHeight, cellsPerColumn);
index = gridX + gridY * cellsPerRow;
break;
case JList.VERTICAL_WRAP:
// determine visible rows and cells per column
- int visibleRows2 = list.getVisibleRowCount();
- if (visibleRows2 <= 0)
- {
- Dimension listDim2 = list.getSize();
- visibleRows2 = listDim2.height / cellHeight;
- }
+ int maxCellHeight2 = getCellHeight(0);
+ int visibleRows2 = list.getHeight() / maxCellHeight2;
int numberOfItems2 = list.getModel().getSize();
int cellsPerRow2 = numberOfItems2 / visibleRows2 + 1;
int gridX2 = Math.min(location.x / cellWidth, cellsPerRow2 - 1);
- int gridY2 = Math.min(location.y / cellHeight, visibleRows2);
+ int gridY2 = Math.min(location.y / maxCellHeight2, visibleRows2);
index = gridY2 + gridX2 * visibleRows2;
break;
}
return index;
}
- public Point indexToLocation(JList list, int index)
+ public Point indexToLocation(JList l, int index)
{
int layoutOrientation = list.getLayoutOrientation();
Point loc = null;
@@ -1245,40 +1235,31 @@ public class BasicListUI extends ListUI
break;
case JList.HORIZONTAL_WRAP:
// determine visible rows and cells per row
- int visibleRows = list.getVisibleRowCount();
+ int maxCellHeight = getCellHeight(0);
+ int visibleRows = list.getHeight() / maxCellHeight;
int numberOfCellsPerRow = -1;
- if (visibleRows <= 0)
- {
- Dimension listDim = list.getSize();
- numberOfCellsPerRow = Math.max(listDim.width / cellWidth, 1);
- }
- else
- {
- int numberOfItems = list.getModel().getSize();
- numberOfCellsPerRow = numberOfItems / visibleRows + 1;
- }
+ int numberOfItems = list.getModel().getSize();
+ numberOfCellsPerRow = numberOfItems / visibleRows + 1;
+
// compute coordinates inside the grid
int gridX = index % numberOfCellsPerRow;
int gridY = index / numberOfCellsPerRow;
int locX = gridX * cellWidth;
- int locY = gridY * cellHeight;
+ int locY;
+ locY = gridY * maxCellHeight;
loc = new Point(locX, locY);
break;
case JList.VERTICAL_WRAP:
// determine visible rows and cells per column
- int visibleRows2 = list.getVisibleRowCount();
- if (visibleRows2 <= 0)
- {
- Dimension listDim2 = list.getSize();
- visibleRows2 = listDim2.height / cellHeight;
- }
+ int maxCellHeight2 = getCellHeight(0);
+ int visibleRows2 = list.getHeight() / maxCellHeight2;
// compute coordinates inside the grid
if (visibleRows2 > 0)
{
int gridY2 = index % visibleRows2;
int gridX2 = index / visibleRows2;
int locX2 = gridX2 * cellWidth;
- int locY2 = gridY2 * cellHeight;
+ int locY2 = gridY2 * maxCellHeight2;
loc = new Point(locX2, locY2);
}
else
diff --git a/javax/swing/plaf/basic/BasicLookAndFeel.java b/javax/swing/plaf/basic/BasicLookAndFeel.java
index 13c78add6..2cbca5d30 100644
--- a/javax/swing/plaf/basic/BasicLookAndFeel.java
+++ b/javax/swing/plaf/basic/BasicLookAndFeel.java
@@ -41,16 +41,26 @@ package javax.swing.plaf.basic;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.io.InputStream;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.ResourceBundle;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
+import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.plaf.BorderUIResource;
@@ -59,7 +69,6 @@ import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.InsetsUIResource;
-import javax.swing.text.JTextComponent;
/**
* BasicLookAndFeel
@@ -68,8 +77,68 @@ import javax.swing.text.JTextComponent;
public abstract class BasicLookAndFeel extends LookAndFeel
implements Serializable
{
+ /**
+ * An action that can play an audio file.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private class AudioAction extends AbstractAction
+ {
+ /**
+ * The UIDefaults key that specifies the sound.
+ */
+ Object key;
+
+ /**
+ * Creates a new AudioAction.
+ *
+ * @param key the key that describes the audio action, normally a filename
+ * of an audio file relative to the current package
+ */
+ AudioAction(Object key)
+ {
+ this.key = key;
+ }
+
+ /**
+ * Plays the sound represented by this action.
+ *
+ * @param event the action event that triggers this audio action
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ // We only can handle strings for now.
+ if (key instanceof String)
+ {
+ String name = UIManager.getString(key);
+ InputStream stream = getClass().getResourceAsStream(name);
+ try
+ {
+ Clip clip = AudioSystem.getClip();
+ AudioInputStream audioStream =
+ AudioSystem.getAudioInputStream(stream);
+ clip.open(audioStream);
+ }
+ catch (LineUnavailableException ex)
+ {
+ // Nothing we can do about it.
+ }
+ catch (IOException ex)
+ {
+ // Nothing we can do about it.
+ }
+ catch (UnsupportedAudioFileException e)
+ {
+ // Nothing we can do about it.
+ }
+ }
+ }
+ }
+
static final long serialVersionUID = -6096995660290287879L;
+ private ActionMap audioActionMap;
+
/**
* Creates a new instance of the Basic look and feel.
*/
@@ -148,7 +217,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"TextPaneUI", "javax.swing.plaf.basic.BasicTextPaneUI",
"TextAreaUI", "javax.swing.plaf.basic.BasicTextAreaUI",
"TextFieldUI", "javax.swing.plaf.basic.BasicTextFieldUI",
- "TextPaneUI", "javax.swing.plaf.basic.BasicTextPaneUI",
"ToggleButtonUI", "javax.swing.plaf.basic.BasicToggleButtonUI",
"ToolBarSeparatorUI", "javax.swing.plaf.basic.BasicToolBarSeparatorUI",
"ToolBarUI", "javax.swing.plaf.basic.BasicToolBarUI",
@@ -265,12 +333,12 @@ public abstract class BasicLookAndFeel extends LookAndFeel
}
},
"Button.darkShadow", new ColorUIResource(Color.BLACK),
- "Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "SPACE", "pressed",
- "released SPACE", "released"
- }),
"Button.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"Button.foreground", new ColorUIResource(Color.BLACK),
+ "Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
+ KeyStroke.getKeyStroke("SPACE"), "pressed",
+ KeyStroke.getKeyStroke("released SPACE"), "released"
+ }),
"Button.highlight", new ColorUIResource(Color.WHITE),
"Button.light", new ColorUIResource(Color.LIGHT_GRAY),
"Button.margin", new InsetsUIResource(2, 14, 2, 14),
@@ -281,8 +349,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"CheckBox.border", new BorderUIResource.CompoundBorderUIResource(null,
null),
"CheckBox.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "SPACE", "pressed",
- "released SPACE", "released"
+ KeyStroke.getKeyStroke("SPACE"), "pressed",
+ KeyStroke.getKeyStroke("released SPACE"), "released"
}),
"CheckBox.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"CheckBox.foreground", new ColorUIResource(darkShadow),
@@ -342,12 +410,12 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"ColorChooser.okText", "OK",
"ColorChooser.previewText", "Preview",
"ColorChooser.resetText", "Reset",
- "ColorChooser.rgbBlueMnemonic", new Integer(66),
+ "ColorChooser.rgbBlueMnemonic", "66",
"ColorChooser.rgbBlueText", "Blue",
- "ColorChooser.rgbGreenMnemonic", new Integer(71),
+ "ColorChooser.rgbGreenMnemonic", "78",
"ColorChooser.rgbGreenText", "Green",
"ColorChooser.rgbNameText", "RGB",
- "ColorChooser.rgbRedMnemonic", new Integer(82),
+ "ColorChooser.rgbRedMnemonic", "68",
"ColorChooser.rgbRedText", "Red",
"ColorChooser.sampleText", "Sample Text Sample Text",
"ColorChooser.swatchesDefaultRecentColor", new ColorUIResource(light),
@@ -403,20 +471,63 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"EditorPane.font", new FontUIResource("Serif", Font.PLAIN, 12),
"EditorPane.foreground", new ColorUIResource(Color.black),
"EditorPane.inactiveForeground", new ColorUIResource(Color.gray),
- "EditorPane.keyBindings", new JTextComponent.KeyBinding[] {
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP,
- 0), "caret-up"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
- 0), "caret-down"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,
- 0), "page-up"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,
- 0), "page-down"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
- 0), "insert-break"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
- 0), "insert-tab")
- },
+ "EditorPane.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
+ KeyStroke.getKeyStroke("shift UP"), "selection-up",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("shift ctrl LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("shift KP_UP"), "selection-up",
+ KeyStroke.getKeyStroke("DOWN"), "caret-down",
+ KeyStroke.getKeyStroke("shift ctrl T"), "previous-link-action",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("CUT"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("END"), "caret-end-line",
+ KeyStroke.getKeyStroke("shift PAGE_UP"), "selection-page-up",
+ KeyStroke.getKeyStroke("KP_UP"), "caret-up",
+ KeyStroke.getKeyStroke("DELETE"), "delete-next",
+ KeyStroke.getKeyStroke("ctrl HOME"), "caret-begin",
+ KeyStroke.getKeyStroke("shift LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("ctrl END"), "caret-end",
+ KeyStroke.getKeyStroke("BACK_SPACE"), "delete-previous",
+ KeyStroke.getKeyStroke("shift ctrl RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("KP_LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("shift KP_RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("ctrl SPACE"), "activate-link-action",
+ KeyStroke.getKeyStroke("ctrl H"), "delete-previous",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "unselect",
+ KeyStroke.getKeyStroke("ENTER"), "insert-break",
+ KeyStroke.getKeyStroke("shift HOME"), "selection-begin-line",
+ KeyStroke.getKeyStroke("RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_UP"), "selection-page-left",
+ KeyStroke.getKeyStroke("shift DOWN"), "selection-down",
+ KeyStroke.getKeyStroke("PAGE_DOWN"), "page-down",
+ KeyStroke.getKeyStroke("shift KP_LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("shift ctrl O"), "toggle-componentOrientation",
+ KeyStroke.getKeyStroke("ctrl X"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_DOWN"), "selection-page-right",
+ KeyStroke.getKeyStroke("ctrl C"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("shift END"), "selection-end-line",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("HOME"), "caret-begin-line",
+ KeyStroke.getKeyStroke("ctrl V"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("KP_DOWN"), "caret-down",
+ KeyStroke.getKeyStroke("ctrl A"), "select-all",
+ KeyStroke.getKeyStroke("shift RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("shift ctrl END"), "selection-end",
+ KeyStroke.getKeyStroke("COPY"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl KP_LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("ctrl T"), "next-link-action",
+ KeyStroke.getKeyStroke("shift KP_DOWN"), "selection-down",
+ KeyStroke.getKeyStroke("TAB"), "insert-tab",
+ KeyStroke.getKeyStroke("UP"), "caret-up",
+ KeyStroke.getKeyStroke("shift ctrl HOME"), "selection-begin",
+ KeyStroke.getKeyStroke("shift PAGE_DOWN"), "selection-page-down",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl KP_RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("PAGE_UP"), "page-up",
+ KeyStroke.getKeyStroke("PASTE"), "paste-from-clipboard"
+ }),
"EditorPane.margin", new InsetsUIResource(3, 3, 3, 3),
"EditorPane.selectionBackground", new ColorUIResource(Color.black),
"EditorPane.selectionForeground", new ColorUIResource(Color.white),
@@ -424,51 +535,74 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"FileChooser.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
"ESCAPE", "cancelSelection"
}),
- "FileChooser.cancelButtonMnemonic", new Integer(67),
+ "FileChooser.cancelButtonMnemonic", "67",
"FileChooser.cancelButtonText", "Cancel",
"FileChooser.cancelButtonToolTipText", "Abort file chooser dialog",
- // XXX Don't use gif
-// "FileChooser.detailsViewIcon", new IconUIResource(new ImageIcon("icons/DetailsView.gif")),
"FileChooser.directoryDescriptionText", "Directory",
"FileChooser.fileDescriptionText", "Generic File",
- "FileChooser.helpButtonMnemonic", new Integer(72),
+ "FileChooser.directoryOpenButtonMnemonic", "79",
+ "FileChooser.helpButtonMnemonic", "72",
"FileChooser.helpButtonText", "Help",
"FileChooser.helpButtonToolTipText", "FileChooser help",
- // XXX Don't use gif
-// "FileChooser.homeFolderIcon", new IconUIResource(new ImageIcon("icons/HomeFolder.gif")),
- // XXX Don't use gif
-// "FileChooser.listViewIcon", new IconUIResource(new ImageIcon("icons/ListView.gif")),
"FileChooser.newFolderErrorSeparator", ":",
"FileChooser.newFolderErrorText", "Error creating new folder",
- // XXX Don't use gif
-// "FileChooser.newFolderIcon", new IconUIResource(new ImageIcon("icons/NewFolder.gif")),
- "FileChooser.openButtonMnemonic", new Integer(79),
+ "FileChooser.openButtonMnemonic", "79",
"FileChooser.openButtonText", "Open",
"FileChooser.openButtonToolTipText", "Open selected file",
- "FileChooser.saveButtonMnemonic", new Integer(83),
+ "FileChooser.saveButtonMnemonic", "83",
"FileChooser.saveButtonText", "Save",
"FileChooser.saveButtonToolTipText", "Save selected file",
- // XXX Don't use gif
-// "FileChooser.upFolderIcon", new IconUIResource(new ImageIcon("icons/UpFolder.gif")),
- "FileChooser.updateButtonMnemonic", new Integer(85),
+ "FileChooser.updateButtonMnemonic", "85",
"FileChooser.updateButtonText", "Update",
"FileChooser.updateButtonToolTipText", "Update directory listing",
- // XXX Don't use gif
-// "FileView.computerIcon", new IconUIResource(new ImageIcon("icons/Computer.gif")),
- // XXX Don't use gif
-// "FileView.directoryIcon", new IconUIResource(new ImageIcon("icons/Directory.gif")),
- // XXX Don't use gif
-// "FileView.fileIcon", new IconUIResource(new ImageIcon("icons/File.gif")),
- // XXX Don't use gif
-// "FileView.floppyDriveIcon", new IconUIResource(new ImageIcon("icons/Floppy.gif")),
- // XXX Don't use gif
-// "FileView.hardDriveIcon", new IconUIResource(new ImageIcon("icons/HardDrive.gif")),
"FocusManagerClassName", "TODO",
"FormattedTextField.background", new ColorUIResource(light),
"FormattedTextField.caretForeground", new ColorUIResource(Color.black),
+ "FormattedTextField.margin", new InsetsUIResource(0, 0, 0, 0),
+ "FormattedTextField.caretBlinkRate", new Integer(500),
"FormattedTextField.font",
new FontUIResource("SansSerif", Font.PLAIN, 12),
"FormattedTextField.foreground", new ColorUIResource(Color.black),
+ "FormattedTextField.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
+ KeyStroke.getKeyStroke("KP_UP"), "increment",
+ KeyStroke.getKeyStroke("END"), "caret-end-line",
+ KeyStroke.getKeyStroke("shift ctrl O"), "toggle-componentOrientation",
+ KeyStroke.getKeyStroke("shift KP_LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("shift RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("KP_DOWN"), "decrement",
+ KeyStroke.getKeyStroke("HOME"), "caret-begin-line",
+ KeyStroke.getKeyStroke("ctrl V"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("ctrl H"), "delete-previous",
+ KeyStroke.getKeyStroke("KP_LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("ctrl X"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("UP"), "increment",
+ KeyStroke.getKeyStroke("shift ctrl KP_RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("COPY"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift HOME"), "selection-begin-line",
+ KeyStroke.getKeyStroke("ESCAPE"), "reset-field-edit",
+ KeyStroke.getKeyStroke("RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("DOWN"), "decrement",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("PASTE"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "unselect",
+ KeyStroke.getKeyStroke("ctrl A"), "select-all",
+ KeyStroke.getKeyStroke("shift KP_RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("CUT"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("BACK_SPACE"), "delete-previous",
+ KeyStroke.getKeyStroke("shift ctrl KP_LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("ctrl C"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift END"), "selection-end-line",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("DELETE"), "delete-next",
+ KeyStroke.getKeyStroke("ENTER"), "notify-field-accept",
+ KeyStroke.getKeyStroke("shift LEFT"), "selection-backward"
+ }),
"FormattedTextField.inactiveBackground", new ColorUIResource(light),
"FormattedTextField.inactiveForeground", new ColorUIResource(Color.gray),
"FormattedTextField.selectionBackground",
@@ -504,7 +638,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"InternalFrame.borderLight", new ColorUIResource(Color.LIGHT_GRAY),
"InternalFrame.borderShadow", new ColorUIResource(Color.GRAY),
"InternalFrame.closeIcon", BasicIconFactory.createEmptyFrameIcon(),
- // FIXME: Set a nice icon for InternalFrames here.
"InternalFrame.icon",
new UIDefaults.LazyValue()
{
@@ -533,67 +666,67 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"List.background", new ColorUIResource(Color.white),
"List.border", new BasicBorders.MarginBorder(),
"List.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "ctrl DOWN", "selectNextRowChangeLead",
- "shift UP", "selectPreviousRowExtendSelection",
- "ctrl RIGHT", "selectNextColumnChangeLead",
- "shift ctrl LEFT", "selectPreviousColumnExtendSelection",
- "shift KP_UP", "selectPreviousRowChangeLead",
- "DOWN", "selectNextRow",
- "ctrl UP", "selectPreviousRowChangeLead",
- "ctrl LEFT", "selectPreviousColumnChangeLead",
- "CUT", "cut",
- "END", "selectLastRow",
- "shift PAGE_UP","scrollUpExtendSelection",
- "KP_UP", "selectPreviousRow",
- "shift ctrl UP", "selectPreviousRowExtendSelection",
- "ctrl HOME", "selectFirstRowChangeLead",
- "shift LEFT", "selectPreviousColumnExtendSelection",
- "ctrl END", "selectLastRowChangeLead",
- "ctrl PAGE_DOWN", "scrollDownChangeLead",
- "shift ctrl RIGHT", "selectNextColumnExtendSelection",
- "LEFT", "selectPreviousColumn",
- "ctrl PAGE_UP", "scrollUpChangeLead",
- "KP_LEFT", "selectPreviousColumn",
- "shift KP_RIGHT", "selectNextColumnExtendSelection",
- "SPACE", "addToSelection",
- "ctrl SPACE", "toggleAndAnchor",
- "shift SPACE", "extendTo",
- "shift ctrl SPACE", "moveSelectionTo",
- "shift ctrl DOWN", "selectNextRowExtendSelection",
- "ctrl BACK_SLASH", "clearSelection",
- "shift HOME", "selectFirstRowExtendSelection",
- "RIGHT", "selectNextColumn",
- "shift ctrl PAGE_UP", "scrollUpExtendSelection",
- "shift DOWN", "selectNextRowExtendSelection",
- "PAGE_DOWN", "scrollDown",
- "shift ctrl KP_UP", "selectPreviousRowExtendSelection",
- "shift KP_LEFT", "selectPreviousColumnExtendSelection",
- "ctrl X", "cut",
- "shift ctrl PAGE_DOWN", "scrollDownExtendSelection",
- "ctrl SLASH", "selectAll",
- "ctrl C", "copy",
- "ctrl KP_RIGHT", "selectNextColumnChangeLead",
- "shift END", "selectLastRowExtendSelection",
- "shift ctrl KP_DOWN", "selectNextRowExtendSelection",
- "ctrl KP_LEFT", "selectPreviousColumnChangeLead",
- "HOME", "selectFirstRow",
- "ctrl V", "paste",
- "KP_DOWN", "selectNextRow",
- "ctrl KP_DOWN", "selectNextRowChangeLead",
- "shift RIGHT", "selectNextColumnExtendSelection",
- "ctrl A", "selectAll",
- "shift ctrl END", "selectLastRowExtendSelection",
- "COPY", "copy",
- "ctrl KP_UP", "selectPreviousRowChangeLead",
- "shift ctrl KP_LEFT", "selectPreviousColumnExtendSelection",
- "shift KP_DOWN", "selectNextRowExtendSelection",
- "UP", "selectPreviousRow",
- "shift ctrl HOME", "selectFirstRowExtendSelection",
- "shift PAGE_DOWN", "scrollDownExtendSelection",
- "KP_RIGHT", "selectNextColumn",
- "shift ctrl KP_RIGHT", "selectNextColumnExtendSelection",
- "PAGE_UP", "scrollUp",
- "PASTE", "paste"
+ KeyStroke.getKeyStroke("ctrl DOWN"), "selectNextRowChangeLead",
+ KeyStroke.getKeyStroke("shift UP"), "selectPreviousRowExtendSelection",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "selectNextColumnChangeLead",
+ KeyStroke.getKeyStroke("shift ctrl LEFT"), "selectPreviousColumnExtendSelection",
+ KeyStroke.getKeyStroke("shift KP_UP"), "selectPreviousRowExtendSelection",
+ KeyStroke.getKeyStroke("DOWN"), "selectNextRow",
+ KeyStroke.getKeyStroke("ctrl UP"), "selectPreviousRowChangeLead",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "selectPreviousColumnChangeLead",
+ KeyStroke.getKeyStroke("CUT"), "cut",
+ KeyStroke.getKeyStroke("END"), "selectLastRow",
+ KeyStroke.getKeyStroke("shift PAGE_UP"), "scrollUpExtendSelection",
+ KeyStroke.getKeyStroke("KP_UP"), "selectPreviousRow",
+ KeyStroke.getKeyStroke("shift ctrl UP"), "selectPreviousRowExtendSelection",
+ KeyStroke.getKeyStroke("ctrl HOME"), "selectFirstRowChangeLead",
+ KeyStroke.getKeyStroke("shift LEFT"), "selectPreviousColumnExtendSelection",
+ KeyStroke.getKeyStroke("ctrl END"), "selectLastRowChangeLead",
+ KeyStroke.getKeyStroke("ctrl PAGE_DOWN"), "scrollDownChangeLead",
+ KeyStroke.getKeyStroke("shift ctrl RIGHT"), "selectNextColumnExtendSelection",
+ KeyStroke.getKeyStroke("LEFT"), "selectPreviousColumn",
+ KeyStroke.getKeyStroke("ctrl PAGE_UP"), "scrollUpChangeLead",
+ KeyStroke.getKeyStroke("KP_LEFT"), "selectPreviousColumn",
+ KeyStroke.getKeyStroke("shift KP_RIGHT"), "selectNextColumnExtendSelection",
+ KeyStroke.getKeyStroke("SPACE"), "addToSelection",
+ KeyStroke.getKeyStroke("ctrl SPACE"), "toggleAndAnchor",
+ KeyStroke.getKeyStroke("shift SPACE"), "extendTo",
+ KeyStroke.getKeyStroke("shift ctrl SPACE"), "moveSelectionTo",
+ KeyStroke.getKeyStroke("shift ctrl DOWN"), "selectNextRowExtendSelection",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "clearSelection",
+ KeyStroke.getKeyStroke("shift HOME"), "selectFirstRowExtendSelection",
+ KeyStroke.getKeyStroke("RIGHT"), "selectNextColumn",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_UP"), "scrollUpExtendSelection",
+ KeyStroke.getKeyStroke("shift DOWN"), "selectNextRowExtendSelection",
+ KeyStroke.getKeyStroke("PAGE_DOWN"), "scrollDown",
+ KeyStroke.getKeyStroke("shift ctrl KP_UP"), "selectPreviousRowExtendSelection",
+ KeyStroke.getKeyStroke("shift KP_LEFT"), "selectPreviousColumnExtendSelection",
+ KeyStroke.getKeyStroke("ctrl X"), "cut",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_DOWN"), "scrollDownExtendSelection",
+ KeyStroke.getKeyStroke("ctrl SLASH"), "selectAll",
+ KeyStroke.getKeyStroke("ctrl C"), "copy",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "selectNextColumnChangeLead",
+ KeyStroke.getKeyStroke("shift END"), "selectLastRowExtendSelection",
+ KeyStroke.getKeyStroke("shift ctrl KP_DOWN"), "selectNextRowExtendSelection",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "selectPreviousColumnChangeLead",
+ KeyStroke.getKeyStroke("HOME"), "selectFirstRow",
+ KeyStroke.getKeyStroke("ctrl V"), "paste",
+ KeyStroke.getKeyStroke("KP_DOWN"), "selectNextRow",
+ KeyStroke.getKeyStroke("ctrl KP_DOWN"), "selectNextRowChangeLead",
+ KeyStroke.getKeyStroke("shift RIGHT"), "selectNextColumnExtendSelection",
+ KeyStroke.getKeyStroke("ctrl A"), "selectAll",
+ KeyStroke.getKeyStroke("shift ctrl END"), "selectLastRowExtendSelection",
+ KeyStroke.getKeyStroke("COPY"), "copy",
+ KeyStroke.getKeyStroke("ctrl KP_UP"), "selectPreviousRowChangeLead",
+ KeyStroke.getKeyStroke("shift ctrl KP_LEFT"), "selectPreviousColumnExtendSelection",
+ KeyStroke.getKeyStroke("shift KP_DOWN"), "selectNextRowExtendSelection",
+ KeyStroke.getKeyStroke("UP"), "selectPreviousRow",
+ KeyStroke.getKeyStroke("shift ctrl HOME"), "selectFirstRowExtendSelection",
+ KeyStroke.getKeyStroke("shift PAGE_DOWN"), "scrollDownExtendSelection",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "selectNextColumn",
+ KeyStroke.getKeyStroke("shift ctrl KP_RIGHT"), "selectNextColumnExtendSelection",
+ KeyStroke.getKeyStroke("PAGE_UP"), "scrollUp",
+ KeyStroke.getKeyStroke("PASTE"), "paste"
}),
"List.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"List.foreground", new ColorUIResource(Color.black),
@@ -603,6 +736,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
new BorderUIResource.
LineBorderUIResource(new ColorUIResource(Color.yellow)),
"Menu.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12),
+ "Menu.crossMenuMnemonic", Boolean.TRUE,
"Menu.acceleratorForeground", new ColorUIResource(darkShadow),
"Menu.acceleratorSelectionForeground", new ColorUIResource(Color.white),
"Menu.arrowIcon", BasicIconFactory.getMenuArrowIcon(),
@@ -627,6 +761,10 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"ENTER", "return",
"SPACE", "return"
},
+ "Menu.menuPopupOffsetX", new Integer(0),
+ "Menu.menuPopupOffsetY", new Integer(0),
+ "Menu.submenuPopupOffsetX", new Integer(0),
+ "Menu.submenuPopupOffsetY", new Integer(0),
"Menu.selectionBackground", new ColorUIResource(Color.black),
"Menu.selectionForeground", new ColorUIResource(Color.white),
"MenuBar.background", new ColorUIResource(light),
@@ -638,7 +776,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"MenuBar.windowBindings", new Object[] {
"F10", "takeFocus"
},
- "MenuItem.acceleratorDelimiter", "-",
+ "MenuItem.acceleratorDelimiter", "+",
"MenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12),
"MenuItem.acceleratorForeground", new ColorUIResource(darkShadow),
"MenuItem.acceleratorSelectionForeground",
@@ -657,15 +795,10 @@ public abstract class BasicLookAndFeel extends LookAndFeel
new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0),
"OptionPane.buttonAreaBorder",
new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0),
+ "OptionPane.buttonClickThreshhold", new Integer(500),
"OptionPane.cancelButtonText", "Cancel",
- // XXX Don't use gif
-// "OptionPane.errorIcon",
-// new IconUIResource(new ImageIcon("icons/Error.gif")),
"OptionPane.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"OptionPane.foreground", new ColorUIResource(darkShadow),
- // XXX Don't use gif
-// "OptionPane.informationIcon",
-// new IconUIResource(new ImageIcon("icons/Inform.gif")),
"OptionPane.messageAreaBorder",
new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0),
"OptionPane.messageForeground", new ColorUIResource(darkShadow),
@@ -674,12 +807,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel
BasicOptionPaneUI.MinimumHeight),
"OptionPane.noButtonText", "No",
"OptionPane.okButtonText", "OK",
- // XXX Don't use gif
-// "OptionPane.questionIcon",
-// new IconUIResource(new ImageIcon("icons/Question.gif")),
- // XXX Don't use gif
-// "OptionPane.warningIcon",
-// new IconUIResource(new ImageIcon("icons/Warn.gif")),
"OptionPane.windowBindings", new Object[] {
"ESCAPE", "close"
},
@@ -692,14 +819,45 @@ public abstract class BasicLookAndFeel extends LookAndFeel
null, null),
"PasswordField.caretBlinkRate", new Integer(500),
"PasswordField.caretForeground", new ColorUIResource(Color.black),
- "PasswordField.font", new FontUIResource("Dialog", Font.PLAIN, 12),
+ "PasswordField.font", new FontUIResource("MonoSpaced", Font.PLAIN, 12),
"PasswordField.foreground", new ColorUIResource(Color.black),
"PasswordField.inactiveBackground", new ColorUIResource(light),
"PasswordField.inactiveForeground", new ColorUIResource(Color.gray),
- "PasswordField.keyBindings", new JTextComponent.KeyBinding[] {
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
- 0),
- "notify-field-accept")},
+ "PasswordField.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
+ KeyStroke.getKeyStroke("END"), "caret-end-line",
+ KeyStroke.getKeyStroke("shift ctrl O"), "toggle-componentOrientation",
+ KeyStroke.getKeyStroke("shift KP_LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("shift RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("HOME"), "caret-begin-line",
+ KeyStroke.getKeyStroke("ctrl V"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("ctrl H"), "delete-previous",
+ KeyStroke.getKeyStroke("KP_LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("ctrl X"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl KP_RIGHT"), "selection-end-line",
+ KeyStroke.getKeyStroke("COPY"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift HOME"), "selection-begin-line",
+ KeyStroke.getKeyStroke("RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl LEFT"), "selection-begin-line",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "caret-begin-line",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "caret-end-line",
+ KeyStroke.getKeyStroke("PASTE"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl RIGHT"), "selection-end-line",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "unselect",
+ KeyStroke.getKeyStroke("ctrl A"), "select-all",
+ KeyStroke.getKeyStroke("shift KP_RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("CUT"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "caret-begin-line",
+ KeyStroke.getKeyStroke("BACK_SPACE"), "delete-previous",
+ KeyStroke.getKeyStroke("shift ctrl KP_LEFT"), "selection-begin-line",
+ KeyStroke.getKeyStroke("ctrl C"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift END"), "selection-end-line",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "caret-end-line",
+ KeyStroke.getKeyStroke("DELETE"), "delete-next",
+ KeyStroke.getKeyStroke("ENTER"), "notify-field-accept",
+ KeyStroke.getKeyStroke("shift LEFT"), "selection-backward"
+ }),
"PasswordField.margin", new InsetsUIResource(0, 0, 0, 0),
"PasswordField.selectionBackground", new ColorUIResource(Color.black),
"PasswordField.selectionForeground", new ColorUIResource(Color.white),
@@ -723,8 +881,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel
null),
"RadioButton.darkShadow", new ColorUIResource(shadow),
"RadioButton.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "SPACE", "pressed",
- "released SPACE", "released"
+ KeyStroke.getKeyStroke("SPACE"), "pressed",
+ KeyStroke.getKeyStroke("released SPACE"), "released"
}),
"RadioButton.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"RadioButton.foreground", new ColorUIResource(darkShadow),
@@ -818,18 +976,20 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"Slider.background", new ColorUIResource(light),
"Slider.focus", new ColorUIResource(shadow),
"Slider.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "PAGE_UP", "positiveBlockIncrement",
- "PAGE_DOWN", "negativeBlockIncrement",
- "END", "maxScroll",
- "HOME", "minScroll",
- "LEFT", "negativeUnitIncrement",
- "KP_UP", "positiveUnitIncrement",
- "KP_DOWN", "negativeUnitIncrement",
- "UP", "positiveUnitIncrement",
- "RIGHT", "positiveUnitIncrement",
- "KP_LEFT", "negativeUnitIncrement",
- "DOWN", "negativeUnitIncrement",
- "KP_RIGHT", "positiveUnitIncrement"
+ "ctrl PAGE_DOWN", "negativeBlockIncrement",
+ "PAGE_DOWN", "negativeBlockIncrement",
+ "PAGE_UP", "positiveBlockIncrement",
+ "ctrl PAGE_UP", "positiveBlockIncrement",
+ "KP_RIGHT", "positiveUnitIncrement",
+ "DOWN", "negativeUnitIncrement",
+ "KP_LEFT", "negativeUnitIncrement",
+ "RIGHT", "positiveUnitIncrement",
+ "KP_DOWN", "negativeUnitIncrement",
+ "UP", "positiveUnitIncrement",
+ "KP_UP", "positiveUnitIncrement",
+ "LEFT", "negativeUnitIncrement",
+ "HOME", "minScroll",
+ "END", "maxScroll"
}),
"Slider.focusInsets", new InsetsUIResource(2, 2, 2, 2),
"Slider.foreground", new ColorUIResource(light),
@@ -840,6 +1000,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"Slider.tickHeight", new Integer(12),
"Spinner.background", new ColorUIResource(light),
"Spinner.foreground", new ColorUIResource(light),
+ "Spinner.arrowButtonSize", new DimensionUIResource(16, 5),
+ "Spinner.editorBorderPainted", Boolean.FALSE,
+ "Spinner.font", new FontUIResource("MonoSpaced", Font.PLAIN, 12),
"SplitPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
"F6", "toggleFocus",
"F8", "startResize",
@@ -857,7 +1020,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"SplitPane.background", new ColorUIResource(light),
"SplitPane.border", new BasicBorders.SplitPaneBorder(null, null),
"SplitPane.darkShadow", new ColorUIResource(shadow),
- "SplitPane.dividerSize", new Integer(10),
+ "SplitPane.dividerSize", new Integer(7),
"SplitPane.highlight", new ColorUIResource(highLight),
"SplitPane.shadow", new ColorUIResource(shadow),
"TabbedPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
@@ -871,16 +1034,16 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"TabbedPane.darkShadow", new ColorUIResource(shadow),
"TabbedPane.focus", new ColorUIResource(darkShadow),
"TabbedPane.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "LEFT", "navigateLeft",
- "KP_UP", "navigateUp",
- "ctrl DOWN", "requestFocusForVisibleComponent",
- "UP", "navigateUp",
- "KP_DOWN", "navigateDown",
- "RIGHT", "navigateRight",
- "KP_LEFT", "navigateLeft",
- "ctrl KP_DOWN", "requestFocusForVisibleComponent",
- "KP_RIGHT", "navigateRight",
- "DOWN", "navigateDown"
+ KeyStroke.getKeyStroke("ctrl DOWN"), "requestFocusForVisibleComponent",
+ KeyStroke.getKeyStroke("KP_UP"), "navigateUp",
+ KeyStroke.getKeyStroke("LEFT"), "navigateLeft",
+ KeyStroke.getKeyStroke("ctrl KP_DOWN"), "requestFocusForVisibleComponent",
+ KeyStroke.getKeyStroke("UP"), "navigateUp",
+ KeyStroke.getKeyStroke("KP_DOWN"), "navigateDown",
+ KeyStroke.getKeyStroke("KP_LEFT"), "navigateLeft",
+ KeyStroke.getKeyStroke("RIGHT"), "navigateRight",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "navigateRight",
+ KeyStroke.getKeyStroke("DOWN"), "navigateDown"
}),
"TabbedPane.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"TabbedPane.foreground", new ColorUIResource(darkShadow),
@@ -888,10 +1051,10 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"TabbedPane.light", new ColorUIResource(highLight),
"TabbedPane.selectedTabPadInsets", new InsetsUIResource(2, 2, 2, 1),
"TabbedPane.shadow", new ColorUIResource(shadow),
- "TabbedPane.tabbedPaneTabAreaInsets", new InsetsUIResource(3, 2, 1, 2),
- "TabbedPane.tabbedPaneTabInsets", new InsetsUIResource(1, 4, 1, 4),
"TabbedPane.tabbedPaneContentBorderInsets", new InsetsUIResource(3, 2, 1, 2),
"TabbedPane.tabbedPaneTabPadInsets", new InsetsUIResource(1, 1, 1, 1),
+ "TabbedPane.tabAreaInsets", new InsetsUIResource(3, 2, 0, 2),
+ "TabbedPane.tabInsets", new InsetsUIResource(0, 4, 1, 4),
"TabbedPane.tabRunOverlay", new Integer(2),
"TabbedPane.textIconGap", new Integer(4),
"Table.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
@@ -976,32 +1139,73 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"Table.selectionBackground", new ColorUIResource(new ColorUIResource(0, 0, 128)),
"Table.selectionForeground", new ColorUIResource(new ColorUIResource(255, 255, 255)),
"TableHeader.background", new ColorUIResource(new ColorUIResource(192, 192, 192)),
- "TableHeader.cellBorder", new BorderUIResource.BevelBorderUIResource(0),
"TableHeader.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"TableHeader.foreground", new ColorUIResource(new ColorUIResource(0, 0, 0)),
- "TextArea.background", new ColorUIResource(light),
- "TextArea.border",
- new BorderUIResource(BasicBorders.getMarginBorder()),
+ "TextArea.background", new ColorUIResource(light),
+ "TextArea.border", new BorderUIResource(BasicBorders.getMarginBorder()),
"TextArea.caretBlinkRate", new Integer(500),
"TextArea.caretForeground", new ColorUIResource(Color.black),
"TextArea.font", new FontUIResource("MonoSpaced", Font.PLAIN, 12),
"TextArea.foreground", new ColorUIResource(Color.black),
"TextArea.inactiveForeground", new ColorUIResource(Color.gray),
- "TextArea.keyBindings", new JTextComponent.KeyBinding[] {
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP,
- 0), "caret-up"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
- 0), "caret-down"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,
- 0), "page-up"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,
- 0), "page-down"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
- 0), "insert-break"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
- 0), "insert-tab")
- },
+ "TextArea.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
+ KeyStroke.getKeyStroke("shift UP"), "selection-up",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("shift ctrl LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("shift KP_UP"), "selection-up",
+ KeyStroke.getKeyStroke("DOWN"), "caret-down",
+ KeyStroke.getKeyStroke("shift ctrl T"), "previous-link-action",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("CUT"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("END"), "caret-end-line",
+ KeyStroke.getKeyStroke("shift PAGE_UP"), "selection-page-up",
+ KeyStroke.getKeyStroke("KP_UP"), "caret-up",
+ KeyStroke.getKeyStroke("DELETE"), "delete-next",
+ KeyStroke.getKeyStroke("ctrl HOME"), "caret-begin",
+ KeyStroke.getKeyStroke("shift LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("ctrl END"), "caret-end",
+ KeyStroke.getKeyStroke("BACK_SPACE"), "delete-previous",
+ KeyStroke.getKeyStroke("shift ctrl RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("KP_LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("shift KP_RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("ctrl SPACE"), "activate-link-action",
+ KeyStroke.getKeyStroke("ctrl H"), "delete-previous",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "unselect",
+ KeyStroke.getKeyStroke("ENTER"), "insert-break",
+ KeyStroke.getKeyStroke("shift HOME"), "selection-begin-line",
+ KeyStroke.getKeyStroke("RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_UP"), "selection-page-left",
+ KeyStroke.getKeyStroke("shift DOWN"), "selection-down",
+ KeyStroke.getKeyStroke("PAGE_DOWN"), "page-down",
+ KeyStroke.getKeyStroke("shift KP_LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("shift ctrl O"), "toggle-componentOrientation",
+ KeyStroke.getKeyStroke("ctrl X"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_DOWN"), "selection-page-right",
+ KeyStroke.getKeyStroke("ctrl C"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("shift END"), "selection-end-line",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("HOME"), "caret-begin-line",
+ KeyStroke.getKeyStroke("ctrl V"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("KP_DOWN"), "caret-down",
+ KeyStroke.getKeyStroke("ctrl A"), "select-all",
+ KeyStroke.getKeyStroke("shift RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("shift ctrl END"), "selection-end",
+ KeyStroke.getKeyStroke("COPY"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl KP_LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("ctrl T"), "next-link-action",
+ KeyStroke.getKeyStroke("shift KP_DOWN"), "selection-down",
+ KeyStroke.getKeyStroke("TAB"), "insert-tab",
+ KeyStroke.getKeyStroke("UP"), "caret-up",
+ KeyStroke.getKeyStroke("shift ctrl HOME"), "selection-begin",
+ KeyStroke.getKeyStroke("shift PAGE_DOWN"), "selection-page-down",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl KP_RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("PAGE_UP"), "page-up",
+ KeyStroke.getKeyStroke("PASTE"), "paste-from-clipboard"
+ }),
"TextArea.margin", new InsetsUIResource(0, 0, 0, 0),
"TextArea.selectionBackground", new ColorUIResource(Color.black),
"TextArea.selectionForeground", new ColorUIResource(Color.white),
@@ -1017,17 +1221,41 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"TextField.inactiveForeground", new ColorUIResource(Color.GRAY),
"TextField.light", new ColorUIResource(highLight),
"TextField.highlight", new ColorUIResource(light),
- "TextField.keyBindings", new JTextComponent.KeyBinding[] {
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
- 0),
- "notify-field-accept"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,
- InputEvent.SHIFT_DOWN_MASK),
- "selection-backward"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,
- InputEvent.SHIFT_DOWN_MASK),
- "selection-forward"),
- },
+ "TextField.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
+ KeyStroke.getKeyStroke("ENTER"), "notify-field-accept",
+ KeyStroke.getKeyStroke("LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("BACK_SPACE"), "delete-previous",
+ KeyStroke.getKeyStroke("ctrl X"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl C"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl V"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("shift LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("shift RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("HOME"), "caret-begin-line",
+ KeyStroke.getKeyStroke("END"), "caret-end-line",
+ KeyStroke.getKeyStroke("DELETE"), "delete-next",
+ KeyStroke.getKeyStroke("shift ctrl O"), "toggle-componentOrientation",
+ KeyStroke.getKeyStroke("shift KP_LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("ctrl H"), "delete-previous",
+ KeyStroke.getKeyStroke("KP_LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl KP_RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("COPY"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift HOME"), "selection-begin-line",
+ KeyStroke.getKeyStroke("shift ctrl LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("PASTE"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "unselect",
+ KeyStroke.getKeyStroke("ctrl A"), "select-all",
+ KeyStroke.getKeyStroke("shift KP_RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("CUT"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("shift ctrl KP_LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("shift END"), "selection-end-line",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "caret-next-word"
+ }),
"TextField.margin", new InsetsUIResource(0, 0, 0, 0),
"TextField.selectionBackground", new ColorUIResource(Color.black),
"TextField.selectionForeground", new ColorUIResource(Color.white),
@@ -1038,20 +1266,63 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"TextPane.font", new FontUIResource("Serif", Font.PLAIN, 12),
"TextPane.foreground", new ColorUIResource(Color.black),
"TextPane.inactiveForeground", new ColorUIResource(Color.gray),
- "TextPane.keyBindings", new JTextComponent.KeyBinding[] {
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP,
- 0), "caret-up"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
- 0), "caret-down"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,
- 0), "page-up"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,
- 0), "page-down"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
- 0), "insert-break"),
- new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
- 0), "insert-tab")
- },
+ "TextPane.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
+ KeyStroke.getKeyStroke("shift UP"), "selection-up",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("shift ctrl LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("shift KP_UP"), "selection-up",
+ KeyStroke.getKeyStroke("DOWN"), "caret-down",
+ KeyStroke.getKeyStroke("shift ctrl T"), "previous-link-action",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("CUT"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("END"), "caret-end-line",
+ KeyStroke.getKeyStroke("shift PAGE_UP"), "selection-page-up",
+ KeyStroke.getKeyStroke("KP_UP"), "caret-up",
+ KeyStroke.getKeyStroke("DELETE"), "delete-next",
+ KeyStroke.getKeyStroke("ctrl HOME"), "caret-begin",
+ KeyStroke.getKeyStroke("shift LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("ctrl END"), "caret-end",
+ KeyStroke.getKeyStroke("BACK_SPACE"), "delete-previous",
+ KeyStroke.getKeyStroke("shift ctrl RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("KP_LEFT"), "caret-backward",
+ KeyStroke.getKeyStroke("shift KP_RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("ctrl SPACE"), "activate-link-action",
+ KeyStroke.getKeyStroke("ctrl H"), "delete-previous",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "unselect",
+ KeyStroke.getKeyStroke("ENTER"), "insert-break",
+ KeyStroke.getKeyStroke("shift HOME"), "selection-begin-line",
+ KeyStroke.getKeyStroke("RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_UP"), "selection-page-left",
+ KeyStroke.getKeyStroke("shift DOWN"), "selection-down",
+ KeyStroke.getKeyStroke("PAGE_DOWN"), "page-down",
+ KeyStroke.getKeyStroke("shift KP_LEFT"), "selection-backward",
+ KeyStroke.getKeyStroke("shift ctrl O"), "toggle-componentOrientation",
+ KeyStroke.getKeyStroke("ctrl X"), "cut-to-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_DOWN"), "selection-page-right",
+ KeyStroke.getKeyStroke("ctrl C"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "caret-next-word",
+ KeyStroke.getKeyStroke("shift END"), "selection-end-line",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "caret-previous-word",
+ KeyStroke.getKeyStroke("HOME"), "caret-begin-line",
+ KeyStroke.getKeyStroke("ctrl V"), "paste-from-clipboard",
+ KeyStroke.getKeyStroke("KP_DOWN"), "caret-down",
+ KeyStroke.getKeyStroke("ctrl A"), "select-all",
+ KeyStroke.getKeyStroke("shift RIGHT"), "selection-forward",
+ KeyStroke.getKeyStroke("shift ctrl END"), "selection-end",
+ KeyStroke.getKeyStroke("COPY"), "copy-to-clipboard",
+ KeyStroke.getKeyStroke("shift ctrl KP_LEFT"), "selection-previous-word",
+ KeyStroke.getKeyStroke("ctrl T"), "next-link-action",
+ KeyStroke.getKeyStroke("shift KP_DOWN"), "selection-down",
+ KeyStroke.getKeyStroke("TAB"), "insert-tab",
+ KeyStroke.getKeyStroke("UP"), "caret-up",
+ KeyStroke.getKeyStroke("shift ctrl HOME"), "selection-begin",
+ KeyStroke.getKeyStroke("shift PAGE_DOWN"), "selection-page-down",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "caret-forward",
+ KeyStroke.getKeyStroke("shift ctrl KP_RIGHT"), "selection-next-word",
+ KeyStroke.getKeyStroke("PAGE_UP"), "page-up",
+ KeyStroke.getKeyStroke("PASTE"), "paste-from-clipboard"
+ }),
"TextPane.margin", new InsetsUIResource(3, 3, 3, 3),
"TextPane.selectionBackground", new ColorUIResource(Color.black),
"TextPane.selectionForeground", new ColorUIResource(Color.white),
@@ -1063,8 +1334,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel
new BorderUIResource.CompoundBorderUIResource(null, null),
"ToggleButton.darkShadow", new ColorUIResource(shadow),
"ToggleButton.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "SPACE", "pressed",
- "released SPACE", "released"
+ KeyStroke.getKeyStroke("SPACE"), "pressed",
+ KeyStroke.getKeyStroke("released SPACE"), "released"
}),
"ToggleButton.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"ToggleButton.foreground", new ColorUIResource(darkShadow),
@@ -1095,7 +1366,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"ToolBar.foreground", new ColorUIResource(darkShadow),
"ToolBar.highlight", new ColorUIResource(highLight),
"ToolBar.light", new ColorUIResource(highLight),
- "ToolBar.separatorSize", new DimensionUIResource(20, 20),
+ "ToolBar.separatorSize", new DimensionUIResource(10, 10),
"ToolBar.shadow", new ColorUIResource(shadow),
"ToolTip.background", new ColorUIResource(light),
"ToolTip.border", new BorderUIResource.LineBorderUIResource(Color.lightGray),
@@ -1106,72 +1377,145 @@ public abstract class BasicLookAndFeel extends LookAndFeel
}),
"Tree.background", new ColorUIResource(new Color(255, 255, 255)),
"Tree.changeSelectionWithFocus", Boolean.TRUE,
-// "Tree.closedIcon", new IconUIResource(new ImageIcon("icons/TreeClosed.png")),
-// "Tree.collapsedIcon", new IconUIResource(new ImageIcon("icons/TreeCollapsed.png")),
"Tree.drawsFocusBorderAroundIcon", Boolean.FALSE,
"Tree.editorBorder", new BorderUIResource.LineBorderUIResource(Color.lightGray),
"Tree.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
- "shift PAGE_DOWN", "scrollDownExtendSelection",
- "PAGE_DOWN", "scrollDownChangeSelection",
- "END", "selectLast",
- "ctrl KP_UP", "selectPreviousChangeLead",
- "shift END", "selectLastExtendSelection",
- "HOME", "selectFirst",
- "ctrl END", "selectLastChangeLead",
- "ctrl SLASH", "selectAll",
- "LEFT", "selectParent",
- "shift HOME", "selectFirstExtendSelection",
- "UP", "selectPrevious",
- "ctrl KP_DOWN", "selectNextChangeLead",
- "RIGHT", "selectChild",
- "ctrl HOME", "selectFirstChangeLead",
- "DOWN", "selectNext",
- "ctrl KP_LEFT", "scrollLeft",
- "shift UP", "selectPreviousExtendSelection",
- "F2", "startEditing",
- "ctrl LEFT", "scrollLeft",
- "ctrl KP_RIGHT","scrollRight",
- "ctrl UP", "selectPreviousChangeLead",
- "shift DOWN", "selectNextExtendSelection",
- "ENTER", "toggle",
- "KP_UP", "selectPrevious",
- "KP_DOWN", "selectNext",
- "ctrl RIGHT", "scrollRight",
- "KP_LEFT", "selectParent",
- "KP_RIGHT", "selectChild",
- "ctrl DOWN", "selectNextChangeLead",
- "ctrl A", "selectAll",
- "shift KP_UP", "selectPreviousExtendSelection",
- "shift KP_DOWN","selectNextExtendSelection",
- "ctrl SPACE", "toggleSelectionPreserveAnchor",
- "ctrl shift PAGE_UP", "scrollUpExtendSelection",
- "ctrl BACK_SLASH", "clearSelection",
- "shift SPACE", "extendSelection",
- "ctrl PAGE_UP", "scrollUpChangeLead",
- "shift PAGE_UP","scrollUpExtendSelection",
- "SPACE", "toggleSelectionPreserveAnchor",
- "ctrl shift PAGE_DOWN", "scrollDownExtendSelection",
- "PAGE_UP", "scrollUpChangeSelection",
- "ctrl PAGE_DOWN", "scrollDownChangeLead"
+ KeyStroke.getKeyStroke("ctrl DOWN"), "selectNextChangeLead",
+ KeyStroke.getKeyStroke("shift UP"), "selectPreviousExtendSelection",
+ KeyStroke.getKeyStroke("ctrl RIGHT"), "scrollRight",
+ KeyStroke.getKeyStroke("shift KP_UP"), "selectPreviousExtendSelection",
+ KeyStroke.getKeyStroke("DOWN"), "selectNext",
+ KeyStroke.getKeyStroke("ctrl UP"), "selectPreviousChangeLead",
+ KeyStroke.getKeyStroke("ctrl LEFT"), "scrollLeft",
+ KeyStroke.getKeyStroke("CUT"), "cut",
+ KeyStroke.getKeyStroke("END"), "selectLast",
+ KeyStroke.getKeyStroke("shift PAGE_UP"), "scrollUpExtendSelection",
+ KeyStroke.getKeyStroke("KP_UP"), "selectPrevious",
+ KeyStroke.getKeyStroke("shift ctrl UP"), "selectPreviousExtendSelection",
+ KeyStroke.getKeyStroke("ctrl HOME"), "selectFirstChangeLead",
+ KeyStroke.getKeyStroke("ctrl END"), "selectLastChangeLead",
+ KeyStroke.getKeyStroke("ctrl PAGE_DOWN"), "scrollDownChangeLead",
+ KeyStroke.getKeyStroke("LEFT"), "selectParent",
+ KeyStroke.getKeyStroke("ctrl PAGE_UP"), "scrollUpChangeLead",
+ KeyStroke.getKeyStroke("KP_LEFT"), "selectParent",
+ KeyStroke.getKeyStroke("SPACE"), "addToSelection",
+ KeyStroke.getKeyStroke("ctrl SPACE"), "toggleAndAnchor",
+ KeyStroke.getKeyStroke("shift SPACE"), "extendTo",
+ KeyStroke.getKeyStroke("shift ctrl SPACE"), "moveSelectionTo",
+ KeyStroke.getKeyStroke("ADD"), "expand",
+ KeyStroke.getKeyStroke("ctrl BACK_SLASH"), "clearSelection",
+ KeyStroke.getKeyStroke("shift ctrl DOWN"), "selectNextExtendSelection",
+ KeyStroke.getKeyStroke("shift HOME"), "selectFirstExtendSelection",
+ KeyStroke.getKeyStroke("RIGHT"), "selectChild",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_UP"), "scrollUpExtendSelection",
+ KeyStroke.getKeyStroke("shift DOWN"), "selectNextExtendSelection",
+ KeyStroke.getKeyStroke("PAGE_DOWN"), "scrollDownChangeSelection",
+ KeyStroke.getKeyStroke("shift ctrl KP_UP"), "selectPreviousExtendSelection",
+ KeyStroke.getKeyStroke("SUBTRACT"), "collapse",
+ KeyStroke.getKeyStroke("ctrl X"), "cut",
+ KeyStroke.getKeyStroke("shift ctrl PAGE_DOWN"), "scrollDownExtendSelection",
+ KeyStroke.getKeyStroke("ctrl SLASH"), "selectAll",
+ KeyStroke.getKeyStroke("ctrl C"), "copy",
+ KeyStroke.getKeyStroke("ctrl KP_RIGHT"), "scrollRight",
+ KeyStroke.getKeyStroke("shift END"), "selectLastExtendSelection",
+ KeyStroke.getKeyStroke("shift ctrl KP_DOWN"), "selectNextExtendSelection",
+ KeyStroke.getKeyStroke("ctrl KP_LEFT"), "scrollLeft",
+ KeyStroke.getKeyStroke("HOME"), "selectFirst",
+ KeyStroke.getKeyStroke("ctrl V"), "paste",
+ KeyStroke.getKeyStroke("KP_DOWN"), "selectNext",
+ KeyStroke.getKeyStroke("ctrl A"), "selectAll",
+ KeyStroke.getKeyStroke("ctrl KP_DOWN"), "selectNextChangeLead",
+ KeyStroke.getKeyStroke("shift ctrl END"), "selectLastExtendSelection",
+ KeyStroke.getKeyStroke("COPY"), "copy",
+ KeyStroke.getKeyStroke("ctrl KP_UP"), "selectPreviousChangeLead",
+ KeyStroke.getKeyStroke("shift KP_DOWN"), "selectNextExtendSelection",
+ KeyStroke.getKeyStroke("UP"), "selectPrevious",
+ KeyStroke.getKeyStroke("shift ctrl HOME"), "selectFirstExtendSelection",
+ KeyStroke.getKeyStroke("shift PAGE_DOWN"), "scrollDownExtendSelection",
+ KeyStroke.getKeyStroke("KP_RIGHT"), "selectChild",
+ KeyStroke.getKeyStroke("F2"), "startEditing",
+ KeyStroke.getKeyStroke("PAGE_UP"), "scrollUpChangeSelection",
+ KeyStroke.getKeyStroke("PASTE"), "paste"
}),
"Tree.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"Tree.foreground", new ColorUIResource(Color.black),
"Tree.hash", new ColorUIResource(new Color(128, 128, 128)),
"Tree.leftChildIndent", new Integer(7),
"Tree.rightChildIndent", new Integer(13),
- "Tree.rowHeight", new Integer(0),
+ "Tree.rowHeight", new Integer(16),
"Tree.scrollsOnExpand", Boolean.TRUE,
"Tree.selectionBackground", new ColorUIResource(Color.black),
"Tree.nonSelectionBackground", new ColorUIResource(new Color(255, 255, 255)),
"Tree.selectionBorderColor", new ColorUIResource(Color.black),
"Tree.selectionBorder", new BorderUIResource.LineBorderUIResource(Color.black),
"Tree.selectionForeground", new ColorUIResource(new Color(255, 255, 255)),
- "Tree.textBackground", new ColorUIResource(new Color(192, 192, 192)),
- "Tree.textForeground", new ColorUIResource(new Color(0, 0, 0)),
"Viewport.background", new ColorUIResource(light),
"Viewport.foreground", new ColorUIResource(Color.black),
"Viewport.font", new FontUIResource("Dialog", Font.PLAIN, 12)
};
defaults.putDefaults(uiDefaults);
}
-} // class BasicLookAndFeel
+
+ /**
+ * Returns the <code>ActionMap</code> that stores all the actions that are
+ * responsibly for rendering auditory cues.
+ *
+ * @return the action map that stores all the actions that are
+ * responsibly for rendering auditory cues
+ *
+ * @see #createAudioAction
+ * @see #playSound
+ *
+ * @since 1.4
+ */
+ protected ActionMap getAudioActionMap()
+ {
+ if (audioActionMap != null)
+ audioActionMap = new ActionMap();
+ return audioActionMap;
+ }
+
+ /**
+ * Creates an <code>Action</code> that can play an auditory cue specified by
+ * the key. The UIDefaults value for the key is normally a String that points
+ * to an audio file relative to the current package.
+ *
+ * @param key a UIDefaults key that specifies the sound
+ *
+ * @return an action that can play the sound
+ *
+ * @see #playSound
+ *
+ * @since 1.4
+ */
+ protected Action createAudioAction(Object key)
+ {
+ return new AudioAction(key);
+ }
+
+ /**
+ * Plays the sound of the action if it is listed in
+ * <code>AuditoryCues.playList</code>.
+ *
+ * @param audioAction the audio action to play
+ */
+ protected void playSound(Action audioAction)
+ {
+ if (audioAction instanceof AudioAction)
+ {
+ Object[] playList = (Object[]) UIManager.get("AuditoryCues.playList");
+ for (int i = 0; i < playList.length; ++i)
+ {
+ if (playList[i].equals(((AudioAction) audioAction).key))
+ {
+ ActionEvent ev = new ActionEvent(this,
+ ActionEvent.ACTION_PERFORMED,
+ (String) playList[i]);
+ audioAction.actionPerformed(ev);
+ break;
+ }
+ }
+ }
+ }
+
+}
diff --git a/javax/swing/plaf/basic/BasicMenuItemUI.java b/javax/swing/plaf/basic/BasicMenuItemUI.java
index c8754a3e0..63f0ce206 100644
--- a/javax/swing/plaf/basic/BasicMenuItemUI.java
+++ b/javax/swing/plaf/basic/BasicMenuItemUI.java
@@ -206,7 +206,10 @@ public class BasicMenuItemUI extends MenuItemUI
map.remove((KeyStroke)e.getOldValue());
else
map = new ComponentInputMapUIResource(menuItem);
- map.put((KeyStroke)e.getNewValue(), "doClick");
+
+ KeyStroke accelerator = (KeyStroke) e.getNewValue();
+ if (accelerator != null)
+ map.put(accelerator, "doClick");
}
}
}
@@ -485,7 +488,9 @@ public class BasicMenuItemUI extends MenuItemUI
InputMap focusedWindowMap = SwingUtilities.getUIInputMap(menuItem, JComponent.WHEN_IN_FOCUSED_WINDOW);
if (focusedWindowMap == null)
focusedWindowMap = new ComponentInputMapUIResource(menuItem);
- focusedWindowMap.put(menuItem.getAccelerator(), "doClick");
+ KeyStroke accelerator = menuItem.getAccelerator();
+ if (accelerator != null)
+ focusedWindowMap.put(accelerator, "doClick");
SwingUtilities.replaceUIInputMap(menuItem, JComponent.WHEN_IN_FOCUSED_WINDOW, focusedWindowMap);
ActionMap UIActionMap = SwingUtilities.getUIActionMap(menuItem);
@@ -555,17 +560,16 @@ public class BasicMenuItemUI extends MenuItemUI
// Menu item is considered to be highlighted when it is selected.
// But we don't want to paint the background of JCheckBoxMenuItems
ButtonModel mod = menuItem.getModel();
- if ((menuItem.isSelected() && checkIcon == null) || (mod != null &&
- mod.isArmed())
- && (menuItem.getParent() instanceof MenuElement))
+ if (menuItem.isContentAreaFilled())
{
- if (menuItem.isContentAreaFilled())
- {
- g.setColor(selectionBackground);
- g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
- }
- }
-
+ if ((menuItem.isSelected() && checkIcon == null) || (mod != null &&
+ mod.isArmed())
+ && (menuItem.getParent() instanceof MenuElement))
+ g.setColor(selectionBackground);
+ else
+ g.setColor(bgColor);
+ g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
+ }
}
/**
@@ -608,7 +612,7 @@ public class BasicMenuItemUI extends MenuItemUI
FontMetrics fm = g.getFontMetrics(f);
SwingUtilities.calculateInnerArea(m, br);
SwingUtilities.calculateInsetArea(br, m.getInsets(), vr);
- paintBackground(g, m, m.getBackground());
+ paintBackground(g, m, background);
/*
* MenuItems insets are equal to menuItems margin, space between text and
diff --git a/javax/swing/plaf/basic/BasicScrollPaneUI.java b/javax/swing/plaf/basic/BasicScrollPaneUI.java
index 808ed2763..71671b799 100644
--- a/javax/swing/plaf/basic/BasicScrollPaneUI.java
+++ b/javax/swing/plaf/basic/BasicScrollPaneUI.java
@@ -505,7 +505,8 @@ public class BasicScrollPaneUI extends ScrollPaneUI
JViewport oldViewport = (JViewport) ev.getOldValue();
oldViewport.removeChangeListener(viewportChangeListener);
JViewport newViewport = (JViewport) ev.getNewValue();
- oldViewport.addChangeListener(viewportChangeListener);
+ newViewport.addChangeListener(viewportChangeListener);
+ syncScrollPaneWithViewport();
}
}
diff --git a/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/javax/swing/plaf/basic/BasicTabbedPaneUI.java
index 1ee041097..a8f52cef6 100644
--- a/javax/swing/plaf/basic/BasicTabbedPaneUI.java
+++ b/javax/swing/plaf/basic/BasicTabbedPaneUI.java
@@ -1549,9 +1549,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
textIconGap = UIManager.getInt("TabbedPane.textIconGap");
tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
- tabInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabInsets");
+ tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
selectedTabPadInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabPadInsets");
- tabAreaInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabAreaInsets");
+ tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
contentBorderInsets = UIManager.getInsets("TabbedPane.tabbedPaneContentBorderInsets");
calcRect = new Rectangle();
diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java
index be668671b..fc3889484 100644
--- a/javax/swing/plaf/basic/BasicTextUI.java
+++ b/javax/swing/plaf/basic/BasicTextUI.java
@@ -46,15 +46,20 @@ 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;
import javax.swing.JComponent;
+import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
@@ -62,6 +67,7 @@ import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TextUI;
import javax.swing.plaf.UIResource;
import javax.swing.text.BadLocationException;
@@ -615,15 +621,25 @@ public abstract class BasicTextUI extends TextUI
*/
protected Keymap createKeymap()
{
+ JTextComponent.KeyBinding[] bindings = null;
String prefix = getPropertyPrefix();
- JTextComponent.KeyBinding[] bindings =
- (JTextComponent.KeyBinding[]) UIManager.get(prefix + ".keyBindings");
+ InputMapUIResource m = (InputMapUIResource) UIManager.get(prefix + ".focusInputMap");
+ if (m != null)
+ {
+ KeyStroke[] keys = m.keys();
+ int len = keys.length;
+ bindings = new JTextComponent.KeyBinding[len];
+ for (int i = 0; i < len; i++)
+ {
+ KeyStroke curr = keys[i];
+ bindings[i] = new JTextComponent.KeyBinding(curr,
+ (String) m.get(curr));
+ }
+ }
if (bindings == null)
{
bindings = new JTextComponent.KeyBinding[0];
- // FIXME: Putting something into the defaults map is certainly wrong.
- // Must be fixed somehow.
- UIManager.put(prefix + ".keyBindings", bindings);
+ UIManager.put(prefix + ".focusInputMap", bindings);
}
Keymap km = JTextComponent.addKeymap(getKeymapName(),
@@ -636,18 +652,45 @@ public abstract class BasicTextUI extends TextUI
* Installs the keyboard actions on the text components.
*/
protected void installKeyboardActions()
- {
- // load any bindings for the older Keymap interface
+ {
+ // load key bindings for the older interface
Keymap km = JTextComponent.getKeymap(getKeymapName());
if (km == null)
km = createKeymap();
textComponent.setKeymap(km);
// load any bindings for the newer InputMap / ActionMap interface
- SwingUtilities.replaceUIInputMap(textComponent,
- JComponent.WHEN_FOCUSED,
+ SwingUtilities.replaceUIInputMap(textComponent, JComponent.WHEN_FOCUSED,
getInputMap(JComponent.WHEN_FOCUSED));
- SwingUtilities.replaceUIActionMap(textComponent, getActionMap());
+ SwingUtilities.replaceUIActionMap(textComponent, createActionMap());
+
+ ActionMap parentActionMap = new ActionMapUIResource();
+ Action[] actions = textComponent.getActions();
+ for (int j = 0; j < actions.length; j++)
+ {
+ Action currAction = actions[j];
+ parentActionMap.put(currAction.getValue(Action.NAME), currAction);
+ }
+
+ SwingUtilities.replaceUIActionMap(textComponent, parentActionMap);
+ }
+
+ /**
+ * Creates an ActionMap to be installed on the text component.
+ *
+ * @return an ActionMap to be installed on the text component
+ */
+ ActionMap createActionMap()
+ {
+ Action[] actions = textComponent.getActions();
+ ActionMap am = new ActionMapUIResource();
+ for (int i = 0; i < actions.length; ++i)
+ {
+ String name = (String) actions[i].getValue(Action.NAME);
+ if (name != null)
+ am.put(name, actions[i]);
+ }
+ return am;
}
/**
@@ -674,46 +717,6 @@ public abstract class BasicTextUI extends TextUI
}
/**
- * Returns the ActionMap to be installed on the text component.
- *
- * @return the ActionMap to be installed on the text component
- */
- // FIXME: The UIDefaults have no entries for .actionMap, so this should
- // be handled somehow different.
- ActionMap getActionMap()
- {
- String prefix = getPropertyPrefix();
- ActionMap am = (ActionMap) UIManager.get(prefix + ".actionMap");
- if (am == null)
- {
- am = createActionMap();
- // FIXME: Putting something in the UIDefaults map is certainly wrong.
- // However, the whole method seems wrong and must be replaced by
- // something that is less wrong.
- UIManager.put(prefix + ".actionMap", am);
- }
- return am;
- }
-
- /**
- * Creates an ActionMap to be installed on the text component.
- *
- * @return an ActionMap to be installed on the text component
- */
- ActionMap createActionMap()
- {
- Action[] actions = textComponent.getActions();
- ActionMap am = new ActionMapUIResource();
- for (int i = 0; i < actions.length; ++i)
- {
- String name = (String) actions[i].getValue(Action.NAME);
- if (name != null)
- am.put(name, actions[i]);
- }
- return am;
- }
-
- /**
* Uninstalls this TextUI from the text component.
*
* @param component the text component to uninstall the UI from
diff --git a/javax/swing/plaf/basic/BasicTreeUI.java b/javax/swing/plaf/basic/BasicTreeUI.java
index 4100442a0..3bb803a56 100644
--- a/javax/swing/plaf/basic/BasicTreeUI.java
+++ b/javax/swing/plaf/basic/BasicTreeUI.java
@@ -112,7 +112,6 @@ import javax.swing.tree.TreeSelectionModel;
* the Basic look and feel.
*
* @see javax.swing.JTree
- *
* @author Lillian Angel (langel@redhat.com)
* @author Sascha Brawer (brawer@dandelis.ch)
*/
@@ -173,7 +172,7 @@ public class BasicTreeUI extends TreeUI
/** Size needed to completely display all the nodes. */
protected Dimension preferredSize;
-
+
/** Minimum size needed to completely display all the nodes. */
protected Dimension preferredMinSize;
@@ -225,7 +224,7 @@ 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();
@@ -234,29 +233,38 @@ public class BasicTreeUI extends TreeUI
/** The action bound to KeyStrokes. */
TreeAction action;
-
+
/** Boolean to keep track of editing. */
boolean isEditing;
-
+
/** The current path of the visible nodes in the tree. */
TreePath currentVisiblePath;
-
+
/** The gap between the icon and text. */
int gap = 4;
-
- /** Default row height, if none was set. */
- int rowHeight = 20;
+
+ /** The max height of the nodes in the tree. */
+ int maxHeight = 0;
/** Listeners */
private PropertyChangeListener propertyChangeListener;
+
private FocusListener focusListener;
+
private TreeSelectionListener treeSelectionListener;
+
private MouseListener mouseListener;
+
private KeyListener keyListener;
+
private PropertyChangeListener selectionModelPropertyChangeListener;
+
private ComponentListener componentListener;
+
CellEditorListener cellEditorListener;
+
private TreeExpansionListener treeExpansionListener;
+
private TreeModelListener treeModelListener;
/**
@@ -437,7 +445,7 @@ public class BasicTreeUI extends TreeUI
protected void setRowHeight(int rowHeight)
{
if (rowHeight == 0)
- rowHeight = this.rowHeight;
+ rowHeight = Math.max(getMaxHeight(tree), 20);
treeState.setRowHeight(rowHeight);
}
@@ -625,19 +633,49 @@ public class BasicTreeUI extends TreeUI
*/
public Rectangle getPathBounds(JTree tree, TreePath path)
{
- Rectangle bounds = null;
int row = -1;
Object cell = null;
if (path != null)
{
row = getRowForPath(tree, path);
cell = path.getLastPathComponent();
- bounds = new Rectangle(0, row * getRowHeight(), 0, 0);
}
- return nodeDimensions.getNodeDimensions(cell, row,
- getLevel(cell),
+ return nodeDimensions.getNodeDimensions(cell, row, getLevel(cell),
tree.isExpanded(path),
- bounds);
+ new Rectangle());
+ }
+
+ /**
+ * Returns the max height of all the nodes in the tree.
+ *
+ * @param tree -
+ * the current tree
+ * @return the max height.
+ */
+ private int getMaxHeight(JTree tree)
+ {
+ if (maxHeight != 0)
+ return maxHeight;
+
+ Icon e = UIManager.getIcon("Tree.openIcon");
+ Icon c = UIManager.getIcon("Tree.closedIcon");
+ Icon l = UIManager.getIcon("Tree.leafIcon");
+ int rc = getRowCount(tree);
+ int iconHeight = 0;
+
+ for (int row = 0; row < rc; row++)
+ {
+ if (isLeaf(row))
+ iconHeight = l.getIconHeight();
+ else if (tree.isExpanded(row))
+ iconHeight = e.getIconHeight();
+ else
+ iconHeight = c.getIconHeight();
+
+ maxHeight = Math.max(maxHeight, iconHeight + gap);
+ }
+
+ return maxHeight;
}
/**
@@ -684,7 +722,7 @@ public class BasicTreeUI extends TreeUI
{
if (dest.equals(nodes[row]))
return row;
- row++;
+ row++;
}
}
return -1;
@@ -720,7 +758,7 @@ public class BasicTreeUI extends TreeUI
*/
public TreePath getClosestPathForLocation(JTree tree, int x, int y)
{
- int row = Math.round(y / getRowHeight());
+ int row = Math.round(y / getMaxHeight(tree));
TreePath path = getPathForRow(tree, row);
// no row is visible at this node
@@ -977,10 +1015,12 @@ public class BasicTreeUI extends TreeUI
protected TreeCellEditor createDefaultCellEditor()
{
if (currentCellRenderer != null)
- return new DefaultTreeCellEditor(tree,
+ return new DefaultTreeCellEditor(
+ tree,
(DefaultTreeCellRenderer) currentCellRenderer,
cellEditor);
- return new DefaultTreeCellEditor(tree,
+ return new DefaultTreeCellEditor(
+ tree,
(DefaultTreeCellRenderer) createDefaultCellRenderer(),
cellEditor);
}
@@ -1034,7 +1074,8 @@ public class BasicTreeUI extends TreeUI
protected void uninstallKeyboardActions()
{
action = null;
- tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(null);
+ tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
+ null);
tree.getActionMap().setParent(null);
}
@@ -1094,7 +1135,7 @@ public class BasicTreeUI extends TreeUI
{
Enumeration expanded = tree.getExpandedDescendants(path);
while (expanded.hasMoreElements())
- treeState.setExpandedState(((TreePath) expanded.nextElement()), true);
+ treeState.setExpandedState(((TreePath) expanded.nextElement()), true);
}
/**
@@ -1125,7 +1166,7 @@ public class BasicTreeUI extends TreeUI
protected void updateCellEditor()
{
if (tree.isEditable() && cellEditor == null)
- setCellEditor(createDefaultCellEditor());
+ setCellEditor(createDefaultCellEditor());
createdCellEditor = true;
}
@@ -1136,10 +1177,10 @@ public class BasicTreeUI extends TreeUI
{
if (tree != null)
{
- if(tree.getCellRenderer() == null)
- {
- if(currentCellRenderer == null)
- currentCellRenderer = createDefaultCellRenderer();
+ if (tree.getCellRenderer() == null)
+ {
+ if (currentCellRenderer == null)
+ currentCellRenderer = createDefaultCellRenderer();
tree.setCellRenderer(currentCellRenderer);
}
}
@@ -1186,9 +1227,13 @@ public class BasicTreeUI extends TreeUI
bounds.width += getCurrentControlIcon(curr).getIconWidth();
maxWidth = Math.max(maxWidth, bounds.x + bounds.width);
}
- preferredSize = new Dimension(maxWidth, (getRowHeight() * path.length));
+
+ maxHeight = 0;
+ maxHeight = getMaxHeight(tree);
+ preferredSize = new Dimension(maxWidth, (maxHeight * path.length));
}
- else preferredSize = new Dimension(0, 0);
+ else
+ preferredSize = new Dimension(0, 0);
validCachedPreferredSize = true;
}
@@ -1201,7 +1246,6 @@ public class BasicTreeUI extends TreeUI
protected void pathWasExpanded(TreePath path)
{
validCachedPreferredSize = false;
- tree.revalidate();
tree.repaint();
}
@@ -1211,7 +1255,6 @@ public class BasicTreeUI extends TreeUI
protected void pathWasCollapsed(TreePath path)
{
validCachedPreferredSize = false;
- tree.revalidate();
tree.repaint();
}
@@ -1345,19 +1388,12 @@ public class BasicTreeUI extends TreeUI
installComponents();
installKeyboardActions();
installListeners();
-
+
setCellEditor(createDefaultCellEditor());
createdCellEditor = true;
isEditing = false;
- TreeModel mod = tree.getModel();
- setModel(mod);
- if (mod != null)
- {
- TreePath path = new TreePath(mod.getRoot());
- if (!tree.isExpanded(path))
- toggleExpandState(path);
- }
+ setModel(tree.getModel());
treeSelectionModel = tree.getSelectionModel();
completeUIInstall();
@@ -1406,8 +1442,7 @@ public class BasicTreeUI extends TreeUI
public void paint(Graphics g, JComponent c)
{
JTree tree = (JTree) c;
- if (currentVisiblePath == null)
- updateCurrentVisiblePath();
+ updateCurrentVisiblePath();
Rectangle clip = g.getClipBounds();
Insets insets = tree.getInsets();
@@ -1451,7 +1486,7 @@ public class BasicTreeUI extends TreeUI
endRow = beginRow;
beginRow = temp;
}
-
+
for (int i = beginRow; i < endRow; i++)
{
TreePath path = getPathForRow(tree, i);
@@ -1508,8 +1543,8 @@ public class BasicTreeUI extends TreeUI
*/
public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
{
- // FIXME: checkConsistancy not implemented, c not used
- if(!validCachedPreferredSize)
+ // FIXME: checkConsistancy not implemented, c not used
+ if (!validCachedPreferredSize)
updateCachedPreferredSize();
return preferredSize;
}
@@ -1524,7 +1559,7 @@ public class BasicTreeUI extends TreeUI
*/
public Dimension getMinimumSize(JComponent c)
{
- Dimension min = getPreferredMinSize();
+ Dimension min = getPreferredMinSize();
if (min == null)
return new Dimension();
return min;
@@ -1636,7 +1671,7 @@ public class BasicTreeUI extends TreeUI
tree.add(editingComponent.getParent());
editingComponent.getParent().validate();
validCachedPreferredSize = false;
- tree.revalidate();
+
((JTextField) editingComponent).requestFocusInWindow(false);
editorTimer.start();
return true;
@@ -1682,12 +1717,13 @@ public class BasicTreeUI extends TreeUI
{
boolean cntlClick = false;
int row = getRowForPath(tree, path);
-
+
if (!isLeaf(row))
{
Rectangle bounds = getPathBounds(tree, path);
- if (hasControlIcons() && (mouseX < bounds.x)
+ if (hasControlIcons()
+ && (mouseX < bounds.x)
&& (mouseX > (bounds.x - getCurrentControlIcon(path).getIconWidth() - gap)))
cntlClick = true;
}
@@ -1725,7 +1761,6 @@ public class BasicTreeUI extends TreeUI
tree.collapsePath(path);
else
tree.expandPath(path);
- updateCurrentVisiblePath();
}
/**
@@ -1739,8 +1774,7 @@ public class BasicTreeUI extends TreeUI
*/
protected boolean isToggleSelectionEvent(MouseEvent event)
{
- return (tree.getSelectionModel().getSelectionMode() ==
- TreeSelectionModel.SINGLE_TREE_SELECTION);
+ return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION);
}
/**
@@ -1754,8 +1788,7 @@ public class BasicTreeUI extends TreeUI
*/
protected boolean isMultiSelectEvent(MouseEvent event)
{
- return (tree.getSelectionModel().getSelectionMode() ==
- TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
+ return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
}
/**
@@ -1834,8 +1867,7 @@ public class BasicTreeUI extends TreeUI
* are pressed for the JTree. The actionPerformed method is called when a key
* that has been registered for the JTree is received.
*/
- class TreeAction
- extends AbstractAction
+ class TreeAction extends AbstractAction
{
/**
@@ -1877,7 +1909,7 @@ public class BasicTreeUI extends TreeUI
else if (e.getActionCommand().equals("toggle"))
{
if (tree.isEditing())
- tree.stopEditing();
+ tree.stopEditing();
else
{
Object last = lead.getLastPathComponent();
@@ -1903,8 +1935,7 @@ public class BasicTreeUI extends TreeUI
* to the true receiver after altering the actionCommand property of the
* event.
*/
- private static class ActionListenerProxy
- extends AbstractAction
+ private static class ActionListenerProxy extends AbstractAction
{
ActionListener target;
@@ -1929,9 +1960,7 @@ public class BasicTreeUI extends TreeUI
/**
* The timer that updates the editor component.
*/
- private class EditorUpdateTimer
- extends Timer
- implements ActionListener
+ private class EditorUpdateTimer extends Timer implements ActionListener
{
/**
* Creates a new EditorUpdateTimer object with a default delay of 0.3
@@ -1975,8 +2004,8 @@ public class BasicTreeUI extends TreeUI
/**
* Updates the preferred size when scrolling, if necessary.
*/
- public class ComponentHandler extends ComponentAdapter
- implements ActionListener
+ public class ComponentHandler extends ComponentAdapter implements
+ ActionListener
{
/**
* Timer used when inside a scrollpane and the scrollbar is adjusting
@@ -2006,8 +2035,8 @@ public class BasicTreeUI extends TreeUI
}
/**
- * Creates, if necessary, and starts a Timer to check if needed to resize the
- * bounds
+ * Creates, if necessary, and starts a Timer to check if needed to resize
+ * the bounds
*/
protected void startTimer()
{
@@ -2082,7 +2111,6 @@ public class BasicTreeUI extends TreeUI
tree.requestFocusInWindow(false);
editorTimer.stop();
validCachedPreferredSize = false;
- tree.revalidate();
tree.repaint();
}
@@ -2113,7 +2141,6 @@ public class BasicTreeUI extends TreeUI
editorTimer.stop();
isEditing = false;
validCachedPreferredSize = false;
- tree.revalidate();
tree.repaint();
}
}// CellEditorHandler
@@ -2121,8 +2148,7 @@ public class BasicTreeUI extends TreeUI
/**
* Repaints the lead selection row when focus is lost/grained.
*/
- public class FocusHandler
- implements FocusListener
+ public class FocusHandler implements FocusListener
{
/**
* Constructor
@@ -2161,8 +2187,7 @@ public class BasicTreeUI extends TreeUI
* This is used to get multiple key down events to appropriately genereate
* events.
*/
- public class KeyHandler
- extends KeyAdapter
+ public class KeyHandler extends KeyAdapter
{
/** Key code that is being generated for. */
protected Action repeatKeyAction;
@@ -2247,7 +2272,7 @@ public class BasicTreeUI extends TreeUI
boolean cntlClick = isLocationInExpandControl(path, click.x, click.y);
boolean isLeaf = isLeaf(row);
-
+
TreeCellRenderer tcr = getCellRenderer();
Icon icon;
if (isLeaf)
@@ -2256,17 +2281,17 @@ public class BasicTreeUI extends TreeUI
icon = UIManager.getIcon("Tree.openIcon");
else
icon = UIManager.getIcon("Tree.closedIcon");
-
+
if (tcr instanceof DefaultTreeCellRenderer)
{
- Icon tmp = ((DefaultTreeCellRenderer) tcr).getIcon();
- if (tmp != null)
- icon = tmp;
+ Icon tmp = ((DefaultTreeCellRenderer) tcr).getIcon();
+ if (tmp != null)
+ icon = tmp;
}
-
+
// add gap*2 for the space before and after the text
if (icon != null)
- bounds.width += icon.getIconWidth() + gap*2;
+ bounds.width += icon.getIconWidth() + gap * 2;
boolean inBounds = bounds.contains(click.x, click.y);
if ((inBounds || cntlClick) && tree.isVisible(path))
@@ -2275,9 +2300,9 @@ public class BasicTreeUI extends TreeUI
{
selectPath(tree, path);
if (e.getClickCount() == 2 && !isLeaf(row))
- toggleExpandState(path);
+ toggleExpandState(path);
}
-
+
if (cntlClick)
{
handleExpandControlClick(path, click.x, click.y);
@@ -2455,8 +2480,7 @@ public class BasicTreeUI extends TreeUI
* BasicTreeUI method. X location does not include insets, that is handled in
* getPathBounds.
*/
- public class NodeDimensionsHandler
- extends AbstractLayoutCache.NodeDimensions
+ public class NodeDimensionsHandler extends AbstractLayoutCache.NodeDimensions
{
/**
* Constructor
@@ -2467,10 +2491,10 @@ public class BasicTreeUI extends TreeUI
}
/**
- * Returns, by reference in bounds, the size and x origin to place value at.
- * The calling method is responsible for determining the Y location.
- * If bounds is null, a newly created Rectangle should be returned,
- * otherwise the value should be placed in bounds and returned.
+ * Returns, by reference in bounds, the size and x origin to place value at.
+ * The calling method is responsible for determining the Y location. If
+ * bounds is null, a newly created Rectangle should be returned, otherwise
+ * the value should be placed in bounds and returned.
*
* @param cell
* the value to be represented
@@ -2498,8 +2522,10 @@ public class BasicTreeUI extends TreeUI
{
size.x = getRowX(row, depth);
size.width = SwingUtilities.computeStringWidth(fm, s);
- size.height = fm.getHeight();
+ size.height = getMaxHeight(tree);
+ size.y = size.height * row;
}
+
return size;
}
@@ -2520,8 +2546,7 @@ public class BasicTreeUI extends TreeUI
* PropertyChangeListener for the tree. Updates the appropriate varaible, or
* TreeState, based on what changes.
*/
- public class PropertyChangeHandler
- implements PropertyChangeListener
+ public class PropertyChangeHandler implements PropertyChangeListener
{
/**
@@ -2544,8 +2569,6 @@ public class BasicTreeUI extends TreeUI
if ((event.getPropertyName()).equals("rootVisible"))
{
validCachedPreferredSize = false;
- updateCurrentVisiblePath();
- tree.revalidate();
tree.repaint();
}
}
@@ -2555,8 +2578,8 @@ public class BasicTreeUI extends TreeUI
* Listener on the TreeSelectionModel, resets the row selection if any of the
* properties of the model change.
*/
- public class SelectionModelPropertyChangeHandler
- implements PropertyChangeListener
+ public class SelectionModelPropertyChangeHandler implements
+ PropertyChangeListener
{
/**
@@ -2583,8 +2606,7 @@ public class BasicTreeUI extends TreeUI
/**
* ActionListener that invokes cancelEditing when action performed.
*/
- public class TreeCancelEditingAction
- extends AbstractAction
+ public class TreeCancelEditingAction extends AbstractAction
{
/**
@@ -2621,8 +2643,7 @@ public class BasicTreeUI extends TreeUI
/**
* Updates the TreeState in response to nodes expanding/collapsing.
*/
- public class TreeExpansionHandler
- implements TreeExpansionListener
+ public class TreeExpansionHandler implements TreeExpansionListener
{
/**
@@ -2642,8 +2663,6 @@ public class BasicTreeUI extends TreeUI
public void treeExpanded(TreeExpansionEvent event)
{
validCachedPreferredSize = false;
- updateCurrentVisiblePath();
- tree.revalidate();
tree.repaint();
}
@@ -2656,8 +2675,6 @@ public class BasicTreeUI extends TreeUI
public void treeCollapsed(TreeExpansionEvent event)
{
validCachedPreferredSize = false;
- updateCurrentVisiblePath();
- tree.revalidate();
tree.repaint();
}
}// TreeExpansionHandler
@@ -2666,8 +2683,7 @@ public class BasicTreeUI extends TreeUI
* TreeHomeAction is used to handle end/home actions. Scrolls either the first
* or last cell to be visible based on direction.
*/
- public class TreeHomeAction
- extends AbstractAction
+ public class TreeHomeAction extends AbstractAction
{
/** direction is either home or end */
@@ -2713,8 +2729,7 @@ public class BasicTreeUI extends TreeUI
* TreeIncrementAction is used to handle up/down actions. Selection is moved
* up or down based on direction.
*/
- public class TreeIncrementAction
- extends AbstractAction
+ public class TreeIncrementAction extends AbstractAction
{
/** Specifies the direction to adjust the selection by. */
@@ -2746,7 +2761,7 @@ public class BasicTreeUI extends TreeUI
if (e.getActionCommand().equals("selectPreviousChangeLead"))
{
Object prev = getPreviousVisibleNode(last);
-
+
if (prev != null)
{
TreePath newPath = new TreePath(getPathToRoot(prev, 0));
@@ -2767,7 +2782,7 @@ public class BasicTreeUI extends TreeUI
else if (e.getActionCommand().equals("selectPrevious"))
{
Object prev = getPreviousVisibleNode(last);
-
+
if (prev != null)
{
TreePath newPath = new TreePath(getPathToRoot(prev, 0));
@@ -2777,7 +2792,7 @@ public class BasicTreeUI extends TreeUI
else if (e.getActionCommand().equals("selectNext"))
{
Object next = getNextVisibleNode(last);
-
+
if (next != null)
{
TreePath newPath = new TreePath(getPathToRoot(next, 0));
@@ -2847,8 +2862,6 @@ public class BasicTreeUI extends TreeUI
public void treeNodesChanged(TreeModelEvent e)
{
validCachedPreferredSize = false;
- updateCurrentVisiblePath();
- tree.revalidate();
tree.repaint();
}
@@ -2863,8 +2876,6 @@ public class BasicTreeUI extends TreeUI
public void treeNodesInserted(TreeModelEvent e)
{
validCachedPreferredSize = false;
- updateCurrentVisiblePath();
- tree.revalidate();
tree.repaint();
}
@@ -2882,8 +2893,6 @@ public class BasicTreeUI extends TreeUI
public void treeNodesRemoved(TreeModelEvent e)
{
validCachedPreferredSize = false;
- updateCurrentVisiblePath();
- tree.revalidate();
tree.repaint();
}
@@ -2902,9 +2911,7 @@ public class BasicTreeUI extends TreeUI
if (e.getPath().length == 1
&& !e.getPath()[0].equals(treeModel.getRoot()))
tree.expandPath(new TreePath(treeModel.getRoot()));
- updateCurrentVisiblePath();
validCachedPreferredSize = false;
- tree.revalidate();
tree.repaint();
}
}// TreeModelHandler
@@ -3102,7 +3109,7 @@ public class BasicTreeUI extends TreeUI
return true;
return false;
}
-
+
/**
* Returns control icon. It is null if the LookAndFeel does not implements the
* control icons. Package private for use in inner classes.
@@ -3127,10 +3134,9 @@ public class BasicTreeUI extends TreeUI
*/
Object getParent(Object root, Object node)
{
- if (root == null || node == null ||
- root.equals(node))
+ if (root == null || node == null || root.equals(node))
return null;
-
+
if (node instanceof TreeNode)
return ((TreeNode) node).getParent();
return findNode(root, node);
@@ -3163,7 +3169,7 @@ public class BasicTreeUI extends TreeUI
}
return null;
}
-
+
/**
* Get previous visible node in the tree. Package private for use in inner
* classes.
@@ -3182,8 +3188,8 @@ public class BasicTreeUI extends TreeUI
while (i < nodes.length && !node.equals(nodes[i]))
i++;
// return the next node
- if (i-1 >= 0)
- return nodes[i-1];
+ if (i - 1 >= 0)
+ return nodes[i - 1];
}
return null;
}
@@ -3191,7 +3197,7 @@ public class BasicTreeUI extends TreeUI
/**
* Returns the next node in the tree Package private for use in inner classes.
*
- * @param curr -
+ * @param curr -
* current node
* @return the next node in the tree
*/
@@ -3208,7 +3214,7 @@ public class BasicTreeUI extends TreeUI
node = getParent(treeModel.getRoot(), node);
}
while (sibling == null && node != null);
-
+
return sibling;
}
@@ -3250,7 +3256,7 @@ public class BasicTreeUI extends TreeUI
* Returns the next sibling in the tree Package private for use in inner
* classes.
*
- * @param node -
+ * @param node -
* current node
* @return the next sibling in the tree
*/
@@ -3270,7 +3276,7 @@ public class BasicTreeUI extends TreeUI
return treeModel.getChild(parent, index);
}
-
+
/**
* Returns the previous sibling in the tree Package private for use in inner
* classes.
@@ -3309,15 +3315,13 @@ public class BasicTreeUI extends TreeUI
{
if (path != null)
{
- if (tree.getSelectionModel().getSelectionMode() ==
- TreeSelectionModel.SINGLE_TREE_SELECTION)
+ if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION)
{
tree.getSelectionModel().clearSelection();
tree.addSelectionPath(path);
tree.setLeadSelectionPath(path);
}
- else if (tree.getSelectionModel().getSelectionMode() ==
- TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
+ else if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
{
// TODO
}
@@ -3325,8 +3329,8 @@ public class BasicTreeUI extends TreeUI
{
tree.addSelectionPath(path);
tree.setLeadSelectionPath(path);
- tree.getSelectionModel().setSelectionMode
- (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
+ tree.getSelectionModel().setSelectionMode(
+ TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
}
}
}
@@ -3351,7 +3355,8 @@ public class BasicTreeUI extends TreeUI
return new Object[depth];
}
- Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node), depth + 1);
+ Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node),
+ depth + 1);
path[path.length - depth - 1] = node;
return path;
}
@@ -3374,7 +3379,7 @@ public class BasicTreeUI extends TreeUI
Object root = treeModel.getRoot();
if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root)))
count--;
-
+
do
{
current = getParent(root, current);
@@ -3441,28 +3446,32 @@ public class BasicTreeUI extends TreeUI
* @param x
* is the center position in x-direction
* @param y
- * is the center position in y-direction
+ * is the center position in y-direction
*/
protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
{
x -= icon.getIconWidth() / 2;
y -= icon.getIconHeight() / 2;
-
+
if (x < 0)
x = 0;
if (y < 0)
y = 0;
-
+
icon.paintIcon(c, g, x, y);
}
-
+
/**
* Draws a dashed horizontal line.
*
- * @param g - the graphics configuration.
- * @param y - the y location to start drawing at
- * @param x1 - the x location to start drawing at
- * @param x2 - the x location to finish drawing at
+ * @param g -
+ * the graphics configuration.
+ * @param y -
+ * the y location to start drawing at
+ * @param x1 -
+ * the x location to start drawing at
+ * @param x2 -
+ * the x location to finish drawing at
*/
protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
{
@@ -3470,14 +3479,18 @@ public class BasicTreeUI extends TreeUI
for (int i = x1; i < x2; i += 2)
g.drawLine(i, y, i + 1, y);
}
-
+
/**
* Draws a dashed vertical line.
*
- * @param g - the graphics configuration.
- * @param x - the x location to start drawing at
- * @param y1 - the y location to start drawing at
- * @param y2 - the y location to finish drawing at
+ * @param g -
+ * the graphics configuration.
+ * @param x -
+ * the x location to start drawing at
+ * @param y1 -
+ * the y location to start drawing at
+ * @param y2 -
+ * the y location to finish drawing at
*/
protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
{
@@ -3485,72 +3498,89 @@ public class BasicTreeUI extends TreeUI
for (int i = y1; i < y2; i += 2)
g.drawLine(x, i, x, i + 1);
}
-
+
/**
- * Paints the expand (toggle) part of a row. The receiver should NOT modify
+ * Paints the expand (toggle) part of a row. The receiver should NOT modify
* clipBounds, or insets.
*
- * @param g - the graphics configuration
- * @param clipBounds -
- * @param insets -
- * @param bounds - bounds of expand control
- * @param path - path to draw control for
- * @param row - row to draw control for
- * @param isExpanded - is the row expanded
- * @param hasBeenExpanded - has the row already been expanded
- * @param isLeaf - is the path a leaf
+ * @param g -
+ * the graphics configuration
+ * @param clipBounds -
+ * @param insets -
+ * @param bounds -
+ * bounds of expand control
+ * @param path -
+ * path to draw control for
+ * @param row -
+ * row to draw control for
+ * @param isExpanded -
+ * is the row expanded
+ * @param hasBeenExpanded -
+ * has the row already been expanded
+ * @param isLeaf -
+ * is the path a leaf
*/
protected void paintExpandControl(Graphics g, Rectangle clipBounds,
Insets insets, Rectangle bounds,
- TreePath path, int row,
- boolean isExpanded, boolean hasBeenExpanded,
- boolean isLeaf)
+ TreePath path, int row, boolean isExpanded,
+ boolean hasBeenExpanded, boolean isLeaf)
{
if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf))
{
Icon icon = getCurrentControlIcon(path);
int iconW = icon.getIconWidth();
- int x = bounds.x - rightChildIndent + iconW/2;
+ int x = bounds.x - rightChildIndent + iconW / 2;
if (x + iconW > bounds.x)
x = bounds.x - rightChildIndent - gap;
- icon.paintIcon(tree, g, x, bounds.y + bounds.height/2 - icon.getIconHeight()/2);
+ icon.paintIcon(tree, g, x, bounds.y + bounds.height / 2
+ - icon.getIconHeight() / 2);
}
}
/**
- * Paints the horizontal part of the leg. The receiver should NOT modify
- * clipBounds, or insets.
- * NOTE: parentRow can be -1 if the root is not visible.
- *
- * @param g - the graphics configuration
- * @param clipBounds -
- * @param insets -
- * @param bounds - bounds of the cell
- * @param path - path to draw leg for
- * @param row - row to start drawing at
- * @param isExpanded - is the row expanded
- * @param hasBeenExpanded - has the row already been expanded
- * @param isLeaf - is the path a leaf
+ * Paints the horizontal part of the leg. The receiver should NOT modify
+ * clipBounds, or insets. NOTE: parentRow can be -1 if the root is not
+ * visible.
+ *
+ * @param g -
+ * the graphics configuration
+ * @param clipBounds -
+ * @param insets -
+ * @param bounds -
+ * bounds of the cell
+ * @param path -
+ * path to draw leg for
+ * @param row -
+ * row to start drawing at
+ * @param isExpanded -
+ * is the row expanded
+ * @param hasBeenExpanded -
+ * has the row already been expanded
+ * @param isLeaf -
+ * is the path a leaf
*/
protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
Insets insets, Rectangle bounds,
TreePath path, int row,
- boolean isExpanded, boolean hasBeenExpanded,
+ boolean isExpanded,
+ boolean hasBeenExpanded,
boolean isLeaf)
{
if (row != 0)
- paintHorizontalLine(g, tree, bounds.y + bounds.height/2, bounds.x - gap - 2,
- bounds.x);
+ paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, bounds.x - gap
+ - 2, bounds.x);
}
-
+
/**
- * Paints the vertical part of the leg. The receiver should NOT modify
+ * Paints the vertical part of the leg. The receiver should NOT modify
* clipBounds, insets.
*
- * @param g - the graphics configuration.
- * @param clipBounds -
- * @param insets -
- * @param path - the path to draw the vertical part for.
+ * @param g -
+ * the graphics configuration.
+ * @param clipBounds -
+ * @param insets -
+ * @param path -
+ * the path to draw the vertical part for.
*/
protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
Insets insets, TreePath path)
@@ -3564,56 +3594,65 @@ public class BasicTreeUI extends TreeUI
if (numChild > 0 && tree.isExpanded(currPath))
{
Rectangle bounds = getPathBounds(tree, currPath);
- Rectangle lastChildBounds = getPathBounds(tree,
- new TreePath(getPathToRoot(
- treeModel.getChild(curr, numChild - 1),
- 0)));
- paintVerticalLine(g, tree, bounds.x + gap + 2, bounds.y +
- bounds.height - 2, lastChildBounds.y +
- lastChildBounds.height/2);
+ Rectangle lastChildBounds = getPathBounds(
+ tree,
+ new TreePath(
+ getPathToRoot(
+ treeModel.getChild(
+ curr,
+ numChild - 1),
+ 0)));
+ paintVerticalLine(g, tree, bounds.x + gap + 2, bounds.y
+ + bounds.height - 2,
+ lastChildBounds.y + lastChildBounds.height / 2);
}
}
}
/**
- * Paints the renderer part of a row. The receiver should NOT modify clipBounds,
- * or insets.
+ * Paints the renderer part of a row. The receiver should NOT modify
+ * clipBounds, or insets.
*
- * @param g - the graphics configuration
- * @param clipBounds -
- * @param insets -
- * @param bounds - bounds of expand control
- * @param path - path to draw control for
- * @param row - row to draw control for
- * @param isExpanded - is the row expanded
- * @param hasBeenExpanded - has the row already been expanded
- * @param isLeaf - is the path a leaf
- */
- protected void paintRow(Graphics g, Rectangle clipBounds,
- Insets insets, Rectangle bounds,
- TreePath path, int row,
+ * @param g -
+ * the graphics configuration
+ * @param clipBounds -
+ * @param insets -
+ * @param bounds -
+ * bounds of expand control
+ * @param path -
+ * path to draw control for
+ * @param row -
+ * row to draw control for
+ * @param isExpanded -
+ * is the row expanded
+ * @param hasBeenExpanded -
+ * has the row already been expanded
+ * @param isLeaf -
+ * is the path a leaf
+ */
+ protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets,
+ Rectangle bounds, TreePath path, int row,
boolean isExpanded, boolean hasBeenExpanded,
boolean isLeaf)
{
boolean selected = tree.isPathSelected(path);
boolean hasIcons = false;
Object node = path.getLastPathComponent();
-
+
if (tree.isVisible(path))
{
if (!validCachedPreferredSize)
updateCachedPreferredSize();
-
-
- paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
-
+
+ paintExpandControl(g, clipBounds, insets, bounds, path, row,
+ isExpanded, hasBeenExpanded, isLeaf);
+
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);
}
@@ -3622,9 +3661,12 @@ public class BasicTreeUI extends TreeUI
TreeCellRenderer dtcr = tree.getCellRenderer();
if (dtcr == null)
dtcr = createDefaultCellRenderer();
-
+
Component c = dtcr.getTreeCellRendererComponent(tree, node,
- selected, isExpanded, isLeaf, row, tree.hasFocus());
+ selected,
+ isExpanded, isLeaf,
+ row,
+ tree.hasFocus());
rendererPane.paintComponent(g, c, c.getParent(), bounds);
}
}
@@ -3637,16 +3679,21 @@ public class BasicTreeUI extends TreeUI
{
// TODO: Implement this properly.
}
-
+
/**
* Returns true if the expand (toggle) control should be drawn for the
* specified row.
*
- * @param path - current path to check for.
- * @param row - current row to check for.
- * @param isExpanded - true if the path is expanded
- * @param hasBeenExpanded - true if the path has been expanded already
- * @param isLeaf - true if the row is a lead
+ * @param path -
+ * current path to check for.
+ * @param row -
+ * current row to check for.
+ * @param isExpanded -
+ * true if the path is expanded
+ * @param hasBeenExpanded -
+ * true if the path has been expanded already
+ * @param isLeaf -
+ * true if the row is a lead
*/
protected boolean shouldPaintExpandControl(TreePath path, int row,
boolean isExpanded,
@@ -3656,10 +3703,9 @@ public class BasicTreeUI extends TreeUI
Object node = path.getLastPathComponent();
return (!isLeaf && getLevel(node) != 0 && hasControlIcons());
}
-
+
/**
- * Updates the cached current TreePath of all visible
- * nodes in the tree.
+ * Updates the cached current TreePath of all visible nodes in the tree.
*/
void updateCurrentVisiblePath()
{
@@ -3667,19 +3713,22 @@ public class BasicTreeUI extends TreeUI
return;
Object next = treeModel.getRoot();
+ if (next == null)
+ return;
+
TreePath rootPath = new TreePath(next);
Rectangle bounds = getPathBounds(tree, rootPath);
-
+
// If root is not a valid size to be visible, or is
// not visible and the tree is expanded, then the next node acts
// as the root
- if ((bounds.width == 0 && bounds.height == 0) || (!isRootVisible()
- && tree.isExpanded(new TreePath(next))))
+ if ((bounds.width == 0 && bounds.height == 0)
+ || (!isRootVisible() && tree.isExpanded(new TreePath(next))))
{
next = getNextNode(next);
rootPath = new TreePath(next);
}
-
+
Object root = next;
TreePath current = null;
while (next != null)
@@ -3688,7 +3737,7 @@ public class BasicTreeUI extends TreeUI
current = rootPath;
else
current = current.pathByAddingChild(next);
-
+
do
{
TreePath path = new TreePath(getPathToRoot(next, 0));
@@ -3712,19 +3761,23 @@ public class BasicTreeUI extends TreeUI
}
}
}
- while (next != null &&
- !tree.isVisible(new TreePath(getPathToRoot(next, 0))));
+ while (next != null
+ && !tree.isVisible(new TreePath(getPathToRoot(next, 0))));
}
currentVisiblePath = current;
tree.setVisibleRowCount(getRowCount(tree));
- if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0 &&
- currentVisiblePath != null)
- selectPath(tree, new TreePath(getPathToRoot(currentVisiblePath.
- getPathComponent(0), 0)));
+ if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0
+ && currentVisiblePath != null)
+ selectPath(
+ tree,
+ new TreePath(
+ getPathToRoot(
+ currentVisiblePath.getPathComponent(0),
+ 0)));
}
-
+
/**
* Get next visible node in the currentVisiblePath. Package private for use in
* inner classes.
@@ -3743,8 +3796,8 @@ public class BasicTreeUI extends TreeUI
while (i < nodes.length && !node.equals(nodes[i]))
i++;
// return the next node
- if (i+1 < nodes.length)
- return nodes[i+1];
+ if (i + 1 < nodes.length)
+ return nodes[i + 1];
}
return null;
}
diff --git a/javax/swing/plaf/metal/MetalFileChooserUI.java b/javax/swing/plaf/metal/MetalFileChooserUI.java
index d6ede95c4..65e54cf42 100644
--- a/javax/swing/plaf/metal/MetalFileChooserUI.java
+++ b/javax/swing/plaf/metal/MetalFileChooserUI.java
@@ -48,8 +48,11 @@ import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.text.NumberFormat;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -73,8 +76,11 @@ import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
+import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
+import javax.swing.JViewport;
+import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
@@ -85,6 +91,12 @@ import javax.swing.filechooser.FileSystemView;
import javax.swing.filechooser.FileView;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicFileChooserUI;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+
+import java.sql.Date;
+
+import java.text.DateFormat;
import java.util.List;
@@ -98,6 +110,145 @@ public class MetalFileChooserUI
{
/**
+ * A renderer for the files and directories in the file chooser table.
+ */
+ class TableFileRenderer
+ extends DefaultTableCellRenderer
+ {
+
+ /**
+ * Creates a new renderer.
+ */
+ public TableFileRenderer()
+ {
+ super();
+ }
+
+ /**
+ * Returns a component that can render the specified value.
+ *
+ * @param table the table
+ * @param value the string value of the cell
+ * @param isSelected is the item selected?
+ * @param hasFocus does the item have the focus?
+ * @param row the row
+ * @param column the column
+ *
+ * @return The renderer.
+ */
+ public Component getTableCellRendererComponent(JTable table, Object value,
+ boolean isSelected, boolean hasFocus, int row, int column)
+ {
+ if (column == 0)
+ {
+ FileView v = getFileView(getFileChooser());
+ ListModel lm = fileList.getModel();
+ if (row < lm.getSize())
+ setIcon(v.getIcon((File) lm.getElementAt(row)));
+ }
+ else
+ setIcon(null);
+
+ setText(value.toString());
+ setOpaque(true);
+ setEnabled(table.isEnabled());
+ setFont(fileList.getFont());
+
+ if (startEditing && column == 0 || !isSelected)
+ {
+ setBackground(table.getBackground());
+ setForeground(table.getForeground());
+ }
+ else
+ {
+ setBackground(table.getSelectionBackground());
+ setForeground(table.getSelectionForeground());
+ }
+
+ if (hasFocus)
+ setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
+ else
+ setBorder(noFocusBorder);
+
+ return this;
+ }
+ }
+
+ /**
+ * ActionListener for the list view.
+ */
+ class ListViewActionListener implements ActionListener
+ {
+
+ /**
+ * This method is invoked when an action occurs.
+ *
+ * @param e -
+ * the <code>ActionEvent</code> that occurred
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ if (!listView)
+ {
+ int[] index = fileTable.getSelectedRows();
+ listView = true;
+ JFileChooser fc = getFileChooser();
+ fc.remove(fileTablePanel);
+ createList(fc);
+
+ fileList.getSelectionModel().clearSelection();
+ if (index.length > 0)
+ for (int i = 0; i < index.length; i++)
+ fileList.getSelectionModel().addSelectionInterval(index[i], index[i]);
+
+ fc.add(fileListPanel, BorderLayout.CENTER);
+ fc.revalidate();
+ fc.repaint();
+ }
+ }
+ }
+
+ /**
+ * ActionListener for the details view.
+ */
+ class DetailViewActionListener implements ActionListener
+ {
+
+ /**
+ * This method is invoked when an action occurs.
+ *
+ * @param e -
+ * the <code>ActionEvent</code> that occurred
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ if (listView)
+ {
+ int[] index = fileList.getSelectedIndices();
+ JFileChooser fc = getFileChooser();
+ listView = false;
+ fc.remove(fileListPanel);
+
+ if (fileTable == null)
+ createDetailsView(fc);
+ else
+ updateTable();
+
+ fileTable.getSelectionModel().clearSelection();
+ if (index.length > 0)
+ {
+ for (int i = 0; i < index.length; i++)
+ fileTable.getSelectionModel().addSelectionInterval(index[i], index[i]);
+ }
+
+ fc.add(fileTablePanel, BorderLayout.CENTER);
+ fc.revalidate();
+ fc.repaint();
+ }
+ }
+ }
+
+ /**
* A property change listener.
*/
class MetalFileChooserPropertyChangeListener
@@ -122,14 +273,40 @@ public class MetalFileChooserUI
String n = e.getPropertyName();
if (n.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY))
{
+ int mode = -1;
if (filechooser.isMultiSelectionEnabled())
- fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ mode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
else
- fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ mode = ListSelectionModel.SINGLE_SELECTION;
+
+ if (listView)
+ fileList.setSelectionMode(mode);
+ else
+ fileTable.setSelectionMode(mode);
}
else if (n.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
{
File file = filechooser.getSelectedFile();
+
+ if (file != null
+ && filechooser.getDialogType() == JFileChooser.SAVE_DIALOG)
+ {
+ if (file.isDirectory() && filechooser.isTraversable(file))
+ {
+ directoryLabel = look;
+ dirLabel.setText(directoryLabel);
+ filechooser.setApproveButtonText(openButtonText);
+ filechooser.setApproveButtonToolTipText(openButtonToolTipText);
+ }
+ else if (file.isFile())
+ {
+ directoryLabel = save;
+ dirLabel.setText(directoryLabel);
+ filechooser.setApproveButtonText(saveButtonText);
+ filechooser.setApproveButtonToolTipText(saveButtonToolTipText);
+ }
+ }
+
if (file == null)
setFileName(null);
else
@@ -138,18 +315,38 @@ public class MetalFileChooserUI
index = getModel().indexOf(file);
if (index >= 0)
{
- fileList.setSelectedIndex(index);
- fileList.ensureIndexIsVisible(index);
- fileList.revalidate();
- fileList.repaint();
+ if (listView)
+ {
+ fileList.setSelectedIndex(index);
+ fileList.ensureIndexIsVisible(index);
+ fileList.revalidate();
+ fileList.repaint();
+ }
+ else
+ {
+ fileTable.getSelectionModel().addSelectionInterval(index, index);
+ fileTable.scrollRectToVisible(fileTable.getCellRect(index, 0, true));
+ fileTable.revalidate();
+ fileTable.repaint();
+ }
}
}
else if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY))
{
- fileList.clearSelection();
- fileList.revalidate();
- fileList.repaint();
+ if (listView)
+ {
+ fileList.clearSelection();
+ fileList.revalidate();
+ fileList.repaint();
+ }
+ else
+ {
+ fileTable.clearSelection();
+ fileTable.revalidate();
+ fileTable.repaint();
+ }
+
setDirectorySelected(false);
File currentDirectory = filechooser.getCurrentDirectory();
setDirectory(currentDirectory);
@@ -225,7 +422,25 @@ public class MetalFileChooserUI
if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
|| n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
|| n.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY))
- rescanCurrentDirectory(filechooser);
+ {
+ // Remove editing component
+ if (fileTable != null)
+ fileTable.removeAll();
+ if (fileList != null)
+ fileList.removeAll();
+ startEditing = false;
+
+ // Set text on button back to original.
+ if (filechooser.getDialogType() == JFileChooser.SAVE_DIALOG)
+ {
+ directoryLabel = save;
+ dirLabel.setText(directoryLabel);
+ filechooser.setApproveButtonText(saveButtonText);
+ filechooser.setApproveButtonToolTipText(saveButtonToolTipText);
+ }
+
+ rescanCurrentDirectory(filechooser);
+ }
filechooser.revalidate();
filechooser.repaint();
@@ -665,6 +880,7 @@ public class MetalFileChooserUI
editFile = null;
fc = getFileChooser();
lastSelected = null;
+ startEditing = false;
}
/**
@@ -674,25 +890,23 @@ public class MetalFileChooserUI
*/
public void mouseClicked(MouseEvent e)
{
- if (e.getClickCount() == 1)
+ if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1)
{
int index = list.locationToIndex(e.getPoint());
File[] sf = fc.getSelectedFiles();
if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1))
- && index >= 0 && editFile == null && list.isSelectedIndex(index))
+ && index >= 0 && !startEditing && list.isSelectedIndex(index))
{
Object tmp = list.getModel().getElementAt(index);
if (lastSelected != null && lastSelected.equals(tmp))
editFile(index);
lastSelected = tmp;
}
- else if (editFile != null)
- {
+ else
completeEditing();
- editFile = null;
- lastSelected = null;
- }
}
+ else
+ completeEditing();
}
/**
@@ -701,50 +915,289 @@ public class MetalFileChooserUI
* @param index -
* the current index of the item in the list to be edited.
*/
- private void editFile(int index)
+ void editFile(int index)
{
- list.ensureIndexIsVisible(index);
+ Rectangle bounds = list.getCellBounds(index, index);
+ list.scrollRectToVisible(bounds);
editFile = (File) list.getModel().getElementAt(index);
if (editFile.canWrite())
{
- Rectangle bounds = list.getCellBounds(index, index);
- Icon icon = getFileView(fc).getIcon(editFile);
+ startEditing = true;
editField = new JTextField(editFile.getName());
- // FIXME: add action listener for typing
- // FIXME: painting for textfield is messed up when typing
- list.add(editField);
- editField.requestFocus();
- editField.selectAll();
+ editField.addActionListener(new EditingActionListener());
+ Icon icon = getFileView(fc).getIcon(editFile);
if (icon != null)
- bounds.x += icon.getIconWidth() + 4;
+ {
+ int padding = icon.getIconWidth() + 4;
+ bounds.x += padding;
+ bounds.width -= padding;
+ }
editField.setBounds(bounds);
+
+ list.add(editField);
+
+ editField.requestFocus();
+ editField.selectAll();
}
else
- {
- editField = null;
- editFile = null;
- lastSelected = null;
- }
+ completeEditing();
+ list.repaint();
}
/**
* Completes the editing.
*/
- private void completeEditing()
+ void completeEditing()
{
- if (editField != null)
+ if (editField != null && editFile != null)
{
String text = editField.getText();
- if (text != null && !text.equals(""))
- editFile.renameTo(new File(text));
+ if (text != null && text != "" && !text.equals(fc.getName(editFile)))
+ if (editFile.renameTo
+ (fc.getFileSystemView().createFileObject
+ (fc.getCurrentDirectory(), text)))
+ rescanCurrentDirectory(fc);
list.remove(editField);
- list.revalidate();
- list.repaint();
}
+ startEditing = false;
+ editFile = null;
+ lastSelected = null;
+ editField = null;
+ list.repaint();
+ }
+
+ /**
+ * ActionListener for the editing text field.
+ */
+ class EditingActionListener implements ActionListener
+ {
+
+ /**
+ * This method is invoked when an action occurs.
+ *
+ * @param e -
+ * the <code>ActionEvent</code> that occurred
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ if (e.getActionCommand().equals("notify-field-accept"))
+ completeEditing();
+ else if (editField != null)
+ {
+ list.remove(editField);
+ startEditing = false;
+ editFile = null;
+ lastSelected = null;
+ editField = null;
+ list.repaint();
+ }
+ }
}
}
+ /**
+ * A mouse listener for the {@link JFileChooser}.
+ * This listener is used for the table
+ */
+ private class TableClickListener extends MouseAdapter
+ {
+
+ /** Stores instance of the table */
+ JTable table;
+
+ /** Stores instance of the file chooser */
+ JFileChooser fc;
+
+ /** The last selected file. */
+ Object lastSelected = null;
+
+ /**
+ * Stores the current file that is being edited.
+ * It is null if nothing is currently being edited.
+ */
+ File editFile;
+
+ /** The textfield used for editing. */
+ JTextField editField;
+
+ /**
+ * Creates a new listener.
+ *
+ * @param table
+ * the directory/file table
+ * @param fc
+ * the JFileChooser
+ */
+ public TableClickListener(JTable table, JFileChooser fc)
+ {
+ this.table = table;
+ this.fc = fc;
+ lastSelected = fileList.getSelectedValue();
+ setDirectorySelected(false);
+ startEditing = false;
+ editFile = null;
+ editField = null;
+ }
+
+ /**
+ * Receives notification of a mouse click event.
+ *
+ * @param e
+ * the event.
+ */
+ public void mouseClicked(MouseEvent e)
+ {
+ int row = table.getSelectedRow();
+ Object selVal = fileList.getModel().getElementAt(row);
+ if (selVal == null)
+ return;
+ FileSystemView fsv = fc.getFileSystemView();
+ if (e.getClickCount() == 1 &&
+ selVal.equals(lastSelected) &&
+ e.getButton() == MouseEvent.BUTTON1)
+ {
+ File[] sf = fc.getSelectedFiles();
+ if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1))
+ && !startEditing)
+ {
+ editFile = (File) selVal;
+ editFile(row);
+ }
+ }
+ else if (e.getClickCount() >= 2 &&
+ selVal.equals(lastSelected))
+ {
+ if (startEditing)
+ completeEditing();
+ File f = fsv.createFileObject(lastSelected.toString());
+ if (fc.isTraversable(f))
+ {
+ fc.setCurrentDirectory(f);
+ fc.rescanCurrentDirectory();
+ }
+ else
+ {
+ fc.setSelectedFile(f);
+ fc.approveSelection();
+ closeDialog();
+ }
+ }
+ else
+ {
+ if (startEditing)
+ completeEditing();
+ String path = selVal.toString();
+ File f = fsv.createFileObject(path);
+ fc.setSelectedFile(f);
+ if (fc.isTraversable(f))
+ {
+ setDirectorySelected(true);
+ setDirectory(f);
+ }
+ else
+ {
+ setDirectorySelected(false);
+ setDirectory(null);
+ }
+ lastSelected = selVal;
+ if (f.isFile())
+ setFileName(path.substring(path.lastIndexOf("/") + 1));
+ else if (fc.getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY)
+ setFileName(path);
+ }
+ fileTable.repaint();
+ }
+
+ /**
+ * Sets up the text editor for the current file.
+ *
+ * @param row -
+ * the current row of the item in the list to be edited.
+ */
+ void editFile(int row)
+ {
+ Rectangle bounds = table.getCellRect(row, 0, true);
+ table.scrollRectToVisible(bounds);
+ if (editFile.canWrite())
+ {
+ startEditing = true;
+ editField = new JTextField(editFile.getName());
+ editField.addActionListener(new EditingActionListener());
+
+ // Need to adjust y pos
+ bounds.y = row * table.getRowHeight();
+ editField.setBounds(bounds);
+
+ table.add(editField);
+
+ editField.requestFocus();
+ editField.selectAll();
+ }
+ else
+ completeEditing();
+ table.repaint();
+ }
+
+ /**
+ * Completes the editing.
+ */
+ void completeEditing()
+ {
+ if (editField != null && editFile != null)
+ {
+ String text = editField.getText();
+ if (text != null && text != "" && !text.equals(fc.getName(editFile)))
+ if (editFile.renameTo
+ (fc.getFileSystemView().createFileObject
+ (fc.getCurrentDirectory(), text)))
+ rescanCurrentDirectory(fc);
+ table.remove(editField);
+ }
+ startEditing = false;
+ editFile = null;
+ editField = null;
+ table.repaint();
+ }
+
+ /**
+ * ActionListener for the editing text field.
+ */
+ class EditingActionListener implements ActionListener
+ {
+
+ /**
+ * This method is invoked when an action occurs.
+ *
+ * @param e -
+ * the <code>ActionEvent</code> that occurred
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ if (e.getActionCommand().equals("notify-field-accept"))
+ completeEditing();
+ else if (editField != null)
+ {
+ table.remove(editField);
+ startEditing = false;
+ editFile = null;
+ editField = null;
+ table.repaint();
+ }
+ }
+ }
+
+ /**
+ * Closes the dialog.
+ */
+ public void closeDialog()
+ {
+ Window owner = SwingUtilities.windowForComponent(fc);
+ if (owner instanceof JDialog)
+ ((JDialog) owner).dispose();
+ }
+ }
+
/** The text for a label describing the directory combo box. */
private String directoryLabel;
@@ -783,10 +1236,16 @@ public class MetalFileChooserUI
private JButton approveButton;
/** The file list. */
- private JList fileList;
+ JList fileList;
+
+ /** The file table. */
+ JTable fileTable;
/** The panel containing the file list. */
- private JPanel fileListPanel;
+ JPanel fileListPanel;
+
+ /** The panel containing the file table. */
+ JPanel fileTablePanel;
/** The filter combo box model. */
private FilterComboBoxModel filterModel;
@@ -794,6 +1253,30 @@ public class MetalFileChooserUI
/** The action map. */
private ActionMap actionMap;
+ /** True if currently in list view. */
+ boolean listView;
+
+ /** True if we can or have started editing a cell. */
+ boolean startEditing;
+
+ /** The scrollpane used for the table and list. */
+ JScrollPane scrollPane;
+
+ /** The text for the label when saving. */
+ String save;
+
+ /** The text for the label when opening a directory. */
+ String look;
+
+ /** The label for the file combo box. */
+ JLabel dirLabel;
+
+ /** Listeners. */
+ ListSelectionListener listSelList;
+ MouseListener doubleClickList;
+ SingleClickListener singleClickList;
+ TableClickListener tableClickList;
+
/**
* A factory method that returns a UI delegate for the specified
* component.
@@ -839,21 +1322,25 @@ public class MetalFileChooserUI
{
fc.setLayout(new BorderLayout());
topPanel = new JPanel(new BorderLayout());
- topPanel.add(new JLabel(directoryLabel), BorderLayout.WEST);
+ dirLabel = new JLabel(directoryLabel);
+ topPanel.add(dirLabel, BorderLayout.WEST);
this.controls = new JPanel();
addControlButtons();
JPanel dirPanel = new JPanel(new VerticalMidLayout());
- dirPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
directoryModel = createDirectoryComboBoxModel(fc);
directoryComboBox = new JComboBox(directoryModel);
directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
dirPanel.add(directoryComboBox);
topPanel.add(dirPanel);
topPanel.add(controls, BorderLayout.EAST);
+ topPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 0, 8));
fc.add(topPanel, BorderLayout.NORTH);
- fileListPanel = createList(fc);
- fc.add(fileListPanel);
+
+ JPanel list = createList(fc);
+ list.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
+ fc.add(list, BorderLayout.CENTER);
+
JPanel bottomPanel = getBottomPanel();
filterModel = createFilterComboBoxModel();
JComboBox fileFilterCombo = new JComboBox(filterModel);
@@ -861,34 +1348,37 @@ public class MetalFileChooserUI
fileTextField = new JTextField();
JPanel fileNamePanel = new JPanel(new VerticalMidLayout());
+ fileNamePanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 5));
fileNamePanel.add(fileTextField);
JPanel row1 = new JPanel(new BorderLayout());
row1.add(new JLabel(this.fileLabel), BorderLayout.WEST);
row1.add(fileNamePanel);
bottomPanel.add(row1);
- JPanel filterPanel = new JPanel(new VerticalMidLayout());
- filterPanel.add(fileFilterCombo);
JPanel row2 = new JPanel(new BorderLayout());
row2.add(new JLabel(this.filterLabel), BorderLayout.WEST);
- row2.add(filterPanel);
+ row2.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
+ row2.add(fileFilterCombo);
bottomPanel.add(row2);
JPanel buttonPanel = new JPanel(new ButtonLayout());
- buttonPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 0));
approveButton = new JButton(getApproveSelectionAction());
approveButton.setText(getApproveButtonText(fc));
approveButton.setToolTipText(getApproveButtonToolTipText(fc));
approveButton.setMnemonic(getApproveButtonMnemonic(fc));
buttonPanel.add(approveButton);
+ buttonPanel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0));
JButton cancelButton = new JButton(getCancelSelectionAction());
cancelButton.setText(cancelButtonText);
cancelButton.setToolTipText(cancelButtonToolTipText);
cancelButton.setMnemonic(cancelButtonMnemonic);
buttonPanel.add(cancelButton);
- bottomPanel.add(buttonPanel);
+ bottomPanel.add(buttonPanel, BorderLayout.SOUTH);
+ bottomPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8));
fc.add(bottomPanel, BorderLayout.SOUTH);
+
+ fc.add(getAccessoryPanel(), BorderLayout.EAST);
}
/**
@@ -902,6 +1392,8 @@ public class MetalFileChooserUI
fc.remove(bottomPanel);
bottomPanel = null;
fc.remove(fileListPanel);
+ fc.remove(fileTablePanel);
+ fileTablePanel = null;
fileListPanel = null;
fc.remove(topPanel);
topPanel = null;
@@ -944,7 +1436,13 @@ public class MetalFileChooserUI
protected void installStrings(JFileChooser fc)
{
super.installStrings(fc);
- directoryLabel = "Look In: ";
+ look = "Look In: ";
+ save = "Save In: ";
+ if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
+ directoryLabel = save;
+ else
+ directoryLabel = look;
+
fileLabel = "File Name: ";
filterLabel = "Files of Type: ";
@@ -981,10 +1479,13 @@ public class MetalFileChooserUI
protected void installListeners(JFileChooser fc)
{
directoryComboBox.setAction(new DirectoryComboBoxAction());
- fileList.addListSelectionListener(createListSelectionListener(fc));
- fileList.addMouseListener(this.createDoubleClickListener(fc, fileList));
- fileList.addMouseListener(new SingleClickListener(fileList));
fc.addPropertyChangeListener(filterModel);
+ listSelList = createListSelectionListener(fc);
+ doubleClickList = this.createDoubleClickListener(fc, fileList);
+ singleClickList = new SingleClickListener(fileList);
+ fileList.addListSelectionListener(listSelList);
+ fileList.addMouseListener(doubleClickList);
+ fileList.addMouseListener(singleClickList);
super.installListeners(fc);
}
@@ -992,6 +1493,13 @@ public class MetalFileChooserUI
{
super.uninstallListeners(fc);
fc.removePropertyChangeListener(filterModel);
+ directoryComboBox.setAction(null);
+ fileList.removeListSelectionListener(listSelList);
+ fileList.removeMouseListener(doubleClickList);
+ fileList.removeMouseListener(singleClickList);
+
+ if (fileTable != null)
+ fileTable.removeMouseListener(tableClickList);
}
protected ActionMap getActionMap()
@@ -1010,7 +1518,7 @@ public class MetalFileChooserUI
{
ActionMap map = new ActionMap();
map.put("approveSelection", getApproveSelectionAction());
- map.put("cancelSelection", null); // FIXME: implement this one
+ map.put("cancelSelection", getCancelSelectionAction());
map.put("Go Up", getChangeToParentDirectoryAction());
return map;
}
@@ -1024,13 +1532,25 @@ public class MetalFileChooserUI
*/
protected JPanel createList(JFileChooser fc)
{
- JPanel panel = new JPanel(new BorderLayout());
- fileList = new JList(getModel());
- fileList.setLayoutOrientation(JList.VERTICAL_WRAP);
- fileList.setVisibleRowCount(0);
- fileList.setCellRenderer(new FileRenderer());
- panel.add(new JScrollPane(fileList));
- return panel;
+ if (fileList == null)
+ {
+ 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());
+ }
+ else
+ {
+ fileList.setModel(getModel());
+ fileListPanel.removeAll();
+ scrollPane.getViewport().setView(fileList);
+ }
+ fileListPanel.add(scrollPane);
+
+ return fileListPanel;
}
/**
@@ -1042,13 +1562,108 @@ public class MetalFileChooserUI
*/
protected JPanel createDetailsView(JFileChooser fc)
{
- // FIXME: implement this. The details view is a panel containing a table
- // inside a JScrollPane - it gets displayed when the user clicks on the
- // "details" button.
- return new JPanel();
+ fileTablePanel = new JPanel(new BorderLayout());
+
+ Object[] cols = new Object[] {"Name", "Size", "Modified"};
+ Object[][] rows = new Object[fileList.getModel().getSize()][3];
+
+ fileTable = new JTable(new DefaultTableModel(rows, cols));
+
+ if (fc.isMultiSelectionEnabled())
+ fileTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ else
+ fileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ fileTable.setShowGrid(false);
+ fileTable.setColumnSelectionAllowed(false);
+ fileTable.setDefaultRenderer(Object.class, new TableFileRenderer());
+
+ tableClickList = new TableClickListener(fileTable, fc);
+ fileTable.addMouseListener(tableClickList);
+
+ return updateTable();
+ }
+
+ /**
+ * Sets the values in the table, and puts it in the panel.
+ *
+ * @return the panel containing the table.
+ */
+ JPanel updateTable()
+ {
+ DefaultTableModel mod = (DefaultTableModel) fileTable.getModel();
+ ListModel lm = fileList.getModel();
+ DateFormat dt = DateFormat.getDateTimeInstance(DateFormat.SHORT,
+ DateFormat.SHORT);
+ File curr = null;
+ int size = lm.getSize();
+ int rc = mod.getRowCount();
+
+ // If there are not enough rows
+ for (int x = rc; x < size; x++)
+ mod.addRow(new Object[3]);
+
+ for (int i = 0; i < size; i++)
+ {
+ curr = (File) lm.getElementAt(i);
+ fileTable.setValueAt(curr.getName(), i, 0);
+ fileTable.setValueAt(formatSize(curr.length()), i, 1);
+ fileTable.setValueAt(dt.format(new Date(curr.lastModified())), i, 2);
+ }
+
+ // If there are too many rows
+ while (rc > size)
+ mod.removeRow(--rc);
+
+ scrollPane.getViewport().setView(fileTable);
+ scrollPane.setColumnHeaderView(fileTable.getTableHeader());
+
+ fileTablePanel.removeAll();
+ fileTablePanel.add(scrollPane);
+
+ return fileTablePanel;
}
/**
+ * Formats bytes into the appropriate size.
+ *
+ * @param bytes -
+ * the number of bytes to convert
+ * @return a string representation of the size
+ */
+ private String formatSize(long bytes)
+ {
+ NumberFormat nf = NumberFormat.getNumberInstance();
+ long mb = (long) Math.pow(2, 20);
+ long kb = (long) Math.pow(2, 10);
+ long gb = (long) Math.pow(2, 30);
+ double size = 0;
+ String id = "";
+
+ if ((bytes / gb) >= 1)
+ {
+ size = (double) bytes / (double) gb;
+ id = "GB";
+ }
+ else if ((bytes / mb) >= 1)
+ {
+ size = (double) bytes / (double) mb;
+ id = "MB";
+ }
+ else if ((bytes / kb) >= 1)
+ {
+ size = (double) bytes / (double) kb;
+ id = "KB";
+ }
+ else
+ {
+ size = bytes;
+ id = "Bytes";
+ }
+
+ return nf.format(size) + " " + id;
+ }
+ /**
* Creates a listener that monitors selections in the directory/file list
* and keeps the {@link JFileChooser} component up to date.
*
@@ -1070,10 +1685,12 @@ public class MetalFileChooserUI
*/
public Dimension getPreferredSize(JComponent c)
{
- // FIXME: not likely to be a fixed value
- return new Dimension(500, 326);
+ Dimension tp = topPanel.getPreferredSize();
+ Dimension bp = bottomPanel.getPreferredSize();
+ Dimension fl = fileListPanel.getPreferredSize();
+ return new Dimension(fl.width, tp.height + bp.height + fl.height);
}
-
+
/**
* Returns the minimum size for the file chooser component.
*
@@ -1081,8 +1698,10 @@ public class MetalFileChooserUI
*/
public Dimension getMinimumSize(JComponent c)
{
- // FIXME: not likely to be a fixed value
- return new Dimension(506, 326);
+ Dimension tp = topPanel.getMinimumSize();
+ Dimension bp = bottomPanel.getMinimumSize();
+ Dimension fl = fileListPanel.getMinimumSize();
+ return new Dimension(fl.width, tp.height + bp.height + fl.height);
}
/**
@@ -1179,15 +1798,17 @@ public class MetalFileChooserUI
newFolderButton.setMargin(new Insets(0, 0, 0, 0));
controls.add(newFolderButton);
- JToggleButton listButton = new JToggleButton();
- listButton.setIcon(this.listViewIcon);
+ JToggleButton listButton = new JToggleButton(this.listViewIcon);
listButton.setMargin(new Insets(0, 0, 0, 0));
- // FIXME: this button needs an action that handles a click
+ listButton.addActionListener(new ListViewActionListener());
+ listButton.setSelected(true);
+ listView = true;
controls.add(listButton);
JToggleButton detailButton = new JToggleButton(this.detailsViewIcon);
detailButton.setMargin(new Insets(0, 0, 0, 0));
- // FIXME: this button needs an action that handles a click
+ detailButton.addActionListener(new DetailViewActionListener());
+ detailButton.setSelected(false);
controls.add(detailButton);
ButtonGroup buttonGroup = new ButtonGroup();
@@ -1195,26 +1816,29 @@ public class MetalFileChooserUI
buttonGroup.add(detailButton);
}
+ /**
+ * Removes all the buttons from the control panel.
+ */
protected void removeControlButtons()
{
controls.removeAll();
+ controls.revalidate();
+ controls.repaint();
}
- public void ensureFileIsVisible(JFileChooser fc, File f)
- {
- // FIXME: do something here - probably this figures out whether the
- // list or table view is current, and forwards the request to the
- // appropriate one...
- super.ensureFileIsVisible(fc, f);
- }
-
+ /**
+ * Updates the current directory.
+ *
+ * @param the file chooser to update.
+ */
public void rescanCurrentDirectory(JFileChooser fc)
{
- // FIXME: this will need to take into account whether the list view or
- // the table view is current
directoryModel.setSelectedItem(fc.getCurrentDirectory());
getModel().validateFileCache();
- fileList.revalidate();
+ if (!listView)
+ updateTable();
+ else
+ createList(fc);
}
/**
@@ -1239,28 +1863,15 @@ public class MetalFileChooserUI
{
fileTextField.setText(filename);
}
-
- protected void setDirectorySelected(boolean directorySelected)
- {
- // FIXME: do something here
- super.setDirectorySelected(directorySelected);
- }
-
- public String getDirectoryName()
- {
- // FIXME: do something here
- return super.getDirectoryName();
- }
-
- public void setDirectoryName(String dirname)
- {
- // FIXME: do something here
- super.setDirectoryName(dirname);
- }
+ /**
+ * DOCUMENT ME!!
+ *
+ * @param e - DOCUMENT ME!
+ */
public void valueChanged(ListSelectionEvent e)
{
- // FIXME: implement
+ // FIXME: Not sure what we should be doing here, if anything.
}
/**
diff --git a/javax/swing/plaf/metal/MetalLookAndFeel.java b/javax/swing/plaf/metal/MetalLookAndFeel.java
index 30dc6c8c6..5acccd6e4 100644
--- a/javax/swing/plaf/metal/MetalLookAndFeel.java
+++ b/javax/swing/plaf/metal/MetalLookAndFeel.java
@@ -81,8 +81,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public MetalLookAndFeel()
{
- if (theme == null)
- createDefaultTheme();
+ createDefaultTheme();
}
/**
@@ -90,7 +89,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
protected void createDefaultTheme()
{
- setCurrentTheme(new DefaultMetalTheme());
+ if (theme == null)
+ setCurrentTheme(new DefaultMetalTheme());
}
/**
@@ -124,7 +124,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public String getDescription()
{
- return "Metal look and feel";
+ return "The Java(tm) Look and Feel";
}
/**
@@ -134,7 +134,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public String getID()
{
- return "MetalLookAndFeel";
+ return "Metal";
}
/**
@@ -144,7 +144,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public String getName()
{
- return "MetalLookAndFeel";
+ return "Metal";
}
public UIDefaults getDefaults()
@@ -154,7 +154,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel
LAF_defaults = super.getDefaults();
// add custom theme entries to the table
- theme.addCustomEntriesToTable(LAF_defaults);
+ if (theme != null)
+ theme.addCustomEntriesToTable(LAF_defaults);
}
// Returns the default values for this look and feel.
@@ -168,7 +169,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getAcceleratorForeground()
{
- return theme.getAcceleratorForeground();
+ if (theme != null)
+ return theme.getAcceleratorForeground();
+ return null;
}
/**
@@ -179,7 +182,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getAcceleratorSelectedForeground()
{
- return theme.getAcceleratorSelectedForeground();
+ if (theme != null)
+ return theme.getAcceleratorSelectedForeground();
+ return null;
}
/**
@@ -189,7 +194,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getBlack()
{
- return theme.getBlack();
+ if (theme != null)
+ return theme.getBlack();
+ return null;
}
/**
@@ -199,7 +206,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getControl()
{
- return theme.getControl();
+ if (theme != null)
+ return theme.getControl();
+ return null;
}
/**
@@ -210,7 +219,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getControlDarkShadow()
{
- return theme.getControlDarkShadow();
+ if (theme != null)
+ return theme.getControlDarkShadow();
+ return null;
}
/**
@@ -220,7 +231,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getControlDisabled()
{
- return theme.getControlDisabled();
+ if (theme != null)
+ return theme.getControlDisabled();
+ return null;
}
/**
@@ -231,7 +244,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getControlHighlight()
{
- return theme.getControlHighlight();
+ if (theme != null)
+ return theme.getControlHighlight();
+ return null;
}
/**
@@ -242,7 +257,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getControlInfo()
{
- return theme.getControlInfo();
+ if (theme != null)
+ return theme.getControlInfo();
+ return null;
}
/**
@@ -253,7 +270,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getControlShadow()
{
- return theme.getControlShadow();
+ if (theme != null)
+ return theme.getControlShadow();
+ return null;
}
/**
@@ -263,7 +282,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getControlTextColor()
{
- return theme.getControlTextColor();
+ if (theme != null)
+ return theme.getControlTextColor();
+ return null;
}
/**
@@ -273,7 +294,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static FontUIResource getControlTextFont()
{
- return theme.getControlTextFont();
+ if (theme != null)
+ return theme.getControlTextFont();
+ return null;
}
/**
@@ -284,7 +307,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getDesktopColor()
{
- return theme.getDesktopColor();
+ if (theme != null)
+ return theme.getDesktopColor();
+ return null;
}
/**
@@ -295,7 +320,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getFocusColor()
{
- return theme.getFocusColor();
+ if (theme != null)
+ return theme.getFocusColor();
+ return null;
}
/**
@@ -306,7 +333,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getHighlightedTextColor()
{
- return theme.getHighlightedTextColor();
+ if (theme != null)
+ return theme.getHighlightedTextColor();
+ return null;
}
/**
@@ -317,7 +346,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getInactiveControlTextColor()
{
- return theme.getInactiveControlTextColor();
+ if (theme != null)
+ return theme.getInactiveControlTextColor();
+ return null;
}
/**
@@ -328,7 +359,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getInactiveSystemTextColor()
{
- return theme.getInactiveSystemTextColor();
+ if (theme != null)
+ return theme.getInactiveSystemTextColor();
+ return null;
}
/**
@@ -340,7 +373,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getMenuBackground()
{
- return theme.getMenuBackground();
+ if (theme != null)
+ return theme.getMenuBackground();
+ return null;
}
/**
@@ -353,7 +388,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getMenuDisabledForeground()
{
- return theme.getMenuDisabledForeground();
+ if (theme != null)
+ return theme.getMenuDisabledForeground();
+ return null;
}
/**
@@ -366,7 +403,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getMenuForeground()
{
- return theme.getMenuForeground();
+ if (theme != null)
+ return theme.getMenuForeground();
+ return null;
}
/**
@@ -379,7 +418,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getMenuSelectedBackground()
{
- return theme.getMenuSelectedBackground();
+ if (theme != null)
+ return theme.getMenuSelectedBackground();
+ return null;
}
/**
@@ -392,7 +433,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getMenuSelectedForeground()
{
- return theme.getMenuSelectedForeground();
+ if (theme != null)
+ return theme.getMenuSelectedForeground();
+ return null;
}
/**
@@ -402,7 +445,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static FontUIResource getMenuTextFont()
{
- return theme.getMenuTextFont();
+ if (theme != null)
+ return theme.getMenuTextFont();
+ return null;
}
/**
@@ -412,7 +457,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getPrimaryControl()
{
- return theme.getPrimaryControl();
+ if (theme != null)
+ return theme.getPrimaryControl();
+ return null;
}
/**
@@ -423,7 +470,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getPrimaryControlDarkShadow()
{
- return theme.getPrimaryControlDarkShadow();
+ if (theme != null)
+ return theme.getPrimaryControlDarkShadow();
+ return null;
}
/**
@@ -434,7 +483,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getPrimaryControlHighlight()
{
- return theme.getPrimaryControlHighlight();
+ if (theme != null)
+ return theme.getPrimaryControlHighlight();
+ return null;
}
/**
@@ -445,7 +496,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getPrimaryControlInfo()
{
- return theme.getPrimaryControlInfo();
+ if (theme != null)
+ return theme.getPrimaryControlInfo();
+ return null;
}
/**
@@ -456,7 +509,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getPrimaryControlShadow()
{
- return theme.getPrimaryControlShadow();
+ if (theme != null)
+ return theme.getPrimaryControlShadow();
+ return null;
}
/**
@@ -466,7 +521,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getSeparatorBackground()
{
- return theme.getSeparatorBackground();
+ if (theme != null)
+ return theme.getSeparatorBackground();
+ return null;
}
/**
@@ -476,7 +533,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getSeparatorForeground()
{
- return theme.getSeparatorForeground();
+ if (theme != null)
+ return theme.getSeparatorForeground();
+ return null;
}
/**
@@ -486,7 +545,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static FontUIResource getSubTextFont()
{
- return theme.getSubTextFont();
+ if (theme != null)
+ return theme.getSubTextFont();
+ return null;
}
/**
@@ -496,7 +557,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getSystemTextColor()
{
- return theme.getSystemTextColor();
+ if (theme != null)
+ return theme.getSystemTextColor();
+ return null;
}
/**
@@ -506,7 +569,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static FontUIResource getSystemTextFont()
{
- return theme.getSystemTextFont();
+ if (theme != null)
+ return theme.getSystemTextFont();
+ return null;
}
/**
@@ -516,7 +581,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getTextHighlightColor()
{
- return theme.getTextHighlightColor();
+ if (theme != null)
+ return theme.getTextHighlightColor();
+ return null;
}
/**
@@ -526,7 +593,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getUserTextColor()
{
- return theme.getUserTextColor();
+ if (theme != null)
+ return theme.getUserTextColor();
+ return null;
}
/**
@@ -536,7 +605,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static FontUIResource getUserTextFont()
{
- return theme.getUserTextFont();
+ if (theme != null)
+ return theme.getUserTextFont();
+ return null;
}
/**
@@ -546,7 +617,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getWhite()
{
- return theme.getWhite();
+ if (theme != null)
+ return theme.getWhite();
+ return null;
}
/**
@@ -556,7 +629,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getWindowBackground()
{
- return theme.getWindowBackground();
+ if (theme != null)
+ return theme.getWindowBackground();
+ return null;
}
/**
@@ -566,7 +641,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getWindowTitleBackground()
{
- return theme.getWindowTitleBackground();
+ if (theme != null)
+ return theme.getWindowTitleBackground();
+ return null;
}
/**
@@ -578,7 +655,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static FontUIResource getWindowTitleFont()
{
- return theme.getWindowTitleFont();
+ if (theme != null)
+ return theme.getWindowTitleFont();
+ return null;
}
/**
@@ -588,7 +667,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getWindowTitleForeground()
{
- return theme.getWindowTitleForeground();
+ if (theme != null)
+ return theme.getWindowTitleForeground();
+ return null;
}
/**
@@ -599,7 +680,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getWindowTitleInactiveBackground()
{
- return theme.getWindowTitleInactiveBackground();
+ if (theme != null)
+ return theme.getWindowTitleInactiveBackground();
+ return null;
}
/**
@@ -610,7 +693,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
*/
public static ColorUIResource getWindowTitleInactiveForeground()
{
- return theme.getWindowTitleInactiveForeground();
+ if (theme != null)
+ return theme.getWindowTitleInactiveForeground();
+ return null;
}
/**
@@ -851,7 +936,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"EditorPane.background", getWindowBackground(),
"EditorPane.caretForeground", getUserTextColor(),
- "EditorPane.font", new FontUIResource("Dialog", Font.PLAIN, 12),
+ "EditorPane.font", new FontUIResource("Dialog", Font.BOLD, 12),
"EditorPane.foreground", getUserTextColor(),
"EditorPane.inactiveForeground", getInactiveSystemTextColor(),
"EditorPane.selectionBackground", getTextHighlightColor(),
@@ -878,7 +963,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel
MetalIconFactory.getFileChooserHomeFolderIcon(),
"FileChooser.detailsViewIcon",
MetalIconFactory.getFileChooserDetailViewIcon(),
-
+ "FileChooser.fileNameLabelMnemonic", new Integer(78),
+ "FileChooser.filesOfTypeLabelMnemonic",new Integer(84),
+ "FileChooser.lookInLabelMnemonic", new Integer(73),
"FileView.computerIcon", MetalIconFactory.getTreeComputerIcon(),
"FileView.directoryIcon", MetalIconFactory.getTreeFolderIcon(),
"FileView.fileIcon", MetalIconFactory.getTreeLeafIcon(),
@@ -896,15 +983,20 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"InternalFrame.icon", MetalIconFactory.getInternalFrameDefaultMenuIcon(),
"InternalFrame.closeIcon",
MetalIconFactory.getInternalFrameCloseIcon(16),
+ "InternalFrame.closeSound", "sounds/FrameClose.wav",
"InternalFrame.inactiveTitleBackground", getWindowTitleInactiveBackground(),
"InternalFrame.inactiveTitleForeground", getWindowTitleInactiveForeground(),
"InternalFrame.maximizeIcon",
MetalIconFactory.getInternalFrameMaximizeIcon(16),
+ "InternalFrame.maximizeSound", "sounds/FrameMaximize.wav",
"InternalFrame.iconifyIcon",
MetalIconFactory.getInternalFrameMinimizeIcon(16),
+ "InternalFrame.minimizeSound", "sounds/FrameMinimize.wav",
"InternalFrame.paletteBorder", new MetalBorders.PaletteBorder(),
"InternalFrame.paletteCloseIcon", new MetalIconFactory.PaletteCloseIcon(),
"InternalFrame.paletteTitleHeight", new Integer(11),
+ "InternalFrame.restoreDownSound", "sounds/FrameRestoreDown.wav",
+ "InternalFrame.restoreUpSound", "sounds/FrameRestoreUp.wav",
"Label.background", getControl(),
"Label.disabledForeground", getInactiveSystemTextColor(),
@@ -927,12 +1019,14 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"Menu.background", getMenuBackground(),
"Menu.border", new MetalBorders.MenuItemBorder(),
"Menu.borderPainted", Boolean.TRUE,
- "Menu.checkIcon", MetalIconFactory.getMenuItemCheckIcon(),
+ "MenuItem.commandSound", "sounds/MenuItemCommand.wav",
"Menu.disabledForeground", getMenuDisabledForeground(),
"Menu.font", getControlTextFont(),
"Menu.foreground", getMenuForeground(),
"Menu.selectionBackground", getMenuSelectedBackground(),
"Menu.selectionForeground", getMenuSelectedForeground(),
+ "Menu.submenuPopupOffsetX", new Integer(-4),
+ "Menu.submenuPopupOffsetY", new Integer(-3),
"MenuBar.background", getMenuBackground(),
"MenuBar.border", new MetalBorders.MenuBarBorder(),
@@ -941,12 +1035,14 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"MenuBar.highlight", getControlHighlight(),
"MenuBar.shadow", getControlShadow(),
+ "MenuItem.acceleratorDelimiter", "-",
"MenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 10),
"MenuItem.acceleratorForeground", getAcceleratorForeground(),
"MenuItem.acceleratorSelectionForeground", getAcceleratorSelectedForeground(),
"MenuItem.arrowIcon", MetalIconFactory.getMenuItemArrowIcon(),
"MenuItem.background", getMenuBackground(),
"MenuItem.border", new MetalBorders.MenuItemBorder(),
+ "MenuItem.borderPainted", Boolean.TRUE,
"MenuItem.disabledForeground", getMenuDisabledForeground(),
"MenuItem.font", getControlTextFont(),
"MenuItem.foreground", getMenuForeground(),
@@ -954,6 +1050,10 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"MenuItem.selectionForeground", getMenuSelectedForeground(),
"OptionPane.background", getControl(),
+ "OptionPane.errorSound", "sounds/OptionPaneError.wav",
+ "OptionPane.informationSound", "sounds/OptionPaneInformation.wav",
+ "OptionPane.questionSound", "sounds/OptionPaneQuestion.wav",
+ "OptionPane.warningSound", "sounds/OptionPaneWarning.wav",
"OptionPane.errorDialog.border.background", new ColorUIResource(153, 51, 51),
"OptionPane.errorDialog.titlePane.background", new ColorUIResource(255, 153, 153),
"OptionPane.errorDialog.titlePane.foreground", new ColorUIResource(51, 0, 0),
@@ -977,6 +1077,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
new BorderUIResource(MetalBorders.getTextFieldBorder()),
"PasswordField.caretForeground", getUserTextColor(),
"PasswordField.foreground", getUserTextColor(),
+ "PasswordField.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"PasswordField.inactiveBackground", getControl(),
"PasswordField.inactiveForeground", getInactiveSystemTextColor(),
"PasswordField.selectionBackground", getTextHighlightColor(),
@@ -986,6 +1087,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"PopupMenu.border", new MetalBorders.PopupMenuBorder(),
"PopupMenu.font", new FontUIResource("Dialog", Font.BOLD, 12),
"PopupMenu.foreground", getMenuForeground(),
+ "PopupMenu.popupSound", "sounds/PopupMenuPopup.wav",
"ProgressBar.background", getControl(),
"ProgressBar.border", new BorderUIResource.LineBorderUIResource(getControlDarkShadow(), 1),
@@ -1021,6 +1123,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"RadioButtonMenuItem.borderPainted", Boolean.TRUE,
"RadioButtonMenuItem.checkIcon",
MetalIconFactory.getRadioButtonMenuItemIcon(),
+ "RadioButtonMenuItem.commandSound", "sounds/MenuItemCommand.wav",
"RadioButtonMenuItem.disabledForeground", getMenuDisabledForeground(),
"RadioButtonMenuItem.font", MetalLookAndFeel.getControlTextFont(),
"RadioButtonMenuItem.foreground", getMenuForeground(),
@@ -1030,6 +1133,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"RadioButtonMenuItem.selectionForeground",
MetalLookAndFeel.getMenuSelectedForeground(),
+ "ScrollBar.allowsAbsolutePositioning", Boolean.TRUE,
"ScrollBar.background", getControl(),
"ScrollBar.darkShadow", getControlDarkShadow(),
"ScrollBar.foreground", getControl(),
@@ -1065,6 +1169,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"Slider.verticalThumbIcon",
MetalIconFactory.getVerticalSliderThumbIcon(),
+ "Spinner.arrowButtonInsets", new InsetsUIResource(0, 0, 0, 0),
"Spinner.background", getControl(),
"Spinner.font", new FontUIResource("Dialog", Font.BOLD, 12),
"Spinner.foreground", getControl(),
@@ -1072,6 +1177,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"SplitPane.background", getControl(),
"SplitPane.darkShadow", getControlDarkShadow(),
"SplitPane.dividerFocusColor", getPrimaryControl(),
+ "SplitPane.dividerSize", new Integer(10),
"SplitPane.highlight", getControlHighlight(),
"SplitPane.shadow", getControlShadow(),
@@ -1174,6 +1280,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"ToolTip.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"ToolTip.foreground", getPrimaryControlInfo(),
"ToolTip.foregroundInactive", getControlDarkShadow(),
+ "ToolTip.hideAccelerator", Boolean.FALSE,
"Tree.background", getWindowBackground(),
"Tree.closedIcon", MetalIconFactory.getTreeFolderIcon(),
diff --git a/javax/swing/plaf/metal/MetalRadioButtonUI.java b/javax/swing/plaf/metal/MetalRadioButtonUI.java
index de71fe8e5..9fb960f68 100644
--- a/javax/swing/plaf/metal/MetalRadioButtonUI.java
+++ b/javax/swing/plaf/metal/MetalRadioButtonUI.java
@@ -176,7 +176,7 @@ public class MetalRadioButtonUI
protected void paintFocus(Graphics g, Rectangle t, Dimension d)
{
g.setColor(focusColor);
- g.drawRect(t.x - 1, t.y + 2, t.width + 2, t.height - 4);
+ g.drawRect(t.x - 1, t.y - 1, t.width + 2, t.height + 2);
}
}
diff --git a/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/javax/swing/plaf/metal/MetalSplitPaneDivider.java
index e9adfe46e..34a964cb3 100644
--- a/javax/swing/plaf/metal/MetalSplitPaneDivider.java
+++ b/javax/swing/plaf/metal/MetalSplitPaneDivider.java
@@ -105,7 +105,7 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider
/**
* This helper class acts as the Layout Manager for the divider.
*/
- protected class MetalDividerLayout implements LayoutManager
+ public class MetalDividerLayout implements LayoutManager
{
/** The right button. */
BasicArrowButton rb;
@@ -116,7 +116,7 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider
/**
* Creates a new DividerLayout object.
*/
- protected MetalDividerLayout()
+ public MetalDividerLayout()
{
// Nothing to do here
}
@@ -132,7 +132,7 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider
// Nothing to do here, constraints are set depending on
// orientation in layoutContainer
}
-
+
/**
* This method is called to lay out the container.
*
diff --git a/javax/swing/text/AbstractDocument.java b/javax/swing/text/AbstractDocument.java
index 76e758c6d..395f39e4c 100644
--- a/javax/swing/text/AbstractDocument.java
+++ b/javax/swing/text/AbstractDocument.java
@@ -541,11 +541,13 @@ public abstract class AbstractDocument implements Document, Serializable
writeLock();
UndoableEdit undo = content.insertString(offset, text);
+ if (undo != null)
+ event.addEdit(undo);
+
insertUpdate(event, attributes);
writeUnlock();
- if (event.modified)
- fireInsertUpdate(event);
+ fireInsertUpdate(event);
if (undo != null)
fireUndoableEditUpdate(new UndoableEditEvent(this, undo));
}
@@ -1327,7 +1329,14 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Object getAttribute(Object key)
{
- return attributes.getAttribute(key);
+ Object result = attributes.getAttribute(key);
+ if (result == null && element_parent != null)
+ {
+ AttributeSet parentSet = element_parent.getAttributes();
+ if (parentSet != null)
+ result = parentSet.getAttribute(key);
+ }
+ return result;
}
/**
@@ -1905,6 +1914,15 @@ public abstract class AbstractDocument implements Document, Serializable
// XXX - Fully qualify ElementChange to work around gcj bug #2499.
return (DocumentEvent.ElementChange) changes.get(elem);
}
+
+ /**
+ * Returns a String description of the change event. This returns the
+ * toString method of the Vector of edits.
+ */
+ public String toString()
+ {
+ return edits.toString();
+ }
}
/**
diff --git a/javax/swing/text/DefaultCaret.java b/javax/swing/text/DefaultCaret.java
index de512c37f..0d00bf8d5 100644
--- a/javax/swing/text/DefaultCaret.java
+++ b/javax/swing/text/DefaultCaret.java
@@ -829,9 +829,12 @@ public class DefaultCaret extends Rectangle
public void setDot(int dot)
{
if (dot >= 0)
- {
+ {
+ Document doc = textComponent.getDocument();
+ if (doc != null)
+ this.dot = Math.min(dot, doc.getLength());
+ this.dot = Math.max(this.dot, 0);
this.mark = dot;
- this.dot = dot;
handleHighlight();
adjustVisibility(this);
appear();
diff --git a/javax/swing/text/DefaultEditorKit.java b/javax/swing/text/DefaultEditorKit.java
index fa8c050b0..88094b898 100644
--- a/javax/swing/text/DefaultEditorKit.java
+++ b/javax/swing/text/DefaultEditorKit.java
@@ -38,8 +38,10 @@ exception statement from your version. */
package javax.swing.text;
+import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -698,6 +700,53 @@ public class DefaultEditorKit extends EditorKit
new InsertContentAction(),
new InsertTabAction(),
new PasteAction(),
+ new TextAction(beginLineAction)
+ {
+ 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++;
+ t.setCaretPosition(cur);
+ }
+ catch (BadLocationException ble)
+ {
+ // Do nothing here.
+ }
+ }
+ },
+ new TextAction(endLineAction)
+ {
+ 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--;
+ t.setCaretPosition(cur);
+ }
+ catch (BadLocationException ble)
+ {
+ // Nothing to do here
+ }
+ }
+ },
new TextAction(deleteNextCharAction)
{
public void actionPerformed(ActionEvent event)
@@ -899,7 +948,7 @@ public class DefaultEditorKit extends EditorKit
content.append("\n");
}
- document.insertString(offset, content.toString(),
+ document.insertString(offset, content.substring(0, content.length() - 1),
SimpleAttributeSet.EMPTY);
}
diff --git a/javax/swing/text/DefaultFormatter.java b/javax/swing/text/DefaultFormatter.java
index 1b339366d..dfeac12b7 100644
--- a/javax/swing/text/DefaultFormatter.java
+++ b/javax/swing/text/DefaultFormatter.java
@@ -400,6 +400,8 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter
public String valueToString(Object value)
throws ParseException
{
+ if (value == null)
+ return "";
return value.toString();
}
diff --git a/javax/swing/text/DefaultFormatterFactory.java b/javax/swing/text/DefaultFormatterFactory.java
new file mode 100644
index 000000000..84a1676d2
--- /dev/null
+++ b/javax/swing/text/DefaultFormatterFactory.java
@@ -0,0 +1,280 @@
+/* DefaultFormatterFactory.java -- FIXME: briefly describe file purpose
+ Copyright (C) 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. */
+
+
+package javax.swing.text;
+
+import java.io.Serializable;
+
+import javax.swing.JFormattedTextField;
+import javax.swing.JFormattedTextField.AbstractFormatter;
+import javax.swing.JFormattedTextField.AbstractFormatterFactory;
+
+/**
+ * This class is Swing's only concrete implementation of
+ * JFormattedTextField.AbstractFormatterFactory. It holds several
+ * formatters and determines the best one to be used based on the
+ * passed-in value from the text field.
+ *
+ * @author Anthony Balkissoon abalkiss at redhat dot com
+ * @since 1.4
+ */
+public class DefaultFormatterFactory extends AbstractFormatterFactory implements
+ Serializable
+{
+ /**
+ * The default formatter.
+ **/
+ AbstractFormatter defaultFormatter;
+
+ /**
+ * The formatter to use when the JFormattedTextField has focus and either the
+ * value isn't null or the value is null but no <code>nullFormatter</code>
+ * has been specified.
+ */
+ AbstractFormatter editFormatter;
+
+ /**
+ * The formatter to use when the JFormattedTextField doesn't havefocus and
+ * either the value isn't null or the value is null but no
+ * <code>nullFormatter</code> has been specified.
+ */
+ AbstractFormatter displayFormatter;
+
+ /**
+ * The formatter to use when the value of the JFormattedTextField is null.
+ */
+ AbstractFormatter nullFormatter;
+
+ /**
+ * Creates a DefaultFormatterFactory with no formatters
+ */
+ public DefaultFormatterFactory()
+ {
+ // Nothing to be done here.
+ }
+
+ /**
+ * Creates a new DefaultFormatterFactory with the specified formatters.
+ * @param defaultFormat the formatter to use if no other appropriate non-null
+ * formatted can be found.
+ */
+ public DefaultFormatterFactory(AbstractFormatter defaultFormat)
+ {
+ defaultFormatter = defaultFormat;
+ }
+
+ /**
+ * Creates a new DefaultFormatterFactory with the specified formatters.
+ * @param defaultFormat the formatter to use if no other appropriate non-null
+ * formatted can be found.
+ * @param displayFormat the formatter to use if the JFormattedTextField
+ * doesn't have focus and either the value is not null or the value is null
+ * but no <code>nullFormatter</code> has been specified.
+ */
+ public DefaultFormatterFactory(AbstractFormatter defaultFormat,
+ AbstractFormatter displayFormat)
+ {
+ defaultFormatter = defaultFormat;
+ displayFormatter = displayFormat;
+ }
+
+ /**
+ * Creates a new DefaultFormatterFactory with the specified formatters.
+ * @param defaultFormat the formatter to use if no other appropriate non-null
+ * formatted can be found.
+ * @param displayFormat the formatter to use if the JFormattedTextField
+ * doesn't have focus and either the value is not null or the value is null
+ * but no <code>nullFormatter</code> has been specified.
+ * @param editFormat the formatter to use if the JFormattedTextField has
+ * focus and either the value is not null or the value is null but not
+ * <code>nullFormatter</code> has been specified.
+ */
+ public DefaultFormatterFactory(AbstractFormatter defaultFormat,
+ AbstractFormatter displayFormat,
+ AbstractFormatter editFormat)
+ {
+ defaultFormatter = defaultFormat;
+ displayFormatter = displayFormat;
+ editFormatter = editFormat;
+ }
+
+ /**
+ * Creates a new DefaultFormatterFactory with the specified formatters.
+ * @param defaultFormat the formatter to use if no other appropriate non-null
+ * formatted can be found.
+ * @param displayFormat the formatter to use if the JFormattedTextField
+ * doesn't have focus and either the value is not null or the value is null
+ * but no <code>nullFormatter</code> has been specified.
+ * @param editFormat the formatter to use if the JFormattedTextField has
+ * focus and either the value is not null or the value is null but not
+ * <code>nullFormatter</code> has been specified.
+ * @param nullFormat the formatter to use when the value of the
+ * JFormattedTextField is null.
+ */
+ public DefaultFormatterFactory(AbstractFormatter defaultFormat,
+ AbstractFormatter displayFormat,
+ AbstractFormatter editFormat,
+ AbstractFormatter nullFormat)
+ {
+ defaultFormatter = defaultFormat;
+ displayFormatter = displayFormat;
+ editFormatter = editFormat;
+ nullFormatter = nullFormat;
+ }
+
+ /**
+ * Returns the formatted to be used if no other appropriate non-null
+ * formatter can be found.
+ * @return the formatted to be used if no other appropriate non-null
+ * formatter can be found.
+ */
+ public AbstractFormatter getDefaultFormatter()
+ {
+ return defaultFormatter;
+ }
+
+ /**
+ * Sets the formatted to be used if no other appropriate non-null formatter
+ * can be found.
+ * @param defaultFormatter the formatted to be used if no other appropriate
+ * non-null formatter can be found.
+ */
+ public void setDefaultFormatter(AbstractFormatter defaultFormatter)
+ {
+ this.defaultFormatter = defaultFormatter;
+ }
+
+ /**
+ * Gets the <code>displayFormatter</code>. This is the formatter to use if
+ * the JFormattedTextField is not being edited and either the value is not
+ * null or the value is null and no <code>nullFormatter<code> has been
+ * specified.
+ * @return the formatter to use if
+ * the JFormattedTextField is not being edited and either the value is not
+ * null or the value is null and no <code>nullFormatter<code> has been
+ * specified.
+ */
+ public AbstractFormatter getDisplayFormatter()
+ {
+ return displayFormatter;
+ }
+
+ /**
+ * Sets the <code>displayFormatter</code>. This is the formatter to use if
+ * the JFormattedTextField is not being edited and either the value is not
+ * null or the value is null and no <code>nullFormatter<code> has been
+ * specified.
+ * @param displayFormatter the formatter to use.
+ */
+ public void setDisplayFormatter(AbstractFormatter displayFormatter)
+ {
+ this.displayFormatter = displayFormatter;
+ }
+
+ /**
+ * Gets the <code>editFormatter</code>. This is the formatter to use if the
+ * JFormattedTextField is being edited and either the value is not null or
+ * the value is null and no <code>nullFormatter<code> has been specified.
+ * @return the formatter to use if the JFormattedTextField is being edited
+ * and the value is not null or the value is null but no nullFormatted has
+ * been specified.
+ */
+ public AbstractFormatter getEditFormatter()
+ {
+ return editFormatter;
+ }
+
+ /**
+ * Sets the <code>editFormatter</code>. This is the formatter to use if the
+ * JFormattedTextField is being edited and either the value is not null or
+ * the value is null and no <code>nullFormatter<code> has been specified.
+ * @param editFormatter the formatter to use.
+ */
+ public void setEditFormatter(AbstractFormatter editFormatter)
+ {
+ this.editFormatter = editFormatter;
+ }
+
+ /**
+ * Gets the formatter to use if the value of the JFormattedTextField is null.
+ * @return the formatter to use for null values.
+ */
+ public AbstractFormatter getNullFormatter()
+ {
+ return nullFormatter;
+ }
+
+ /**
+ * Sets the <code>nullFormatter</code>. This is the formatter to use if the
+ * value of the JFormattedTextField is null.
+ * @param nullFormatter the formatter to use for null values.
+ */
+ public void setNullFormatter(AbstractFormatter nullFormatter)
+ {
+ this.nullFormatter = nullFormatter;
+ }
+
+ /**
+ * Returns the appropriate formatter based on the state of
+ * <code>tf</code>. If <code>tf<code> is null we return null, otherwise
+ * we return one of the following:
+ * 1. Returns <code>nullFormatter</code> if <code>tf.getValue()</code> is
+ * null and <code>nullFormatter</code> is not.
+ * 2. Returns <code>editFormatter</code> if <code>tf.hasFocus()</code> is
+ * true and <code>editFormatter</code> is not null.
+ * 3. Returns <code>displayFormatter</code> if <code>tf.hasFocus()</code> is
+ * false and <code>displayFormatter</code> is not null.
+ * 4. Otherwise returns <code>defaultFormatter</code>.
+ */
+ public AbstractFormatter getFormatter(JFormattedTextField tf)
+ {
+ if (tf == null)
+ return null;
+
+ if (tf.getValue() == null && nullFormatter != null)
+ return nullFormatter;
+
+ if (tf.hasFocus() && editFormatter != null)
+ return editFormatter;
+
+ if (!tf.hasFocus() && displayFormatter != null)
+ return displayFormatter;
+
+ return defaultFormatter;
+ }
+}
diff --git a/javax/swing/text/DefaultStyledDocument.java b/javax/swing/text/DefaultStyledDocument.java
index 49ab14e54..1df77b44d 100644
--- a/javax/swing/text/DefaultStyledDocument.java
+++ b/javax/swing/text/DefaultStyledDocument.java
@@ -48,6 +48,7 @@ import java.util.Vector;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
+import javax.swing.event.UndoableEditEvent;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.UndoableEdit;
@@ -428,6 +429,9 @@ public class DefaultStyledDocument extends AbstractDocument
/** 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
@@ -485,6 +489,85 @@ 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
+ */
+ public void remove(int offs, int len, DefaultDocumentEvent ev)
+ {
+ offset = offs;
+ length = len;
+ documentEvent = ev;
+ removeUpdate();
+ }
+
+ /**
+ * Updates the element structure of the document in response to removal of
+ * content. It removes the affected {@link Element}s from the document
+ * structure.
+ */
+ protected void removeUpdate()
+ {
+ int startParagraph = root.getElementIndex(offset);
+ int endParagraph = root.getElementIndex(offset + length);
+ Element[] empty = new Element[0];
+ int removeStart = -1;
+ int removeEnd = -1;
+ for (int i = startParagraph; i < endParagraph; i++)
+ {
+ Element paragraph = root.getElement(i);
+ int contentStart = paragraph.getElementIndex(offset);
+ int contentEnd = paragraph.getElementIndex(offset + length);
+ if (contentStart == paragraph.getStartOffset()
+ && contentEnd == paragraph.getEndOffset())
+ {
+ // In this case we only need to remove the whole paragraph. We
+ // do this in one go after this loop and only record the indices
+ // here.
+ if (removeStart == -1)
+ {
+ removeStart = i;
+ removeEnd = i;
+ }
+ else
+ removeEnd = i;
+ }
+ else
+ {
+ // In this case we remove a couple of child elements from this
+ // paragraph.
+ int removeLen = contentEnd - contentStart;
+ 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));
+ }
+ }
+ // Now we remove paragraphs from the root that have been tagged for
+ // removal.
+ if (removeStart != -1)
+ {
+ int removeLen = removeEnd - removeStart;
+ 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));
+ }
+ }
+
+ /**
* 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.
@@ -675,8 +758,11 @@ public class DefaultStyledDocument extends AbstractDocument
public void insert(int offset, int length, ElementSpec[] data,
DefaultDocumentEvent ev)
{
+ if (length == 0)
+ return;
this.offset = offset;
this.length = length;
+ this.endOffset = offset + length;
documentEvent = ev;
// Push the root and the paragraph at offset onto the element stack.
elementStack.clear();
@@ -703,9 +789,11 @@ public class DefaultStyledDocument extends AbstractDocument
{
case ElementSpec.StartTagType:
numStartTags++;
+ documentEvent.modified = true;
break;
case ElementSpec.EndTagType:
numEndTags++;
+ documentEvent.modified = true;
break;
default:
insertContentTag(data[i]);
@@ -799,7 +887,7 @@ public class DefaultStyledDocument extends AbstractDocument
}
return ret;
}
-
+
/**
* Inserts a content element into the document structure.
*
@@ -810,6 +898,7 @@ public class DefaultStyledDocument extends AbstractDocument
prepareContentInsertion();
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
@@ -824,66 +913,77 @@ public class DefaultStyledDocument extends AbstractDocument
Element current = paragraph.getElement(currentIndex);
Element next = paragraph.getElement(currentIndex + 1);
+ if (next == null)
+ return;
+
Element newEl1 = createLeafElement(paragraph,
current.getAttributes(),
- current.getStartOffset(),
+ current.getStartOffset(),
offset);
Element newEl2 = createLeafElement(paragraph,
- current.getAttributes(),
+ current.getAttributes(),
offset,
next.getEndOffset());
- Element[] add = new Element[] {newEl1, newEl2};
- Element[] remove = new Element[] {current, next};
+ Element[] add = new Element[] { newEl1, newEl2 };
+ Element[] remove = new Element[] { current, next };
paragraph.replace(currentIndex, 2, add);
-
// Add this action to the document event.
addEdit(paragraph, currentIndex, remove, add);
}
- else
+ else if (dir == ElementSpec.JoinFractureDirection)
+ {
+ // TODO: What should be done here?
+ }
+ else if (dir == ElementSpec.OriginateDirection)
{
BranchElement paragraph = (BranchElement) elementStack.peek();
int index = paragraph.getElementIndex(offset);
Element current = paragraph.getElement(index);
-
+
Element[] added;
- Element[] removed;
+ Element[] removed = new Element[] {current};
Element[] splitRes = split(current, offset, length);
- // Special case for when offset == startOffset or offset == endOffset.
if (splitRes[0] == null)
{
added = new Element[2];
- added[0] = createLeafElement(paragraph, tag.getAttributes(),
- offset, offset + length);
+ 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, tag.getAttributes(),
- offset, offset + length);
+ added[0] = createLeafElement(paragraph, tagAtts, offset,
+ endOffset);
added[1] = splitRes[1];
- removed = new Element[] { current };
}
- else if (current.getEndOffset() - length == offset)
+ 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, tag.getAttributes(),
- offset, offset + length);
- removed = new Element[] { current };
+ added[1] = createLeafElement(paragraph, tagAtts, offset,
+ endOffset);
}
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, tag.getAttributes(),
- offset, offset + length);
+ added[1] = createLeafElement(paragraph, tagAtts, offset,
+ endOffset);
added[2] = splitRes[1];
- removed = new Element[] { current };
- }
+ }
paragraph.replace(index, removed.length, added);
addEdit(paragraph, index, removed, added);
}
@@ -1014,7 +1114,7 @@ public class DefaultStyledDocument extends AbstractDocument
*/
public String getName()
{
- return "section";
+ return SectionElementName;
}
}
@@ -1135,8 +1235,7 @@ public class DefaultStyledDocument extends AbstractDocument
// Use createBranchElement() and createLeafElement instead.
SectionElement section = new SectionElement();
- BranchElement paragraph =
- (BranchElement) createBranchElement(section, null);
+ BranchElement paragraph = new BranchElement(section, null);
paragraph.setResolveParent(getStyle(StyleContext.DEFAULT_STYLE));
tmp = new Element[1];
tmp[0] = paragraph;
@@ -1233,7 +1332,11 @@ public class DefaultStyledDocument extends AbstractDocument
{
Element paragraph = getParagraphElement(position);
AttributeSet attributes = paragraph.getAttributes();
- return (Style) attributes.getResolveParent();
+ AttributeSet a = attributes.getResolveParent();
+ // If the resolve parent is not of type Style, we return null.
+ if (a instanceof Style)
+ return (Style) a;
+ return null;
}
/**
@@ -1302,50 +1405,54 @@ public class DefaultStyledDocument extends AbstractDocument
AttributeSet attributes,
boolean replace)
{
- DefaultDocumentEvent ev =
- new DefaultDocumentEvent(offset, length,
- DocumentEvent.EventType.CHANGE);
-
- // Modify the element structure so that the interval begins at an element
- // start and ends at an element end.
- buffer.change(offset, length, ev);
-
- Element root = getDefaultRootElement();
- // Visit all paragraph elements within the specified interval
- int paragraphCount = root.getElementCount();
- for (int pindex = 0; pindex < paragraphCount; pindex++)
+ // Exit early if length is 0, so no DocumentEvent is created or fired.
+ if (length == 0)
+ return;
+ try
{
- Element paragraph = root.getElement(pindex);
- // Skip paragraphs that lie outside the interval.
- if ((paragraph.getStartOffset() > offset + length)
- || (paragraph.getEndOffset() < offset))
- continue;
-
- // Visit content elements within this paragraph
- int contentCount = paragraph.getElementCount();
- for (int cindex = 0; cindex < contentCount; cindex++)
+ // 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);
+
+ // Modify the element structure so that the interval begins at an
+ // element
+ // start and ends at an element end.
+ buffer.change(offset, length, ev);
+
+ Element root = getDefaultRootElement();
+ // Visit all paragraph elements within the specified interval
+ int end = offset + length;
+ Element curr;
+ for (int pos = offset; pos < end; )
{
- Element content = paragraph.getElement(cindex);
- // Skip content that lies outside the interval.
- if ((content.getStartOffset() > offset + length)
- || (content.getEndOffset() < offset))
- continue;
-
- if (content instanceof AbstractElement)
- {
- AbstractElement el = (AbstractElement) content;
- if (replace)
- el.removeAttributes(el);
- el.addAttributes(attributes);
- }
- else
- throw new AssertionError("content elements are expected to be"
- + "instances of "
- + "javax.swing.text.AbstractDocument.AbstractElement");
+ // 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.
+ if (replace)
+ a.removeAttributes(a);
+ // Add all the new attributes.
+ a.addAttributes(attributes);
+ // Increment pos so we can check the next CharacterElement.
+ pos = curr.getEndOffset();
}
+ fireChangedUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
+ }
+ finally
+ {
+ writeUnlock();
}
-
- fireChangedUpdate(ev);
}
/**
@@ -1357,14 +1464,36 @@ public class DefaultStyledDocument extends AbstractDocument
public void setLogicalStyle(int position, Style style)
{
Element el = getParagraphElement(position);
- if (el instanceof AbstractElement)
- {
- AbstractElement ael = (AbstractElement) el;
- ael.setResolveParent(style);
- }
- else
- throw new AssertionError("paragraph elements are expected to be"
- + "instances of javax.swing.text.AbstractDocument.AbstractElement");
+ // getParagraphElement doesn't return null but subclasses might so
+ // we check for null here.
+ 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");
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
/**
@@ -1380,15 +1509,47 @@ public class DefaultStyledDocument extends AbstractDocument
AttributeSet attributes,
boolean replace)
{
- int index = offset;
- while (index < offset + length)
+ try
{
- AbstractElement par = (AbstractElement) getParagraphElement(index);
- AttributeContext ctx = getAttributeContext();
- if (replace)
- par.removeAttributes(par);
- par.addAttributes(attributes);
- index = par.getElementCount();
+ // 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);
+
+ // Have to iterate through all the _paragraph_ elements that are
+ // contained or partially contained in the interval
+ // (offset, offset + length).
+ Element rootElement = getDefaultRootElement();
+ int startElement = rootElement.getElementIndex(offset);
+ int endElement = rootElement.getElementIndex(offset + length - 1);
+ if (endElement < startElement)
+ endElement = startElement;
+
+ for (int i = startElement; i <= endElement; i++)
+ {
+ Element par = rootElement.getElement(i);
+ MutableAttributeSet a = (MutableAttributeSet) par.getAttributes();
+ // Add the change to the DocumentEvent.
+ ev.addEdit(new AttributeUndoableEdit(par, attributes, replace));
+ // If replace is true remove the old attributes.
+ if (replace)
+ a.removeAttributes(a);
+ // Add the new attributes.
+ a.addAttributes(attributes);
+ }
+ fireChangedUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
+ }
+ finally
+ {
+ writeUnlock();
}
}
@@ -1402,9 +1563,14 @@ public class DefaultStyledDocument extends AbstractDocument
protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
{
super.insertUpdate(ev, attr);
+ // If the attribute set is null, use an empty attribute set.
+ if (attr == null)
+ attr = SimpleAttributeSet.EMPTY;
int offset = ev.getOffset();
int length = ev.getLength();
int endOffset = offset + length;
+ AttributeSet paragraphAttributes =
+ getParagraphElement(endOffset).getAttributes();
Segment txt = new Segment();
try
{
@@ -1419,66 +1585,104 @@ public class DefaultStyledDocument extends AbstractDocument
int len = 0;
Vector specs = new Vector();
-
+ ElementSpec finalStartTag = null;
+ 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);
+ }
+ }
+ catch (BadLocationException ble)
+ {
+ // This shouldn't happen.
+ AssertionError ae = new AssertionError();
+ ae.initCause(ble);
+ throw ae;
+ }
+ }
- for (int i = offset; i < endOffset; ++i)
+
+ for (int i = txt.offset; i < segmentEnd; ++i)
{
len++;
if (txt.array[i] == '\n')
{
- ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType,
- len);
-
- // If we are at the last index, then check if we could probably be
- // joined with the next element.
- if (i == endOffset - 1)
- {
- if (next.getAttributes().isEqual(attr))
- spec.setDirection(ElementSpec.JoinNextDirection);
- }
- // If we are at the first new element, then check if it could be
- // joined with the previous element.
- else if (specs.size() == 0)
- {
- if (prev.getAttributes().isEqual(attr))
- spec.setDirection(ElementSpec.JoinPreviousDirection);
- }
-
- specs.add(spec);
+ // Add the ElementSpec for the content.
+ specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
// Add ElementSpecs for the newline.
- ElementSpec endTag = new ElementSpec(null, ElementSpec.EndTagType);
- specs.add(endTag);
- ElementSpec startTag = new ElementSpec(null,
+ specs.add(new ElementSpec(null, ElementSpec.EndTagType));
+ finalStartTag = new ElementSpec(paragraphAttributes,
ElementSpec.StartTagType);
- startTag.setDirection(ElementSpec.JoinFractureDirection);
- specs.add(startTag);
-
+ specs.add(finalStartTag);
len = 0;
- offset += len;
}
}
// 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
+ // handleInsertAfterNewline.
+ if (finalStartTag != null)
{
- ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType, len);
- // If we are at the first new element, then check if it could be
- // joined with the previous element.
- if (specs.size() == 0)
+ if (prevCharWasNewline)
+ finalStartTag.setDirection(finalStartDirection);
+ else if (prevParagraph.getEndOffset() != endOffset)
+ finalStartTag.setDirection(ElementSpec.JoinFractureDirection);
+ else
{
- if (prev.getAttributes().isEqual(attr))
- spec.setDirection(ElementSpec.JoinPreviousDirection);
+ // If there is an element AFTER this one, then set the
+ // direction to JoinNextDirection.
+ Element parent = prevParagraph.getParentElement();
+ int index = parent.getElementIndex(offset);
+ if (index + 1 < parent.getElementCount()
+ && !parent.getElement(index + 1).isLeaf())
+ finalStartTag.setDirection(ElementSpec.JoinNextDirection);
}
- // Check if we could probably be joined with the next element.
- else if (next.getAttributes().isEqual(attr))
- spec.setDirection(ElementSpec.JoinNextDirection);
-
- specs.add(spec);
}
-
+
+ // If we are at the last index, then check if we could probably be
+ // joined with the next element.
+ ElementSpec last = (ElementSpec) specs.lastElement();
+ if (next.getAttributes().isEqual(attr)
+ && last.getType() == ElementSpec.ContentType)
+ 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()]);
@@ -1486,6 +1690,47 @@ public class DefaultStyledDocument extends AbstractDocument
}
/**
+ * 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)
+ {
+ if (prevParagraph.getParentElement() == paragraph.getParentElement())
+ {
+ specs.add(new ElementSpec(a, ElementSpec.EndTagType));
+ specs.add(new ElementSpec(a, ElementSpec.StartTagType));
+ if (prevParagraph.getEndOffset() != 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)
+ 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
+ */
+ protected void removeUpdate(DefaultDocumentEvent ev)
+ {
+ super.removeUpdate(ev);
+ buffer.remove(ev.getOffset(), ev.getLength(), ev);
+ }
+
+ /**
* Returns an enumeration of all style names.
*
* @return an enumeration of all style names
@@ -1506,6 +1751,35 @@ public class DefaultStyledDocument extends AbstractDocument
// 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.
*
@@ -1515,37 +1789,58 @@ public class DefaultStyledDocument extends AbstractDocument
protected void insert(int offset, ElementSpec[] data)
throws BadLocationException
{
- writeLock();
- // First we insert the content.
- int index = offset;
- for (int i = 0; i < data.length; i++)
+ try
{
- ElementSpec spec = data[i];
- if (spec.getArray() != null && spec.getLength() > 0)
+ // writeLock() and writeUnlock() should always be in a try/finally
+ // 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++)
{
- String insertString = new String(spec.getArray(), spec.getOffset(),
- spec.getLength());
- content.insertString(index, insertString);
+ // Collect all inserts into one so we can get the correct
+ // ElementEdit
+ ElementSpec spec = data[i];
+ if (spec.getArray() != null && spec.getLength() > 0)
+ contentBuffer.append(spec.getArray(), spec.getOffset(),
+ spec.getLength());
}
- index += spec.getLength();
+
+ int length = contentBuffer.length();
+
+ // 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);
+ ev.addEdit(edit);
+
+ for (int i = 0; i < data.length; i++)
+ {
+ ElementSpec spec = data[i];
+ AttributeSet atts = spec.getAttributes();
+ if (atts != null)
+ insertUpdate(ev, atts);
+ }
+
+ // Finally we must update the document structure and fire the insert
+ // update event.
+ buffer.insert(offset, length, data, ev);
+ fireInsertUpdate(ev);
}
- // Update the view structure.
- DefaultDocumentEvent ev = new DefaultDocumentEvent(offset, index - offset,
- DocumentEvent.EventType.INSERT);
- for (int i = 0; i < data.length; i++)
+ finally
{
- ElementSpec spec = data[i];
- AttributeSet atts = spec.getAttributes();
- if (atts != null)
- insertUpdate(ev, atts);
+ writeUnlock();
}
-
- // Finally we must update the document structure and fire the insert update
- // event.
- buffer.insert(offset, index - offset, data, ev);
- if (ev.modified)
- fireInsertUpdate(ev);
- writeUnlock();
}
/**
@@ -1573,4 +1868,9 @@ public class DefaultStyledDocument extends AbstractDocument
throw err;
}
}
+
+ static boolean attributeSetsAreSame (AttributeSet a, AttributeSet b)
+ {
+ return (a == null && b == null) || (a != null && a.isEqual(b));
+ }
}
diff --git a/javax/swing/text/GapContent.java b/javax/swing/text/GapContent.java
index 1e62a4695..c0f9beae2 100644
--- a/javax/swing/text/GapContent.java
+++ b/javax/swing/text/GapContent.java
@@ -64,6 +64,7 @@ import javax.swing.undo.UndoableEdit;
public class GapContent
implements AbstractDocument.Content, Serializable
{
+
/**
* A {@link Position} implementation for <code>GapContent</code>.
*/
@@ -449,7 +450,7 @@ public class GapContent
// We store the actual array index in the GapContentPosition. The real
// offset is then calculated in the GapContentPosition.
int mark = offset;
- if (offset > gapStart)
+ if (offset >= gapStart)
mark += gapEnd - gapStart;
GapContentPosition pos = new GapContentPosition(mark);
@@ -584,8 +585,9 @@ public class GapContent
{
if (gapStart != position)
shiftGap(position);
+
// Remove content
- if (rmSize > 0)
+ if (rmSize > 0)
shiftGapEndUp(gapEnd + rmSize);
// If gap is too small, enlarge the gap.
diff --git a/javax/swing/text/InternationalFormatter.java b/javax/swing/text/InternationalFormatter.java
index a7ed18166..ba3cffaba 100644
--- a/javax/swing/text/InternationalFormatter.java
+++ b/javax/swing/text/InternationalFormatter.java
@@ -228,6 +228,8 @@ public class InternationalFormatter
public String valueToString(Object value)
throws ParseException
{
+ if (value == null)
+ return "";
if (format != null)
return format.format(value);
else
diff --git a/javax/swing/text/JTextComponent.java b/javax/swing/text/JTextComponent.java
index 87f884986..afa1f24a6 100644
--- a/javax/swing/text/JTextComponent.java
+++ b/javax/swing/text/JTextComponent.java
@@ -380,12 +380,18 @@ public abstract class JTextComponent extends JComponent
public KeyStroke[] allKeys()
{
KeyStroke[] superKeys = super.allKeys();
- KeyStroke[] mapKeys = map.getBoundKeyStrokes();
- KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length];
- for (int i = 0; i < superKeys.length; ++i)
+ KeyStroke[] mapKeys = map.getBoundKeyStrokes();
+ int skl = 0;
+ int mkl = 0;
+ if (superKeys != null)
+ skl = superKeys.length;
+ if (mapKeys != null)
+ mkl = mapKeys.length;
+ KeyStroke[] bothKeys = new KeyStroke[skl + mkl];
+ for (int i = 0; i < skl; ++i)
bothKeys[i] = superKeys[i];
- for (int i = 0; i < mapKeys.length; ++i)
- bothKeys[i + superKeys.length] = mapKeys[i];
+ for (int i = 0; i < mkl; ++i)
+ bothKeys[i + skl] = mapKeys[i];
return bothKeys;
}
}
@@ -906,49 +912,16 @@ public abstract class JTextComponent extends JComponent
public JTextComponent()
{
Keymap defkeymap = getKeymap(DEFAULT_KEYMAP);
- boolean creatingKeymap = false;
if (defkeymap == null)
{
defkeymap = addKeymap(DEFAULT_KEYMAP, null);
defkeymap.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction());
- creatingKeymap = true;
}
setFocusable(true);
setEditable(true);
enableEvents(AWTEvent.KEY_EVENT_MASK);
updateUI();
-
- // need to do this after updateUI()
- if (creatingKeymap)
- loadKeymap(
- defkeymap,
- new KeyBinding[] {
- new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
- DefaultEditorKit.backwardAction),
- new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
- DefaultEditorKit.forwardAction),
- new KeyBinding(KeyStroke.getKeyStroke("typed \b"),
- DefaultEditorKit.deletePrevCharAction),
- new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_X,
- KeyEvent.CTRL_DOWN_MASK),
- DefaultEditorKit.cutAction),
- new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C,
- KeyEvent.CTRL_DOWN_MASK),
- DefaultEditorKit.copyAction),
- new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V,
- KeyEvent.CTRL_DOWN_MASK),
- DefaultEditorKit.pasteAction),
- new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,
- KeyEvent.SHIFT_DOWN_MASK),
- DefaultEditorKit.selectionBackwardAction),
- new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,
- KeyEvent.SHIFT_DOWN_MASK),
- DefaultEditorKit.selectionForwardAction),
- new KeyBinding(KeyStroke.getKeyStroke("typed \u007f"),
- DefaultEditorKit.deleteNextCharAction)
- },
- getActions());
}
public void setDocument(Document newDoc)
diff --git a/javax/swing/text/StyleContext.java b/javax/swing/text/StyleContext.java
index 4dfca6de1..c93adf895 100644
--- a/javax/swing/text/StyleContext.java
+++ b/javax/swing/text/StyleContext.java
@@ -362,9 +362,8 @@ public class StyleContext
public boolean isEqual(AttributeSet attr)
{
- return attr != null
- && attr.containsAttributes(this)
- && this.containsAttributes(attr);
+ return getAttributeCount() == attr.getAttributeCount()
+ && this.containsAttributes(attr);
}
public String toString()
diff --git a/javax/swing/text/StyledEditorKit.java b/javax/swing/text/StyledEditorKit.java
index e71f992b5..c4eef4463 100644
--- a/javax/swing/text/StyledEditorKit.java
+++ b/javax/swing/text/StyledEditorKit.java
@@ -67,7 +67,7 @@ public class StyledEditorKit extends DefaultEditorKit
*/
public UnderlineAction()
{
- super("TODO"); // TODO: Figure out name for this action.
+ super("font-underline");
}
/**
@@ -97,7 +97,7 @@ public class StyledEditorKit extends DefaultEditorKit
*/
public ItalicAction()
{
- super("TODO"); // TODO: Figure out correct name of this Action.
+ super("font-italic");
}
/**
@@ -127,7 +127,7 @@ public class StyledEditorKit extends DefaultEditorKit
*/
public BoldAction()
{
- super("TODO"); // TODO: Figure out correct name of this Action.
+ super("font-bold");
}
/**
@@ -585,8 +585,26 @@ public class StyledEditorKit extends DefaultEditorKit
public Action[] getActions()
{
Action[] actions1 = super.getActions();
- Action[] myActions = new Action[] { new BoldAction(), new ItalicAction(),
- new UnderlineAction() };
+ Action[] myActions = new Action[] {
+ new FontSizeAction("font-size-8", 8),
+ new FontSizeAction("font-size-10", 10),
+ new FontSizeAction("font-size-12", 12),
+ new FontSizeAction("font-size-14", 14),
+ new FontSizeAction("font-size-16", 16),
+ new FontSizeAction("font-size-18", 18),
+ new FontSizeAction("font-size-24", 24),
+ new FontSizeAction("font-size-36", 36),
+ new FontSizeAction("font-size-48", 48),
+ new FontFamilyAction("font-family-Serif", "Serif"),
+ new FontFamilyAction("font-family-Monospaced", "Monospaced"),
+ new FontFamilyAction("font-family-SansSerif", "SansSerif"),
+ new AlignmentAction("left-justify", StyleConstants.ALIGN_LEFT),
+ new AlignmentAction("center-justify", StyleConstants.ALIGN_CENTER),
+ new AlignmentAction("right-justify", StyleConstants.ALIGN_RIGHT),
+ new BoldAction(),
+ new ItalicAction(),
+ new UnderlineAction()
+ };
return TextAction.augmentList(actions1, myActions);
}
@@ -696,9 +714,8 @@ public class StyledEditorKit extends DefaultEditorKit
protected void createInputAttributes(Element element,
MutableAttributeSet set)
{
- AttributeSet atts = element.getAttributes();
- set.removeAttributes(set);
// FIXME: Filter out component, icon and element name attributes.
- set.addAttributes(atts);
+ set.removeAttributes(set);
+ set.addAttributes(element.getAttributes());
}
}
diff --git a/javax/swing/text/TableView.java b/javax/swing/text/TableView.java
new file mode 100644
index 000000000..d3113b82b
--- /dev/null
+++ b/javax/swing/text/TableView.java
@@ -0,0 +1,465 @@
+/* TableView.java -- A view impl for tables inside styled text
+ 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.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.SizeRequirements;
+import javax.swing.event.DocumentEvent;
+
+/**
+ * A {@link View} implementation for rendering tables inside styled text.
+ * Tables are rendered as vertical boxes (see {@link BoxView}). These boxes
+ * have a number of child views, which are the rows of the table. These are
+ * horizontal boxes containing the actuall cells of the table. These cells
+ * can be arbitrary view implementations and are fetched via the
+ * {@link ViewFactory} returned by {@link View#getViewFactory}.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class TableView
+ extends BoxView
+{
+
+ /**
+ * A view implementation that renders a row of a <code>TableView</code>.
+ * This is implemented as a horizontal box that contains the actual cells
+ * of the table.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ public class TableRow
+ extends BoxView
+ {
+ /**
+ * Creates a new instance of <code>TableRow</code>.
+ *
+ * @param el the element for which to create a row view
+ */
+ public TableRow(Element el)
+ {
+ super(el, X_AXIS);
+ }
+
+ /**
+ * Replaces some child views with a new set of child views. This is
+ * implemented to call the superclass behaviour and invalidates the row
+ * grid so that rows and columns will be recalculated.
+ *
+ * @param offset the start offset at which to replace views
+ * @param length the number of views to remove
+ * @param views the new set of views
+ */
+ public void replace(int offset, int length, View[] views)
+ {
+ super.replace(offset, length, views);
+ layoutChanged(X_AXIS);
+ }
+
+ /**
+ * Lays out the box's child views along the major axis. This is
+ * reimplemented so that the child views all have the width of their
+ * column.
+ *
+ * @param targetSpan the total span of the view
+ * @param axis the axis that is laid out
+ * @param offsets an array that holds the offsets of the child views after
+ * this method returned
+ * @param spans an array that holds the spans of the child views after this
+ * method returned
+ */
+ 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.
+ assert(offsets.length == columnOffsets.length);
+ assert(spans.length == columnSpans.length);
+ assert(offsets.length == spans.length);
+ for (int i = 0; i < offsets.length; ++i)
+ {
+ offsets[i] = columnOffsets[i];
+ spans[i] = columnSpans[i];
+ }
+ }
+
+ /**
+ * Lays out the box's child views along the minor axis (the orthogonal axis
+ * to the major axis). This is reimplemented to call the super behaviour
+ * and then adjust the span of the child views that span multiple rows.
+ *
+ * @param targetSpan the total span of the view
+ * @param axis the axis that is laid out
+ * @param offsets an array that holds the offsets of the child views after
+ * this method returned
+ * @param spans an array that holds the spans of the child views after this
+ * method returned
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ // FIXME: Figure out how to fetch the row heights from the TableView's
+ // element.
+ super.layoutMajorAxis(targetSpan, axis, offsets, spans);
+ }
+
+ /**
+ * Determines the resizeability of this view along the specified axis.
+ *
+ * @param axis the axis of which to fetch the resizability
+ *
+ * @return the resize weight or &lt;= 0 if this view is not resizable
+ *
+ * @throws IllegalArgumentException when an illegal axis is specified
+ */
+ public int getResizeWeight(int axis)
+ {
+ // TODO: Figure out if this is ok. I would think so, but better test
+ // this.
+ return 0;
+ }
+
+ /**
+ * Returns the child view that represents the specified position in the
+ * model. This is reimplemented because in this view we do not necessarily
+ * have a one to one mapping of child elements to child views.
+ *
+ * @param pos the model position for which to query the view
+ * @param a the allocation of this view
+ *
+ * @return the view that corresponds to the specified model position or
+ * <code>null</code> if there is none
+ */
+ protected View getViewAtPosition(int pos, Rectangle a)
+ {
+ // FIXME: Do not call super here. Instead walk through the child views
+ // and look for a range that contains the given position.
+ return super.getViewAtPosition(pos, a);
+ }
+ }
+
+ /**
+ * This class is deprecated and not used anymore. Table cells are
+ * rendered by an arbitrary <code>View</code> implementation.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ *
+ * @deprecated Table cells are now rendered by an arbitrary <code>View</code>
+ * implementation.
+ */
+ public class TableCell
+ extends BoxView
+ {
+
+ /**
+ * The row number of this cell.
+ */
+ private int row;
+
+ /**
+ * The column number of this cell.
+ */
+ private int column;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param el the element
+ *
+ * @deprecated Table cells are now rendered by an arbitrary
+ * <code>View</code> implementation.
+ */
+ public TableCell(Element el)
+ {
+ super(el, X_AXIS);
+ }
+
+ /**
+ * Returns the number of columns that this cell spans.
+ *
+ * @return the number of columns that this cell spans
+ *
+ * @deprecated Table cells are now rendered by an arbitrary
+ * <code>View</code> implementation.
+ */
+ public int getColumnCount()
+ {
+ // TODO: Figure out if this is right. However, this is not so important
+ // since this class isn't used anyway (except maybe be application code
+ // that still uses this deprecated class).
+ return 1;
+ }
+
+ /**
+ * Returns the number of rows that this cell spans.
+ *
+ * @return the number of rows that this cell spans
+ *
+ * @deprecated Table cells are now rendered by an arbitrary
+ * <code>View</code> implementation.
+ */
+ public int getRowCount()
+ {
+ // TODO: Figure out if this is right. However, this is not so important
+ // since this class isn't used anyway (except maybe be application code
+ // that still uses this deprecated class).
+ return 1;
+ }
+
+ /**
+ * Sets the grid location of this table cell.
+ *
+ * @param r the row of this cell
+ * @param c the column of this cell
+ *
+ * @deprecated Table cells are now rendered by an arbitrary
+ * <code>View</code> implementation.
+ */
+ public void setGridLocation(int r, int c)
+ {
+ row = r;
+ column = c;
+ }
+
+ /**
+ * Returns the row number of this cell.
+ *
+ * @return the row number of this cell
+ *
+ * @deprecated Table cells are now rendered by an arbitrary
+ * <code>View</code> implementation.
+ */
+ public int getGridRow()
+ {
+ return row;
+ }
+
+ /**
+ * Returns the column number of this cell.
+ *
+ * @return the column number of this cell
+ *
+ * @deprecated Table cells are now rendered by an arbitrary
+ * <code>View</code> implementation.
+ */
+ public int getGridColumn()
+ {
+ return column;
+ }
+ }
+
+ /**
+ * The offsets of the columns of this table. Package private to avoid
+ * synthetic accessor methods.
+ */
+ int[] columnOffsets;
+
+ /**
+ * The spans of the columns of this table. Package private to avoid
+ * synthetic accessor methods.
+ */
+ int[] columnSpans;
+
+ /**
+ * The size requirements of the columns.
+ */
+ private SizeRequirements[] columnRequirements;
+
+ /**
+ * Creates a new instance of <code>TableView</code>.
+ *
+ * @param el the element for which to create a table view
+ */
+ 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);
+ }
+
+ /**
+ * Replaces a number of child views with a set of new child views. This is
+ * implemented to call the superclass behaviour and invalidate the layout.
+ *
+ * @param offset the offset at which to replace child views
+ * @param length the number of child views to remove
+ * @param views the new set of views
+ */
+ public void replace(int offset, int length, View[] views)
+ {
+ super.replace(offset, length, views);
+ layoutChanged(Y_AXIS);
+ }
+
+ /**
+ * Creates a view for a table row.
+ *
+ * @param el the element that represents the table row
+ *
+ * @return a view for rendering the table row
+ */
+ protected TableRow createTableRow(Element el)
+ {
+ return new TableRow(el);
+ }
+
+ /**
+ * Creates a view for a table cell. This method is deprecated and not used
+ * anymore.
+ *
+ * @param el the element that represents the table cell
+ *
+ * @return a view for rendering the table cell
+ *
+ * @deprecated Table cells are now rendered by an arbitrary
+ * <code>View</code> implementation.
+ */
+ protected TableCell createTableCell(Element el)
+ {
+ return new TableCell(el);
+ }
+
+ protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e,
+ Shape a, ViewFactory vf)
+ {
+ // TODO: Figure out what to do here.
+ }
+
+ /**
+ * Lays out the columns to fit within the specified target span.
+ *
+ * @param targetSpan the total span for the columns
+ * @param offsets an array that holds the offsets of the columns when this
+ * method returns
+ * @param spans an array that holds the spans of the columns when this method
+ * returns
+ * @param reqs the size requirements for each column
+ */
+ protected void layoutColumns(int targetSpan, int[] offsets, int spans[],
+ SizeRequirements[] reqs)
+ {
+ // TODO: Figure out what exactly to do here.
+ }
+
+ /**
+ * Lays out the child views along the minor axis of the table (that is the
+ * horizontal axis). This is implemented to call {@link #layoutColumns} to
+ * layout the column layout of this table, and then forward to the superclass
+ * to actually lay out the rows.
+ *
+ * @param targetSpan the available span along the minor (horizontal) axis
+ * @param axis the axis
+ * @param offsets an array that holds the offsets of the columns when this
+ * method returns
+ * @param spans an array that holds the spans of the columns when this method
+ * returns
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ // TODO: Prepare size requirements for the columns.
+ layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
+ super.layoutMinorAxis(targetSpan, axis, offsets, spans);
+ }
+
+ /**
+ * Calculates the requirements of this view for the minor (== horizontal)
+ * axis.
+ *
+ * This is reimplemented to calculate the requirements as the sum of the
+ * size requirements of the columns.
+ *
+ * @param axis the axis
+ * @param req the size requirements object to use, if <code>null</code> a new
+ * one will be created
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements req)
+ {
+ // TODO: Maybe prepare columnRequirements.
+ SizeRequirements res = req;
+ if (res == null)
+ res = new SizeRequirements();
+ else
+ {
+ res.alignment = 0.5f;
+ res.maximum = 0;
+ res.minimum = 0;
+ res.preferred = 0;
+ }
+
+ for (int i = 0; i < columnRequirements.length; ++i)
+ {
+ res.minimum += columnRequirements[i].minimum;
+ res.preferred += columnRequirements[i].preferred;
+ res.maximum += columnRequirements[i].maximum;
+ // TODO: Do we have to handle alignment somehow?
+ }
+ return res;
+ }
+
+ /**
+ * Returns the child view that represents the specified position in the
+ * model. This is reimplemented because in this view we do not necessarily
+ * have a one to one mapping of child elements to child views.
+ *
+ * @param pos the model position for which to query the view
+ * @param a the allocation of this view
+ *
+ * @return the view that corresponds to the specified model position or
+ * <code>null</code> if there is none
+ */
+ protected View getViewAtPosition(int pos, Rectangle a)
+ {
+ // FIXME: Do not call super here. Instead walk through the child views
+ // and look for a range that contains the given position.
+ return super.getViewAtPosition(pos, a);
+ }
+}
diff --git a/javax/swing/text/View.java b/javax/swing/text/View.java
index 2de85446f..b835842bc 100644
--- a/javax/swing/text/View.java
+++ b/javax/swing/text/View.java
@@ -447,9 +447,11 @@ public abstract class View implements SwingConstants
protected void updateLayout(DocumentEvent.ElementChange ec,
DocumentEvent ev, Shape shape)
{
- Rectangle b = shape.getBounds();
- if (ec != null)
- preferenceChanged(this, true, true);
+ if (ec != null && shape != null)
+ preferenceChanged(null, true, true);
+ Container c = getContainer();
+ if (c != null)
+ c.repaint();
}
/**
diff --git a/javax/swing/text/html/BlockView.java b/javax/swing/text/html/BlockView.java
new file mode 100644
index 000000000..6274e7b17
--- /dev/null
+++ b/javax/swing/text/html/BlockView.java
@@ -0,0 +1,301 @@
+/* BlockView.java --
+ Copyright (C) 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. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.SizeRequirements;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BoxView;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * @author Lillian Angel <langel@redhat.com>
+ */
+public class BlockView extends BoxView
+{
+
+ /**
+ * Creates a new view that represents an html box.
+ * This can be used for a number of elements.
+ *
+ * @param elem - the element to create a view for
+ * @param axis - either View.X_AXIS or View.Y_AXIS
+ */
+ public BlockView(Element elem, int axis)
+ {
+ super(elem, axis);
+ }
+
+ /**
+ * Creates the parent view for this. It is called before
+ * any other methods, if the parent view is working properly.
+ * Implemented to forward to the superclass and call
+ * setPropertiesFromAttributes to set the paragraph
+ * properties.
+ *
+ * @param parent - the new parent, or null if the view
+ * is being removed from a parent it was added to.
+ */
+ public void setParent(View parent)
+ {
+ super.setParent(parent);
+
+ if (parent != null)
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Calculates the requirements along the major axis.
+ * This is implemented to call the superclass and then
+ * adjust it if the CSS width or height attribute is specified
+ * and applicable.
+ *
+ * @param axis - the axis to check the requirements for.
+ * @param r - the SizeRequirements. If null, one is created.
+ * @return the new SizeRequirements object.
+ */
+ protected SizeRequirements calculateMajorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ SizeRequirements sr = super.calculateMajorAxisRequirements(axis, r);
+ // FIXME: adjust it if the CSS width or height attribute is specified
+ // and applicable
+ return sr;
+ }
+
+ /**
+ * Calculates the requirements along the minor axis.
+ * This is implemented to call the superclass and then
+ * adjust it if the CSS width or height attribute is specified
+ * and applicable.
+ *
+ * @param axis - the axis to check the requirements for.
+ * @param r - the SizeRequirements. If null, one is created.
+ * @return the new SizeRequirements object.
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ SizeRequirements sr = super.calculateMinorAxisRequirements(axis, r);
+ // FIXME: adjust it if the CSS width or height attribute is specified
+ // and applicable.
+ return sr;
+ }
+
+ /**
+ * Lays out the box along the minor axis (the axis that is
+ * perpendicular to the axis that it represents). The results
+ * of the layout are placed in the given arrays which are
+ * the allocations to the children along the minor axis.
+ *
+ * @param targetSpan - the total span given to the view, also
+ * used to layout the children.
+ * @param axis - the minor axis
+ * @param offsets - the offsets from the origin of the view for
+ * all the child views. This is a return value and is filled in by this
+ * function.
+ * @param spans - the span of each child view. This is a return value and is
+ * filled in by this function.
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis,
+ int[] offsets, int[] spans)
+ {
+ // FIXME: Not implemented.
+ super.layoutMinorAxis(targetSpan, axis, offsets, spans);
+ }
+
+ /**
+ * Paints using the given graphics configuration and shape.
+ * This delegates to the css box painter to paint the
+ * border and background prior to the interior.
+ *
+ * @param g - Graphics configuration
+ * @param a - the Shape to render into.
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ Rectangle rect = (Rectangle) a;
+ // FIXME: not fully implemented
+ getStyleSheet().getBoxPainter(getAttributes()).paint(g, rect.x, rect.y,
+ rect.width,
+ rect.height, this);
+ super.paint(g, a);
+ }
+
+ /**
+ * Fetches the attributes to use when painting.
+ *
+ * @return the attributes of this model.
+ */
+ public AttributeSet getAttributes()
+ {
+ return getStyleSheet().getViewAttributes(this);
+ }
+
+ /**
+ * Gets the resize weight.
+ *
+ * @param axis - the axis to get the resize weight for.
+ * @return the resize weight.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public int getResizeWeight(int axis) throws IllegalArgumentException
+ {
+ // Can't resize the Y_AXIS
+ if (axis == Y_AXIS)
+ return 0;
+ if (axis == X_AXIS)
+ return 1;
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Gets the alignment.
+ *
+ * @param axis - the axis to get the alignment for.
+ * @return the alignment.
+ */
+ public float getAlignment(int axis)
+ {
+ if (axis == X_AXIS)
+ return 0.0F;
+ if (axis == Y_AXIS)
+ {
+ if (getViewCount() == 0)
+ return 0.0F;
+ float prefHeight = getPreferredSpan(Y_AXIS);
+ float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS);
+ return (firstRowHeight / 2.F) / prefHeight;
+ }
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Gives notification from the document that attributes were
+ * changed in a location that this view is responsible for.
+ *
+ * @param ev - the change information
+ * @param a - the current shape of the view
+ * @param f - the factory to use to rebuild if the view has children.
+ */
+ public void changedUpdate(DocumentEvent ev,
+ Shape a, ViewFactory f)
+ {
+ super.changedUpdate(ev, a, f);
+
+ // If more elements were added, then need to set the properties for them
+ int currPos = ev.getOffset();
+ if (currPos <= getStartOffset() && (currPos + ev.getLength()) >= getEndOffset())
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Determines the preferred span along the axis.
+ *
+ * @param axis - the view to get the preferred span for.
+ * @return the span the view would like to be painted into >=0/
+ * The view is usually told to paint into the span that is returned,
+ * although the parent may choose to resize or break the view.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public float getPreferredSpan(int axis) throws IllegalArgumentException
+ {
+ if (axis == X_AXIS || axis == Y_AXIS)
+ return super.getPreferredSpan(axis);
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Determines the minimum span along the axis.
+ *
+ * @param axis - the axis to get the minimum span for.
+ * @return the span the view would like to be painted into >=0/
+ * The view is usually told to paint into the span that is returned,
+ * although the parent may choose to resize or break the view.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public float getMinimumSpan(int axis) throws IllegalArgumentException
+ {
+ if (axis == X_AXIS || axis == Y_AXIS)
+ return super.getMinimumSpan(axis);
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Determines the maximum span along the axis.
+ *
+ * @param axis - the axis to get the maximum span for.
+ * @return the span the view would like to be painted into >=0/
+ * The view is usually told to paint into the span that is returned,
+ * although the parent may choose to resize or break the view.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public float getMaximumSpan(int axis) throws IllegalArgumentException
+ {
+ if (axis == X_AXIS || axis == Y_AXIS)
+ return super.getMaximumSpan(axis);
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Updates any cached values that come from attributes.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ // FIXME: Not implemented (need to use StyleSheet).
+ }
+
+ /**
+ * Gets the default style sheet.
+ *
+ * @return the style sheet
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ StyleSheet styleSheet = new StyleSheet();
+ styleSheet.importStyleSheet(getClass().getResource(HTMLEditorKit.DEFAULT_CSS));
+ return styleSheet;
+ }
+}
diff --git a/javax/swing/text/html/CSS.java b/javax/swing/text/html/CSS.java
index 029ad26f8..c248e758e 100644
--- a/javax/swing/text/html/CSS.java
+++ b/javax/swing/text/html/CSS.java
@@ -37,6 +37,7 @@ exception statement from your version. */
package javax.swing.text.html;
+import java.io.Serializable;
import java.util.HashMap;
/**
@@ -46,7 +47,7 @@ import java.util.HashMap;
*
* @author Roman Kennke (kennke@aicas.com)
*/
-public class CSS
+public class CSS implements Serializable
{
/**
* Returns an array of all CSS attributes.
diff --git a/javax/swing/text/html/CSSParser.java b/javax/swing/text/html/CSSParser.java
new file mode 100644
index 000000000..0bf76eb80
--- /dev/null
+++ b/javax/swing/text/html/CSSParser.java
@@ -0,0 +1,568 @@
+/* CSSParser.java --
+ Copyright (C) 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. */
+
+
+package javax.swing.text.html;
+
+import java.io.*;
+
+/**
+ * Parses a CSS document. This works by way of a delegate that implements the
+ * CSSParserCallback interface. The delegate is notified of the following
+ * events:
+ * - Import statement: handleImport
+ * - Selectors handleSelector. This is invoked for each string. For example if
+ * the Reader contained p, bar , a {}, the delegate would be notified 4 times,
+ * for 'p,' 'bar' ',' and 'a'.
+ * - When a rule starts, startRule
+ * - Properties in the rule via the handleProperty. This
+ * is invoked one per property/value key, eg font size: foo;, would cause the
+ * delegate to be notified once with a value of 'font size'.
+ * - Values in the rule via the handleValue, this is notified for the total value.
+ * - When a rule ends, endRule
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+class CSSParser
+{
+
+ /**
+ * Receives all information about the CSS document structure while parsing it.
+ * The methods are invoked by parser.
+ */
+ static interface CSSParserCallback
+ {
+ /**
+ * Handles the import statment in the document.
+ *
+ * @param imp - the import string
+ */
+ public abstract void handleImport(String imp);
+
+ /**
+ * Called when the start of a rule is encountered.
+ */
+ public abstract void startRule();
+
+ /**
+ * Called when the end of a rule is encountered.
+ */
+ public abstract void endRule();
+
+ /**
+ * Handles the selector of a rule.
+ *
+ * @param selector - the selector in the rule
+ */
+ public abstract void handleSelector(String selector);
+
+ /**
+ * Handles the properties in the document.
+ *
+ * @param property - the property in the document.
+ */
+ public abstract void handleProperty(String property);
+
+ /**
+ * Handles the values in the document.
+ *
+ * @param value - the value to handle.
+ */
+ public abstract void handleValue(String value);
+
+ }
+
+ /**
+ * The identifier of the rule.
+ */
+ private static final int IDENTIFIER = 1;
+
+ /**
+ * The open bracket.
+ */
+ private static final int BRACKET_OPEN = 2;
+
+ /**
+ * The close bracket.
+ */
+ private static final int BRACKET_CLOSE = 3;
+
+ /**
+ * The open brace.
+ */
+ private static final int BRACE_OPEN = 4;
+
+ /**
+ * The close brace.
+ */
+ private static final int BRACE_CLOSE = 5;
+
+ /**
+ * The open parentheses.
+ */
+ private static final int PAREN_OPEN = 6;
+
+ /**
+ * The close parentheses.
+ */
+ private static final int PAREN_CLOSE = 7;
+
+ /**
+ * The end of the document.
+ */
+ private static final int END = -1;
+
+ /**
+ * The character mapping in the document.
+ */
+ // FIXME: What is this used for?
+ private static final char[] charMapping = null;
+
+ /**
+ * Set to true if one character has been read ahead.
+ */
+ private boolean didPushChar;
+
+ /**
+ * The read ahead character.
+ */
+ private int pushedChar;
+
+ /**
+ * Temporary place to hold identifiers.
+ */
+ private StringBuffer unitBuffer;
+
+ /**
+ * Used to indicate blocks.
+ */
+ private int[] unitStack;
+
+ /**
+ * Number of valid blocks.
+ */
+ private int stackCount;
+
+ /**
+ * Holds the incoming CSS rules.
+ */
+ private Reader reader;
+
+ /**
+ * Set to true when the first non @ rule is encountered.
+ */
+ private boolean encounteredRuleSet;
+
+ /**
+ * The call back used to parse.
+ */
+ private CSSParser.CSSParserCallback callback;
+
+ /**
+ * nextToken() inserts the string here.
+ */
+ private char[] tokenBuffer;
+
+ /**
+ * Current number of chars in tokenBufferLength.
+ */
+ private int tokenBufferLength;
+
+ /**
+ * Set to true if any whitespace is read.
+ */
+ private boolean readWS;
+
+ /**
+ * Constructor
+ */
+ CSSParser()
+ {
+ unitBuffer = new StringBuffer();
+ tokenBuffer = new char[10];
+ }
+
+ /**
+ * Appends a character to the token buffer.
+ *
+ * @param c - the character to append
+ */
+ private void append(char c)
+ {
+ if (tokenBuffer.length >= tokenBufferLength)
+ {
+ char[] temp = new char[tokenBufferLength * 2];
+ if (tokenBuffer != null)
+ System.arraycopy(tokenBuffer, 0, temp, 0, tokenBufferLength);
+
+ temp[tokenBufferLength] = c;
+ tokenBuffer = temp;
+ }
+ else
+ tokenBuffer[tokenBufferLength] = c;
+ tokenBufferLength++;
+ }
+
+ /**
+ * Fetches the next token.
+ *
+ * @param c - the character to fetch.
+ * @return the location
+ * @throws IOException - any i/o error encountered while reading
+ */
+ private int nextToken(char c) throws IOException
+ {
+ readWS = false;
+ int next = readWS();
+
+ switch (next)
+ {
+ case '\"':
+ if (tokenBufferLength > 0)
+ tokenBufferLength--;
+ return IDENTIFIER;
+ case '\'':
+ if (tokenBufferLength > 0)
+ tokenBufferLength--;
+ return IDENTIFIER;
+ case '(':
+ return PAREN_OPEN;
+ case ')':
+ return PAREN_CLOSE;
+ case '{':
+ return BRACE_OPEN;
+ case '}':
+ return BRACE_CLOSE;
+ case '[':
+ return BRACKET_OPEN;
+ case ']':
+ return BRACKET_CLOSE;
+ case -1:
+ return END;
+ default:
+ pushChar(next);
+ getIdentifier(c);
+ return IDENTIFIER;
+ }
+ }
+
+ /**
+ * Reads a character from the stream.
+ *
+ * @return the number of characters read or -1 if end of stream is reached.
+ * @throws IOException - any i/o encountered while reading
+ */
+ private int readChar() throws IOException
+ {
+ if (didPushChar)
+ {
+ didPushChar = false;
+ return pushedChar;
+ }
+ return reader.read();
+ }
+
+ /**
+ * Parses the the contents of the reader using the
+ * callback.
+ *
+ * @param reader - the reader to read from
+ * @param callback - the callback instance
+ * @param parsingDeclaration - true if parsing a declaration
+ * @throws IOException - any i/o error from the reader
+ */
+ void parse(Reader reader, CSSParser.CSSParserCallback callback,
+ boolean parsingDeclaration)
+ throws IOException
+ {
+ this.reader = reader;
+ this.callback = callback;
+
+ try
+ {
+ if (!parsingDeclaration)
+ while(getNextStatement());
+ else
+ parseDeclarationBlock();
+ }
+ catch (IOException ioe)
+ {
+ // Nothing to do here.
+ }
+ }
+
+ /**
+ * Skips any white space, returning the character after the white space.
+ *
+ * @return the character after the whitespace
+ * @throws IOException - any i/o error from the reader
+ */
+ private int readWS() throws IOException
+ {
+ int next = readChar();
+ while (Character.isWhitespace((char) next))
+ {
+ readWS = true;
+ int tempNext = readChar();
+ if (tempNext == END)
+ return next;
+ next = tempNext;
+ }
+
+ // Its all whitespace
+ return END;
+ }
+
+ /**
+ * Gets the next statement, returning false if the end is reached.
+ * A statement is either an At-rule, or a ruleset.
+ *
+ * @return false if the end is reached
+ * @throws IOException - any i/o error from the reader
+ */
+ private boolean getNextStatement() throws IOException
+ {
+ int c = nextToken((char) 0);
+ switch (c)
+ {
+ case PAREN_OPEN:
+ case BRACE_OPEN:
+ case BRACKET_OPEN:
+ parseTillClosed(c);
+ break;
+ case BRACKET_CLOSE:
+ case BRACE_CLOSE:
+ case PAREN_CLOSE:
+ throw new IOException("Not a proper statement.");
+ case IDENTIFIER:
+ if (tokenBuffer[0] == ('@'))
+ parseAtRule();
+ else
+ parseRuleSet();
+ break;
+ case END:
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Parses an @ rule, stopping at a matching brace pair, or ;.
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseAtRule() throws IOException
+ {
+ // An At-Rule begins with the "@" character followed immediately by a keyword.
+ // Following the keyword separated by a space is an At-rule statement appropriate
+ // to the At-keyword used. If the At-Rule is a simple declarative statement
+ // (charset, import, fontdef), it is terminated by a semi-colon (";".)
+ // If the At-Rule is a conditional or informative statement (media, page, font-face),
+ // it is followed by optional arguments and then a style declaration block inside matching
+ // curly braces ("{", "}".) At-Rules are sometimes nestable, depending on the context.
+ // If any part of an At-Rule is not understood, it should be ignored.
+
+ // FIXME: Not Implemented
+ // call handleimport
+ }
+
+ /**
+ * Parses the next rule set, which is a selector followed by a declaration
+ * block.
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseRuleSet() throws IOException
+ {
+ // call parseDeclarationBlock
+ // call parse selectors
+ // call parse identifiers
+ // call startrule/endrule
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Parses a set of selectors, returning false if the end of the stream is
+ * reached.
+ *
+ * @return false if the end of stream is reached
+ * @throws IOException - any i/o error from the reader
+ */
+ private boolean parseSelectors() throws IOException
+ {
+ // FIXME: Not Implemented
+ // call handleselector
+ return false;
+ }
+
+ /**
+ * Parses a declaration block. Which a number of declarations followed by a
+ * })].
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseDeclarationBlock() throws IOException
+ {
+ // call parseDeclaration
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Parses a single declaration, which is an identifier a : and another identifier.
+ * This returns the last token seen.
+ *
+ * @returns the last token
+ * @throws IOException - any i/o error from the reader
+ */
+ private int parseDeclaration() throws IOException
+ {
+ // call handleValue
+ // FIXME: Not Implemented
+ return 0;
+ }
+
+ /**
+ * Parses identifiers until c is encountered, returning the ending token,
+ * which will be IDENTIFIER if c is found.
+ *
+ * @param c - the stop character
+ * @param wantsBlocks - true if blocks are wanted
+ * @return the ending token
+ * @throws IOException - any i/o error from the reader
+ */
+ private int parseIdentifiers(char c, boolean wantsBlocks) throws IOException
+ {
+ // FIXME: Not implemented
+ // call handleproperty?
+ return 0;
+ }
+
+ /**
+ * Parses till a matching block close is encountered. This is only appropriate
+ * to be called at the top level (no nesting).
+ *
+ * @param i - FIXME
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseTillClosed(int i) throws IOException
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Gets an identifier, returning true if the length of the string is greater
+ * than 0, stopping when c, whitespace, or one of {}()[] is hit.
+ *
+ * @param c - the stop character
+ * @return returns true if the length of the string > 0
+ * @throws IOException - any i/o error from the reader
+ */
+ private boolean getIdentifier(char c) throws IOException
+ {
+ // FIXME: Not Implemented
+ return false;
+ }
+
+ /**
+ * Reads till c is encountered, escaping characters as necessary.
+ *
+ * @param c - the stop character
+ * @throws IOException - any i/o error from the reader
+ */
+ private void readTill(char c) throws IOException
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Parses a comment block.
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void readComment() throws IOException
+ {
+ // Should ignore comments. Read until end of comment.
+ // FIXME: Not implemented
+ }
+
+ /**
+ * Called when a block start is encountered ({[.
+ *
+ * @param start of block
+ */
+ private void startBlock(int start)
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Called when an end block is encountered )]}
+ *
+ * @param end of block
+ */
+ private void endBlock(int end)
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Checks if currently in a block.
+ *
+ * @return true if currently in a block.
+ */
+ private boolean inBlock()
+ {
+ // FIXME: Not Implemented
+ return false;
+ }
+
+ /**
+ * Supports one character look ahead, this will throw if called twice in a row.
+ *
+ * @param c - the character to push.
+ * @throws IOException - if called twice in a row
+ */
+ private void pushChar(int c) throws IOException
+ {
+ if (didPushChar)
+ throw new IOException("pushChar called twice.");
+ didPushChar = true;
+ pushedChar = c;
+ }
+}
+
+ \ No newline at end of file
diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java
index d048a04e6..5b2452b32 100644
--- a/javax/swing/text/html/HTMLDocument.java
+++ b/javax/swing/text/html/HTMLDocument.java
@@ -40,17 +40,32 @@ package javax.swing.text.html;
import java.net.URL;
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Stack;
+import java.util.Vector;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.UndoableEditEvent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.ElementIterator;
+import javax.swing.text.GapContent;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML.Tag;
/**
- * TODO: This class is not yet completetely implemented.
- *
+ * TODO: Add more comments here
+ *
* @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ * @author Anthony Balkissoon (abalkiss@redhat.com)
+ * @author Lillian Angel (langel@redhat.com)
*/
public class HTMLDocument extends DefaultStyledDocument
{
@@ -60,6 +75,195 @@ public class HTMLDocument extends DefaultStyledDocument
public static final String AdditionalComments = "AdditionalComments";
URL baseURL = null;
boolean preservesUnknownTags = true;
+ int tokenThreshold = Integer.MAX_VALUE;
+ HTMLEditorKit.Parser parser;
+ StyleSheet styleSheet;
+ AbstractDocument.Content content;
+
+ /**
+ * Constructs an HTML document using the default buffer size and a default
+ * StyleSheet.
+ */
+ public HTMLDocument()
+ {
+ this(null);
+ }
+
+ /**
+ * Constructs an HTML document with the default content storage
+ * implementation and the specified style/attribute storage mechanism.
+ *
+ * @param styles - the style sheet
+ */
+ public HTMLDocument(StyleSheet styles)
+ {
+ this(new GapContent(BUFFER_SIZE_DEFAULT), styles);
+ }
+
+ /**
+ * Constructs an HTML document with the given content storage implementation
+ * and the given style/attribute storage mechanism.
+ *
+ * @param c - the document's content
+ * @param styles - the style sheet
+ */
+ public HTMLDocument(AbstractDocument.Content c, StyleSheet styles)
+ {
+ this.content = c;
+ if (styles == null)
+ {
+ styles = new StyleSheet();
+ styles.importStyleSheet(getClass().getResource(HTMLEditorKit.
+ DEFAULT_CSS));
+ }
+ this.styleSheet = styles;
+ }
+
+ /**
+ * Gets the style sheet with the document display rules (CSS) that were specified
+ * in the HTML document.
+ *
+ * @return - the style sheet
+ */
+ public StyleSheet getStyleSheet()
+ {
+ return styleSheet;
+ }
+
+ /**
+ * 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");
+ super.create(data);
+ }
+
+ /**
+ * This method creates a root element for the new document.
+ *
+ * @return the new default root
+ */
+ protected AbstractDocument.AbstractElement createDefaultRoot()
+ {
+ // FIXME: Not implemented
+ System.out.println("createDefaultRoot not implemented");
+ return super.createDefaultRoot();
+ }
+
+ /**
+ * This method returns an HTMLDocument.RunElement object attached to
+ * parent representing a run of text from p0 to p1. The run has
+ * attributes described by a.
+ *
+ * @param parent - the parent element
+ * @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);
+ }
+
+ /** 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);
+ }
+
+ /**
+ * Inserts new elements in bulk. This is how elements get created in the
+ * document. The parsing determines what structure is needed and creates the
+ * specification as a set of tokens that describe the edit while leaving the
+ * document free of a write-lock. This method can then be called in bursts by
+ * the reader to acquire a write-lock for a shorter duration (i.e. while the
+ * document is actually being altered).
+ *
+ * @param offset - the starting offset
+ * @param data - the element data
+ * @throws BadLocationException - if the given position does not
+ * represent a valid location in the associated document.
+ */
+ protected void insert(int offset, DefaultStyledDocument.ElementSpec[] data)
+ throws BadLocationException
+ {
+ super.insert(offset, data);
+ }
+
+ /**
+ * Updates document structure as a result of text insertion. This will happen
+ * within a write lock. This implementation simply parses the inserted content
+ * for line breaks and builds up a set of instructions for the element buffer.
+ *
+ * @param chng - a description of the document change
+ * @param attr - the attributes
+ */
+ protected void insertUpdate(AbstractDocument.DefaultDocumentEvent chng,
+ AttributeSet attr)
+ {
+ // FIXME: Not implemented
+ System.out.println("insertUpdate not implemented");
+ super.insertUpdate(chng, attr);
+ }
+
+ /**
+ * Returns the parser used by this HTMLDocument to insert HTML.
+ *
+ * @return the parser used by this HTMLDocument to insert HTML.
+ */
+ public HTMLEditorKit.Parser getParser()
+ {
+ return parser;
+ }
+
+ /**
+ * Sets the parser used by this HTMLDocument to insert HTML.
+ *
+ * @param p the parser to use
+ */
+ public void setParser (HTMLEditorKit.Parser p)
+ {
+ parser = p;
+ }
+ /**
+ * Sets the number of tokens to buffer before trying to display the
+ * Document.
+ *
+ * @param n the number of tokens to buffer
+ */
+ public void setTokenThreshold (int n)
+ {
+ tokenThreshold = n;
+ }
+
+ /**
+ * Returns the number of tokens that are buffered before the document
+ * is rendered.
+ *
+ * @return the number of tokens buffered
+ */
+ public int getTokenThreshold ()
+ {
+ return tokenThreshold;
+ }
/**
* Returns the location against which to resolve relative URLs.
@@ -79,7 +283,7 @@ public class HTMLDocument extends DefaultStyledDocument
public void setBase(URL u)
{
baseURL = u;
- //TODO: also set the base of the StyleSheet
+ styleSheet.setBase(u);
}
/**
@@ -259,10 +463,1133 @@ public class HTMLDocument extends DefaultStyledDocument
return null;
}
+ /**
+ * Gets the name of the element.
+ *
+ * @return the name of the element if it exists, null otherwise.
+ */
public String getName()
{
- //FIXME: this is supposed to do something different from the super class
- return super.getName();
+ return (String) getAttribute(StyleConstants.NameAttribute);
+ }
+ }
+
+ /**
+ * RunElement represents a section of text that has a set of
+ * HTML character level attributes assigned to it.
+ */
+ public class RunElement extends AbstractDocument.LeafElement
+ {
+
+ /**
+ * Constructs an element that has no children. It represents content
+ * within the document.
+ *
+ * @param parent - parent of this
+ * @param a - elements attributes
+ * @param start - the start offset >= 0
+ * @param end - the end offset
+ */
+ public RunElement(Element parent, AttributeSet a, int start, int end)
+ {
+ super(parent, a, start, end);
+ }
+
+ /**
+ * Gets the name of the element.
+ *
+ * @return the name of the element if it exists, null otherwise.
+ */
+ public String getName()
+ {
+ return (String) getAttribute(StyleConstants.NameAttribute);
+ }
+
+ /**
+ * Gets the resolving parent. HTML attributes do not inherit at the
+ * model level, so this method returns null.
+ *
+ * @return null
+ */
+ public AttributeSet getResolveParent()
+ {
+ return null;
+ }
+ }
+
+ /**
+ * A reader to load an HTMLDocument with HTML structure.
+ *
+ * @author Anthony Balkissoon abalkiss at redhat dot com
+ */
+ public class HTMLReader extends HTMLEditorKit.ParserCallback
+ {
+ /** Holds the current character attribute set **/
+ protected MutableAttributeSet charAttr = new SimpleAttributeSet();
+
+ protected Vector parseBuffer = new Vector();
+
+ /** A stack for character attribute sets **/
+ Stack charAttrStack = new Stack();
+
+ /** A mapping between HTML.Tag objects and the actions that handle them **/
+ HashMap tagToAction;
+
+ /** Tells us whether we've received the '</html>' tag yet **/
+ boolean endHTMLEncountered = false;
+
+ /** Variables related to the constructor with explicit insertTag **/
+ int popDepth, pushDepth, offset;
+ HTML.Tag insertTag;
+ boolean insertTagEncountered = false;
+
+ /** A temporary variable that helps with the printing out of debug information **/
+ boolean debug = false;
+
+ void print (String line)
+ {
+ if (debug)
+ System.out.println (line);
+ }
+
+ public class TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action. By default this does nothing.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action. By default does nothing.
+ */
+ public void end(HTML.Tag t)
+ {
+ // Nothing to do here.
+ }
+ }
+
+ public class BlockAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // Tell the parse buffer to open a new block for this tag.
+ blockOpen(t, a);
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // Tell the parse buffer to close this block.
+ blockClose(t);
+ }
+ }
+
+ public class CharacterAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // Put the old attribute set on the stack.
+ pushCharacterStyle();
+
+ // And create the new one by adding the attributes in <code>a</code>.
+ if (a != null)
+ charAttr.addAttribute(t, a.copyAttributes());
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ popCharacterStyle();
+ }
+ }
+
+ public class FormAction extends SpecialAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("FormAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("FormAction.end not implemented");
+ }
+ }
+
+ public class HiddenAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("HiddenAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("HiddenAction.end not implemented");
+ }
+ }
+
+ public class IsindexAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("IsindexAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("IsindexAction.end not implemented");
+ }
+ }
+
+ public class ParagraphAction extends BlockAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("ParagraphAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("ParagraphAction.end not implemented");
+ }
+ }
+
+ public class PreAction extends BlockAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("PreAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("PreAction.end not implemented");
+ }
+ }
+
+ public class SpecialAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("SpecialAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("SpecialAction.end not implemented");
+ }
+ }
+
+ class AreaAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("AreaAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("AreaAction.end not implemented");
+ }
+ }
+
+ class BaseAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("BaseAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("BaseAction.end not implemented");
+ }
+ }
+
+ class HeadAction extends BlockAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("HeadAction.start not implemented: "+t);
+ super.start(t, a);
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("HeadAction.end not implemented: "+t);
+ super.end(t);
+ }
+ }
+
+ class LinkAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("LinkAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("LinkAction.end not implemented");
+ }
+ }
+
+ class MapAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("MapAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("MapAction.end not implemented");
+ }
+ }
+
+ class MetaAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("MetaAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("MetaAction.end not implemented");
+ }
+ }
+
+ class StyleAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("StyleAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("StyleAction.end not implemented");
+ }
+ }
+
+ class TitleAction extends TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement.
+ print ("TitleAction.start not implemented");
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // FIXME: Implement.
+ print ("TitleAction.end not implemented");
+ }
+ }
+
+ public HTMLReader(int offset)
+ {
+ this (offset, 0, 0, null);
+ }
+
+ public HTMLReader(int offset, int popDepth, int pushDepth,
+ HTML.Tag insertTag)
+ {
+ print ("HTMLReader created with pop: "+popDepth
+ + " push: "+pushDepth + " offset: "+offset
+ + " tag: "+insertTag);
+ this.insertTag = insertTag;
+ this.offset = offset;
+ this.popDepth = popDepth;
+ this.pushDepth = pushDepth;
+ initTags();
+ }
+
+ void initTags()
+ {
+ tagToAction = new HashMap(72);
+ CharacterAction characterAction = new CharacterAction();
+ HiddenAction hiddenAction = new HiddenAction();
+ AreaAction areaAction = new AreaAction();
+ BaseAction baseAction = new BaseAction();
+ BlockAction blockAction = new BlockAction();
+ SpecialAction specialAction = new SpecialAction();
+ ParagraphAction paragraphAction = new ParagraphAction();
+ HeadAction headAction = new HeadAction();
+ FormAction formAction = new FormAction();
+ IsindexAction isindexAction = new IsindexAction();
+ LinkAction linkAction = new LinkAction();
+ MapAction mapAction = new MapAction();
+ PreAction preAction = new PreAction();
+ MetaAction metaAction = new MetaAction();
+ StyleAction styleAction = new StyleAction();
+ TitleAction titleAction = new TitleAction();
+
+
+ tagToAction.put(HTML.Tag.A, characterAction);
+ tagToAction.put(HTML.Tag.ADDRESS, characterAction);
+ tagToAction.put(HTML.Tag.APPLET, hiddenAction);
+ tagToAction.put(HTML.Tag.AREA, areaAction);
+ tagToAction.put(HTML.Tag.B, characterAction);
+ tagToAction.put(HTML.Tag.BASE, baseAction);
+ tagToAction.put(HTML.Tag.BASEFONT, characterAction);
+ tagToAction.put(HTML.Tag.BIG, characterAction);
+ tagToAction.put(HTML.Tag.BLOCKQUOTE, blockAction);
+ tagToAction.put(HTML.Tag.BODY, blockAction);
+ tagToAction.put(HTML.Tag.BR, specialAction);
+ tagToAction.put(HTML.Tag.CAPTION, blockAction);
+ tagToAction.put(HTML.Tag.CENTER, blockAction);
+ tagToAction.put(HTML.Tag.CITE, characterAction);
+ tagToAction.put(HTML.Tag.CODE, characterAction);
+ tagToAction.put(HTML.Tag.DD, blockAction);
+ tagToAction.put(HTML.Tag.DFN, characterAction);
+ tagToAction.put(HTML.Tag.DIR, blockAction);
+ tagToAction.put(HTML.Tag.DIV, blockAction);
+ tagToAction.put(HTML.Tag.DL, blockAction);
+ tagToAction.put(HTML.Tag.DT, paragraphAction);
+ tagToAction.put(HTML.Tag.EM, characterAction);
+ tagToAction.put(HTML.Tag.FONT, characterAction);
+ tagToAction.put(HTML.Tag.FORM, blockAction);
+ tagToAction.put(HTML.Tag.FRAME, specialAction);
+ tagToAction.put(HTML.Tag.FRAMESET, blockAction);
+ tagToAction.put(HTML.Tag.H1, paragraphAction);
+ tagToAction.put(HTML.Tag.H2, paragraphAction);
+ tagToAction.put(HTML.Tag.H3, paragraphAction);
+ tagToAction.put(HTML.Tag.H4, paragraphAction);
+ tagToAction.put(HTML.Tag.H5, paragraphAction);
+ tagToAction.put(HTML.Tag.H6, paragraphAction);
+ tagToAction.put(HTML.Tag.HEAD, headAction);
+ tagToAction.put(HTML.Tag.HR, specialAction);
+ tagToAction.put(HTML.Tag.HTML, blockAction);
+ tagToAction.put(HTML.Tag.I, characterAction);
+ tagToAction.put(HTML.Tag.IMG, specialAction);
+ tagToAction.put(HTML.Tag.INPUT, formAction);
+ tagToAction.put(HTML.Tag.ISINDEX, isindexAction);
+ tagToAction.put(HTML.Tag.KBD, characterAction);
+ tagToAction.put(HTML.Tag.LI, blockAction);
+ tagToAction.put(HTML.Tag.LINK, linkAction);
+ tagToAction.put(HTML.Tag.MAP, mapAction);
+ tagToAction.put(HTML.Tag.MENU, blockAction);
+ tagToAction.put(HTML.Tag.META, metaAction);
+ tagToAction.put(HTML.Tag.NOFRAMES, blockAction);
+ tagToAction.put(HTML.Tag.OBJECT, specialAction);
+ tagToAction.put(HTML.Tag.OL, blockAction);
+ tagToAction.put(HTML.Tag.OPTION, formAction);
+ tagToAction.put(HTML.Tag.P, paragraphAction);
+ tagToAction.put(HTML.Tag.PARAM, hiddenAction);
+ tagToAction.put(HTML.Tag.PRE, preAction);
+ tagToAction.put(HTML.Tag.SAMP, characterAction);
+ tagToAction.put(HTML.Tag.SCRIPT, hiddenAction);
+ tagToAction.put(HTML.Tag.SELECT, formAction);
+ tagToAction.put(HTML.Tag.SMALL, characterAction);
+ tagToAction.put(HTML.Tag.STRIKE, characterAction);
+ tagToAction.put(HTML.Tag.S, characterAction);
+ tagToAction.put(HTML.Tag.STRONG, characterAction);
+ tagToAction.put(HTML.Tag.STYLE, styleAction);
+ tagToAction.put(HTML.Tag.SUB, characterAction);
+ tagToAction.put(HTML.Tag.SUP, characterAction);
+ tagToAction.put(HTML.Tag.TABLE, blockAction);
+ tagToAction.put(HTML.Tag.TD, blockAction);
+ tagToAction.put(HTML.Tag.TEXTAREA, formAction);
+ tagToAction.put(HTML.Tag.TH, blockAction);
+ tagToAction.put(HTML.Tag.TITLE, titleAction);
+ tagToAction.put(HTML.Tag.TR, blockAction);
+ tagToAction.put(HTML.Tag.TT, characterAction);
+ tagToAction.put(HTML.Tag.U, characterAction);
+ tagToAction.put(HTML.Tag.UL, blockAction);
+ tagToAction.put(HTML.Tag.VAR, characterAction);
+ }
+
+ /**
+ * Pushes the current character style onto the stack.
+ *
+ */
+ protected void pushCharacterStyle()
+ {
+ charAttrStack.push(charAttr);
+ }
+
+ /**
+ * Pops a character style off of the stack and uses it as the
+ * current character style.
+ *
+ */
+ protected void popCharacterStyle()
+ {
+ if (!charAttrStack.isEmpty())
+ charAttr = (MutableAttributeSet) charAttrStack.pop();
+ }
+
+ /**
+ * Registers a given tag with a given Action. All of the well-known tags
+ * are registered by default, but this method can change their behaviour
+ * or add support for custom or currently unsupported tags.
+ *
+ * @param t the Tag to register
+ * @param a the Action for the Tag
+ */
+ protected void registerTag(HTML.Tag t, HTMLDocument.HTMLReader.TagAction a)
+ {
+ tagToAction.put (t, a);
+ }
+
+ /**
+ * This is the last method called on the HTMLReader, allowing any pending
+ * changes to be flushed to the HTMLDocument.
+ */
+ public void flush() throws BadLocationException
+ {
+ DefaultStyledDocument.ElementSpec[] elements;
+ elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()];
+ parseBuffer.copyInto(elements);
+ parseBuffer.removeAllElements();
+ insert(offset, elements);
+ offset += HTMLDocument.this.getLength() - offset;
+ }
+
+ /**
+ * This method is called by the parser to indicate a block of
+ * text was encountered. Should insert the text appropriately.
+ *
+ * @param data the text that was inserted
+ * @param pos the position at which the text was inserted
+ */
+ public void handleText(char[] data, int pos)
+ {
+ if (data != null && data.length > 0)
+ addContent(data, 0, data.length);
+ }
+
+ /**
+ * This method is called by the parser and should route the call to
+ * the proper handler for the tag.
+ *
+ * @param t the HTML.Tag
+ * @param a the attribute set
+ * @param pos the position at which the tag was encountered
+ */
+ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
+ {
+ // Don't call the Action if we've already seen </html>.
+ if (endHTMLEncountered)
+ return;
+
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.start(t, a);
+ }
+
+ /**
+ * This method called by parser to handle a comment block.
+ *
+ * @param data the comment
+ * @param pos the position at which the comment was encountered
+ */
+ public void handleComment(char[] data, int pos)
+ {
+ // Don't call the Action if we've already seen </html>.
+ if (endHTMLEncountered)
+ return;
+
+ TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
+ if (action != null)
+ {
+ action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
+ action.end (HTML.Tag.COMMENT);
+ }
+ }
+
+ /**
+ * This method is called by the parser and should route the call to
+ * the proper handler for the tag.
+ *
+ * @param t the HTML.Tag
+ * @param pos the position at which the tag was encountered
+ */
+ public void handleEndTag(HTML.Tag t, int pos)
+ {
+ // Don't call the Action if we've already seen </html>.
+ if (endHTMLEncountered)
+ return;
+
+ // If this is the </html> tag we need to stop calling the Actions
+ if (t == HTML.Tag.HTML)
+ endHTMLEncountered = true;
+
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.end(t);
+ }
+
+ /**
+ * This is a callback from the parser that should be routed to the
+ * appropriate handler for the tag.
+ *
+ * @param t the HTML.Tag that was encountered
+ * @param a the attribute set
+ * @param pos the position at which the tag was encountered
+ */
+ public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
+ {
+ // Don't call the Action if we've already seen </html>.
+ if (endHTMLEncountered)
+ return;
+
+ TagAction action = (TagAction) tagToAction.get (t);
+ if (action != null)
+ {
+ action.start(t, a);
+ action.end(t);
+ }
+ }
+
+ /**
+ * This is invoked after the stream has been parsed but before it has been
+ * flushed.
+ *
+ * @param eol one of \n, \r, or \r\n, whichever was encountered the most in
+ * parsing the stream
+ * @since 1.3
+ */
+ public void handleEndOfLineString(String eol)
+ {
+ // FIXME: Implement.
+ print ("HTMLReader.handleEndOfLineString not implemented yet");
+ }
+
+ /**
+ * Adds the given text to the textarea document. Called only when we are
+ * within a textarea.
+ *
+ * @param data the text to add to the textarea
+ */
+ protected void textAreaContent(char[] data)
+ {
+ // FIXME: Implement.
+ print ("HTMLReader.textAreaContent not implemented yet");
+ }
+
+ /**
+ * Adds the given text that was encountered in a <PRE> element.
+ *
+ * @param data the text
+ */
+ protected void preContent(char[] data)
+ {
+ // FIXME: Implement
+ print ("HTMLReader.preContent not implemented yet");
+ }
+
+ /**
+ * Instructs the parse buffer to create a block element with the given
+ * attributes.
+ *
+ * @param t the tag that requires opening a new block
+ * @param attr the attribute set for the new block
+ */
+ protected void blockOpen(HTML.Tag t, MutableAttributeSet attr)
+ {
+ printBuffer();
+ DefaultStyledDocument.ElementSpec element;
+ element = new DefaultStyledDocument.ElementSpec(attr.copyAttributes(),
+ DefaultStyledDocument.ElementSpec.StartTagType);
+ parseBuffer.addElement(element);
+ printBuffer();
+ }
+
+ /**
+ * Instructs the parse buffer to close the block element associated with
+ * the given HTML.Tag
+ *
+ * @param t the HTML.Tag that is closing its block
+ */
+ protected void blockClose(HTML.Tag t)
+ {
+ printBuffer();
+ DefaultStyledDocument.ElementSpec element;
+ element = new DefaultStyledDocument.ElementSpec(null,
+ DefaultStyledDocument.ElementSpec.EndTagType);
+ parseBuffer.addElement(element);
+ printBuffer();
}
+
+ /**
+ * Adds text to the appropriate context using the current character
+ * attribute set.
+ *
+ * @param data the text to add
+ * @param offs the offset at which to add it
+ * @param length the length of the text to add
+ */
+ protected void addContent(char[] data, int offs, int length)
+ {
+ addContent(data, offs, length, true);
+ }
+
+ /**
+ * Adds text to the appropriate context using the current character
+ * attribute set, and possibly generating an IMPLIED Tag if necessary.
+ *
+ * @param data the text to add
+ * @param offs the offset at which to add it
+ * @param length the length of the text to add
+ * @param generateImpliedPIfNecessary whether or not we should generate
+ * an HTML.Tag.IMPLIED tag if necessary
+ */
+ protected void addContent(char[] data, int offs, int length,
+ boolean generateImpliedPIfNecessary)
+ {
+ // 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;
+ element = new DefaultStyledDocument.ElementSpec(attributes,
+ DefaultStyledDocument.ElementSpec.ContentType,
+ data, offs, length);
+
+ printBuffer();
+ // Add the element to the buffer
+ parseBuffer.addElement(element);
+ printBuffer();
+
+ if (parseBuffer.size() > HTMLDocument.this.getTokenThreshold())
+ {
+ try
+ {
+ flush();
+ }
+ catch (BadLocationException ble)
+ {
+ // TODO: what to do here?
+ }
+ }
+ }
+
+ /**
+ * Adds content that is specified in the attribute set.
+ *
+ * @param t the HTML.Tag
+ * @param a the attribute set specifying the special content
+ */
+ protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a)
+ {
+ // FIXME: Implement
+ print ("HTMLReader.addSpecialElement not implemented yet");
+ }
+
+ void printBuffer()
+ {
+ print ("\n*********BUFFER**********");
+ for (int i = 0; i < parseBuffer.size(); i ++)
+ print (" "+parseBuffer.get(i));
+ print ("***************************");
+ }
+ }
+
+ /**
+ * Gets the reader for the parser to use when loading the document with HTML.
+ *
+ * @param pos - the starting position
+ * @return - the reader
+ */
+ public HTMLEditorKit.ParserCallback getReader(int pos)
+ {
+ return new HTMLReader(pos);
+ }
+
+ /**
+ * Gets the reader for the parser to use when loading the document with HTML.
+ *
+ * @param pos - the starting position
+ * @param popDepth - the number of EndTagTypes to generate before inserting
+ * @param pushDepth - the number of StartTagTypes with a direction
+ * of JoinNextDirection that should be generated before inserting,
+ * but after the end tags have been generated.
+ * @param insertTag - the first tag to start inserting into document
+ * @return - the reader
+ */
+ public HTMLEditorKit.ParserCallback getReader(int pos,
+ int popDepth,
+ int pushDepth,
+ HTML.Tag insertTag)
+ {
+ return new HTMLReader(pos, popDepth, pushDepth, insertTag);
+ }
+
+ /**
+ * Gets the child element that contains the attribute with the value or null.
+ * Not thread-safe.
+ *
+ * @param e - the element to begin search at
+ * @param attribute - the desired attribute
+ * @param value - the desired value
+ * @return the element found with the attribute and value specified or null
+ * if it is not found.
+ */
+ public Element getElement(Element e, Object attribute, Object value)
+ {
+ if (e != null)
+ {
+ if (e.getAttributes().containsAttribute(attribute, value))
+ return e;
+
+ int count = e.getElementCount();
+ for (int j = 0; j < count; j++)
+ {
+ Element child = e.getElement(j);
+ if (child.getAttributes().containsAttribute(attribute, value))
+ return child;
+
+ Element grandChild = getElement(child, attribute, value);
+ if (grandChild != null)
+ return grandChild;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the element that has the given id Attribute. If it is not found,
+ * null is returned. This method works on an Attribute, not a character tag.
+ * This is not thread-safe.
+ *
+ * @param attrId - the Attribute id to look for
+ * @return the element that has the given id.
+ */
+ public Element getElement(String attrId)
+ {
+ Element root = getDefaultRootElement();
+ return getElement(root, HTML.getAttributeKey(attrId) , attrId);
+ }
+
+ /**
+ * Replaces the children of the given element with the contents of
+ * the string. The document must have an HTMLEditorKit.Parser set.
+ * This will be seen as at least two events, n inserts followed by a remove.
+ *
+ * @param elem - the brance element whose children will be replaced
+ * @param htmlText - the string to be parsed and assigned to element.
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalArgumentException - if elem is a leaf
+ * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set
+ */
+ public void setInnerHTML(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ if (elem.isLeaf())
+ throw new IllegalArgumentException("Element is a leaf");
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+ // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
+ System.out.println("setInnerHTML not implemented");
+ }
+
+ /**
+ * Replaces the given element in the parent with the string. When replacing
+ * a leaf, this will attempt to make sure there is a newline present if one is
+ * needed. This may result in an additional element being inserted.
+ * This will be seen as at least two events, n inserts followed by a remove.
+ * The HTMLEditorKit.Parser must be set.
+ *
+ * @param elem - the branch element whose parent will be replaced
+ * @param htmlText - the string to be parsed and assigned to elem
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+ public void setOuterHTML(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+ // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
+ System.out.println("setOuterHTML not implemented");
+ }
+
+ /**
+ * Inserts the string before the start of the given element.
+ * The parser must be set.
+ *
+ * @param elem - the element to be the root for the new text.
+ * @param htmlText - the string to be parsed and assigned to elem
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser has not been set
+ */
+ public void insertBeforeStart(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+ // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
+ System.out.println("insertBeforeStart not implemented");
+ }
+
+ /**
+ * Inserts the string at the end of the element. If elem's children
+ * are leaves, and the character at elem.getEndOffset() - 1 is a newline,
+ * then it will be inserted before the newline. The parser must be set.
+ *
+ * @param elem - the element to be the root for the new text
+ * @param htmlText - the text to insert
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+ public void insertBeforeEnd(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+ // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
+ System.out.println("insertBeforeEnd not implemented");
+ }
+
+ /**
+ * Inserts the string after the end of the given element.
+ * The parser must be set.
+ *
+ * @param elem - the element to be the root for the new text
+ * @param htmlText - the text to insert
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+ public void insertAfterEnd(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+ // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
+ System.out.println("insertAfterEnd not implemented");
+ }
+
+ /**
+ * Inserts the string at the start of the element.
+ * The parser must be set.
+ *
+ * @param elem - the element to be the root for the new text
+ * @param htmlText - the text to insert
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+ public void insertAfterStart(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+ // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
+ System.out.println("insertAfterStart not implemented");
+ }
+
+ /**
+ * This method sets the attributes associated with the paragraph containing
+ * offset. If replace is false, s is merged with existing attributes. The
+ * length argument determines how many characters are affected by the new
+ * attributes. This is often the entire paragraph.
+ *
+ * @param offset -
+ * the offset into the paragraph (must be at least 0)
+ * @param length -
+ * the number of characters affected (must be at least 0)
+ * @param s -
+ * the attributes
+ * @param replace -
+ * whether to replace existing attributes, or merge them
+ */
+ public void setParagraphAttributes(int offset, int length, AttributeSet s,
+ boolean replace)
+ {
+ // FIXME: Not implemented.
+ System.out.println("setParagraphAttributes not implemented");
+ super.setParagraphAttributes(offset, length, s, replace);
+ }
+
+ /**
+ * This method flags a change in the document.
+ *
+ * @param e - the Document event
+ */
+ protected void fireChangedUpdate(DocumentEvent e)
+ {
+ // FIXME: Not implemented.
+ System.out.println("fireChangedUpdate not implemented");
+ super.fireChangedUpdate(e);
+ }
+
+ /**
+ * This method fires an event intended to be caught by Undo listeners. It
+ * simply calls the super version inherited from DefaultStyledDocument. With
+ * this method, an HTML editor could easily provide undo support.
+ *
+ * @param e - the UndoableEditEvent
+ */
+ protected void fireUndoableEditUpdate(UndoableEditEvent e)
+ {
+ super.fireUndoableEditUpdate(e);
}
}
diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java
index a52d96c74..79e620327 100644
--- a/javax/swing/text/html/HTMLEditorKit.java
+++ b/javax/swing/text/html/HTMLEditorKit.java
@@ -38,28 +38,563 @@ exception statement from your version. */
package javax.swing.text.html;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.awt.Cursor;
+
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
+import java.io.StringReader;
+import java.io.Writer;
+import javax.accessibility.Accessible;
+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;
+import javax.swing.text.TextAction;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
import javax.swing.text.html.parser.ParserDelegator;
/**
- * This class is NOT implemented. This file currently holds only
- * declarations of the two enclosing classes, necessary for testing
- * the implemented javax.swing.text.html.parser package.
- *
- * @author No authorship is taken, implement the class and be!
- * TODO: replace this header after implementing the class.
+ * @author Lillian Angel (langel at redhat dot com)
*/
public class HTMLEditorKit
extends StyledEditorKit
- implements Serializable, Cloneable
+ implements Serializable, Cloneable, Accessible
{
+
+ /**
+ * Fires the hyperlink events on the associated component
+ * when needed.
+ */
+ public static class LinkController
+ extends MouseAdapter
+ implements MouseMotionListener, Serializable
+ {
+
+ /**
+ * Constructor
+ */
+ public LinkController()
+ {
+ super();
+ }
+
+ /**
+ * Dispatched when the mouse is clicked. If the component
+ * is read-only, then the clicked event is used to drive an
+ * attempt to follow the reference specified by a link
+ *
+ * @param e - the mouse event
+ */
+ public void mouseClicked(MouseEvent e)
+ {
+ /*
+ These MouseInputAdapter methods generate mouse appropriate events around
+ hyperlinks (entering, exiting, and activating).
+ */
+ // FIXME: Not implemented.
+ }
+
+ /**
+ * Dispatched when the mouse is dragged on a component.
+ *
+ * @param e - the mouse event.
+ */
+ public void mouseDragged(MouseEvent e)
+ {
+ /*
+ These MouseInputAdapter methods generate mouse appropriate events around
+ hyperlinks (entering, exiting, and activating).
+ */
+ // FIXME: Not implemented.
+ }
+
+ /**
+ * Dispatched when the mouse cursor has moved into the component.
+ *
+ * @param e - the mouse event.
+ */
+ public void mouseMoved(MouseEvent e)
+ {
+ /*
+ These MouseInputAdapter methods generate mouse appropriate events around
+ hyperlinks (entering, exiting, and activating).
+ */
+ // FIXME: Not implemented.
+ }
+
+ /**
+ * If the given position represents a link, then linkActivated is called
+ * on the JEditorPane. Implemented to forward to the method with the same
+ * name, but pos == editor == -1.
+ *
+ * @param pos - the position
+ * @param editor - the editor pane
+ */
+ protected void activateLink(int pos,
+ JEditorPane editor)
+ {
+ /*
+ This method creates and fires a HyperlinkEvent if the document is an
+ instance of HTMLDocument and the href tag of the link is not null.
+ */
+ // FIXME: Not implemented.
+ }
+ }
+
+ /**
+ * This class is used to insert a string of HTML into an existing
+ * document. At least 2 HTML.Tags need to be supplied. The first Tag (parentTag)
+ * identifies the parent in the document to add the elements to. The second, (addTag),
+ * identifies that the first tag should be added to the document as seen in the string.
+ * The parser will generate all appropriate (opening/closing tags_ even if they are not
+ * in the HTML string passed in.
+ */
+ public static class InsertHTMLTextAction
+ extends HTMLTextAction
+ {
+
+ /**
+ * Tag in HTML to start adding tags from.
+ */
+ protected HTML.Tag addTag;
+
+ /**
+ * Alternate tag in HTML to start adding tags from if parentTag is
+ * not found and alternateParentTag is not found.
+ */
+ protected HTML.Tag alternateAddTag;
+
+ /**
+ * Alternate tag to check if parentTag is not found.
+ */
+ protected HTML.Tag alternateParentTag;
+
+ /**
+ * HTML to insert.
+ */
+ protected String html;
+
+ /**
+ * Tag to check for in the document.
+ */
+ protected HTML.Tag parentTag;
+
+ /**
+ * Initializes all fields.
+ *
+ * @param name - the name of the document.
+ * @param html - the html to insert
+ * @param parentTag - the parent tag to check for
+ * @param addTag - the tag to start adding from
+ */
+ public InsertHTMLTextAction(String name, String html,
+ HTML.Tag parentTag, HTML.Tag addTag)
+ {
+ this(name, html, parentTag, addTag, null, null);
+ }
+
+ /**
+ * Initializes all fields and calls super
+ *
+ * @param name - the name of the document.
+ * @param html - the html to insert
+ * @param parentTag - the parent tag to check for
+ * @param addTag - the tag to start adding from
+ * @param alternateParentTag - the alternate parent tag
+ * @param alternateAddTag - the alternate add tag
+ */
+ public InsertHTMLTextAction(String name, String html, HTML.Tag parentTag,
+ HTML.Tag addTag, HTML.Tag alternateParentTag,
+ HTML.Tag alternateAddTag)
+ {
+ super(name);
+ // Fields are for easy access when the action is applied to an actual
+ // document.
+ this.html = html;
+ this.parentTag = parentTag;
+ this.addTag = addTag;
+ this.alternateParentTag = alternateParentTag;
+ this.alternateAddTag = alternateAddTag;
+ }
+
+ /**
+ * HTMLEditorKit.insertHTML is called. If an exception is
+ * thrown, it is wrapped in a RuntimeException and thrown.
+ *
+ * @param editor - the editor to use to get the editorkit
+ * @param doc -
+ * the Document to insert the HTML into.
+ * @param offset -
+ * where to begin inserting the HTML.
+ * @param html -
+ * the String to insert
+ * @param popDepth -
+ * the number of ElementSpec.EndTagTypes to generate before
+ * inserting
+ * @param pushDepth -
+ * the number of ElementSpec.StartTagTypes with a direction of
+ * ElementSpec.JoinNextDirection that should be generated before
+ * @param addTag -
+ * the first tag to start inserting into document
+ */
+ protected void insertHTML(JEditorPane editor, HTMLDocument doc, int offset,
+ String html, int popDepth, int pushDepth,
+ HTML.Tag addTag)
+ {
+ try
+ {
+ super.getHTMLEditorKit(editor).insertHTML(doc, offset, html,
+ popDepth, pushDepth, addTag);
+ }
+ catch (IOException e)
+ {
+ throw (RuntimeException) new RuntimeException("Parser is null.").initCause(e);
+ }
+ catch (BadLocationException ex)
+ {
+ throw (RuntimeException) new RuntimeException("BadLocationException: "
+ + offset).initCause(ex);
+ }
+ }
+
+ /**
+ * Invoked when inserting at a boundary. Determines the number of pops,
+ * and then the number of pushes that need to be performed. The it calls
+ * insertHTML.
+ *
+ * @param editor -
+ * the editor to use to get the editorkit
+ * @param doc -
+ * the Document to insert the HTML into.
+ * @param offset -
+ * where to begin inserting the HTML.
+ * @param insertElement -
+ * the element to insert
+ * @param html -
+ * the html to insert
+ * @param parentTag -
+ * the parent tag
+ * @param addTag -
+ * the first tag
+ */
+ protected void insertAtBoundary(JEditorPane editor,
+ HTMLDocument doc, int offset,
+ Element insertElement,
+ String html, HTML.Tag parentTag,
+ HTML.Tag addTag)
+ {
+ /*
+ As its name implies, this protected method is used when HTML is inserted at a
+ boundary. (A boundary in this case is an offset in doc that exactly matches the
+ beginning offset of the parentTag.) It performs the extra work required to keep
+ the tag stack in shape and then calls insertHTML(). The editor and doc argu-
+ ments are the editor pane and document where the HTML should go. The offset
+ argument represents the cursor location or selection start in doc. The insert-
+ Element and parentTag arguments are used to calculate the proper number of
+ tag pops and pushes before inserting the HTML (via html and addTag, which are
+ passed directly to insertHTML()).
+ */
+ // FIXME: not implemented
+ }
+
+ /**
+ * Invoked when inserting at a boundary. Determines the number of pops,
+ * and then the number of pushes that need to be performed. The it calls
+ * insertHTML.
+ *
+ * @param editor - the editor to use to get the editorkit
+ * @param doc -
+ * the Document to insert the HTML into.
+ * @param offset -
+ * where to begin inserting the HTML.
+ * @param insertElement - the element to insert
+ * @param html - the html to insert
+ * @param parentTag - the parent tag
+ * @param addTag - the first tag
+ *
+ * @deprecated as of v1.3, use insertAtBoundary
+ */
+ protected void insertAtBoundry(JEditorPane editor,
+ HTMLDocument doc,
+ int offset, Element insertElement,
+ String html, HTML.Tag parentTag,
+ HTML.Tag addTag)
+ {
+ insertAtBoundary(editor, doc, offset, insertElement,
+ html, parentTag, addTag);
+ }
+
+ /**
+ * Inserts the HTML.
+ *
+ * @param ae - the action performed
+ */
+ public void actionPerformed(ActionEvent ae)
+ {
+ Object source = ae.getSource();
+ if (source instanceof JEditorPane)
+ {
+ JEditorPane pane = ((JEditorPane) source);
+ Document d = pane.getDocument();
+ if (d instanceof HTMLDocument)
+ insertHTML(pane, (HTMLDocument) d, 0, html, 0, 0, addTag);
+ // FIXME: is this correct parameters?
+ }
+ // FIXME: else not implemented
+ }
+ }
+
+ /**
+ * Abstract Action class that helps inserting HTML into an existing document.
+ */
+ public abstract static class HTMLTextAction
+ extends StyledEditorKit.StyledTextAction
+ {
+
+ /**
+ * Constructor
+ */
+ public HTMLTextAction(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Gets the HTMLDocument from the JEditorPane.
+ *
+ * @param e - the editor pane
+ * @return the html document.
+ */
+ protected HTMLDocument getHTMLDocument(JEditorPane e)
+ {
+ Document d = e.getDocument();
+ if (d instanceof HTMLDocument)
+ return (HTMLDocument) d;
+ throw new IllegalArgumentException("Document is not a HTMLDocument.");
+ }
+
+ /**
+ * Gets the HTMLEditorKit
+ *
+ * @param e - the JEditorPane to get the HTMLEditorKit from.
+ * @return the HTMLEditorKit
+ */
+ protected HTMLEditorKit getHTMLEditorKit(JEditorPane e)
+ {
+ EditorKit d = e.getEditorKit();
+ if (d instanceof HTMLEditorKit)
+ return (HTMLEditorKit) d;
+ throw new IllegalArgumentException("EditorKit is not a HTMLEditorKit.");
+ }
+
+ /**
+ * Returns an array of Elements that contain the offset.
+ * The first elements corresponds to the roots of the doc.
+ *
+ * @param doc - the document to get the Elements from.
+ * @param offset - the offset the Elements must contain
+ * @return an array of all the elements containing the offset.
+ */
+ protected Element[] getElementsAt(HTMLDocument doc,
+ int offset)
+ {
+ return getElementsAt(doc.getDefaultRootElement(), offset, 0);
+ }
+
+ /**
+ * Helper function to get all elements using recursion.
+ */
+ private Element[] getElementsAt(Element root, int offset, int depth)
+ {
+ Element[] elements = null;
+ if (root != null)
+ {
+ if (root.isLeaf())
+ {
+ elements = new Element[depth + 1];
+ elements[depth] = root;
+ return elements;
+ }
+ elements = getElementsAt(root.getElement(root.getElementIndex(offset)),
+ offset, depth + 1);
+ elements[depth] = root;
+ }
+ return elements;
+ }
+
+ /**
+ * Returns the number of elements, starting at the deepest point, needed
+ * to get an element representing tag. -1 if no elements are found, 0 if
+ * the parent of the leaf at offset represents the tag.
+ *
+ * @param doc -
+ * the document to search
+ * @param offset -
+ * the offset to check
+ * @param tag -
+ * the tag to look for
+ * @return - the number of elements needed to get an element representing
+ * tag.
+ */
+ protected int elementCountToTag(HTMLDocument doc,
+ int offset, HTML.Tag tag)
+ {
+ Element root = doc.getDefaultRootElement();
+ int num = -1;
+ Element next = root.getElement(root.getElementIndex(offset));
+
+ while (!next.isLeaf())
+ {
+ num++;
+ if (next.getAttributes().
+ getAttribute(StyleConstants.NameAttribute).equals(tag))
+ return num;
+ next = next.getElement(next.getElementIndex(offset));
+ }
+ return num;
+ }
+
+ /**
+ * Gets the deepest element at offset with the
+ * matching tag.
+ *
+ * @param doc - the document to search
+ * @param offset - the offset to check for
+ * @param tag - the tag to match
+ * @return - the element that is found, null if not found.
+ */
+ protected Element findElementMatchingTag(HTMLDocument doc,
+ int offset, HTML.Tag tag)
+ {
+ Element element = doc.getDefaultRootElement();
+ Element tagElement = null;
+
+ while (element != null)
+ {
+ Object otag = element.getAttributes().getAttribute(
+ StyleConstants.NameAttribute);
+ if (otag instanceof HTML.Tag && otag.equals(tag))
+ tagElement = element;
+ element = element.getElement(element.getElementIndex(offset));
+ }
+
+ return tagElement;
+ }
+ }
+
+ /**
+ * A {@link ViewFactory} that is able to create {@link View}s for
+ * the <code>Element</code>s that are supported.
+ */
+ public static class HTMLFactory
+ implements ViewFactory
+ {
+
+ /**
+ * Constructor
+ */
+ public HTMLFactory()
+ {
+ // Do Nothing here.
+ }
+
+ /**
+ * Creates a {@link View} for the specified <code>Element</code>.
+ *
+ * @param element the <code>Element</code> to create a <code>View</code>
+ * for
+ * @return the <code>View</code> for the specified <code>Element</code>
+ * or <code>null</code> if the type of <code>element</code> is
+ * not supported
+ */
+ public View create(Element element)
+ {
+ View view = null;
+ Object attr = element.getAttributes().getAttribute(
+ StyleConstants.NameAttribute);
+ if (attr instanceof HTML.Tag)
+ {
+ HTML.Tag tag = (HTML.Tag) attr;
+
+ if (tag.equals(HTML.Tag.IMPLIED) || tag.equals(HTML.Tag.P)
+ || tag.equals(HTML.Tag.H1) || tag.equals(HTML.Tag.H2)
+ || tag.equals(HTML.Tag.H3) || tag.equals(HTML.Tag.H4)
+ || tag.equals(HTML.Tag.H5) || tag.equals(HTML.Tag.H6)
+ || tag.equals(HTML.Tag.DT))
+ view = new ParagraphView(element);
+ else if (tag.equals(HTML.Tag.LI) || tag.equals(HTML.Tag.DL)
+ || tag.equals(HTML.Tag.DD) || tag.equals(HTML.Tag.BODY)
+ || tag.equals(HTML.Tag.HTML) || tag.equals(HTML.Tag.CENTER)
+ || tag.equals(HTML.Tag.DIV)
+ || tag.equals(HTML.Tag.BLOCKQUOTE)
+ || tag.equals(HTML.Tag.PRE))
+ 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.MENU) || tag.equals(HTML.Tag.DIR)
+ || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
+ view = new ListView(element);
+ else if (tag.equals(HTML.Tag.IMG))
+ view = new ImageView(element);
+ else if (tag.equals(HTML.Tag.HR))
+ 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);
+ else if (tag.equals(HTML.Tag.OBJECT))
+ view = new ObjectView(element);
+ else if (tag.equals(HTML.Tag.FRAMESET))
+ 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);
+ }
+ return view;
+ }
+ }
+
/**
* The abstract HTML parser declaration.
*/
@@ -76,9 +611,7 @@ public class HTMLEditorKit
* @throws IOException, normally if the reader throws one.
*/
public abstract void parse(Reader reader, ParserCallback callback,
- boolean ignoreCharSet
- )
- throws IOException;
+ boolean ignoreCharSet) throws IOException;
}
/**
@@ -96,11 +629,19 @@ public class HTMLEditorKit
public static final Object IMPLIED = "_implied_";
/**
+ * Constructor
+ */
+ public ParserCallback()
+ {
+ // Nothing to do here.
+ }
+
+ /**
* The parser calls this method after it finishes parsing the document.
*/
public void flush() throws BadLocationException
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
/**
@@ -110,7 +651,7 @@ public class HTMLEditorKit
*/
public void handleComment(char[] comment, int position)
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
/**
@@ -121,7 +662,7 @@ public class HTMLEditorKit
*/
public void handleEndOfLineString(String end_of_line)
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
/**
@@ -133,7 +674,7 @@ public class HTMLEditorKit
*/
public void handleEndTag(HTML.Tag tag, int position)
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
/**
@@ -144,7 +685,7 @@ public class HTMLEditorKit
*/
public void handleError(String message, int position)
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
/**
@@ -157,7 +698,7 @@ public class HTMLEditorKit
public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes,
int position)
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
/**
@@ -168,10 +709,9 @@ public class HTMLEditorKit
* @param position The tag position in the text being parsed
*/
public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes,
- int position
- )
+ int position)
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
/**
@@ -181,7 +721,7 @@ public class HTMLEditorKit
*/
public void handleText(char[] text, int position)
{
- // TODO: What to do here, if anything?
+ // Nothing to do here.
}
}
@@ -255,7 +795,83 @@ public class HTMLEditorKit
* The "ident paragraph right" action.
*/
public static final String PARA_INDENT_RIGHT = "html-para-indent-right";
-
+
+ /**
+ * Actions for HTML
+ */
+ private static final Action[] defaultActions = {
+ // FIXME: Add default actions for html
+ };
+
+ /**
+ * The current style sheet.
+ */
+ StyleSheet styleSheet;
+
+ /**
+ * The ViewFactory for HTMLFactory.
+ */
+ HTMLFactory viewFactory;
+
+ /**
+ * The Cursor for links.
+ */
+ Cursor linkCursor;
+
+ /**
+ * The default cursor.
+ */
+ Cursor defaultCursor;
+
+ /**
+ * The parser.
+ */
+ Parser parser;
+
+ /**
+ * The mouse listener used for links.
+ */
+ LinkController mouseListener;
+
+ /**
+ * Style context for this editor.
+ */
+ StyleContext styleContext;
+
+ /** The content type */
+ String contentType = "text/html";
+
+ /** The input attributes defined by default.css */
+ MutableAttributeSet inputAttributes;
+
+ /** The editor pane used. */
+ JEditorPane editorPane;
+
+ /**
+ * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet.
+ */
+ public HTMLEditorKit()
+ {
+ super();
+ styleContext = new StyleContext();
+ styleSheet = new StyleSheet();
+ styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS));
+ // FIXME: Set inputAttributes with default.css
+ }
+
+ /**
+ * Gets a factory suitable for producing views of any
+ * models that are produced by this kit.
+ *
+ * @return the view factory suitable for producing views.
+ */
+ public ViewFactory getViewFactory()
+ {
+ if (viewFactory == null)
+ viewFactory = new HTMLFactory();
+ return viewFactory;
+ }
+
/**
* Create a text storage model for this type of editor.
*
@@ -263,18 +879,298 @@ public class HTMLEditorKit
*/
public Document createDefaultDocument()
{
- HTMLDocument document = new HTMLDocument();
+ HTMLDocument document = new HTMLDocument(getStyleSheet());
+ document.setParser(getParser());
return document;
}
/**
* Get the parser that this editor kit uses for reading HTML streams. This
* method can be overridden to use the alternative parser.
- *
+ *
* @return the HTML parser (by default, {@link ParserDelegator}).
*/
protected Parser getParser()
{
- return new ParserDelegator();
+ if (parser == null)
+ parser = new ParserDelegator();
+ return parser;
+ }
+
+ /**
+ * Inserts HTML into an existing document.
+ *
+ * @param doc - the Document to insert the HTML into.
+ * @param offset - where to begin inserting the HTML.
+ * @param html - the String to insert
+ * @param popDepth - the number of ElementSpec.EndTagTypes
+ * to generate before inserting
+ * @param pushDepth - the number of ElementSpec.StartTagTypes
+ * with a direction of ElementSpec.JoinNextDirection that
+ * should be generated before
+ * @param insertTag - the first tag to start inserting into document
+ * @throws IOException - on any I/O error
+ * @throws BadLocationException - if pos represents an invalid location
+ * within the document
+ */
+ public void insertHTML(HTMLDocument doc, int offset, String html,
+ int popDepth, int pushDepth, HTML.Tag insertTag)
+ throws BadLocationException, IOException
+ {
+ Parser parser = getParser();
+ if (offset < 0 || offset > doc.getLength())
+ throw new BadLocationException("Bad location", offset);
+ if (parser == null)
+ throw new IOException("Parser is null.");
+
+ ParserCallback pc = ((HTMLDocument) doc).getReader
+ (offset, popDepth, pushDepth, insertTag);
+
+ // FIXME: What should ignoreCharSet be set to?
+
+ // parser.parse inserts html into the buffer
+ parser.parse(new StringReader(html), pc, false);
+ pc.flush();
+ }
+
+ /**
+ * Inserts content from the given stream. Inserting HTML into a non-empty
+ * document must be inside the body Element, if you do not insert into
+ * the body an exception will be thrown. When inserting into a non-empty
+ * document all tags outside of the body (head, title) will be dropped.
+ *
+ * @param in - the stream to read from
+ * @param doc - the destination for the insertion
+ * @param pos - the location in the document to place the content
+ * @throws IOException - on any I/O error
+ * @throws BadLocationException - if pos represents an invalid location
+ * within the document
+ */
+ public void read(Reader in, Document doc, int pos) throws IOException,
+ BadLocationException
+ {
+ if (doc instanceof HTMLDocument)
+ {
+ Parser parser = getParser();
+ if (pos < 0 || pos > doc.getLength())
+ throw new BadLocationException("Bad location", pos);
+ if (parser == null)
+ throw new IOException("Parser is null.");
+
+ HTMLDocument hd = ((HTMLDocument) doc);
+ hd.setBase(editorPane.getPage());
+ ParserCallback pc = hd.getReader(pos);
+
+ // FIXME: What should ignoreCharSet be set to?
+
+ // parser.parse inserts html into the buffer
+ parser.parse(in, pc, false);
+ pc.flush();
+ }
+ else
+ // read in DefaultEditorKit is called.
+ // the string is inserted in the document as usual.
+ super.read(in, doc, pos);
+ }
+
+ /**
+ * Writes content from a document to the given stream in
+ * an appropriate format.
+ *
+ * @param out - the stream to write to
+ * @param doc - the source for the write
+ * @param pos - the location in the document to get the content.
+ * @param len - the amount to write out
+ * @throws IOException - on any I/O error
+ * @throws BadLocationException - if pos represents an invalid location
+ * within the document
+ */
+ public void write(Writer out, Document doc, int pos, int len)
+ throws IOException, BadLocationException
+ {
+ if (doc instanceof HTMLDocument)
+ {
+ // FIXME: Not implemented. Use HTMLWriter.
+ out.write(doc.getText(pos, len));
+ }
+ else
+ super.write(out, doc, pos, len);
+ }
+
+ /**
+ * Gets the content type that the kit supports.
+ * This kit supports the type text/html.
+ *
+ * @returns the content type supported.
+ */
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ /**
+ * Creates a copy of the editor kit.
+ *
+ * @return a copy of this.
+ */
+ public Object clone()
+ {
+ // FIXME: Need to clone all fields
+ return (HTMLEditorKit) super.clone();
+ }
+
+ /**
+ * Copies the key/values in elements AttributeSet into set.
+ * This does not copy component, icon, or element names attributes.
+ * This is called anytime the caret moves over a different location.
+ *
+ * @param element - the element to create the input attributes for.
+ * @param set - the set to copy the values into.
+ */
+ protected void createInputAttributes(Element element,
+ MutableAttributeSet set)
+ {
+ set.removeAttributes(set);
+ set.addAttributes(element.getAttributes());
+ // FIXME: Not fully implemented.
+ }
+
+ /**
+ * Called when this is installed into the JEditorPane.
+ *
+ * @param c - the JEditorPane installed into.
+ */
+ public void install(JEditorPane c)
+ {
+ super.install(c);
+ mouseListener = new LinkController();
+ c.addMouseListener(mouseListener);
+ editorPane = c;
+ // FIXME: need to set up hyperlinklistener object
+ }
+
+ /**
+ * Called when the this is removed from the JEditorPane.
+ * It unregisters any listeners.
+ *
+ * @param c - the JEditorPane being removed from.
+ */
+ public void deinstall(JEditorPane c)
+ {
+ super.deinstall(c);
+ c.removeMouseListener(mouseListener);
+ mouseListener = null;
+ editorPane = null;
+ }
+
+ /**
+ * Gets the AccessibleContext associated with this.
+ *
+ * @return the AccessibleContext for this.
+ */
+ public AccessibleContext getAccessibleContext()
+ {
+ // FIXME: Should return an instance of
+ // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext
+ // Not implemented yet.
+ return null;
+ }
+
+ /**
+ * Gets the action list. This list is supported by the superclass
+ * augmented by the collection of actions defined locally for style
+ * operations.
+ *
+ * @return an array of all the actions
+ */
+ public Action[] getActions()
+ {
+ return TextAction.augmentList(super.getActions(), defaultActions);
+ }
+
+ /**
+ * Returns the default cursor.
+ *
+ * @return the default cursor
+ */
+ public Cursor getDefaultCursor()
+ {
+ if (defaultCursor == null)
+ defaultCursor = Cursor.getDefaultCursor();
+ return defaultCursor;
+ }
+
+ /**
+ * Returns the cursor for links.
+ *
+ * @return the cursor for links.
+ */
+ public Cursor getLinkCursor()
+ {
+ if (linkCursor == null)
+ linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
+ return linkCursor;
+ }
+
+ /**
+ * Sets the Cursor for links.
+ *
+ * @param cursor - the new cursor for links.
+ */
+ public void setLinkCursor(Cursor cursor)
+ {
+ linkCursor = cursor;
+ }
+
+ /**
+ * Sets the default cursor.
+ *
+ * @param cursor - the new default cursor.
+ */
+ public void setDefaultCursor(Cursor cursor)
+ {
+ defaultCursor = cursor;
+ }
+
+ /**
+ * Gets the input attributes used for the styled editing actions.
+ *
+ * @return the attribute set
+ */
+ public MutableAttributeSet getInputAttributes()
+ {
+ return inputAttributes;
+ }
+
+ /**
+ * Get the set of styles currently being used to render the HTML elements.
+ * By default the resource specified by DEFAULT_CSS gets loaded, and is
+ * shared by all HTMLEditorKit instances.
+ *
+ * @return the style sheet.
+ */
+ public StyleSheet getStyleSheet()
+ {
+ if (styleSheet == null)
+ {
+ styleSheet = new StyleSheet();
+ styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS));
+ }
+ return styleSheet;
+ }
+
+ /**
+ * Set the set of styles to be used to render the various HTML elements.
+ * These styles are specified in terms of CSS specifications. Each document
+ * produced by the kit will have a copy of the sheet which it can add the
+ * document specific styles to. By default, the StyleSheet specified is shared
+ * by all HTMLEditorKit instances.
+ *
+ * @param s - the new style sheet
+ */
+ public void setStyleSheet(StyleSheet s)
+ {
+ styleSheet = s;
}
+
}
diff --git a/javax/swing/text/html/StyleSheet.java b/javax/swing/text/html/StyleSheet.java
new file mode 100644
index 000000000..2466a2808
--- /dev/null
+++ b/javax/swing/text/html/StyleSheet.java
@@ -0,0 +1,937 @@
+/* StyleSheet.java --
+ Copyright (C) 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. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Element;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.Style;
+import javax.swing.text.StyleContext;
+import javax.swing.text.View;
+
+
+/**
+ * This class adds support for defining the visual characteristics of HTML views
+ * being rendered. This enables views to be customized by a look-and-feel, mulitple
+ * views over the same model can be rendered differently. Each EditorPane has its
+ * own StyleSheet, but by default one sheet will be shared by all of the HTMLEditorKit
+ * instances. An HTMLDocument can also have a StyleSheet, which holds specific CSS
+ * specs.
+ *
+ * In order for Views to store less state and therefore be more lightweight,
+ * the StyleSheet can act as a factory for painters that handle some of the
+ * rendering tasks. Since the StyleSheet may be used by views over multiple
+ * documents the HTML attributes don't effect the selector being used.
+ *
+ * The rules are stored as named styles, and other information is stored to
+ * translate the context of an element to a rule.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+public class StyleSheet extends StyleContext
+{
+
+ /** The base URL */
+ URL base;
+
+ /** Base font size (int) */
+ int baseFontSize;
+
+ /** The style sheets stored. */
+ StyleSheet[] styleSheet;
+
+ /**
+ * Constructs a StyleSheet.
+ */
+ public StyleSheet()
+ {
+ super();
+ baseFontSize = 4; // Default font size from CSS
+ }
+
+ /**
+ * Gets the style used to render the given tag. The element represents the tag
+ * and can be used to determine the nesting, where the attributes will differ
+ * if there is nesting inside of elements.
+ *
+ * @param t - the tag to translate to visual attributes
+ * @param e - the element representing the tag
+ * @return the set of CSS attributes to use to render the tag.
+ */
+ public Style getRule(HTML.Tag t, Element e)
+ {
+ // FIXME: Not implemented.
+ return null;
+ }
+
+ /**
+ * Gets the rule that best matches the selector. selector is a space
+ * separated String of element names. The attributes of the returned
+ * Style will change as rules are added and removed.
+ *
+ * @param selector - the element names separated by spaces
+ * @return the set of CSS attributes to use to render
+ */
+ public Style getRule(String selector)
+ {
+ // FIXME: Not implemented.
+ return null;
+ }
+
+ /**
+ * Adds a set if rules to the sheet. The rules are expected to be in valid
+ * CSS format. This is called as a result of parsing a <style> tag
+ *
+ * @param rule - the rule to add to the sheet
+ */
+ public void addRule(String rule)
+ {
+ CssParser cp = new CssParser();
+ try
+ {
+ cp.parse(base, new StringReader(rule), false, false);
+ }
+ catch (IOException io)
+ {
+ // Do nothing here.
+ }
+ }
+
+ /**
+ * Translates a CSS declaration into an AttributeSet. This is called
+ * as a result of encountering an HTML style attribute.
+ *
+ * @param decl - the declaration to get
+ * @return the AttributeSet representing the declaration
+ */
+ public AttributeSet getDeclaration(String decl)
+ {
+ if (decl == null)
+ return SimpleAttributeSet.EMPTY;
+ // FIXME: Not implemented.
+ return null;
+ }
+
+ /**
+ * Loads a set of rules that have been specified in terms of CSS grammar.
+ * If there are any conflicts with existing rules, the new rule is added.
+ *
+ * @param in - the stream to read the CSS grammar from.
+ * @param ref - the reference URL. It is the location of the stream, it may
+ * be null. All relative URLs specified in the stream will be based upon this
+ * parameter.
+ * @throws IOException - For any IO error while reading
+ */
+ public void loadRules(Reader in, URL ref) throws IOException
+ {
+ CssParser cp = new CssParser();
+ cp.parse(ref, in, false, false);
+ }
+
+ /**
+ * Gets a set of attributes to use in the view. This is a set of
+ * attributes that can be used for View.getAttributes
+ *
+ * @param v - the view to get the set for
+ * @return the AttributeSet to use in the view.
+ */
+ public AttributeSet getViewAttributes(View v)
+ {
+ // FIXME: Not implemented.
+ return null;
+ }
+
+ /**
+ * Removes a style previously added.
+ *
+ * @param nm - the name of the style to remove
+ */
+ public void removeStyle(String nm)
+ {
+ // FIXME: Not implemented.
+ super.removeStyle(nm);
+ }
+
+ /**
+ * Adds the rules from ss to those of the receiver. ss's rules will
+ * override the old rules. An added StyleSheet will never override the rules
+ * of the receiving style sheet.
+ *
+ * @param ss - the new StyleSheet.
+ */
+ public void addStyleSheet(StyleSheet ss)
+ {
+ if (styleSheet == null)
+ styleSheet = new StyleSheet[] {ss};
+ else
+ System.arraycopy(new StyleSheet[] {ss}, 0, styleSheet,
+ styleSheet.length, 1);
+ }
+
+ /**
+ * Removes ss from those of the receiver
+ *
+ * @param ss - the StyleSheet to remove.
+ */
+ public void removeStyleSheet(StyleSheet ss)
+ {
+ if (styleSheet.length == 1 && styleSheet[0].equals(ss))
+ styleSheet = null;
+ else
+ {
+ for (int i = 0; i < styleSheet.length; i++)
+ {
+ StyleSheet curr = styleSheet[i];
+ if (curr.equals(ss))
+ {
+ StyleSheet[] tmp = new StyleSheet[styleSheet.length - 1];
+ if (i != 0 && i != (styleSheet.length - 1))
+ {
+ System.arraycopy(styleSheet, 0, tmp, 0, i);
+ System.arraycopy(styleSheet, i + 1, tmp, i,
+ styleSheet.length - i - 1);
+ }
+ else if (i == 0)
+ System.arraycopy(styleSheet, 1, tmp, 0, styleSheet.length - 1);
+ else
+ System.arraycopy(styleSheet, 0, tmp, 0, styleSheet.length - 1);
+
+ styleSheet = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns an array of the linked StyleSheets. May return null.
+ *
+ * @return - An array of the linked StyleSheets.
+ */
+ public StyleSheet[] getStyleSheets()
+ {
+ return styleSheet;
+ }
+
+ /**
+ * Imports a style sheet from the url. The rules are directly added to the
+ * receiver.
+ *
+ * @param url - the URL to import the StyleSheet from.
+ */
+ public void importStyleSheet(URL url)
+ {
+ // FIXME: Not implemented
+ }
+
+ /**
+ * Sets the base url. All import statements that are relative, will be
+ * relative to base.
+ *
+ * @param base -
+ * the base URL.
+ */
+ public void setBase(URL base)
+ {
+ this.base = base;
+ }
+
+ /**
+ * Gets the base url.
+ *
+ * @return - the base
+ */
+ public URL getBase()
+ {
+ return base;
+ }
+
+ /**
+ * Adds a CSS attribute to the given set.
+ *
+ * @param attr - the attribute set
+ * @param key - the attribute to add
+ * @param value - the value of the key
+ */
+ public void addCSSAttribute(MutableAttributeSet attr, CSS.Attribute key,
+ String value)
+ {
+ attr.addAttribute(key, value);
+ }
+
+ /**
+ * Adds a CSS attribute to the given set.
+ * This method parses the value argument from HTML based on key.
+ * Returns true if it finds a valid value for the given key,
+ * and false otherwise.
+ *
+ * @param attr - the attribute set
+ * @param key - the attribute to add
+ * @param value - the value of the key
+ * @return true if a valid value was found.
+ */
+ public boolean addCSSAttributeFromHTML(MutableAttributeSet attr, CSS.Attribute key,
+ String value)
+ {
+ // FIXME: Need to parse value from HTML based on key.
+ attr.addAttribute(key, value);
+ return attr.containsAttribute(key, value);
+ }
+
+ /**
+ * Converts a set of HTML attributes to an equivalent set of CSS attributes.
+ *
+ * @param htmlAttrSet - the set containing the HTML attributes.
+ * @return the set of CSS attributes
+ */
+ public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet)
+ {
+ // FIXME: Not implemented.
+ return null;
+ }
+
+ /**
+ * Adds an attribute to the given set and returns a new set. This is implemented
+ * to convert StyleConstants attributes to CSS before forwarding them to the superclass.
+ * The StyleConstants attribute do not have corresponding CSS entry, the attribute
+ * is stored (but will likely not be used).
+ *
+ * @param old - the old set
+ * @param key - the non-null attribute key
+ * @param value - the attribute value
+ * @return the updated set
+ */
+ public AttributeSet addAttribute(AttributeSet old, Object key,
+ Object value)
+ {
+ // FIXME: Not implemented.
+ return super.addAttribute(old, key, value);
+ }
+
+ /**
+ * Adds a set of attributes to the element. If any of these attributes are
+ * StyleConstants, they will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old set
+ * @param attr - the attributes to add
+ * @return the updated attribute set
+ */
+ public AttributeSet addAttributes(AttributeSet old, AttributeSet attr)
+ {
+ // FIXME: Not implemented.
+ return super.addAttributes(old, attr);
+ }
+
+ /**
+ * Removes an attribute from the set. If the attribute is a
+ * StyleConstants, it will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old set
+ * @param key - the non-null attribute key
+ * @return the updated set
+ */
+ public AttributeSet removeAttribute(AttributeSet old, Object key)
+ {
+ // FIXME: Not implemented.
+ return super.removeAttribute(old, key);
+ }
+
+ /**
+ * Removes an attribute from the set. If any of the attributes are
+ * StyleConstants, they will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old set
+ * @param attrs - the attributes to remove
+ * @return the updated set
+ */
+ public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs)
+ {
+ // FIXME: Not implemented.
+ return super.removeAttributes(old, attrs);
+ }
+
+ /**
+ * Removes a set of attributes for the element. If any of the attributes is a
+ * StyleConstants, they will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old attribute set
+ * @param names - the attribute names
+ * @return the update attribute set
+ */
+ public AttributeSet removeAttributes(AttributeSet old, Enumeration names)
+ {
+ // FIXME: Not implemented.
+ return super.removeAttributes(old, names);
+ }
+
+ /**
+ * Creates a compact set of attributes that might be shared. This is a hook
+ * for subclasses that want to change the behaviour of SmallAttributeSet.
+ *
+ * @param a - the set of attributes to be represented in the compact form.
+ * @return the set of attributes created
+ */
+ protected StyleContext.SmallAttributeSet createSmallAttributeSet(AttributeSet a)
+ {
+ return super.createSmallAttributeSet(a);
+ }
+
+ /**
+ * Creates a large set of attributes. This set is not shared. This is a hook
+ * for subclasses that want to change the behaviour of the larger attribute
+ * storage format.
+ *
+ * @param a - the set of attributes to be represented in the larger form.
+ * @return the large set of attributes.
+ */
+ protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
+ {
+ return super.createLargeAttributeSet(a);
+ }
+
+ /**
+ * Gets the font to use for the given set.
+ *
+ * @param a - the set to get the font for.
+ * @return the font for the set
+ */
+ public Font getFont(AttributeSet a)
+ {
+ return super.getFont(a);
+ }
+
+ /**
+ * Takes a set of attributes and turns it into a foreground
+ * color specification. This is used to specify things like, brigher, more hue
+ * etc.
+ *
+ * @param a - the set to get the foreground color for
+ * @return the foreground color for the set
+ */
+ public Color getForeground(AttributeSet a)
+ {
+ return super.getForeground(a);
+ }
+
+ /**
+ * Takes a set of attributes and turns it into a background
+ * color specification. This is used to specify things like, brigher, more hue
+ * etc.
+ *
+ * @param a - the set to get the background color for
+ * @return the background color for the set
+ */
+ public Color getBackground(AttributeSet a)
+ {
+ return super.getBackground(a);
+ }
+
+ /**
+ * Gets the box formatter to use for the given set of CSS attributes.
+ *
+ * @param a - the given set
+ * @return the box formatter
+ */
+ public BoxPainter getBoxPainter(AttributeSet a)
+ {
+ return new BoxPainter(a);
+ }
+
+ /**
+ * Gets the list formatter to use for the given set of CSS attributes.
+ *
+ * @param a - the given set
+ * @return the list formatter
+ */
+ public ListPainter getListPainter(AttributeSet a)
+ {
+ return new ListPainter(a);
+ }
+
+ /**
+ * Sets the base font size between 1 and 7.
+ *
+ * @param sz - the new font size for the base.
+ */
+ public void setBaseFontSize(int sz)
+ {
+ if (sz <= 7 && sz >= 1)
+ baseFontSize = sz;
+ }
+
+ /**
+ * Sets the base font size from the String. It can either identify
+ * a specific font size (between 1 and 7) or identify a relative
+ * font size such as +1 or -2.
+ *
+ * @param size - the new font size as a String.
+ */
+ public void setBaseFontSize(String size)
+ {
+ size.trim();
+ int temp = 0;
+ try
+ {
+ if (size.length() == 2)
+ {
+ int i = new Integer(size.substring(1)).intValue();
+ if (size.startsWith("+"))
+ temp = baseFontSize + i;
+ else if (size.startsWith("-"))
+ temp = baseFontSize - i;
+ }
+ else if (size.length() == 1)
+ temp = new Integer(size.substring(0)).intValue();
+
+ if (temp <= 7 && temp >= 1)
+ baseFontSize = temp;
+ }
+ catch (NumberFormatException nfe)
+ {
+ // Do nothing here
+ }
+ }
+
+ /**
+ * TODO
+ *
+ * @param pt - TODO
+ * @return TODO
+ */
+ public static int getIndexOfSize(float pt)
+ {
+ // FIXME: Not implemented.
+ return 0;
+ }
+
+ /**
+ * Gets the point size, given a size index.
+ *
+ * @param index - the size index
+ * @return the point size.
+ */
+ public float getPointSize(int index)
+ {
+ // FIXME: Not implemented.
+ return 0;
+ }
+
+ /**
+ * Given the string of the size, returns the point size value.
+ *
+ * @param size - the string representation of the size.
+ * @return - the point size value.
+ */
+ public float getPointSize(String size)
+ {
+ // FIXME: Not implemented.
+ return 0;
+ }
+
+ /**
+ * Converst a color string to a color. If it is not found, null is returned.
+ *
+ * @param color - the color string such as "RED" or "#NNNNNN"
+ * @return the Color, or null if not found.
+ */
+ public Color stringToColor(String color)
+ {
+ color = color.toLowerCase();
+ if (color.equals("black") || color.equals("#000000"))
+ return Color.BLACK;
+ else if (color.equals("aqua") || color.equals("#00FFFF"))
+ return new Color(127, 255, 212);
+ else if (color.equals("gray") || color.equals("#808080"))
+ return Color.GRAY;
+ else if (color.equals("navy") || color.equals("#000080"))
+ return new Color(0, 0, 128);
+ else if (color.equals("silver") || color.equals("#C0C0C0"))
+ return Color.LIGHT_GRAY;
+ else if (color.equals("green") || color.equals("#008000"))
+ return Color.GREEN;
+ else if (color.equals("olive") || color.equals("#808000"))
+ return new Color(128, 128, 0);
+ else if (color.equals("teal") || color.equals("#008080"))
+ return new Color(0, 128, 128);
+ else if (color.equals("blue") || color.equals("#0000FF"))
+ return Color.BLUE;
+ else if (color.equals("lime") || color.equals("#00FF00"))
+ return new Color(0, 255, 0);
+ else if (color.equals("purple") || color.equals("#800080"))
+ return new Color(128, 0, 128);
+ else if (color.equals("white") || color.equals("#FFFFFF"))
+ return Color.WHITE;
+ else if (color.equals("fuchsia") || color.equals("#FF00FF"))
+ return Color.MAGENTA;
+ else if (color.equals("maroon") || color.equals("#800000"))
+ return new Color(128, 0, 0);
+ else if (color.equals("Red") || color.equals("#FF0000"))
+ return Color.RED;
+ else if (color.equals("Yellow") || color.equals("#FFFF00"))
+ return Color.YELLOW;
+ return null;
+ }
+
+ /**
+ * This class carries out some of the duties of CSS formatting. This enables views
+ * to present the CSS formatting while not knowing how the CSS values are cached.
+ *
+ * This object is reponsible for the insets of a View and making sure
+ * the background is maintained according to the CSS attributes.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+ public static class BoxPainter extends Object implements Serializable
+ {
+
+ /**
+ * Attribute set for painter
+ */
+ AttributeSet as;
+
+ /**
+ * Package-private constructor.
+ *
+ * @param as - AttributeSet for painter
+ */
+ BoxPainter(AttributeSet as)
+ {
+ this.as = as;
+ }
+
+ /**
+ * Gets the inset needed on a given side to account for the margin, border
+ * and padding.
+ *
+ * @param size - the size of the box to get the inset for. View.TOP, View.LEFT,
+ * View.BOTTOM or View.RIGHT.
+ * @param v - the view making the request. This is used to get the AttributeSet,
+ * amd may be used to resolve percentage arguments.
+ * @return the inset
+ * @throws IllegalArgumentException - for an invalid direction.
+ */
+ public float getInset(int size, View v)
+ {
+ // FIXME: Not implemented.
+ return 0;
+ }
+
+ /**
+ * Paints the CSS box according to the attributes given. This should
+ * paint the border, padding and background.
+ *
+ * @param g - the graphics configuration
+ * @param x - the x coordinate
+ * @param y - the y coordinate
+ * @param w - the width of the allocated area
+ * @param h - the height of the allocated area
+ * @param v - the view making the request
+ */
+ public void paint(Graphics g, float x, float y, float w, float h, View v)
+ {
+ // FIXME: Not implemented.
+ }
+ }
+
+ /**
+ * This class carries out some of the CSS list formatting duties. Implementations
+ * of this class enable views to present the CSS formatting while not knowing anything
+ * about how the CSS values are being cached.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+ public static class ListPainter extends Object implements Serializable
+ {
+
+ /**
+ * Attribute set for painter
+ */
+ AttributeSet as;
+
+ /**
+ * Package-private constructor.
+ *
+ * @param as - AttributeSet for painter
+ */
+ ListPainter(AttributeSet as)
+ {
+ this.as = as;
+ }
+
+ /**
+ * Paints the CSS list decoration according to the attributes given.
+ *
+ * @param g - the graphics configuration
+ * @param x - the x coordinate
+ * @param y - the y coordinate
+ * @param w - the width of the allocated area
+ * @param h - the height of the allocated area
+ * @param v - the view making the request
+ * @param item - the list item to be painted >=0.
+ */
+ public void paint(Graphics g, float x, float y, float w, float h, View v,
+ int item)
+ {
+ // FIXME: Not implemented.
+ }
+ }
+
+ /**
+ * The parser callback for the CSSParser.
+ */
+ class CssParser implements CSSParser.CSSParserCallback
+ {
+ /**
+ * A vector of all the selectors.
+ * Each element is an array of all the selector tokens
+ * in a single rule.
+ */
+ Vector selectors;
+
+ /** A vector of all the selector tokens in a rule. */
+ Vector selectorTokens;
+
+ /** Name of the current property. */
+ String propertyName;
+
+ /** The set of CSS declarations */
+ MutableAttributeSet declaration;
+
+ /**
+ * True if parsing a declaration, that is the Reader will not
+ * contain a selector.
+ */
+ boolean parsingDeclaration;
+
+ /** True if the attributes are coming from a linked/imported style. */
+ boolean isLink;
+
+ /** The base URL */
+ URL base;
+
+ /** The parser */
+ CSSParser parser;
+
+ /**
+ * Constructor
+ */
+ CssParser()
+ {
+ selectors = new Vector();
+ selectorTokens = new Vector();
+ parser = new CSSParser();
+ base = StyleSheet.this.base;
+ declaration = new SimpleAttributeSet();
+ }
+
+ /**
+ * Parses the passed in CSS declaration into an AttributeSet.
+ *
+ * @param s - the declaration
+ * @return the set of attributes containing the property and value.
+ */
+ public AttributeSet parseDeclaration(String s)
+ {
+ try
+ {
+ return parseDeclaration(new StringReader(s));
+ }
+ catch (IOException e)
+ {
+ // Do nothing here.
+ }
+ return null;
+ }
+
+ /**
+ * Parses the passed in CSS declaration into an AttributeSet.
+ *
+ * @param r - the reader
+ * @return the attribute set
+ * @throws IOException from the reader
+ */
+ public AttributeSet parseDeclaration(Reader r) throws IOException
+ {
+ parse(base, r, true, false);
+ return declaration;
+ }
+
+ /**
+ * Parse the given CSS stream
+ *
+ * @param base - the url
+ * @param r - the reader
+ * @param parseDec - True if parsing a declaration
+ * @param isLink - True if parsing a link
+ */
+ public void parse(URL base, Reader r, boolean parseDec, boolean isLink) throws IOException
+ {
+ parsingDeclaration = parseDec;
+ this.isLink = isLink;
+ this.base = base;
+
+ // flush out all storage
+ propertyName = null;
+ selectors.clear();
+ selectorTokens.clear();
+ declaration.removeAttributes(declaration);
+
+ parser.parse(r, this, parseDec);
+ }
+
+ /**
+ * Invoked when a valid @import is encountered,
+ * will call importStyleSheet if a MalformedURLException
+ * is not thrown in creating the URL.
+ *
+ * @param s - the string after @import
+ */
+ public void handleImport(String s)
+ {
+ if (s != null)
+ {
+ try
+ {
+ if (s.startsWith("url(") && s.endsWith(")"))
+ s = s.substring(4, s.length() - 1);
+ if (s.indexOf("\"") >= 0)
+ s = s.replaceAll("\"","");
+
+ URL url = new URL(s);
+ if (url == null && base != null)
+ url = new URL(base, s);
+
+ importStyleSheet(url);
+ }
+ catch (MalformedURLException e)
+ {
+ // Do nothing here.
+ }
+ }
+ }
+
+ /**
+ * A selector has been encountered.
+ *
+ * @param s - a selector (e.g. P or UL or even P,)
+ */
+ public void handleSelector(String s)
+ {
+ if (s.endsWith(","))
+ s = s.substring(0, s.length() - 1);
+
+ selectorTokens.addElement(s);
+ addSelector();
+ }
+
+ /**
+ * Invoked when the start of a rule is encountered.
+ */
+ public void startRule()
+ {
+ addSelector();
+ }
+
+ /**
+ * Invoked when a property name is encountered.
+ *
+ * @param s - the property
+ */
+ public void handleProperty(String s)
+ {
+ propertyName = s;
+ }
+
+ /**
+ * Invoked when a property value is encountered.
+ *
+ * @param s - the value
+ */
+ public void handleValue(String s)
+ {
+ // call addCSSAttribute
+ // FIXME: Not implemented
+ }
+
+ /**
+ * Invoked when the end of a rule is encountered.
+ */
+ public void endRule()
+ {
+ // FIXME: Not implemented
+ // add rules
+ propertyName = null;
+ }
+
+ /**
+ * Adds the selector to the vector.
+ */
+ private void addSelector()
+ {
+ int length = selectorTokens.size();
+ if (length > 0)
+ {
+ Object[] sel = new Object[length];
+ System.arraycopy(selectorTokens.toArray(), 0, sel, 0, length);
+ selectors.add(sel);
+ selectorTokens.clear();
+ }
+ }
+ }
+}
diff --git a/javax/swing/text/html/default.css b/javax/swing/text/html/default.css
new file mode 100644
index 000000000..f2a44f8c8
--- /dev/null
+++ b/javax/swing/text/html/default.css
@@ -0,0 +1,378 @@
+/* default.css --
+ Copyright (C) 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. */
+
+nobr {
+ white-space: nowrap;
+}
+
+ol {
+ margin-right: 50px;
+ margin-top: 10px;
+ margin-left: 50px;
+ margin-bottom: 10px;
+ list-style-type: decimal;
+}
+
+u {
+ text-decoration: underline;
+}
+
+s {
+ text-decoration: line-through;
+}
+
+p {
+ margin-top: 15px;
+}
+
+dd p {
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+ol li p {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+
+address {
+ font-style: italic;
+ color: blue;
+}
+
+i {
+ font-style: italic;
+}
+
+h6 {
+ margin-top: 10px;
+ font-size: xx-small;
+ font-weight: bold;
+ margin-bottom: 10px;
+}
+
+h5 {
+ margin-top: 10px;
+ font-size: x-small;
+ font-weight: bold;
+ margin-bottom: 10px;
+}
+
+h4 {
+ margin-top: 10px;
+ font-size: small;
+ font-weight: bold;
+ margin-bottom: 10px;
+}
+
+h3 {
+ margin-top: 10px;
+ font-size: medium;
+ font-weight: bold;
+ margin-bottom: 10px;
+}
+
+dir li p {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+h2 {
+ margin-top: 10px;
+ font-size: large;
+ font-weight: bold;
+ margin-bottom: 10px;
+}
+
+b {
+ font-weight: bold;
+}
+
+h1 {
+ margin-top: 10px;
+ font-size: x-large;
+ font-weight: bold;
+ margin-bottom: 10px;
+}
+
+caption {
+ text-align: center;
+ caption-side: top;
+}
+
+a {
+ text-decoration: underline;
+ color: blue;
+}
+
+ul li ul li ul li {
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+menu {
+ margin-right: 40px;
+ margin-top: 10px;
+ margin-left: 40px;
+ margin-bottom: 10px;
+}
+
+menu li p {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+sup {
+ vertical-align: super;
+}
+
+body {
+ margin-right: 0px;
+ margin-left: 0px;
+ font-family: Serif;
+ font-size: 14pt;
+ font-weight: normal;
+ color: black;
+}
+
+ul li ul li ul {
+ margin-right: 25px;
+ margin-left: 25px;
+ list-style-type: square;
+}
+
+blockquote {
+ margin-right: 35px;
+ margin-left: 35px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+samp {
+ font-family: Monospaced;
+ font-size: small;
+}
+
+cite {
+ font-style: italic;
+}
+
+sub {
+ vertical-align: sub;
+}
+
+em {
+ font-style: italic;
+}
+
+ul li p {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+ul li ul li {
+ margin-right: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+var {
+ font-style: italic;
+ font-weight: bold;
+}
+
+table {
+ border-color: Gray;
+ border-style: outset;
+}
+
+dfn {
+ font-style: italic;
+}
+
+menu li {
+ margin-right: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+strong {
+ font-weight: bold;
+}
+
+ul {
+ margin-right: 50px;
+ margin-top: 10px;
+ margin-left: 50px;
+ margin-bottom: 10px;
+ list-style-type: disc;
+}
+
+center {
+ text-align: center;
+}
+
+ul li ul {
+ margin-right: 25px;
+ margin-left: 25px;
+ list-style-type: circle;
+}
+
+kbd {
+ font-family: Monospaced;
+ font-size: small;
+}
+
+dir li {
+ margin-right: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+ul li menu {
+ margin-right: 25px;
+ margin-left: 25px;
+ list-style-type: circle;
+}
+
+dt {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+ol li {
+ margin-right: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+li p {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+default {
+}
+
+strike {
+ text-decoration: line-through;
+}
+
+dl {
+ margin-left: 0px;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+tt {
+ font-family: Monospaced;
+}
+
+ul li {
+ margin-right: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+dir {
+ margin-right: 40px;
+ margin-top: 10px;
+ margin-left: 40px;
+ margin-bottom: 10px;
+}
+
+tr {
+ text-align: left;
+}
+
+pre p {
+ margin-top: 0px;
+}
+
+dd {
+ margin-right: 40px;
+ margin-top: 0px;
+ margin-left: 40px;
+ margin-bottom: 0px;
+}
+
+th {
+ padding-bottom: 3px;
+ text-align: center;
+ padding-top: 3px;
+ padding-right: 3px;
+ padding-left: 3px;
+ font-weight: bold;
+ border-color: Gray;
+ border-style: inset;
+}
+
+pre {
+ margin-top: 5px;
+ font-family: Monospaced;
+ margin-bottom: 5px;
+}
+
+td {
+ padding-bottom: 3px;
+ padding-top: 3px;
+ padding-right: 3px;
+ padding-left: 3px;
+ border-color: Gray;
+ border-style: inset;
+}
+
+code {
+ font-family: Monospaced;
+ font-size: small;
+}
+
+small {
+ font-size: x-small;
+}
+
+big {
+ font-size: x-large;
+}
diff --git a/javax/swing/tree/DefaultTreeModel.java b/javax/swing/tree/DefaultTreeModel.java
index b6205c5db..c9ba7884a 100644
--- a/javax/swing/tree/DefaultTreeModel.java
+++ b/javax/swing/tree/DefaultTreeModel.java
@@ -148,12 +148,6 @@ public class DefaultTreeModel
*/
public void setRoot(TreeNode root)
{
- // Sanity Check
- if (root == null)
- {
- throw new IllegalArgumentException("null root");
- }
- // Set new root
this.root = root;
}
diff --git a/javax/swing/tree/DefaultTreeSelectionModel.java b/javax/swing/tree/DefaultTreeSelectionModel.java
index b30481425..61418316a 100644
--- a/javax/swing/tree/DefaultTreeSelectionModel.java
+++ b/javax/swing/tree/DefaultTreeSelectionModel.java
@@ -116,7 +116,7 @@ public class DefaultTreeSelectionModel
*/
public DefaultTreeSelectionModel()
{
- setSelectionMode(SINGLE_TREE_SELECTION);
+ setSelectionMode(DISCONTIGUOUS_TREE_SELECTION);
listenerList = new EventListenerList();
}