home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 November
/
Chip_1998-11_cd.bin
/
tema
/
Cafe
/
jfc.bin
/
DefaultTextUI.java
< prev
next >
Wrap
Text File
|
1998-02-26
|
37KB
|
1,086 lines
/*
* @(#)DefaultTextUI.java 1.79 98/02/02
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package com.sun.java.swing.text;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import com.sun.java.swing.*;
import com.sun.java.swing.plaf.*;
import com.sun.java.swing.text.*;
import com.sun.java.swing.event.*;
import com.sun.java.swing.border.Border;
/**
* <p>
* Basis of a text components look-and-feel. This provides the
* basic editor view and controller services that may be useful
* when creating a look-and-feel for an extension of
* JTextComponent.
* <p>
* To minimize the effort required to build a text UI, this class
* does a number of things on the programmers behalf. To build a
* view of the model, one of the strategies can be employed.
* <ol>
* <li>
* One strategy is to simply redefine the
* ViewFactory interface in the UI. By default, this UI itself acts
* as the factory for View implementations. This is useful
* for simple factories. To do this reimplement the
* <a href="#create">create</a> method.
* <li>
* A common strategy for creating more complex types of documents
* is to have the EditorKit implementation return a factory. Since
* the EditorKit ties all of the pieces necessary to maintain a type
* of document, the factory is typically an important part of that
* and should be produced by the EditorKit implementation.
* <li>
* A less common way to create more complex types is to have
* the UI implementation create a.
* seperate object for the factory. To do this, the
* <a href="#createViewFactory">createViewFactory</a>
* method should be reimplemented to return some factory.
* </ol>
* <p>
* Most state is held in the associated JTextComponent as bound
* properties, and the UI installs default values for the
* various properties. This default will install something for
* all of the properties. Typically, a LAF implementation will
* do more however. At a minimum, a LAF would generally install
* key bindings.
* <p>
* Warning: serialized objects of this class will not be compatible with
* future swing releases. The current serialization support is appropriate
* for short term storage or RMI between Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*
* @author Timothy Prinzing
* @version 1.79 02/02/98
*/
public abstract class DefaultTextUI extends TextUI implements ViewFactory, Serializable {
/**
* Creates a new UI.
*/
public DefaultTextUI() {
painted = false;
}
/**
* Creates the object to use for a caret. By default an
* instance of JCaret is created. This method
* can be redefined to provide something else that implements
* the InputPosition interface or a subclass of JCaret.
*
* @return the caret object
*/
protected Caret createCaret() {
return new DefaultCaret();
}
/**
* Creates the object to use for adding highlights. By default
* an instance of JHighlighter is created. This method
* can be redefined to provide something else that implements
* the Highlighter interface or a subclass of JHighlighter.
*
* @return the highlighter
*/
protected Highlighter createHighlighter() {
return new DefaultHighlighter();
}
/**
* Creates the keymap to use for the text component, and installs
* any necessary bindings into it.
*
* @return the keymap
*/
protected abstract Keymap createKeymap();
/**
* This method gets called when a bound property is changed
* on the associated JTextComponent. This is a hook
* which UI implementations may change to reflect how the
* UI displays bound properties of JTextComponent subclasses.
* This is implemented to do nothing (ie. the response to
* properties in JTextComponent itself are handled prior
* to calling this method).
*/
protected void propertyChange(PropertyChangeEvent evt) {
}
/**
* Gets the name used as a key to lookup properties through the
* UIManager. This is used as a prefix to all the standard
* text properties.
*
* @return the name
*/
protected abstract String getPropertyPrefix();
/**
* Initializes component properties, e.g. font, foreground, and
* background. The font, foreground, and background
* properties are only set if their current value is either null
* or a UIResource, other properties are set if the current
* value is null.
*
* @see #uninstallDefaults
* @see #installUI
*/
protected void installDefaults(JComponent c)
{
String prefix = getPropertyPrefix();
Font f = editor.getFont();
if ((f == null) || (f instanceof UIResource)) {
editor.setFont(UIManager.getFont(prefix + ".font"));
}
Color bg = editor.getBackground();
if ((bg == null) || (bg instanceof UIResource)) {
editor.setBackground(UIManager.getColor(prefix + ".background"));
}
Color fg = editor.getForeground();
if ((fg == null) || (fg instanceof UIResource)) {
editor.setForeground(UIManager.getColor(prefix + ".foreground"));
}
Color color = editor.getCaretColor();
if ((color == null) || (color instanceof UIResource)) {
editor.setCaretColor(UIManager.getColor(prefix + ".caretForeground"));
}
Color s = editor.getSelectionColor();
if ((s == null) || (s instanceof UIResource)) {
editor.setSelectionColor(UIManager.getColor(prefix + ".selectionBackground"));
}
Color sfg = editor.getSelectedTextColor();
if ((sfg == null) || (sfg instanceof UIResource)) {
editor.setSelectedTextColor(UIManager.getColor(prefix + ".selectionForeground"));
}
Color dfg = editor.getDisabledTextColor();
if ((dfg == null) || (dfg instanceof UIResource)) {
editor.setDisabledTextColor(UIManager.getColor(prefix + ".inactiveForeground"));
}
Border b = editor.getBorder();
if ((b == null) || (b instanceof UIResource)) {
editor.setBorder(UIManager.getBorder(prefix + ".border"));
}
// PENDING(prinz) these should be marked with UIResource if
// created by the LAF.
Caret caret = createCaret();
editor.setCaret(caret);
Object o = UIManager.get(prefix + ".caretBlinkRate");
if ((o != null) && (o instanceof Integer)) {
Integer rate = (Integer) o;
caret.setBlinkRate(rate.intValue());
}
}
/**
* Sets the component properties that haven't been explicitly overriden to
* null. A property is considered overridden if its current value
* is not a UIResource.
*
* @see #installDefaults
* @see #uninstallUI
*/
protected void uninstallDefaults(JComponent c)
{
if (editor.getCaretColor() instanceof UIResource) {
editor.setCaretColor(null);
}
if (editor.getSelectionColor() instanceof UIResource) {
editor.setSelectionColor(null);
}
if (editor.getDisabledTextColor() instanceof UIResource) {
editor.setDisabledTextColor(null);
}
if (editor.getSelectedTextColor() instanceof UIResource) {
editor.setSelectedTextColor(null);
}
if (editor.getBorder() instanceof UIResource) {
editor.setBorder(null);
}
// PENDING(prinz) these should be marked as a UIResource
// if installed by the UI.
editor.setCaret(null);
}
protected void installListeners(JComponent c) {
}
protected void uninstallListeners(JComponent c) {
}
/**
* Paints a background for the view. This will only be
* called if isOpaque() on the associated component is
* true. The default is to paint the background color
* of the component.
*
* @param g the graphics context
*/
protected void paintBackground(Graphics g) {
g.setColor(editor.getBackground());
Dimension d = editor.getSize();
g.fillRect(0, 0, d.width, d.height);
}
/**
* Fetches the text component associated with this
* UI implementation. This will be null until
* the ui has been installed.
*
* @return the component
*/
protected final JTextComponent getComponent() {
return editor;
}
/**
* Flags model changes.
* This is called whenever the model has changed.
* It is implemented to rebuild the view hierarchy
* to represent the default root element of the
* associated model.
*/
protected void modelChanged() {
// create a view hierarchy
ViewFactory f = rootView.getViewFactory();
Document doc = editor.getDocument();
Element elem = doc.getDefaultRootElement();
setView(f.create(elem));
}
/**
* Sets the current root of the view hierarchy.
*
* @param v the root view
*/
protected final void setView(View v) {
rootView.setView(v);
painted = false;
editor.invalidate();
}
/**
* Paints the interface safely with a guarantee that
* the model won't change from the view of this thread.
* This does the following things, rendering from
* back to front.
* <ol>
* <li>
* If the component is marked as opaque, the background
* is painted in the current background color of the
* component.
* <li>
* The highlights (if any) are painted.
* <li>
* The view hierarchy is painted.
* <li>
* The caret is painted.
* </ol>
*
* @param g the graphics context
* @param c the editor component
*/
protected void paintSafely(Graphics g) {
painted = true;
Highlighter highlighter = editor.getHighlighter();
Caret caret = editor.getCaret();
// paint the background
if (editor.isOpaque()) {
paintBackground(g);
}
// paint the highlights
if (highlighter != null) {
highlighter.paint(g);
}
// paint the view hierarchy
Rectangle alloc = getVisibleEditorRect();
rootView.paint(g, alloc);
// paint the caret
if (caret != null) {
caret.paint(g);
}
}
// --- ComponentUI methods --------------------------------------------
/**
* Installs the UI for a component. This does the following
* things.
* <ol>
* <li>
* Set the associated component to opaque (can be changed
* easily by a subclass or on JTextComponent directly),
* which is the most common case. This will cause the
* component's background color to be painted.
* <li>
* Install the default caret and highlighter into the
* associated component.
* <li>
* Attach to the editor and model. If there is no
* model, a default one is created.
* <li>
* create the view factory and the view hierarchy used
* to represent the model.
* </ol>
*
* @param c the component
* @see ComponentUI#installUI
*/
public void installUI(JComponent c) {
if (c instanceof JTextComponent) {
editor = (JTextComponent) c;
// install defaults
installDefaults(c);
// common case is background painted... this can
// easily be changed by subclasses or from outside
// of the component.
editor.setOpaque(true);
editor.setAutoscrolls(true);
editor.setHighlighter(createHighlighter());
// attach to the model and editor
editor.addPropertyChangeListener(updateHandler);
Document doc = editor.getDocument();
if (doc == null) {
// no model, create a default one. This will
// fire a notification to the updateHandler
// which takes care of the rest.
editor.setDocument(getEditorKit().createDefaultDocument());
} else {
doc.addDocumentListener(updateHandler);
modelChanged();
}
// install keymap
installListeners(c);
editor.setKeymap(createKeymap());
} else {
throw new Error("TextUI needs JTextComponent");
}
}
/**
* Deinstalls the UI for a component.
*
* @param c the component
* @see ComponentUI#uninstallUI
*/
public void uninstallUI(JComponent c) {
// detach from the model
editor.removePropertyChangeListener(updateHandler);
editor.getDocument().removeDocumentListener(updateHandler);
// view part
painted = false;
uninstallDefaults(c);
editor.setHighlighter(null);
rootView.setView(null);
c.removeAll();
// controller part
editor.setKeymap(null);
uninstallListeners(c);
}
/**
* Paints the interface. This is routed to
* <code>paintSafely</code> under the guarantee that
* the model won't change from the view of this thread
* while it's rendering. This enables the model to
* potentially be updated asynchronously.
*
* @param g the graphics context
* @param c the editor component
*/
public final void paint(Graphics g, JComponent c) {
if ((rootView.getViewCount() > 0) && (rootView.getView(0) != null)) {
Runnable painter = new SafePainter(g);
Document doc = editor.getDocument();
doc.render(painter);
}
}
/**
* Gets the preferred size for the editor component.
*
* @param c the editor component
* @return the size
*/
public Dimension getPreferredSize(JComponent c) {
Insets i = c.getInsets();
return new Dimension(
(int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) +
(long) i.left + (long) i.right, Integer.MAX_VALUE),
(int) Math.min((long) rootView.getPreferredSpan(View.Y_AXIS) +
(long) i.top + (long) i.bottom, Integer.MAX_VALUE)
);
}
/**
* Gets the minimum size for the editor component.
*
* @param c the editor component
* @return the size
*/
public Dimension getMinimumSize(JComponent c) {
Insets i = c.getInsets();
long width = (rootView.getResizeWeight(View.X_AXIS) > 0) ? 1 :
Math.min((long) rootView.getPreferredSpan(View.X_AXIS) + (long) i.left + (long) i.right, Integer.MAX_VALUE);
long height = (rootView.getResizeWeight(View.Y_AXIS) > 0) ? 1 :
Math.min((long) rootView.getPreferredSpan(View.Y_AXIS) + (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
return new Dimension((int) width, (int) height);
}
/**
* Gets the maximum size for the editor component.
*
* @param c the editor component
* @return the size
*/
public Dimension getMaximumSize(JComponent c) {
Insets i = c.getInsets();
long width = (rootView.getResizeWeight(View.X_AXIS) > 0) ? Integer.MAX_VALUE :
Math.min((long) rootView.getPreferredSpan(View.X_AXIS) + (long) i.left + (long) i.right, Integer.MAX_VALUE);
long height = (rootView.getResizeWeight(View.Y_AXIS) > 0) ? Integer.MAX_VALUE :
Math.min((long) rootView.getPreferredSpan(View.Y_AXIS) + (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
return new Dimension((int) width, (int) height);
}
// ---- TextUI methods -------------------------------------------
/**
* Gets the portion of the editor visibile on the screen.
*
* @return the bounding box for the visible portion
*/
protected Rectangle getVisibleEditorRect() {
Rectangle alloc = new Rectangle(editor.getSize());
Insets insets = editor.getInsets();
alloc.x += insets.left;
alloc.y += insets.top;
alloc.width -= insets.left + insets.right;
alloc.height -= insets.top + insets.bottom;
return alloc;
}
/**
* Converts the given location in the model to a place in
* the view coordinate system.
*
* @param pos the local location in the model to translate
* @return the coordinates as a rectangle
* @exception BadLocationException if the given position does not
* represent a valid location in the associated document
* @see TextUI#modelToView
*/
public Rectangle modelToView(int pos) throws BadLocationException {
if (painted) {
Rectangle alloc = getVisibleEditorRect();
Shape s = rootView.modelToView(pos, alloc);
return s.getBounds();
}
return null;
}
/**
* Converts the given place in the view coordinate system
* to the nearest representative location in the model.
*
* @param pt the location in the view to translate. This
* should be in the same coordinate system as the mouse events.
* @return the offset from the start of the document
* @see TextUI#viewToModel
*/
public int viewToModel(Point pt) {
if (painted) {
Rectangle alloc = getVisibleEditorRect();
return rootView.viewToModel(pt.x, pt.y, alloc);
}
return -1;
}
/**
* Causes the portion of the view responsible for the
* given part of the model to be repainted.
*
* @param p0 the beginning of the range
* @param p1 the end of the range
* @see TextUI#damageRange
*/
public void damageRange(int p0, int p1) {
if (painted) {
Rectangle alloc = getVisibleEditorRect();
try {
Shape s0 = rootView.modelToView(p0,alloc);
Shape s1 = rootView.modelToView(p1,alloc);
if (s0 != null && s1 != null) {
Rectangle r0 = s0.getBounds();
Rectangle r1 = s1.getBounds();
if (r0.y == r1.y) {
editor.repaint(r0.x, r0.y, r1.x - r0.x + 1, r0.height);
} else {
editor.repaint(alloc.x, r0.y, alloc.width, r1.y - r0.y + r1.height);
}
}
} catch (BadLocationException e) {}
}
}
/**
* Fetches the EditorKit for the UI.
*
* @return the editor capabilities
* @see TextUI#getEditorKit
*/
public EditorKit getEditorKit() {
return defaultKit;
}
/**
* Fetches a View with the allocation of the associated
* text component (ie the root of the hierarchy) that
* can be traversed to determine how the model is being
* represented spatially.
*
* @return the view
* @see TextUI#getRootView
*/
public View getRootView() {
return rootView;
}
/**
* Fetches the default margin space for the text ui.
*
* @return the margins
*/
public Insets getDefaultMargin() {
return new Insets(0,0,0,0);
}
// --- ViewFactory methods ------------------------------
/**
* Creates a view for an element.
* If a subclass wishes to directly implement the factory
* producing the view(s), it should reimplement this
* method. By default it simply returns null indicating
* it is unable to represent the element.
*
* @param elem the element
* @return the view
*/
public View create(Element elem) {
return null;
}
/**
* Creates a view for an element.
* If a subclass wishes to directly implement the factory
* producing the view(s), it should reimplement this
* method. By default it simply returns null indicating
* it is unable to represent the part of the element.
*
* @param elem the element
* @param p0 the starting offset
* @param p1 the ending offset
* @return the view
*/
public View create(Element elem, int p0, int p1) {
return null;
}
// --- serialization ---------------------------------------------
private void readObject(ObjectInputStream s)
throws ClassNotFoundException, IOException
{
s.defaultReadObject();
rootView = new RootView();
updateHandler = new UpdateHandler();
}
// ----- member variables ---------------------------------------
private static final EditorKit defaultKit = new DefaultEditorKit();
transient JTextComponent editor;
transient boolean painted;
transient RootView rootView = new RootView();
transient UpdateHandler updateHandler = new UpdateHandler();
/**
* Root view that acts as a gateway between the component
* and the View hierarchy.
*/
class RootView extends View {
RootView() {
super(null);
}
void setView(View v) {
if (view != null) {
// get rid of back reference so that the old
// hierarchy can be garbage collected.
view.setParent(null);
}
view = v;
if (view != null) {
view.setParent(this);
}
}
/**
* Determines the preferred span for this view along an axis.
*
* @param axis may be either X_AXIS or Y_AXIS
* @return the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
*/
public float getPreferredSpan(int axis) {
if (view != null) {
return view.getPreferredSpan(axis);
}
return 10;
}
/**
* Specifies that a preference has changed.
* Child views can call this on the parent to indicate that
* the preference has changed. The root view routes this to
* invalidate on the hosting component.
* <p>
* This can be called on a different thread from the
* event dispatching thread and is basically unsafe to
* propagate into the component. To make this safe,
* the operation is transferred over to the event dispatching
* thread for completion. It is a design goal that all view
* methods be safe to call without concern for concurrency,
* and this behavior helps make that true.
*
* @param child the child view
* @param width true if the width preference has changed
* @param height true if the height preference has changed
*/
public void preferenceChanged(View child, boolean width, boolean height) {
editor.revalidate();
}
/**
* Determines the desired alignment for this view along an axis.
*
* @param axis may be either X_AXIS or Y_AXIS
* @return the desired alignment, where 0.0 indicates the origin
* and 1.0 the full span away from the origin
*/
public float getAlignment(int axis) {
if (view != null) {
return view.getAlignment(axis);
}
return 0;
}
/**
* Renders the view.
*
* @param g the graphics context
* @param allocation the region to render into
*/
public void paint(Graphics g, Shape allocation) {
if (view != null) {
Rectangle alloc = allocation.getBounds();
view.setSize(alloc.width, alloc.height);
view.paint(g, allocation);
}
}
/**
* Sets the view parent.
*
* @param parent the parent view
*/
public void setParent(View parent) {
throw new StateInvariantError("Can't set parent on root view");
}
/**
* Returns the number of views in this view. Since
* this view simply wraps the root of the view hierarchy
* it has exactly one child.
*
* @return the number of views
* @see #getView
*/
public int getViewCount() {
return 1;
}
/**
* Gets the n-th view in this container.
*
* @param n the number of the view to get
* @return the view
*/
public View getView(int n) {
return view;
}
/**
* Fetches the allocation for the given child view.
* This enables finding out where various views
* are located, without assuming the views store
* their location. This returns the given allocation
* since this view simply acts as a gateway between
* the view hierarchy and the associated component.
*
* @param index the index of the child
* @param a the allocation to this view.
* @return the allocation to the child
*/
public Shape getChildAllocation(int index, Shape a) {
return a;
}
/**
* Provides a mapping from the document model coordinate space
* to the coordinate space of the view mapped to it.
*
* @param pos the position to convert
* @param a the allocated region to render into
* @return the bounding box of the given position
*/
public Shape modelToView(int pos, Shape a) throws BadLocationException {
if (view != null) {
return view.modelToView(pos, a);
}
return null;
}
/**
* Provides a mapping from the view coordinate space to the logical
* coordinate space of the model.
*
* @param x x coordinate of the view location to convert
* @param y y coordinate of the view location to convert
* @param a the allocated region to render into
* @return the location within the model that best represents the
* given point in the view
*/
public int viewToModel(float x, float y, Shape a) {
if (view != null) {
return view.viewToModel(x, y, a);
}
return -1;
}
/**
* Gives notification that something was inserted into the document
* in a location that this view is responsible for.
*
* @param e the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
*/
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
if (view != null) {
view.insertUpdate(e, a, f);
}
}
/**
* Gives notification that something was removed from the document
* in a location that this view is responsible for.
*
* @param e the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
*/
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
if (view != null) {
view.removeUpdate(e, a, f);
}
}
/**
* Gives notification from the document that attributes were changed
* in a location that this view is responsible for.
*
* @param e the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
*/
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
if (view != null) {
view.changedUpdate(e, a, f);
}
}
/**
* Returns the document model underlying the view.
*
* @return the model
*/
public Document getDocument() {
return editor.getDocument();
}
/**
* Returns the starting offset into the model for this view.
*
* @return the starting offset
*/
public int getStartOffset() {
if (view != null) {
return view.getStartOffset();
}
return getElement().getStartOffset();
}
/**
* Returns the ending offset into the model for this view.
*
* @return the ending offset
*/
public int getEndOffset() {
if (view != null) {
return view.getEndOffset();
}
return getElement().getEndOffset();
}
/**
* Gets the element that this view is mapped to.
*
* @return the view
*/
public Element getElement() {
if (view != null) {
return view.getElement();
}
return editor.getDocument().getDefaultRootElement();
}
/**
* Breaks this view on the given axis at the given length.
*
* @param axis may be either X_AXIS or Y_AXIS
* @param len specifies where a break is desired in the span
* @param the current allocation of the view
* @return the fragment of the view that represents the given span
* if the view can be broken, otherwise null
*/
public View breakView(int axis, float len, Shape a) {
throw new StateInvariantError("Can't break root view");
}
/**
* Determines the resizability of the view along the
* given axis. A value of 0 or less is not resizable.
*
* @param axis may be either X_AXIS or Y_AXIS
* @return the weight
*/
public int getResizeWeight(int axis) {
if (view != null) {
return view.getResizeWeight(axis);
}
return 0;
}
/**
* Sets the view size.
*
* @param width the width
* @param height the height
*/
public void setSize(float width, float height) {
if (view != null) {
view.setSize(width, height);
}
}
/**
* Fetches the container hosting the view. This is useful for
* things like scheduling a repaint, finding out the host
* components font, etc. The default implementation
* of this is to forward the query to the parent view.
*
* @return the container
*/
public Container getContainer() {
return editor;
}
/**
* Fetches the factory to be used for building the
* various view fragments that make up the view that
* represents the model. This is what determines
* how the model will be represented. This is implemented
* to fetch the factory provided by the associated
* EditorKit unless that is null, in which case this
* simply returns the DefaultTextUI itself which allows
* subclasses to implement a simple factory directly without
* creating extra objects.
*
* @return the factory
*/
public ViewFactory getViewFactory() {
EditorKit kit = getEditorKit();
ViewFactory f = kit.getViewFactory();
if (f != null) {
return f;
}
return DefaultTextUI.this;
}
private View view;
}
class SafePainter implements Runnable {
SafePainter(Graphics g) {
this.g = g;
}
/**
* Render the UI. This will be called by the
* associated model.
*/
public void run() {
paintSafely(g);
}
Graphics g;
}
/**
* Handles updates from various places. If the model is changed,
* this class unregisters as a listener to the old model and
* registers with the new model. If the document model changes,
* the change is forwarded to the root view. If the focus
* accelerator changes, a new keystroke is registered to request
* focus.
*/
class UpdateHandler implements PropertyChangeListener, DocumentListener {
// --- PropertyChangeListener methods -----------------------
/**
* This method gets called when a bound property is changed.
* We are looking for document changes on the editor.
*/
public final void propertyChange(PropertyChangeEvent evt) {
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
if ((oldValue instanceof Document) || (newValue instanceof Document)) {
if (oldValue != null) {
((Document)oldValue).removeDocumentListener(this);
}
if (newValue != null) {
((Document)newValue).addDocumentListener(this);
}
modelChanged();
}
DefaultTextUI.this.propertyChange(evt);
}
// --- DocumentListener methods -----------------------
/**
* The insert notification. Gets sent to the root of the view structure
* that represents the portion of the model being represented by the
* editor. The factory is added as an argument to the update so that
* the views can update themselves in a dynamic (not hardcoded) way.
*
* @param e The change notification from the currently associated
* document.
* @see DocumentListener#insertUpdate
*/
public final void insertUpdate(DocumentEvent e) {
Rectangle alloc = (painted) ? new Rectangle(editor.getSize()) : null;
rootView.insertUpdate(e, alloc, rootView.getViewFactory());
}
/**
* The remove notification. Gets sent to the root of the view structure
* that represents the portion of the model being represented by the
* editor. The factory is added as an argument to the update so that
* the views can update themselves in a dynamic (not hardcoded) way.
*
* @param e The change notification from the currently associated
* document.
* @see DocumentListener#removeUpdate
*/
public final void removeUpdate(DocumentEvent e) {
Rectangle alloc = (painted) ? new Rectangle(editor.getSize()) : null;
rootView.removeUpdate(e, alloc, rootView.getViewFactory());
}
/**
* The change notification. Gets sent to the root of the view structure
* that represents the portion of the model being represented by the
* editor. The factory is added as an argument to the update so that
* the views can update themselves in a dynamic (not hardcoded) way.
*
* @param e The change notification from the currently associated
* document.
* @see DocumentListener#changeUpdate
*/
public final void changedUpdate(DocumentEvent e) {
Rectangle alloc = (painted) ? new Rectangle(editor.getSize()) : null;
rootView.changedUpdate(e, alloc, rootView.getViewFactory());
}
}
}