001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.awt.Graphics;
023: import java.awt.Rectangle;
024: import java.awt.Shape;
025: import javax.swing.event.DocumentEvent;
026: import javax.swing.text.Position.Bias;
027:
028: /**
029: * This is utility class to manage child view creation.
030: *
031: */
032: public final class ViewTestHelpers {
033: private ViewTestHelpers() {
034: }
035:
036: /**
037: * Default child view height.
038: */
039: private static final int HEIGHT = 16;
040:
041: /**
042: * Default child view width.
043: */
044: private static final int WIDTH = 25;
045:
046: /**
047: * Width multipliers to change the default width.
048: */
049: private static final int[] WIDTH_MULTIPLIER = new int[] { 1, 3, 4,
050: 2 };
051:
052: /**
053: * Height multipliers to change the default height.
054: */
055: private static final int[] HEIGHT_MULTIPLIER = new int[] { 2, 1, 3,
056: 1 };
057:
058: /**
059: * Alignments for children to change the default alignment (center = 0.5).
060: */
061: private static final float[] ALIGNMENT = new float[] { 0.0f, 0.25f,
062: 1.0f, 0.5f };
063:
064: /**
065: * One character width. It is used in model/view translations.
066: */
067: public static final int POS = 4;
068:
069: /**
070: * Returns the width of the child. It uses multipliers to change widths of
071: * children where applicable.
072: *
073: * @param id child number (index)
074: * @return the child width
075: */
076: public static int getWidth(final int id) {
077: return 0 <= id && id < WIDTH_MULTIPLIER.length ? WIDTH
078: * WIDTH_MULTIPLIER[id] : WIDTH;
079: }
080:
081: /**
082: * Returns the height of the child. It uses multipliers to change heights
083: * of children where applicable.
084: *
085: * @param id child number (index)
086: * @return the child height
087: */
088: public static int getHeight(final int id) {
089: return 0 <= id && id < HEIGHT_MULTIPLIER.length ? HEIGHT
090: * HEIGHT_MULTIPLIER[id] : HEIGHT;
091: }
092:
093: /**
094: * Returns child desired alignment. It uses <code>ALIGNMENT</code> array
095: * where possible.
096: *
097: * @param axis axis along which alignment is requested (current unused)
098: * @param id child number (index)
099: * @return the child alignment
100: */
101: public static float getAlign(final int axis, final int id) {
102: return 0 <= id && id < ALIGNMENT.length ? ALIGNMENT[id] : 0.5f;
103: }
104:
105: /**
106: * Represents children of the main view. Methods are implemented so that
107: * the behavior is predictable.
108: */
109: public static class ChildView extends View {
110: private final int id;
111:
112: public ChildView(final Element element, final int ID) {
113: super (element);
114: id = ID;
115: }
116:
117: @Override
118: public float getPreferredSpan(final int axis) {
119: return axis == X_AXIS ? getWidth(id) : getHeight(id);
120: }
121:
122: public int getID() {
123: return id;
124: }
125:
126: @Override
127: public Shape modelToView(final int pos, final Shape shape,
128: final Bias bias) throws BadLocationException {
129: Rectangle bounds = shape.getBounds();
130: bounds.x += (pos - getStartOffset()) * POS;
131: bounds.width = 1;
132: bounds.height = (int) getPreferredSpan(Y_AXIS);
133: return bounds;
134: }
135:
136: @Override
137: public void paint(final Graphics g, final Shape shape) {
138: }
139:
140: @Override
141: public int viewToModel(final float x, final float y,
142: final Shape shape, final Bias[] biasReturn) {
143: // We don't set biasReturn to a value
144: return (getStartOffset() + (int) (x - shape.getBounds().x)
145: / POS);
146: }
147:
148: @Override
149: public float getAlignment(final int axis) {
150: return getAlign(axis, id);
151: }
152:
153: @Override
154: public void insertUpdate(final DocumentEvent event,
155: final Shape shape, final ViewFactory factory) {
156: preferenceChanged(this , true, true);
157: super .insertUpdate(event, shape, factory);
158: }
159: }
160:
161: /**
162: * Represents children of the main view when <code>flexibleChildren</code>
163: * is set to <code>true</code>. The only difference between
164: * <code>ChildView</code> and this class (<code>FlexibleChildView</code>)
165: * is this class returns different values for its size preferences:
166: * minimum span, maximum and preferred. Its <code>getResizeWeight</code>
167: * also returns positive value, so that views are considered resizable.
168: */
169: public static class FlexibleChildView extends ChildView {
170: public FlexibleChildView(final Element element, final int ID) {
171: super (element, ID);
172: }
173:
174: private static final float[] min = new float[] { 0.25f, 1.0f,
175: 0.5f };
176:
177: private static final float[] max = new float[] { 5.0f, 4.0f,
178: 15.0f };
179:
180: @Override
181: public float getMaximumSpan(final int axis) {
182: float result;
183: if (getID() < max.length) {
184: result = max[getID()]
185: * (axis == X_AXIS ? WIDTH : HEIGHT);
186: } else {
187: result = super .getMaximumSpan(axis);
188: }
189: return result;
190: }
191:
192: @Override
193: public float getMinimumSpan(final int axis) {
194: float result;
195: if (getID() < min.length) {
196: result = min[getID()]
197: * (axis == X_AXIS ? WIDTH : HEIGHT);
198: } else {
199: result = super .getMinimumSpan(axis);
200: }
201: return result;
202: }
203:
204: @Override
205: public int getResizeWeight(final int axis) {
206: int id = getID();
207: if (id < min.length) {
208: int result = (int) ((axis == X_AXIS ? WIDTH : HEIGHT) * (max[id] - min[id]));
209: return result;
210: }
211: return super .getResizeWeight(axis);
212: }
213: }
214:
215: /**
216: * Represents a child view which responsible for rendering of a portion
217: * of the element but not the entire element.
218: */
219: public static class ElementPartView extends ChildView {
220: private final Position start;
221:
222: private final Position end;
223:
224: public ElementPartView(final Element element,
225: final int startOffset, final int endOffset) {
226: super (element, -1);
227: start = createPosition(startOffset);
228: end = createPosition(endOffset);
229: }
230:
231: @Override
232: public int getStartOffset() {
233: return start.getOffset();
234: }
235:
236: @Override
237: public int getEndOffset() {
238: return end.getOffset();
239: }
240:
241: private Position createPosition(final int offset) {
242: Position result = null;
243: try {
244: result = getDocument().createPosition(offset);
245: } catch (BadLocationException e) {
246: e.printStackTrace();
247: }
248: return result;
249: }
250: }
251:
252: /**
253: * Represents view factory to create children
254: * of type <code>ChildView</code>.
255: */
256: public static class ChildrenFactory implements ViewFactory {
257: /**
258: * Determins the ID of the next child created.
259: */
260: private int count = 0;
261:
262: /**
263: * Determins which type of children this factory returns.
264: * By default it returns ordinary children.
265: */
266: private boolean flexibleChildren = false;
267:
268: /**
269: * Creates child views. The type of
270: * the returned view depends on the state of
271: * <code>flexibleChildren</code> flag.
272: */
273: public View create(final Element element) {
274: if (flexibleChildren) {
275: return new FlexibleChildView(element, count++);
276: }
277: return new ChildView(element, count++);
278: }
279:
280: /**
281: * Resets ID counter. The next view created will get id == 0.
282: */
283: public void resetID() {
284: count = 0;
285: }
286:
287: /**
288: * Sets <code>flexibleChildren</code> to <code>true</code> and
289: * resets the ID counter.
290: */
291: public void makeFlexible() {
292: flexibleChildren = true;
293: resetID();
294: }
295: }
296:
297: private static final String text = "javax.swing.text.";
298:
299: private static final String plaf = "javax.swing.plaf.basic.";
300:
301: public static String getViewShortClassName(final View view) {
302: String result = view.getClass().getName();
303: if (result.startsWith(text)) {
304: result = result.substring(text.length());
305: } else if (result.startsWith(plaf)) {
306: result = result.substring(plaf.length());
307: }
308: return result;
309: }
310: }
|