KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > ComponentView


1 /*
2  * @(#)ComponentView.java 1.54 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text;
8
9 import java.awt.*;
10 import javax.swing.SwingUtilities JavaDoc;
11 import javax.swing.event.*;
12
13 /**
14  * Component decorator that implements the view interface. The
15  * entire element is used to represent the component. This acts
16  * as a gateway from the display-only View implementations to
17  * interactive lightweight components (ie it allows components
18  * to be embedded into the View hierarchy).
19  * <p>
20  * The component is placed relative to the text baseline
21  * according to the value returned by
22  * <code>Component.getAlignmentY</code>. For Swing components
23  * this value can be conveniently set using the method
24  * <code>JComponent.setAlignmentY</code>. For example, setting
25  * a value of <code>0.75</code> will cause 75 percent of the
26  * component to be above the baseline, and 25 percent of the
27  * component to be below the baseline.
28  * <p>
29  * This class is implemented to do the extra work necessary to
30  * work properly in the presence of multiple threads (i.e. from
31  * asynchronous notification of model changes for example) by
32  * ensuring that all component access is done on the event thread.
33  * <p>
34  * The component used is determined by the return value of the
35  * createComponent method. The default implementation of this
36  * method is to return the component held as an attribute of
37  * the element (by calling StyleConstants.getComponent). A
38  * limitation of this behavior is that the component cannot
39  * be used by more than one text component (i.e. with a shared
40  * model). Subclasses can remove this constraint by implementing
41  * the createComponent to actually create a component based upon
42  * some kind of specification contained in the attributes. The
43  * ObjectView class in the html package is an example of a
44  * ComponentView implementation that supports multiple component
45  * views of a shared model.
46  *
47  * @author Timothy Prinzing
48  * @version 1.54 12/19/03
49  */

50 public class ComponentView extends View JavaDoc {
51
52     /**
53      * Creates a new ComponentView object.
54      *
55      * @param elem the element to decorate
56      */

57     public ComponentView(Element JavaDoc elem) {
58     super(elem);
59     }
60
61     /**
62      * Create the component that is associated with
63      * this view. This will be called when it has
64      * been determined that a new component is needed.
65      * This would result from a call to setParent or
66      * as a result of being notified that attributes
67      * have changed.
68      */

69     protected Component createComponent() {
70     AttributeSet JavaDoc attr = getElement().getAttributes();
71     Component comp = StyleConstants.getComponent(attr);
72     return comp;
73     }
74
75     /**
76      * Fetch the component associated with the view.
77      */

78     public final Component getComponent() {
79     return createdC;
80     }
81
82     // --- View methods ---------------------------------------------
83

84     /**
85      * The real paint behavior occurs naturally from the association
86      * that the component has with its parent container (the same
87      * container hosting this view). This is implemented to do nothing.
88      *
89      * @param g the graphics context
90      * @param a the shape
91      * @see View#paint
92      */

93     public void paint(Graphics g, Shape a) {
94     if (c != null) {
95         Rectangle alloc = (a instanceof Rectangle) ?
96         (Rectangle) a : a.getBounds();
97         c.setBounds(alloc.x, alloc.y, alloc.width, alloc.height);
98     }
99     }
100
101     /**
102      * Determines the preferred span for this view along an
103      * axis. This is implemented to return the value
104      * returned by Component.getPreferredSize along the
105      * axis of interest.
106      *
107      * @param axis may be either View.X_AXIS or View.Y_AXIS
108      * @return the span the view would like to be rendered into >= 0.
109      * Typically the view is told to render into the span
110      * that is returned, although there is no guarantee.
111      * The parent may choose to resize or break the view.
112      * @exception IllegalArgumentException for an invalid axis
113      */

114     public float getPreferredSpan(int axis) {
115     if ((axis != X_AXIS) && (axis != Y_AXIS)) {
116         throw new IllegalArgumentException JavaDoc("Invalid axis: " + axis);
117     }
118     if (c != null) {
119         Dimension size = c.getPreferredSize();
120         if (axis == View.X_AXIS) {
121         return size.width;
122         } else {
123         return size.height;
124         }
125     }
126     return 0;
127     }
128
129     /**
130      * Determines the minimum span for this view along an
131      * axis. This is implemented to return the value
132      * returned by Component.getMinimumSize along the
133      * axis of interest.
134      *
135      * @param axis may be either View.X_AXIS or View.Y_AXIS
136      * @return the span the view would like to be rendered into >= 0.
137      * Typically the view is told to render into the span
138      * that is returned, although there is no guarantee.
139      * The parent may choose to resize or break the view.
140      * @exception IllegalArgumentException for an invalid axis
141      */

142     public float getMinimumSpan(int axis) {
143     if ((axis != X_AXIS) && (axis != Y_AXIS)) {
144         throw new IllegalArgumentException JavaDoc("Invalid axis: " + axis);
145     }
146     if (c != null) {
147         Dimension size = c.getMinimumSize();
148         if (axis == View.X_AXIS) {
149         return size.width;
150         } else {
151         return size.height;
152         }
153     }
154     return 0;
155     }
156
157     /**
158      * Determines the maximum span for this view along an
159      * axis. This is implemented to return the value
160      * returned by Component.getMaximumSize along the
161      * axis of interest.
162      *
163      * @param axis may be either View.X_AXIS or View.Y_AXIS
164      * @return the span the view would like to be rendered into >= 0.
165      * Typically the view is told to render into the span
166      * that is returned, although there is no guarantee.
167      * The parent may choose to resize or break the view.
168      * @exception IllegalArgumentException for an invalid axis
169      */

170     public float getMaximumSpan(int axis) {
171     if ((axis != X_AXIS) && (axis != Y_AXIS)) {
172         throw new IllegalArgumentException JavaDoc("Invalid axis: " + axis);
173     }
174     if (c != null) {
175         Dimension size = c.getMaximumSize();
176         if (axis == View.X_AXIS) {
177         return size.width;
178         } else {
179         return size.height;
180         }
181     }
182     return 0;
183     }
184
185     /**
186      * Determines the desired alignment for this view along an
187      * axis. This is implemented to give the alignment of the
188      * embedded component.
189      *
190      * @param axis may be either View.X_AXIS or View.Y_AXIS
191      * @return the desired alignment. This should be a value
192      * between 0.0 and 1.0 where 0 indicates alignment at the
193      * origin and 1.0 indicates alignment to the full span
194      * away from the origin. An alignment of 0.5 would be the
195      * center of the view.
196      */

197     public float getAlignment(int axis) {
198     if (c != null) {
199         switch (axis) {
200         case View.X_AXIS:
201         return c.getAlignmentX();
202         case View.Y_AXIS:
203         return c.getAlignmentY();
204         }
205     }
206     return super.getAlignment(axis);
207     }
208
209     /**
210      * Sets the parent for a child view.
211      * The parent calls this on the child to tell it who its
212      * parent is, giving the view access to things like
213      * the hosting Container. The superclass behavior is
214      * executed, followed by a call to createComponent if
215      * the parent view parameter is non-null and a component
216      * has not yet been created. The embedded components parent
217      * is then set to the value returned by <code>getContainer</code>.
218      * If the parent view parameter is null, this view is being
219      * cleaned up, thus the component is removed from its parent.
220      * <p>
221      * The changing of the component hierarchy will
222      * touch the component lock, which is the one thing
223      * that is not safe from the View hierarchy. Therefore,
224      * this functionality is executed immediately if on the
225      * event thread, or is queued on the event queue if
226      * called from another thread (notification of change
227      * from an asynchronous update).
228      *
229      * @param p the parent
230      */

231     public void setParent(View JavaDoc p) {
232     super.setParent(p);
233         if (SwingUtilities.isEventDispatchThread()) {
234         setComponentParent();
235         } else {
236             Runnable JavaDoc callSetComponentParent = new Runnable JavaDoc() {
237                 public void run() {
238             Document JavaDoc doc = getDocument();
239             try {
240             if (doc instanceof AbstractDocument JavaDoc) {
241                 ((AbstractDocument JavaDoc)doc).readLock();
242             }
243             setComponentParent();
244             Container host = getContainer();
245             if (host != null) {
246                 preferenceChanged(null, true, true);
247                 host.repaint();
248             }
249             } finally {
250             if (doc instanceof AbstractDocument JavaDoc) {
251                 ((AbstractDocument JavaDoc)doc).readUnlock();
252             }
253             }
254                 }
255             };
256             SwingUtilities.invokeLater(callSetComponentParent);
257         }
258     }
259
260     /**
261      * Set the parent of the embedded component
262      * with assurance that it is thread-safe.
263      */

264     void setComponentParent() {
265     View JavaDoc p = getParent();
266     if (p != null) {
267         Container parent = getContainer();
268         if (parent != null) {
269         if (c == null) {
270             // try to build a component
271
Component comp = createComponent();
272             if (comp != null) {
273             createdC = comp;
274             c = new Invalidator(comp);
275             }
276         }
277         if (c != null) {
278             if (c.getParent() == null) {
279             // components associated with the View tree are added
280
// to the hosting container with the View as a constraint.
281
parent.add(c, this);
282             }
283         }
284         }
285     } else {
286             if (c != null) {
287                 Container parent = c.getParent();
288                 if (parent != null) {
289                     // remove the component from its hosting container
290
parent.remove(c);
291                 }
292             }
293         }
294     }
295
296     /**
297      * Provides a mapping from the coordinate space of the model to
298      * that of the view.
299      *
300      * @param pos the position to convert >= 0
301      * @param a the allocated region to render into
302      * @return the bounding box of the given position is returned
303      * @exception BadLocationException if the given position does not
304      * represent a valid location in the associated document
305      * @see View#modelToView
306      */

307     public Shape modelToView(int pos, Shape a, Position.Bias JavaDoc b) throws BadLocationException JavaDoc {
308     int p0 = getStartOffset();
309     int p1 = getEndOffset();
310     if ((pos >= p0) && (pos <= p1)) {
311         Rectangle r = a.getBounds();
312         if (pos == p1) {
313         r.x += r.width;
314         }
315         r.width = 0;
316         return r;
317     }
318     throw new BadLocationException JavaDoc(pos + " not in range " + p0 + "," + p1, pos);
319     }
320
321     /**
322      * Provides a mapping from the view coordinate space to the logical
323      * coordinate space of the model.
324      *
325      * @param x the X coordinate >= 0
326      * @param y the Y coordinate >= 0
327      * @param a the allocated region to render into
328      * @return the location within the model that best represents
329      * the given point in the view
330      * @see View#viewToModel
331      */

332     public int viewToModel(float x, float y, Shape a, Position.Bias JavaDoc[] bias) {
333     Rectangle alloc = (Rectangle) a;
334     if (x < alloc.x + (alloc.width / 2)) {
335         bias[0] = Position.Bias.Forward;
336         return getStartOffset();
337     }
338     bias[0] = Position.Bias.Backward;
339     return getEndOffset();
340     }
341
342     // --- member variables ------------------------------------------------
343

344     private Component createdC;
345     private Component c;
346
347     /**
348      * This class feeds the invalidate back to the
349      * hosting View. This is needed to get the View
350      * hierarchy to consider giving the component
351      * a different size (i.e. layout may have been
352      * cached between the associated view and the
353      * container hosting this component).
354      */

355     class Invalidator extends Container {
356
357         // NOTE: When we remove this class we are going to have to some
358
// how enforce setting of the focus traversal keys on the children
359
// so that they don't inherit them from the JEditorPane. We need
360
// to do this as JEditorPane has abnormal bindings (it is a focus cycle
361
// root) and the children typically don't want these bindings as well.
362

363     Invalidator(Component child) {
364         setLayout(null);
365         add(child);
366         cacheChildSizes();
367     }
368         
369     /**
370      * The components invalid layout needs
371      * to be propagated through the view hierarchy
372      * so the views (which position the component)
373      * can have their layout recomputed.
374      */

375     public void invalidate() {
376         super.invalidate();
377         if (getParent() != null) {
378         preferenceChanged(null, true, true);
379         }
380         }
381     
382     public void doLayout() {
383         cacheChildSizes();
384     }
385     
386     public void setBounds(int x, int y, int w, int h) {
387             super.setBounds(x, y, w, h);
388             if (getComponentCount() > 0) {
389                 getComponent(0).setSize(w, h);
390             }
391             cacheChildSizes();
392         }
393
394         public void validateIfNecessary() {
395         if (!isValid()) {
396         validate();
397          }
398     }
399
400     private void cacheChildSizes() {
401             if (getComponentCount() > 0) {
402                 Component child = getComponent(0);
403                 min = child.getMinimumSize();
404                 pref = child.getPreferredSize();
405                 max = child.getMaximumSize();
406                 yalign = child.getAlignmentY();
407                 xalign = child.getAlignmentX();
408             } else {
409                 min = pref = max = new Dimension(0, 0);
410             }
411         }
412         
413     /**
414      * Shows or hides this component depending on the value of parameter
415      * <code>b</code>.
416      * @param <code>b</code> If <code>true</code>, shows this component;
417      * otherwise, hides this component.
418      * @see #isVisible
419      * @since JDK1.1
420      */

421         public void setVisible(boolean b) {
422         super.setVisible(b);
423             if (getComponentCount() > 0) {
424                 getComponent(0).setVisible(b);
425             }
426         }
427         
428         /**
429          * Overridden to fix 4759054. Must return true so that content
430          * is painted when inside a CellRendererPane which is normally
431          * invisible.
432          */

433         public boolean isShowing() {
434             return true;
435         }
436
437         public Dimension getMinimumSize() {
438         validateIfNecessary();
439         return min;
440     }
441
442         public Dimension getPreferredSize() {
443         validateIfNecessary();
444         return pref;
445     }
446
447         public Dimension getMaximumSize() {
448         validateIfNecessary();
449         return max;
450     }
451
452     public float getAlignmentX() {
453         validateIfNecessary();
454         return xalign;
455     }
456
457     public float getAlignmentY() {
458         validateIfNecessary();
459         return yalign;
460     }
461
462         public java.util.Set JavaDoc getFocusTraversalKeys(int id) {
463             return KeyboardFocusManager.getCurrentKeyboardFocusManager().
464             getDefaultFocusTraversalKeys(id);
465         }
466
467     Dimension min;
468     Dimension pref;
469     Dimension max;
470     float yalign;
471     float xalign;
472
473     }
474
475 }
476
477
Popular Tags