History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/text/ComponentView.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/text/ComponentView.java+504−0
@@ -0,0 +1,504 @@
1/*
2 * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package javax.swing.text;
26
27import java.awt.*;
28import java.beans.PropertyChangeEvent;
29import java.beans.PropertyChangeListener;
30import java.util.Set;
31import javax.swing.SwingUtilities;
32import javax.swing.event.*;
33
34/**
35 * Component decorator that implements the view interface. The
36 * entire element is used to represent the component. This acts
37 * as a gateway from the display-only View implementations to
38 * interactive lightweight components (ie it allows components
39 * to be embedded into the View hierarchy).
40 * <p>
41 * The component is placed relative to the text baseline
42 * according to the value returned by
43 * <code>Component.getAlignmentY</code>. For Swing components
44 * this value can be conveniently set using the method
45 * <code>JComponent.setAlignmentY</code>. For example, setting
46 * a value of <code>0.75</code> will cause 75 percent of the
47 * component to be above the baseline, and 25 percent of the
48 * component to be below the baseline.
49 * <p>
50 * This class is implemented to do the extra work necessary to
51 * work properly in the presence of multiple threads (i.e. from
52 * asynchronous notification of model changes for example) by
53 * ensuring that all component access is done on the event thread.
54 * <p>
55 * The component used is determined by the return value of the
56 * createComponent method. The default implementation of this
57 * method is to return the component held as an attribute of
58 * the element (by calling StyleConstants.getComponent). A
59 * limitation of this behavior is that the component cannot
60 * be used by more than one text component (i.e. with a shared
61 * model). Subclasses can remove this constraint by implementing
62 * the createComponent to actually create a component based upon
63 * some kind of specification contained in the attributes. The
64 * ObjectView class in the html package is an example of a
65 * ComponentView implementation that supports multiple component
66 * views of a shared model.
67 *
68 * @author Timothy Prinzing
69 */
70public class ComponentView extends View {
71
72 /**
73 * Creates a new ComponentView object.
74 *
75 * @param elem the element to decorate
76 */
77 public ComponentView(Element elem) {
78 super(elem);
79 }
80
81 /**
82 * Create the component that is associated with
83 * this view. This will be called when it has
84 * been determined that a new component is needed.
85 * This would result from a call to setParent or
86 * as a result of being notified that attributes
87 * have changed.
88 */
89 protected Component createComponent() {
90 AttributeSet attr = getElement().getAttributes();
91 Component comp = StyleConstants.getComponent(attr);
92 return comp;
93 }
94
95 /**
96 * Fetch the component associated with the view.
97 */
98 public final Component getComponent() {
99 return createdC;
100 }
101
102 // --- View methods ---------------------------------------------
103
104 /**
105 * The real paint behavior occurs naturally from the association
106 * that the component has with its parent container (the same
107 * container hosting this view). This is implemented to do nothing.
108 *
109 * @param g the graphics context
110 * @param a the shape
111 * @see View#paint
112 */
113 public void paint(Graphics g, Shape a) {
114 if (c != null) {
115 Rectangle alloc = (a instanceof Rectangle) ?
116 (Rectangle) a : a.getBounds();
117 c.setBounds(alloc.x, alloc.y, alloc.width, alloc.height);
118 }
119 }
120
121 /**
122 * Determines the preferred span for this view along an
123 * axis. This is implemented to return the value
124 * returned by Component.getPreferredSize along the
125 * axis of interest.
126 *
127 * @param axis may be either View.X_AXIS or View.Y_AXIS
128 * @return the span the view would like to be rendered into >= 0.
129 * Typically the view is told to render into the span
130 * that is returned, although there is no guarantee.
131 * The parent may choose to resize or break the view.
132 * @exception IllegalArgumentException for an invalid axis
133 */
134 public float getPreferredSpan(int axis) {
135 if ((axis != X_AXIS) && (axis != Y_AXIS)) {
136 throw new IllegalArgumentException("Invalid axis: " + axis);
137 }
138 if (c != null) {
139 Dimension size = c.getPreferredSize();
140 if (axis == View.X_AXIS) {
141 return size.width;
142 } else {
143 return size.height;
144 }
145 }
146 return 0;
147 }
148
149 /**
150 * Determines the minimum span for this view along an
151 * axis. This is implemented to return the value
152 * returned by Component.getMinimumSize along the
153 * axis of interest.
154 *
155 * @param axis may be either View.X_AXIS or View.Y_AXIS
156 * @return the span the view would like to be rendered into >= 0.
157 * Typically the view is told to render into the span
158 * that is returned, although there is no guarantee.
159 * The parent may choose to resize or break the view.
160 * @exception IllegalArgumentException for an invalid axis
161 */
162 public float getMinimumSpan(int axis) {
163 if ((axis != X_AXIS) && (axis != Y_AXIS)) {
164 throw new IllegalArgumentException("Invalid axis: " + axis);
165 }
166 if (c != null) {
167 Dimension size = c.getMinimumSize();
168 if (axis == View.X_AXIS) {
169 return size.width;
170 } else {
171 return size.height;
172 }
173 }
174 return 0;
175 }
176
177 /**
178 * Determines the maximum span for this view along an
179 * axis. This is implemented to return the value
180 * returned by Component.getMaximumSize along the
181 * axis of interest.
182 *
183 * @param axis may be either View.X_AXIS or View.Y_AXIS
184 * @return the span the view would like to be rendered into >= 0.
185 * Typically the view is told to render into the span
186 * that is returned, although there is no guarantee.
187 * The parent may choose to resize or break the view.
188 * @exception IllegalArgumentException for an invalid axis
189 */
190 public float getMaximumSpan(int axis) {
191 if ((axis != X_AXIS) && (axis != Y_AXIS)) {
192 throw new IllegalArgumentException("Invalid axis: " + axis);
193 }
194 if (c != null) {
195 Dimension size = c.getMaximumSize();
196 if (axis == View.X_AXIS) {
197 return size.width;
198 } else {
199 return size.height;
200 }
201 }
202 return 0;
203 }
204
205 /**
206 * Determines the desired alignment for this view along an
207 * axis. This is implemented to give the alignment of the
208 * embedded component.
209 *
210 * @param axis may be either View.X_AXIS or View.Y_AXIS
211 * @return the desired alignment. This should be a value
212 * between 0.0 and 1.0 where 0 indicates alignment at the
213 * origin and 1.0 indicates alignment to the full span
214 * away from the origin. An alignment of 0.5 would be the
215 * center of the view.
216 */
217 public float getAlignment(int axis) {
218 if (c != null) {
219 switch (axis) {
220 case View.X_AXIS:
221 return c.getAlignmentX();
222 case View.Y_AXIS:
223 return c.getAlignmentY();
224 }
225 }
226 return super.getAlignment(axis);
227 }
228
229 /**
230 * Sets the parent for a child view.
231 * The parent calls this on the child to tell it who its
232 * parent is, giving the view access to things like
233 * the hosting Container. The superclass behavior is
234 * executed, followed by a call to createComponent if
235 * the parent view parameter is non-null and a component
236 * has not yet been created. The embedded components parent
237 * is then set to the value returned by <code>getContainer</code>.
238 * If the parent view parameter is null, this view is being
239 * cleaned up, thus the component is removed from its parent.
240 * <p>
241 * The changing of the component hierarchy will
242 * touch the component lock, which is the one thing
243 * that is not safe from the View hierarchy. Therefore,
244 * this functionality is executed immediately if on the
245 * event thread, or is queued on the event queue if
246 * called from another thread (notification of change
247 * from an asynchronous update).
248 *
249 * @param p the parent
250 */
251 public void setParent(View p) {
252 super.setParent(p);
253 if (SwingUtilities.isEventDispatchThread()) {
254 setComponentParent();
255 } else {
256 Runnable callSetComponentParent = new Runnable() {
257 public void run() {
258 Document doc = getDocument();
259 try {
260 if (doc instanceof AbstractDocument) {
261 ((AbstractDocument)doc).readLock();
262 }
263 setComponentParent();
264 Container host = getContainer();
265 if (host != null) {
266 preferenceChanged(null, true, true);
267 host.repaint();
268 }
269 } finally {
270 if (doc instanceof AbstractDocument) {
271 ((AbstractDocument)doc).readUnlock();
272 }
273 }
274 }
275 };
276 SwingUtilities.invokeLater(callSetComponentParent);
277 }
278 }
279
280 /**
281 * Set the parent of the embedded component
282 * with assurance that it is thread-safe.
283 */
284 void setComponentParent() {
285 View p = getParent();
286 if (p != null) {
287 Container parent = getContainer();
288 if (parent != null) {
289 if (c == null) {
290 // try to build a component
291 Component comp = createComponent();
292 if (comp != null) {
293 createdC = comp;
294 c = new Invalidator(comp);
295 }
296 }
297 if (c != null) {
298 if (c.getParent() == null) {
299 // components associated with the View tree are added
300 // to the hosting container with the View as a constraint.
301 parent.add(c, this);
302 parent.addPropertyChangeListener("enabled", c);
303 }
304 }
305 }
306 } else {
307 if (c != null) {
308 Container parent = c.getParent();
309 if (parent != null) {
310 // remove the component from its hosting container
311 parent.remove(c);
312 parent.removePropertyChangeListener("enabled", c);
313 }
314 }
315 }
316 }
317
318 /**
319 * Provides a mapping from the coordinate space of the model to
320 * that of the view.
321 *
322 * @param pos the position to convert >= 0
323 * @param a the allocated region to render into
324 * @return the bounding box of the given position is returned
325 * @exception BadLocationException if the given position does not
326 * represent a valid location in the associated document
327 * @see View#modelToView
328 */
329 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
330 int p0 = getStartOffset();
331 int p1 = getEndOffset();
332 if ((pos >= p0) && (pos <= p1)) {
333 Rectangle r = a.getBounds();
334 if (pos == p1) {
335 r.x += r.width;
336 }
337 r.width = 0;
338 return r;
339 }
340 throw new BadLocationException(pos + " not in range " + p0 + "," + p1, pos);
341 }
342
343 /**
344 * Provides a mapping from the view coordinate space to the logical
345 * coordinate space of the model.
346 *
347 * @param x the X coordinate >= 0
348 * @param y the Y coordinate >= 0
349 * @param a the allocated region to render into
350 * @return the location within the model that best represents
351 * the given point in the view
352 * @see View#viewToModel
353 */
354 public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
355 Rectangle alloc = (Rectangle) a;
356 if (x < alloc.x + (alloc.width / 2)) {
357 bias[0] = Position.Bias.Forward;
358 return getStartOffset();
359 }
360 bias[0] = Position.Bias.Backward;
361 return getEndOffset();
362 }
363
364 // --- member variables ------------------------------------------------
365
366 private Component createdC;
367 private Invalidator c;
368
369 /**
370 * This class feeds the invalidate back to the
371 * hosting View. This is needed to get the View
372 * hierarchy to consider giving the component
373 * a different size (i.e. layout may have been
374 * cached between the associated view and the
375 * container hosting this component).
376 */
377 class Invalidator extends Container implements PropertyChangeListener {
378
379 // NOTE: When we remove this class we are going to have to some
380 // how enforce setting of the focus traversal keys on the children
381 // so that they don't inherit them from the JEditorPane. We need
382 // to do this as JEditorPane has abnormal bindings (it is a focus cycle
383 // root) and the children typically don't want these bindings as well.
384
385 Invalidator(Component child) {
386 setLayout(null);
387 add(child);
388 cacheChildSizes();
389 }
390
391 /**
392 * The components invalid layout needs
393 * to be propagated through the view hierarchy
394 * so the views (which position the component)
395 * can have their layout recomputed.
396 */
397 public void invalidate() {
398 super.invalidate();
399 if (getParent() != null) {
400 preferenceChanged(null, true, true);
401 }
402 }
403
404 public void doLayout() {
405 cacheChildSizes();
406 }
407
408 public void setBounds(int x, int y, int w, int h) {
409 super.setBounds(x, y, w, h);
410 if (getComponentCount() > 0) {
411 getComponent(0).setSize(w, h);
412 }
413 cacheChildSizes();
414 }
415
416 public void validateIfNecessary() {
417 if (!isValid()) {
418 validate();
419 }
420 }
421
422 private void cacheChildSizes() {
423 if (getComponentCount() > 0) {
424 Component child = getComponent(0);
425 min = child.getMinimumSize();
426 pref = child.getPreferredSize();
427 max = child.getMaximumSize();
428 yalign = child.getAlignmentY();
429 xalign = child.getAlignmentX();
430 } else {
431 min = pref = max = new Dimension(0, 0);
432 }
433 }
434
435 /**
436 * Shows or hides this component depending on the value of parameter
437 * <code>b</code>.
438 * @param b If <code>true</code>, shows this component;
439 * otherwise, hides this component.
440 * @see #isVisible
441 * @since JDK1.1
442 */
443 public void setVisible(boolean b) {
444 super.setVisible(b);
445 if (getComponentCount() > 0) {
446 getComponent(0).setVisible(b);
447 }
448 }
449
450 /**
451 * Overridden to fix 4759054. Must return true so that content
452 * is painted when inside a CellRendererPane which is normally
453 * invisible.
454 */
455 public boolean isShowing() {
456 return true;
457 }
458
459 public Dimension getMinimumSize() {
460 validateIfNecessary();
461 return min;
462 }
463
464 public Dimension getPreferredSize() {
465 validateIfNecessary();
466 return pref;
467 }
468
469 public Dimension getMaximumSize() {
470 validateIfNecessary();
471 return max;
472 }
473
474 public float getAlignmentX() {
475 validateIfNecessary();
476 return xalign;
477 }
478
479 public float getAlignmentY() {
480 validateIfNecessary();
481 return yalign;
482 }
483
484 public Set<AWTKeyStroke> getFocusTraversalKeys(int id) {
485 return KeyboardFocusManager.getCurrentKeyboardFocusManager().
486 getDefaultFocusTraversalKeys(id);
487 }
488
489 public void propertyChange(PropertyChangeEvent ev) {
490 Boolean enable = (Boolean) ev.getNewValue();
491 if (getComponentCount() > 0) {
492 getComponent(0).setEnabled(enable);
493 }
494 }
495
496 Dimension min;
497 Dimension pref;
498 Dimension max;
499 float yalign;
500 float xalign;
501
502 }
503
504}