summaryrefslogtreecommitdiff
path: root/javax/swing/plaf/basic/BasicTextUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'javax/swing/plaf/basic/BasicTextUI.java')
-rw-r--r--javax/swing/plaf/basic/BasicTextUI.java473
1 files changed, 310 insertions, 163 deletions
diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java
index 8e9c8c949..dc30347f5 100644
--- a/javax/swing/plaf/basic/BasicTextUI.java
+++ b/javax/swing/plaf/basic/BasicTextUI.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.SystemProperties;
+
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
@@ -71,6 +73,7 @@ import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TextUI;
import javax.swing.plaf.UIResource;
import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.DefaultCaret;
@@ -120,6 +123,140 @@ public abstract class BasicTextUI extends TextUI
}
}
+ private static class FocusHandler
+ implements FocusListener
+ {
+ public void focusGained(FocusEvent e)
+ {
+ // Nothing to do here.
+ }
+ public void focusLost(FocusEvent e)
+ {
+ JTextComponent textComponent = (JTextComponent) e.getComponent();
+ // Integrates Swing text components with the system clipboard:
+ // The idea is that if one wants to copy text around X11-style
+ // (select text and middle-click in the target component) the focus
+ // will move to the new component which gives the old focus owner the
+ // possibility to paste its selection into the clipboard.
+ if (!e.isTemporary()
+ && textComponent.getSelectionStart()
+ != textComponent.getSelectionEnd())
+ {
+ SecurityManager sm = System.getSecurityManager();
+ try
+ {
+ if (sm != null)
+ sm.checkSystemClipboardAccess();
+
+ Clipboard cb = Toolkit.getDefaultToolkit().getSystemSelection();
+ if (cb != null)
+ {
+ StringSelection selection = new StringSelection(
+ textComponent.getSelectedText());
+ cb.setContents(selection, selection);
+ }
+ }
+ catch (SecurityException se)
+ {
+ // Not allowed to access the clipboard: Ignore and
+ // do not access it.
+ }
+ catch (HeadlessException he)
+ {
+ // There is no AWT: Ignore and do not access the
+ // clipboard.
+ }
+ catch (IllegalStateException ise)
+ {
+ // Clipboard is currently unavaible.
+ }
+ }
+ }
+ }
+
+ /**
+ * This FocusListener triggers repaints on focus shift.
+ */
+ private static FocusListener focusListener;
+
+ /**
+ * Receives notifications when properties of the text component change.
+ */
+ private class Handler
+ implements PropertyChangeListener, DocumentListener
+ {
+ /**
+ * Notifies when a property of the text component changes.
+ *
+ * @param event the PropertyChangeEvent describing the change
+ */
+ public void propertyChange(PropertyChangeEvent event)
+ {
+ if (event.getPropertyName().equals("document"))
+ {
+ // Document changed.
+ Object oldValue = event.getOldValue();
+ if (oldValue != null)
+ {
+ Document oldDoc = (Document) oldValue;
+ oldDoc.removeDocumentListener(handler);
+ }
+ Object newValue = event.getNewValue();
+ if (newValue != null)
+ {
+ Document newDoc = (Document) newValue;
+ newDoc.addDocumentListener(handler);
+ }
+ modelChanged();
+ }
+
+ BasicTextUI.this.propertyChange(event);
+ }
+
+ /**
+ * Notification about a document change event.
+ *
+ * @param ev the DocumentEvent describing the change
+ */
+ public void changedUpdate(DocumentEvent ev)
+ {
+ // Updates are forwarded to the View even if 'getVisibleEditorRect'
+ // method returns null. This means the View classes have to be
+ // aware of that possibility.
+ rootView.changedUpdate(ev, getVisibleEditorRect(),
+ rootView.getViewFactory());
+ }
+
+ /**
+ * Notification about a document insert event.
+ *
+ * @param ev the DocumentEvent describing the insertion
+ */
+ public void insertUpdate(DocumentEvent ev)
+ {
+ // Updates are forwarded to the View even if 'getVisibleEditorRect'
+ // method returns null. This means the View classes have to be
+ // aware of that possibility.
+ rootView.insertUpdate(ev, getVisibleEditorRect(),
+ rootView.getViewFactory());
+ }
+
+ /**
+ * Notification about a document removal event.
+ *
+ * @param ev the DocumentEvent describing the removal
+ */
+ public void removeUpdate(DocumentEvent ev)
+ {
+ // Updates are forwarded to the View even if 'getVisibleEditorRect'
+ // method returns null. This means the View classes have to be
+ // aware of that possibility.
+ rootView.removeUpdate(ev, getVisibleEditorRect(),
+ rootView.getViewFactory());
+ }
+
+ }
+
/**
* This view forms the root of the View hierarchy. However, it delegates
* most calls to another View which is the real root of the hierarchy.
@@ -225,20 +362,10 @@ public abstract class BasicTextUI extends TextUI
return textComponent;
}
- /**
- * Returns the preferred span along the specified <code>axis</code>.
- * This is delegated to the real root view.
- *
- * @param axis the axis for which the preferred span is queried
- *
- * @return the preferred span along the axis
- */
- public float getPreferredSpan(int axis)
+ public void setSize(float w, float h)
{
if (view != null)
- return view.getPreferredSpan(axis);
-
- return Integer.MAX_VALUE;
+ view.setSize(w, h);
}
/**
@@ -312,7 +439,8 @@ public abstract class BasicTextUI extends TextUI
*/
public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
{
- view.insertUpdate(ev, shape, vf);
+ if (view != null)
+ view.insertUpdate(ev, shape, vf);
}
/**
@@ -325,7 +453,8 @@ public abstract class BasicTextUI extends TextUI
*/
public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
{
- view.removeUpdate(ev, shape, vf);
+ if (view != null)
+ view.removeUpdate(ev, shape, vf);
}
/**
@@ -338,7 +467,8 @@ public abstract class BasicTextUI extends TextUI
*/
public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
{
- view.changedUpdate(ev, shape, vf);
+ if (view != null)
+ view.changedUpdate(ev, shape, vf);
}
/**
@@ -400,116 +530,73 @@ public abstract class BasicTextUI extends TextUI
{
return textComponent.getDocument();
}
- }
- /**
- * Receives notifications when properties of the text component change.
- */
- private class PropertyChangeHandler implements PropertyChangeListener
- {
/**
- * Notifies when a property of the text component changes.
- *
- * @param event the PropertyChangeEvent describing the change
+ * Returns the attributes, which is null for the RootView.
*/
- public void propertyChange(PropertyChangeEvent event)
+ public AttributeSet getAttributes()
{
- if (event.getPropertyName().equals("document"))
- {
- // Document changed.
- Object oldValue = event.getOldValue();
- if (oldValue != null)
- {
- Document oldDoc = (Document) oldValue;
- oldDoc.removeDocumentListener(documentHandler);
- }
- Object newValue = event.getNewValue();
- if (newValue != null)
- {
- Document newDoc = (Document) newValue;
- newDoc.addDocumentListener(documentHandler);
- }
- modelChanged();
- }
-
- BasicTextUI.this.propertyChange(event);
+ return null;
}
- }
- /**
- * Listens for changes on the underlying model and forwards notifications
- * to the View. This also updates the caret position of the text component.
- *
- * TODO: Maybe this should somehow be handled through EditorKits
- */
- class DocumentHandler implements DocumentListener
- {
/**
- * Notification about a document change event.
- *
- * @param ev the DocumentEvent describing the change
+ * Overridden to forward to the view.
*/
- public void changedUpdate(DocumentEvent ev)
+ public float getPreferredSpan(int axis)
{
- // Updates are forwarded to the View even if 'getVisibleEditorRect'
- // method returns null. This means the View classes have to be
- // aware of that possibility.
- rootView.changedUpdate(ev, getVisibleEditorRect(),
- rootView.getViewFactory());
+ // The RI returns 10 in the degenerate case.
+ float span = 10;
+ if (view != null)
+ span = view.getPreferredSpan(axis);
+ return span;
}
/**
- * Notification about a document insert event.
- *
- * @param ev the DocumentEvent describing the insertion
+ * Overridden to forward to the real view.
*/
- public void insertUpdate(DocumentEvent ev)
+ public float getMinimumSpan(int axis)
{
- // Updates are forwarded to the View even if 'getVisibleEditorRect'
- // method returns null. This means the View classes have to be
- // aware of that possibility.
- rootView.insertUpdate(ev, getVisibleEditorRect(),
- rootView.getViewFactory());
+ // The RI returns 10 in the degenerate case.
+ float span = 10;
+ if (view != null)
+ span = view.getMinimumSpan(axis);
+ return span;
}
/**
- * Notification about a document removal event.
- *
- * @param ev the DocumentEvent describing the removal
+ * Overridden to return Integer.MAX_VALUE.
*/
- public void removeUpdate(DocumentEvent ev)
+ public float getMaximumSpan(int axis)
{
- // Updates are forwarded to the View even if 'getVisibleEditorRect'
- // method returns null. This means the View classes have to be
- // aware of that possibility.
- rootView.removeUpdate(ev, getVisibleEditorRect(),
- rootView.getViewFactory());
+ // The RI returns Integer.MAX_VALUE here, regardless of the real view's
+ // maximum size.
+ return Integer.MAX_VALUE;
}
}
/**
* The EditorKit used by this TextUI.
*/
- // FIXME: should probably be non-static.
- static EditorKit kit = new DefaultEditorKit();
+ private static EditorKit kit;
/**
- * The root view.
+ * The combined event handler for text components.
+ *
+ * This is package private to avoid accessor methods.
*/
- RootView rootView = new RootView();
+ Handler handler;
/**
- * The text component that we handle.
+ * The root view.
+ *
+ * This is package private to avoid accessor methods.
*/
- JTextComponent textComponent;
+ RootView rootView;
/**
- * Receives notification when the model changes.
+ * The text component that we handle.
*/
- private PropertyChangeHandler updateHandler = new PropertyChangeHandler();
-
- /** The DocumentEvent handler. */
- DocumentHandler documentHandler = new DocumentHandler();
+ JTextComponent textComponent;
/**
* Creates a new <code>BasicTextUI</code> instance.
@@ -558,17 +645,31 @@ public abstract class BasicTextUI extends TextUI
public void installUI(final JComponent c)
{
textComponent = (JTextComponent) c;
+
+ if (rootView == null)
+ rootView = new RootView();
+
installDefaults();
- textComponent.addPropertyChangeListener(updateHandler);
+ installFixedDefaults();
+
+ // These listeners must be installed outside of installListeners(),
+ // because overriding installListeners() doesn't prevent installing
+ // these in the RI, but overriding isntallUI() does.
+ if (handler == null)
+ handler = new Handler();
+ textComponent.addPropertyChangeListener(handler);
Document doc = textComponent.getDocument();
if (doc == null)
{
+ // The Handler takes care of installing the necessary listeners
+ // on the document here.
doc = getEditorKit(textComponent).createDefaultDocument();
textComponent.setDocument(doc);
}
else
{
- doc.addDocumentListener(documentHandler);
+ // Must install the document listener.
+ doc.addDocumentListener(handler);
modelChanged();
}
@@ -586,7 +687,6 @@ public abstract class BasicTextUI extends TextUI
LookAndFeel.installColorsAndFont(textComponent, prefix + ".background",
prefix + ".foreground", prefix + ".font");
LookAndFeel.installBorder(textComponent, prefix + ".border");
- textComponent.setMargin(UIManager.getInsets(prefix + ".margin"));
// Some additional text component only properties.
Color color = textComponent.getCaretColor();
@@ -600,7 +700,7 @@ public abstract class BasicTextUI extends TextUI
color = textComponent.getDisabledTextColor();
if (color == null || color instanceof UIResource)
{
- color = UIManager.getColor(prefix + ".inactiveBackground");
+ color = UIManager.getColor(prefix + ".inactiveForeground");
textComponent.setDisabledTextColor(color);
}
color = textComponent.getSelectedTextColor();
@@ -623,6 +723,15 @@ public abstract class BasicTextUI extends TextUI
textComponent.setMargin(margin);
}
+ }
+
+ /**
+ * Installs defaults that can't be overridden by overriding
+ * installDefaults().
+ */
+ private void installFixedDefaults()
+ {
+ String prefix = getPropertyPrefix();
Caret caret = textComponent.getCaret();
if (caret == null || caret instanceof UIResource)
{
@@ -638,64 +747,18 @@ public abstract class BasicTextUI extends TextUI
}
/**
- * This FocusListener triggers repaints on focus shift.
- */
- private FocusListener focuslistener = new FocusListener() {
- public void focusGained(FocusEvent e)
- {
- textComponent.repaint();
- }
- public void focusLost(FocusEvent e)
- {
- textComponent.repaint();
-
- // Integrates Swing text components with the system clipboard:
- // The idea is that if one wants to copy text around X11-style
- // (select text and middle-click in the target component) the focus
- // will move to the new component which gives the old focus owner the
- // possibility to paste its selection into the clipboard.
- if (!e.isTemporary()
- && textComponent.getSelectionStart()
- != textComponent.getSelectionEnd())
- {
- SecurityManager sm = System.getSecurityManager();
- try
- {
- if (sm != null)
- sm.checkSystemClipboardAccess();
-
- Clipboard cb = Toolkit.getDefaultToolkit().getSystemSelection();
- if (cb != null)
- {
- StringSelection selection = new StringSelection(
- textComponent.getSelectedText());
- cb.setContents(selection, selection);
- }
- }
- catch (SecurityException se)
- {
- // Not allowed to access the clipboard: Ignore and
- // do not access it.
- }
- catch (HeadlessException he)
- {
- // There is no AWT: Ignore and do not access the
- // clipboard.
- }
- catch (IllegalStateException ise)
- {
- // Clipboard is currently unavaible.
- }
- }
- }
- };
-
- /**
* Install all listeners on the text component.
*/
protected void installListeners()
{
- textComponent.addFocusListener(focuslistener);
+ //
+ if (SystemProperties.getProperty("gnu.swing.text.no-xlike-clipboard")
+ == null)
+ {
+ if (focusListener == null)
+ focusListener = new FocusHandler();
+ textComponent.addFocusListener(focusListener);
+ }
}
/**
@@ -834,10 +897,12 @@ public abstract class BasicTextUI extends TextUI
*/
public void uninstallUI(final JComponent component)
{
- super.uninstallUI(component);
+ textComponent.removePropertyChangeListener(handler);
+ textComponent.getDocument().removeDocumentListener(handler);
rootView.setView(null);
uninstallDefaults();
+ uninstallFixedDefaults();
uninstallListeners();
uninstallKeyboardActions();
@@ -850,7 +915,29 @@ public abstract class BasicTextUI extends TextUI
*/
protected void uninstallDefaults()
{
- // Do nothing here.
+ if (textComponent.getCaretColor() instanceof UIResource)
+ textComponent.setCaretColor(null);
+ if (textComponent.getSelectionColor() instanceof UIResource)
+ textComponent.setSelectionColor(null);
+ if (textComponent.getDisabledTextColor() instanceof UIResource)
+ textComponent.setDisabledTextColor(null);
+ if (textComponent.getSelectedTextColor() instanceof UIResource)
+ textComponent.setSelectedTextColor(null);
+ LookAndFeel.uninstallBorder(textComponent);
+ if (textComponent.getMargin() instanceof UIResource)
+ textComponent.setMargin(null);
+ }
+
+ /**
+ * Uninstalls additional fixed defaults that were installed
+ * by installFixedDefaults().
+ */
+ private void uninstallFixedDefaults()
+ {
+ if (textComponent.getCaret() instanceof UIResource)
+ textComponent.setCaret(null);
+ if (textComponent.getHighlighter() instanceof UIResource)
+ textComponent.setHighlighter(null);
}
/**
@@ -859,7 +946,10 @@ public abstract class BasicTextUI extends TextUI
*/
protected void uninstallListeners()
{
- textComponent.removeFocusListener(focuslistener);
+ // Don't nullify the focusListener field, as it is static and shared
+ // between components.
+ if (focusListener != null)
+ textComponent.removeFocusListener(focusListener);
}
/**
@@ -891,14 +981,33 @@ public abstract class BasicTextUI extends TextUI
*/
public Dimension getPreferredSize(JComponent c)
{
- View v = getRootView(textComponent);
-
- float w = v.getPreferredSpan(View.X_AXIS);
- float h = v.getPreferredSpan(View.Y_AXIS);
-
+ Dimension d = c.getSize();
Insets i = c.getInsets();
- return new Dimension((int) w + i.left + i.right,
+ // We need to lock here, since we require the view hierarchy to _not_
+ // change in between.
+ float w;
+ float h;
+ Document doc = textComponent.getDocument();
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
+ {
+ if (d.width > (i.left + i.right) && d.height > (i.top + i.bottom))
+ {
+ rootView.setSize(d.width - i.left - i.right,
+ d.height - i.top - i.bottom);
+ }
+ w = rootView.getPreferredSpan(View.X_AXIS);
+ h = rootView.getPreferredSpan(View.Y_AXIS);
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ Dimension size = new Dimension((int) w + i.left + i.right,
(int) h + i.top + i.bottom);
+ return size;
}
/**
@@ -912,8 +1021,27 @@ public abstract class BasicTextUI extends TextUI
*/
public Dimension getMaximumSize(JComponent c)
{
- // Sun's implementation returns Integer.MAX_VALUE here, so do we.
- return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ Dimension d = new Dimension();
+ Insets i = c.getInsets();
+ Document doc = textComponent.getDocument();
+ // We need to lock here, since we require the view hierarchy to _not_
+ // change in between.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
+ {
+ // Check for overflow here.
+ d.width = (int) Math.min((long) rootView.getMaximumSpan(View.X_AXIS)
+ + i.left + i.right, Integer.MAX_VALUE);
+ d.height = (int) Math.min((long) rootView.getMaximumSpan(View.Y_AXIS)
+ + i.top + i.bottom, Integer.MAX_VALUE);
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ return d;
}
/**
@@ -924,8 +1052,26 @@ public abstract class BasicTextUI extends TextUI
*/
public Dimension getMinimumSize(JComponent c)
{
+ Dimension d = new Dimension();
+ Document doc = textComponent.getDocument();
+ // We need to lock here, since we require the view hierarchy to _not_
+ // change in between.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
+ {
+ d.width = (int) rootView.getMinimumSpan(View.X_AXIS);
+ d.height = (int) rootView.getMinimumSpan(View.Y_AXIS);
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
Insets i = c.getInsets();
- return new Dimension(i.left + i.right, i.top + i.bottom);
+ d.width += i.left + i.right;
+ d.height += i.top + i.bottom;
+ return d;
}
/**
@@ -996,7 +1142,6 @@ public abstract class BasicTextUI extends TextUI
g.setColor(oldColor);
}
-
rootView.paint(g, getVisibleEditorRect());
if (caret != null && textComponent.hasFocus())
@@ -1104,6 +1249,8 @@ public abstract class BasicTextUI extends TextUI
*/
public EditorKit getEditorKit(JTextComponent t)
{
+ if (kit == null)
+ kit = new DefaultEditorKit();
return kit;
}
@@ -1224,7 +1371,7 @@ public abstract class BasicTextUI extends TextUI
*/
public int viewToModel(JTextComponent t, Point pt)
{
- return viewToModel(t, pt, null);
+ return viewToModel(t, pt, new Position.Bias[1]);
}
/**