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: package org.netbeans.swing.tabcontrol.plaf;
043:
044: import javax.swing.*;
045: import java.awt.*;
046: import java.util.ArrayList;
047: import javax.swing.event.ChangeEvent;
048: import javax.swing.event.ChangeListener;
049: import org.netbeans.swing.tabcontrol.TabDisplayer;
050: import org.netbeans.swing.tabcontrol.TabDataModel;
051: import org.openide.awt.HtmlRenderer;
052:
053: /**
054: * @author Dafe Simonek
055: */
056: final class ViewTabLayoutModel2 implements TabLayoutModel,
057: ChangeListener {
058:
059: private TabDisplayer displayer;
060:
061: private ViewTabLayoutModel2.PaddingInfo padding;
062:
063: private java.util.List<Integer> index2Pos;
064: private java.util.List<Integer> pos2Index;
065:
066: private int tabFixedWidth = -1;
067:
068: static final class PaddingInfo {
069: Dimension txtPad;
070: int txtIconsXPad;
071: int iconsXPad;
072: } // end of PaddingInfo
073:
074: /**
075: * Creates a new instance of ViewTabLayoutModel
076: */
077: public ViewTabLayoutModel2(TabDisplayer displayer,
078: PaddingInfo padding) {
079: this .displayer = displayer;
080: this .padding = padding;
081: updatePermutations();
082: displayer.getModel().addChangeListener(this );
083: }
084:
085: public int getH(int index) {
086: checkIndex(index);
087: Insets insets = displayer.getInsets();
088: return displayer.getHeight() - (insets.bottom + insets.top);
089: }
090:
091: public int getY(int index) {
092: checkIndex(index);
093: return displayer.getInsets().top;
094: }
095:
096: public int getW(int index) {
097: checkIndex(index);
098:
099: int tabPos = index2Pos.get(index);
100: return getXCoords()[tabPos] - getX(index);
101: }
102:
103: public int getX(int index) {
104: checkIndex(index);
105:
106: int tabPos = index2Pos.get(index);
107: return tabPos > 0 ? getXCoords()[tabPos - 1] : displayer
108: .getInsets().left;
109: }
110:
111: public int indexOfPoint(int x, int y) {
112: Insets insets = displayer.getInsets();
113: int contentWidth = displayer.getWidth()
114: - (insets.left + insets.right);
115: int contentHeight = displayer.getHeight()
116: - (insets.bottom + insets.top);
117: if (y < insets.top || y > contentHeight || x < insets.left
118: || x > contentWidth) {
119: return -1;
120: }
121: int size = displayer.getModel().size();
122: int diff;
123: int leftSide;
124: int[] tabsXCoordinates = getXCoords();
125: // go through tab positions
126: for (int i = 0; i < size; i++) {
127: if (tabsXCoordinates[i] > 0) {
128: leftSide = i > 0 ? tabsXCoordinates[i - 1]
129: : insets.left;
130: diff = x - leftSide;
131: if ((diff >= 0) && (diff < getW(i))) {
132: return pos2Index.get(i);
133: }
134: }
135: }
136: return -1;
137: }
138:
139: public int dropIndexOfPoint(int x, int y) {
140: Insets insets = displayer.getInsets();
141: int contentWidth = displayer.getWidth()
142: - (insets.left + insets.right);
143: int contentHeight = displayer.getHeight()
144: - (insets.bottom + insets.top);
145: if (y < insets.top || y > contentHeight || x < insets.left
146: || x > contentWidth) {
147: return -1;
148: }
149: // XXX - TBD
150: throw new UnsupportedOperationException(
151: "not implemenetd yet....");
152: /*
153: // can have rounding errors, not important here
154: int size = displayer.getModel().size();
155: float tabWidth = (float) contentWidth / (float) size;
156: // move in between tabs
157: x = x - insets.left + (int) tabWidth / 2;
158: int result = (int) (x / tabWidth);
159: return Math.min(result, displayer.getModel().size());*/
160: }
161:
162: public void setPadding(Dimension d) {
163: // do nothing
164: }
165:
166: /**
167: * Checks validity of given index
168: */
169: private void checkIndex(int index) {
170: int size = displayer.getModel().size();
171: if ((index < 0) || (index >= size)) {
172: throw new IllegalArgumentException(
173: "Index out of valid scope 0.." + (size - 1) + ": "
174: + index);
175: }
176: }
177:
178: private int[] getXCoords() {
179: TabDataModel model = displayer.getModel();
180: int size = model.size();
181: int[] tabsXCoord = new int[size];
182:
183: if (tabFixedWidth < 0) {
184: tabFixedWidth = padding.txtPad.width + padding.txtIconsXPad
185: + padding.iconsXPad;
186: }
187:
188: Insets dispInsets = displayer.getInsets();
189: double curX = dispInsets.left;
190: int maxRight = displayer.getWidth() - dispInsets.right;
191:
192: String curText;
193: int tabIndex;
194: Icon buttonIcon;
195: for (int i = 0; i < size; i++) {
196: tabIndex = pos2Index.get(i);
197: curText = model.getTab(tabIndex).getText();
198: curX += HtmlRenderer
199: .renderString(curText, BasicScrollingTabDisplayerUI
200: .getOffscreenGraphics(), 0, 0,
201: Integer.MAX_VALUE, Integer.MAX_VALUE,
202: displayer.getFont(), Color.BLACK,
203: HtmlRenderer.STYLE_TRUNCATE, false)
204: + tabFixedWidth;
205: if (tabIndex == displayer.getSelectionModel()
206: .getSelectedIndex()) {
207: // add icon sizes if any
208: buttonIcon = displayer.getUI().getButtonIcon(
209: TabControlButton.ID_CLOSE_BUTTON, tabIndex);
210: if (buttonIcon != null) {
211: curX += buttonIcon.getIconWidth();
212: }
213: buttonIcon = displayer.getUI().getButtonIcon(
214: TabControlButton.ID_PIN_BUTTON, tabIndex);
215: if (buttonIcon != null) {
216: curX += buttonIcon.getIconWidth();
217: }
218: }
219:
220: tabsXCoord[i] = Math.round(Math.round(curX));
221: if (curX > maxRight) {
222: break;
223: }
224: }
225:
226: return tabsXCoord;
227: }
228:
229: private void updatePermutations() {
230: int itemCount = displayer.getModel().size();
231: index2Pos = new ArrayList<Integer>(itemCount);
232: pos2Index = new ArrayList<Integer>(itemCount);
233: for (int i = 0; i < itemCount; i++) {
234: index2Pos.add(Integer.valueOf(itemCount - i - 1));
235: pos2Index.add(0, Integer.valueOf(i));
236: }
237: }
238:
239: public void stateChanged(ChangeEvent e) {
240: updatePermutations();
241: }
242:
243: }
|