001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: /*
042: *
043: * BaseTabLayoutModel.java
044: *
045: * Created on May 16, 2003, 4:22 PM
046: */
047:
048: package org.netbeans.swing.tabcontrol.plaf;
049:
050: import org.netbeans.swing.tabcontrol.TabDataModel;
051: import org.openide.awt.HtmlRenderer;
052:
053: import javax.swing.*;
054: import java.awt.*;
055: import java.util.HashMap;
056: import java.util.Map;
057:
058: /**
059: * Default implementation of TabLayoutModel. Simply provides a series of
060: * rectangles for each tab starting at 0 and ending at the last element, with
061: * the width set to the calculated width for the string plus a padding value
062: * assigned in <code>setPadding</code>.
063: * <p>
064: * To implement TabLayoutModel, it is often useful to create an implementation which
065: * wraps an instance of <code>DefaultTabLayoutModel</code>, and uses it to calculate
066: * tab sizes.
067: *
068: * <strong>Do not use this class directly, use DefaultTabLayoutModel - this class
069: * exists to enable unit tests to provide a subclass</strong>
070: *
071: * @author Tim Boudreau
072: */
073: class BaseTabLayoutModel implements TabLayoutModel {
074: protected TabDataModel model;
075: protected int textHeight = -1;
076: protected int padX = 5;
077: protected int padY = 5;
078: protected JComponent renderTarget;
079:
080: protected BaseTabLayoutModel(TabDataModel model,
081: JComponent renderTarget) {
082: this .model = model;
083: this .renderTarget = renderTarget;
084: }
085:
086: private Font getFont() {
087: return renderTarget.getFont();
088: }
089:
090: protected int iconWidth(int index) {
091: Icon ic = model.getTab(index).getIcon();
092: int result;
093: if (ic != null) {
094: result = ic.getIconWidth();
095: } else {
096: result = 0;
097: }
098: return result;
099: }
100:
101: protected int iconHeight(int index) {
102: Icon ic = model.getTab(index).getIcon();
103: int result;
104: if (ic != null) {
105: result = ic.getIconHeight();
106: } else {
107: result = 0;
108: }
109: return result;
110: }
111:
112: protected int textWidth(int index) {
113: try {
114: String text = model.getTab(index).getText();
115: return textWidth(text, getFont());
116: } catch (NullPointerException npe) {
117: IllegalArgumentException iae = new IllegalArgumentException(
118: "Error fetching width for tab "
119: + //NOI18N
120: index + " - model size is " + model.size()
121: + " TabData is "
122: + //NOI18N
123: model.getTab(index) + " model contents: "
124: + model); //NOI18N
125: throw iae;
126: }
127: }
128:
129: private static Map<String, Integer> widthMap = new HashMap<String, Integer>(
130: 31);
131:
132: static int textWidth(String text, Font f) {
133: //Note: If we choose to support multiple fonts in different
134: //tab controls in the system, make the cache non-static and
135: //dump it if the font changes.
136: Integer result = widthMap.get(text);
137: if (result == null) {
138: double wid = HtmlRenderer
139: .renderString(text, BasicScrollingTabDisplayerUI
140: .getOffscreenGraphics(), 0, 0,
141: Integer.MAX_VALUE, Integer.MAX_VALUE, f,
142: Color.BLACK, HtmlRenderer.STYLE_TRUNCATE,
143: false);
144: result = new Integer(Math.round(Math.round(wid)));
145: widthMap.put(text, result);
146: }
147: return result.intValue();
148: }
149:
150: protected int textHeight(int index) {
151: if (textHeight == -1) {
152: //No need to calculate for every string
153: String testStr = "Zgj"; //NOI18N
154: Font f = getFont();
155: textHeight = new Double(f.getStringBounds(
156: testStr,
157: BasicScrollingTabDisplayerUI.getOffscreenGraphics()
158: .getFontRenderContext()).getWidth())
159: .intValue() + 2;
160: }
161: return textHeight;
162: }
163:
164: public int getX(int index) {
165: int result = renderTarget.getInsets().left;
166: for (int i = 0; i < index; i++) {
167: result += getW(i);
168: }
169: return result;
170: }
171:
172: public int getY(int index) {
173: return renderTarget.getInsets().top;
174: }
175:
176: public int getH(int index) {
177: return Math.max(textHeight(index) + padY, model.getTab(index)
178: .getIcon().getIconHeight()
179: + padY);
180: }
181:
182: public int getW(int index) {
183: return textWidth(index) + iconWidth(index) + padX;
184: }
185:
186: public int indexOfPoint(int x, int y) {
187: int max = model.size();
188: int pos = renderTarget.getInsets().left;
189: for (int i = 0; i < max; i++) {
190: pos += getW(i);
191: if (pos > x) {
192: return i;
193: }
194: }
195: return -1;
196: }
197:
198: public int dropIndexOfPoint(int x, int y) {
199: Insets insets = renderTarget.getInsets();
200: int contentWidth = renderTarget.getWidth()
201: - (insets.left + insets.right);
202: int contentHeight = renderTarget.getHeight()
203: - (insets.bottom + insets.top);
204: if (y < insets.top || y > contentHeight || x < insets.left
205: || x > contentWidth) {
206: return -1;
207: }
208: int max = model.size();
209: int pos = insets.left;
210: for (int i = 0; i < max; i++) {
211: int delta = getW(i);
212: pos += delta;
213: if (x <= (pos - delta / 2)) {
214: return i;
215: } else if (x < pos) {
216: return i + 1;
217: }
218: }
219: return max;
220: }
221:
222: public void setPadding(Dimension d) {
223: padX = d.width;
224: padY = d.height;
225: }
226: }
|