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+ */
25+package javax.swing.text;
26+
27+import java.awt.*;
28+import java.beans.PropertyChangeEvent;
29+import java.beans.PropertyChangeListener;
30+import java.util.Set;
31+import javax.swing.SwingUtilities;
32+import 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+ */
70+public 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+}