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: package org.openide.explorer.propertysheet;
042:
043: import java.awt.Color;
044: import java.awt.Component;
045: import java.awt.Dimension;
046: import java.awt.Font;
047: import java.awt.FontMetrics;
048: import java.awt.Graphics;
049: import java.awt.Insets;
050: import java.awt.Rectangle;
051: import java.awt.event.ComponentEvent;
052: import java.awt.event.ComponentListener;
053: import java.awt.event.ContainerEvent;
054: import java.awt.event.ContainerListener;
055:
056: import javax.swing.JComponent;
057: import javax.swing.JViewport;
058: import javax.swing.UIManager;
059: import javax.swing.plaf.ComponentUI;
060: import javax.swing.plaf.ViewportUI;
061: import javax.swing.plaf.basic.BasicViewportUI;
062:
063: /** Viewport UI which will paint a margin if the contained
064: * SheetTable is showing one, so the margin appears to continue
065: * down to the bottom of the component.
066: *
067: * @author Tim Boudreau
068: */
069: class MarginViewportUI extends ViewportUI implements ComponentListener,
070: ContainerListener {
071: private JViewport viewport;
072: private int lastHeight = -1;
073: private int stringWidth = -1;
074: private int stringHeight = -1;
075: private int ascent = -1;
076: Rectangle scratch = new Rectangle();
077: private String emptyString = "THIS IS A BUG"; //NOI18N
078: Color marginColor = UIManager.getColor("controlShadow"); //NOI18N
079: private int marginWidth = PropUtils.getMarginWidth();
080: private boolean marginPainted = false;
081: Dimension lastKnownSize = new Dimension();
082:
083: /** Creates a new instance of MarginViewportUI */
084: private MarginViewportUI(JViewport jv) {
085: this .viewport = jv;
086: }
087:
088: /** Uses a single shared instance, as does BasicViewportUI */
089: public static ComponentUI createUI(JComponent c) {
090: return new MarginViewportUI((JViewport) c);
091: }
092:
093: public void installUI(JComponent c) {
094: super .installUI(c);
095:
096: //Fetch the "no properties" string - it's not going to change
097: //for the life of the session
098: // noPropsString = NbBundle.getMessage(MarginViewportUI.class,
099: // "CTL_NoProperties"); //NOI18N
100: //Set an appropriate font and color. Only really relevant on OS-X to
101: //keep the font consistent with other NB fonts
102: Color fg = UIManager.getColor("controlShadow"); //NOI18N
103:
104: if (fg == null) {
105: fg = Color.LIGHT_GRAY;
106: }
107:
108: c.setForeground(fg);
109:
110: Color bg = UIManager.getColor("window"); //NOI18N
111:
112: if (bg == null) {
113: bg = Color.WHITE;
114: }
115:
116: c.setBackground(bg);
117:
118: Font f = UIManager.getFont("Tree.font"); //NOI18N
119:
120: if (f == null) {
121: f = UIManager.getFont("controlFont"); //NOI18N
122: }
123:
124: if (f != null) {
125: c.setFont(f);
126: }
127:
128: c.addContainerListener(this );
129:
130: Component[] kids = c.getComponents();
131:
132: for (int i = 0; i < kids.length; i++) {
133: //Should almost always be empty anyway, if not only one component,
134: //but for completeness...
135: kids[i].addComponentListener(this );
136: }
137: }
138:
139: public void uninstallUI(JComponent vp) {
140: JViewport jv = (JViewport) vp;
141: Component[] c = jv.getComponents();
142:
143: for (int i = 0; i < c.length; i++) {
144: c[i].removeComponentListener(this );
145: }
146:
147: jv.removeContainerListener(this );
148: }
149:
150: public void setEmptyString(String s) {
151: emptyString = s;
152: stringWidth = -1;
153: stringHeight = -1;
154: }
155:
156: public void setMarginColor(Color c) {
157: marginColor = c;
158: }
159:
160: public void setMarginWidth(int margin) {
161: this .marginWidth = margin;
162: }
163:
164: public void setMarginPainted(boolean val) {
165: if (marginPainted != val) {
166: marginPainted = val;
167: viewport.repaint();
168: }
169: }
170:
171: /** Overridden to draw "no properties" if necessary */
172: public void paint(Graphics g, JComponent c) {
173: Component view = ((JViewport) c).getView();
174:
175: if (view != null) {
176: lastKnownSize = view.getSize();
177: }
178:
179: if (stringWidth == -1) {
180: calcStringSizes(c.getFont(), g);
181: }
182:
183: //Update will have set paintNoProps to the correct value
184: if (shouldPaintEmptyMessage()) {
185: //We need to paint centered "<No Properties>" text
186: g.setFont(c.getFont());
187: g.setColor(c.getForeground());
188:
189: Rectangle r = getEmptyMessageBounds();
190:
191: //See if we really need to do any painting
192: if (g.hitClip(r.x, r.y, r.width, r.height)) {
193: //Paint the string
194: g.drawString(emptyString, r.x, r.y + ascent);
195: }
196: }
197: }
198:
199: private void calcStringSizes(Font f, Graphics g) {
200: FontMetrics fm = g.getFontMetrics(f);
201: stringWidth = fm.stringWidth(emptyString);
202: stringHeight = fm.getHeight();
203: ascent = fm.getMaxAscent();
204: }
205:
206: private Rectangle getEmptyMessageBounds() {
207: Insets ins = viewport.getInsets();
208:
209: scratch.x = ins.left
210: + (((viewport.getWidth() - (ins.left + ins.right)) / 2) - (stringWidth / 2));
211:
212: scratch.y = ins.top
213: + (((viewport.getHeight() - (ins.top + ins.bottom)) / 2) - (stringHeight / 2));
214:
215: scratch.width = stringWidth;
216: scratch.height = stringHeight;
217:
218: return scratch;
219: }
220:
221: public void update(Graphics g, JComponent c) {
222: g.setColor(c.getBackground());
223:
224: boolean margin = shouldPaintMargin();
225:
226: int leftEdge = margin ? marginWidth : 0;
227: g.fillRect(leftEdge, 0, c.getWidth() - leftEdge, c.getHeight());
228:
229: if (margin) {
230: g.setColor(marginColor);
231: g.fillRect(0, 0, marginWidth, c.getHeight());
232: }
233:
234: paint(g, c);
235: }
236:
237: private void scheduleRepaint(Dimension nuSize) {
238: if (!marginPainted
239: && ((nuSize.height > 10) == (lastKnownSize.height > 10))) {
240: // return;
241: }
242:
243: int heightDif = Math.abs(nuSize.height - lastKnownSize.height);
244:
245: if (heightDif == 0) {
246: // return;
247: }
248:
249: // if (heightDif != 0) {
250: Insets ins = viewport.getInsets();
251:
252: /*
253: int left = ins.left;
254: int top = nuSize.height + ins.top;
255: int width = marginWidth;
256: int height = lastKnownSize.height - nuSize.height;
257:
258: viewport.repaint (left, top, width, height);
259: */
260: viewport.repaint(ins.left, ins.top, marginWidth, viewport
261: .getHeight()
262: - (ins.top + ins.bottom));
263:
264: // }
265: // if (nuSize.height < 10) {
266: Rectangle r = getEmptyMessageBounds();
267: viewport.repaint(r.x, r.y, r.width, r.height);
268:
269: // }
270: }
271:
272: private boolean shouldPaintEmptyMessage() {
273: Dimension d = viewport.getView().getSize();
274:
275: return d.height < 10;
276: }
277:
278: private boolean shouldPaintMargin() {
279: return marginPainted & !shouldPaintEmptyMessage();
280: }
281:
282: public void componentAdded(ContainerEvent e) {
283: e.getChild().addComponentListener(this );
284: }
285:
286: public void componentHidden(ComponentEvent e) {
287: }
288:
289: public void componentMoved(ComponentEvent e) {
290: }
291:
292: public void componentRemoved(ContainerEvent e) {
293: e.getChild().removeComponentListener(this );
294: }
295:
296: public void componentResized(ComponentEvent e) {
297: scheduleRepaint(((Component) e.getSource()).getSize());
298: }
299:
300: public void componentShown(ComponentEvent e) {
301: scheduleRepaint(((Component) e.getSource()).getSize());
302: }
303: }
|