1/*
2 * Copyright (c) 1997, 2014, 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.html;
26
27import java.util.Enumeration;
28import java.awt.*;
29import javax.swing.*;
30import javax.swing.border.*;
31import javax.swing.event.*;
32import javax.swing.text.*;
33
34/**
35 * A view implementation to display an unwrapped
36 * preformatted line.<p>
37 * This subclasses ParagraphView, but this really only contains one
38 * Row of text.
39 *
40 * @author  Timothy Prinzing
41 */
42class LineView extends ParagraphView {
43    /** Last place painted at. */
44    int tabBase;
45
46    /**
47     * Creates a LineView object.
48     *
49     * @param elem the element to wrap in a view
50     */
51    public LineView(Element elem) {
52        super(elem);
53    }
54
55    /**
56     * Preformatted lines are not suppressed if they
57     * have only whitespace, so they are always visible.
58     */
59    public boolean isVisible() {
60        return true;
61    }
62
63    /**
64     * Determines the minimum span for this view along an
65     * axis.  The preformatted line should refuse to be
66     * sized less than the preferred size.
67     *
68     * @param axis may be either <code>View.X_AXIS</code> or
69     *  <code>View.Y_AXIS</code>
70     * @return  the minimum span the view can be rendered into
71     * @see View#getPreferredSpan
72     */
73    public float getMinimumSpan(int axis) {
74        return getPreferredSpan(axis);
75    }
76
77    /**
78     * Gets the resize weight for the specified axis.
79     *
80     * @param axis may be either X_AXIS or Y_AXIS
81     * @return the weight
82     */
83    public int getResizeWeight(int axis) {
84        switch (axis) {
85        case View.X_AXIS:
86            return 1;
87        case View.Y_AXIS:
88            return 0;
89        default:
90            throw new IllegalArgumentException("Invalid axis: " + axis);
91        }
92    }
93
94    /**
95     * Gets the alignment for an axis.
96     *
97     * @param axis may be either X_AXIS or Y_AXIS
98     * @return the alignment
99     */
100    public float getAlignment(int axis) {
101        if (axis == View.X_AXIS) {
102            return 0;
103        }
104        return super.getAlignment(axis);
105    }
106
107    /**
108     * Lays out the children.  If the layout span has changed,
109     * the rows are rebuilt.  The superclass functionality
110     * is called after checking and possibly rebuilding the
111     * rows.  If the height has changed, the
112     * <code>preferenceChanged</code> method is called
113     * on the parent since the vertical preference is
114     * rigid.
115     *
116     * @param width  the width to lay out against >= 0.  This is
117     *   the width inside of the inset area.
118     * @param height the height to lay out against >= 0 (not used
119     *   by paragraph, but used by the superclass).  This
120     *   is the height inside of the inset area.
121     */
122    protected void layout(int width, int height) {
123        super.layout(Integer.MAX_VALUE - 1, height);
124    }
125
126    /**
127     * Returns the next tab stop position given a reference position.
128     * This view implements the tab coordinate system, and calls
129     * <code>getTabbedSpan</code> on the logical children in the process
130     * of layout to determine the desired span of the children.  The
131     * logical children can delegate their tab expansion upward to
132     * the paragraph which knows how to expand tabs.
133     * <code>LabelView</code> is an example of a view that delegates
134     * its tab expansion needs upward to the paragraph.
135     * <p>
136     * This is implemented to try and locate a <code>TabSet</code>
137     * in the paragraph element's attribute set.  If one can be
138     * found, its settings will be used, otherwise a default expansion
139     * will be provided.  The base location for tab expansion
140     * is the left inset from the paragraphs most recent allocation
141     * (which is what the layout of the children is based upon).
142     *
143     * @param x the X reference position
144     * @param tabOffset the position within the text stream
145     *   that the tab occurred at >= 0.
146     * @return the trailing end of the tab expansion >= 0
147     * @see TabSet
148     * @see TabStop
149     * @see LabelView
150     */
151    public float nextTabStop(float x, int tabOffset) {
152        // If the text isn't left justified, offset by 10 pixels!
153        if (getTabSet() == null &&
154            StyleConstants.getAlignment(getAttributes()) ==
155            StyleConstants.ALIGN_LEFT) {
156            return getPreTab(x, tabOffset);
157        }
158        return super.nextTabStop(x, tabOffset);
159    }
160
161    /**
162     * Returns the location for the tab.
163     */
164    @SuppressWarnings("deprecation")
165    protected float getPreTab(float x, int tabOffset) {
166        Document d = getDocument();
167        View v = getViewAtPosition(tabOffset, null);
168        if ((d instanceof StyledDocument) && v != null) {
169            // Assume f is fixed point.
170            Font f = ((StyledDocument)d).getFont(v.getAttributes());
171            Container c = getContainer();
172            FontMetrics fm = (c != null) ? c.getFontMetrics(f) :
173                Toolkit.getDefaultToolkit().getFontMetrics(f);
174            int width = getCharactersPerTab() * fm.charWidth('W');
175            int tb = (int)getTabBase();
176            return (float)((((int)x - tb) / width + 1) * width + tb);
177        }
178        return 10.0f + x;
179    }
180
181    /**
182     * @return number of characters per tab, 8.
183     */
184    protected int getCharactersPerTab() {
185        return 8;
186    }
187}
188