001: /*
002: * Copyright (C) 2004 NNL Technology AB
003: * Visit www.infonode.net for information about InfoNode(R)
004: * products and how to contact NNL Technology AB.
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
019: * MA 02111-1307, USA.
020: */
021:
022: // $Id: LookAndFeelDockingTheme.java,v 1.21 2007/01/28 21:25:10 jesper Exp $
023: package net.infonode.docking.theme;
024:
025: import net.infonode.docking.properties.RootWindowProperties;
026: import net.infonode.docking.properties.ViewTitleBarProperties;
027: import net.infonode.docking.properties.WindowBarProperties;
028: import net.infonode.docking.theme.internal.laftheme.TitleBarUI;
029: import net.infonode.docking.theme.internal.laftheme.TitleBarUIListener;
030: import net.infonode.gui.InsetsUtil;
031: import net.infonode.gui.colorprovider.BackgroundColorProvider;
032: import net.infonode.gui.componentpainter.ComponentPainter;
033: import net.infonode.gui.componentpainter.CompoundComponentPainter;
034: import net.infonode.gui.componentpainter.SolidColorComponentPainter;
035: import net.infonode.properties.gui.util.ComponentProperties;
036: import net.infonode.properties.gui.util.ShapedPanelProperties;
037: import net.infonode.properties.propertymap.PropertyMapManager;
038: import net.infonode.tabbedpanel.TabbedUtils;
039: import net.infonode.tabbedpanel.theme.LookAndFeelTheme;
040: import net.infonode.tabbedpanel.titledtab.TitledTabSizePolicy;
041: import net.infonode.util.Direction;
042:
043: import javax.swing.border.Border;
044: import java.awt.*;
045:
046: /**
047: * <p>
048: * An <strong>experimental</strong> theme that tries to replicate the look of
049: * the active look and feel. This may or may not work depending on the look and
050: * feel used.
051: * </p>
052: *
053: * <p>
054: * This is a theme that tries to replicate the look using the active look and
055: * feel. The tab windows will resemble the JTabbedPane look and the view title
056: * bars will resemble the JInternalFrame's title bar. Note that vertical title
057: * bars might not look very nice. The theme uses heavyweight AWT components
058: * internally so the {@link #dispose()} method must be called when the theme is
059: * no longer needed, otherwise the native resources will not be disposed.
060: * </p>
061: *
062: * <p>
063: * The theme uses the hover mechanism so that tab hover effects can be
064: * replicated. Only title bars above or below the view's content are supported.
065: * </p>
066: *
067: * <p>
068: * <strong>This theme is considered to be experimental and is not guaranteed to
069: * be an exact replica of the active look and feel. It is also not guaranteed to
070: * work together with the active look and feel. The theme may be changed,
071: * removed etc in future versions. No support is given for the theme. This theme
072: * doesn't work well with Aqua Look and Feel on Macintosh.</strong>
073: * </p>
074: *
075: * @author johan
076: * @version $Revision: 1.21 $
077: * @see net.infonode.tabbedpanel.theme.LookAndFeelTheme
078: * @since IDW 1.4.0
079: */
080: public class LookAndFeelDockingTheme extends DockingWindowsTheme {
081:
082: private static LookAndFeelTheme tpTheme;
083:
084: private static RootWindowProperties rootProps = new RootWindowProperties();
085:
086: private RootWindowProperties themeRootProps = new RootWindowProperties();
087:
088: private static TitleBarUI titleBarUI;
089:
090: private static int themeCounter = 0;
091:
092: private boolean disposed = false;
093:
094: public LookAndFeelDockingTheme() {
095: if (themeCounter == 0) {
096: tpTheme = new LookAndFeelTheme();
097:
098: titleBarUI = new TitleBarUI(new TitleBarUIListener() {
099: public void updating() {
100: }
101:
102: public void updated() {
103: initTheme(false);
104: }
105: }, false);
106:
107: titleBarUI.init();
108:
109: initTheme(true);
110: }
111:
112: themeCounter++;
113:
114: themeRootProps.addSuperObject(rootProps);
115: }
116:
117: /**
118: * Gets the theme name
119: *
120: * @return name
121: */
122: public String getName() {
123: return "Look and Feel Theme";
124: }
125:
126: /**
127: * Gets the theme RootWindowProperties
128: *
129: * @return the RootWindowProperties
130: */
131: public RootWindowProperties getRootWindowProperties() {
132: return themeRootProps;
133: }
134:
135: /**
136: * <p>
137: * Disposes this theme.
138: * </p>
139: *
140: * <p>
141: * This method must be called in order to dispose the heavyweight AWT
142: * components used internally.
143: * </p>
144: */
145: public void dispose() {
146: if (!disposed) {
147: disposed = true;
148:
149: themeCounter--;
150:
151: if (themeCounter == 0) {
152: titleBarUI.dispose();
153:
154: PropertyMapManager.runBatch(new Runnable() {
155: public void run() {
156: rootProps
157: .getTabWindowProperties()
158: .getTabbedPanelProperties()
159: .removeSuperObject(
160: tpTheme
161: .getTabbedPanelProperties());
162: rootProps
163: .getTabWindowProperties()
164: .getTabProperties()
165: .getTitledTabProperties()
166: .removeSuperObject(
167: tpTheme
168: .getTitledTabProperties());
169: rootProps.getMap().clear(true);
170: }
171: });
172:
173: tpTheme.dispose();
174: }
175: }
176: }
177:
178: private void initTheme(final boolean initial) {
179: PropertyMapManager.runBatch(new Runnable() {
180: public void run() {
181: if (initial) {
182: rootProps.getTabWindowProperties()
183: .getTabbedPanelProperties().addSuperObject(
184: tpTheme.getTabbedPanelProperties());
185: rootProps.getTabWindowProperties()
186: .getTabProperties()
187: .getTitledTabProperties().addSuperObject(
188: tpTheme.getTitledTabProperties());
189: }
190:
191: rootProps.getMap().clear(true);
192:
193: {
194: // Window bar
195: WindowBarProperties barProps = rootProps
196: .getWindowBarProperties();
197: // barProps.setContinuousLayoutEnabled(false);
198: barProps.getTabWindowProperties()
199: .getTabProperties()
200: .getTitledTabProperties().setSizePolicy(
201: TitledTabSizePolicy.EQUAL_SIZE);
202: barProps.getComponentProperties().setBorder(null);
203:
204: final Border contentBorder = tpTheme
205: .getTabbedPanelProperties()
206: .getContentPanelProperties()
207: .getComponentProperties().getBorder();
208:
209: ComponentPainter barContentPainter = tpTheme
210: .getTabbedPanelProperties()
211: .getContentPanelProperties()
212: .getShapedPanelProperties()
213: .getComponentPainter();
214: barProps
215: .getTabWindowProperties()
216: .getTabbedPanelProperties()
217: .getContentPanelProperties()
218: .getShapedPanelProperties()
219: .setOpaque(true)
220: .setComponentPainter(
221: new CompoundComponentPainter(
222: new SolidColorComponentPainter(
223: BackgroundColorProvider.INSTANCE),
224: barContentPainter));
225:
226: barProps.getTabWindowProperties()
227: .getTabbedPanelProperties()
228: .getTabAreaComponentsProperties()
229: .getComponentProperties().setBorder(null);
230: barProps
231: .getTabWindowProperties()
232: .getTabbedPanelProperties()
233: .getContentPanelProperties()
234: .getComponentProperties()
235: .setBorder(new Border() {
236: public void paintBorder(Component c,
237: Graphics g, int x, int y,
238: int width, int height) {
239: }
240:
241: public Insets getBorderInsets(
242: Component c) {
243: Insets insets = (Insets) contentBorder
244: .getBorderInsets(c).clone();
245:
246: Direction areaOrientation = TabbedUtils
247: .getParentTabbedPanelContentPanel(
248: c).getTabbedPanel()
249: .getProperties()
250: .getTabAreaOrientation();
251: int minResizeEdgeInset = InsetsUtil
252: .maxInset(insets);
253:
254: if (areaOrientation == Direction.UP)
255: insets.bottom = Math.max(
256: minResizeEdgeInset,
257: insets.bottom);
258: else if (areaOrientation == Direction.DOWN)
259: insets.top = Math.max(
260: minResizeEdgeInset,
261: insets.top);
262: else if (areaOrientation == Direction.LEFT)
263: insets.right = Math.max(
264: minResizeEdgeInset,
265: insets.right);
266: else
267: insets.left = Math.max(
268: minResizeEdgeInset,
269: insets.left);
270:
271: return insets;
272: }
273:
274: public boolean isBorderOpaque() {
275: return false;
276: }
277: })
278: .setInsets(new Insets(0, 0, 0, 0))
279: .setBackgroundColor(null);
280: }
281:
282: {
283: // Window area
284: final Color top = tpTheme
285: .getBorderColor(Direction.UP);
286: final Color left = tpTheme
287: .getBorderColor(Direction.LEFT);
288: final Color bottom = tpTheme
289: .getBorderColor(Direction.DOWN);
290: final Color right = tpTheme
291: .getBorderColor(Direction.RIGHT);
292:
293: final Insets borderInsets = new Insets(
294: top == null ? 0 : 1, left == null ? 0 : 1,
295: bottom == null ? 0 : 1, right == null ? 0
296: : 1);
297: final boolean borderOpaque = (top != null && top
298: .getAlpha() == 255)
299: || (left != null && left.getAlpha() == 255)
300: || (bottom != null && bottom.getAlpha() == 255)
301: || (right != null && right.getAlpha() == 255);
302:
303: final Border windowAreaBorder = new Border() {
304: public void paintBorder(Component c,
305: Graphics g, int x, int y, int width,
306: int height) {
307: if (top != null) {
308: g.setColor(top);
309: g.drawLine(x, y, x + width
310: - (right == null ? 1 : 2), y);
311: }
312:
313: if (right != null) {
314: g.setColor(right);
315: g.drawLine(x + width - 1, y, x + width
316: - 1, y + height
317: - (bottom == null ? 1 : 2));
318: }
319:
320: if (bottom != null) {
321: g.setColor(bottom);
322: g.drawLine(left == null ? x : x + 1, y
323: + height - 1, x + width - 1, y
324: + height - 1);
325: }
326:
327: if (left != null) {
328: g.setColor(left);
329: g.drawLine(x, top == null ? y : y + 1,
330: x, y + height - 1);
331: }
332: }
333:
334: public Insets getBorderInsets(Component c) {
335: return borderInsets;
336: }
337:
338: public boolean isBorderOpaque() {
339: return borderOpaque;
340: }
341: };
342:
343: rootProps.getWindowAreaProperties().setInsets(
344: new Insets(2, 2, 2, 2)).setBorder(
345: windowAreaBorder).setBackgroundColor(null);
346: rootProps
347: .getWindowAreaShapedPanelProperties()
348: .setComponentPainter(
349: new SolidColorComponentPainter(
350: BackgroundColorProvider.INSTANCE))
351: .setOpaque(true);
352: }
353:
354: {
355: // View title bar
356: ViewTitleBarProperties titleBarProps = rootProps
357: .getViewProperties()
358: .getViewTitleBarProperties();
359: titleBarProps.getNormalProperties()
360: .getShapedPanelProperties().setDirection(
361: titleBarUI.getRenderingDirection());
362:
363: // Normal painter
364: ComponentPainter normalPainter = titleBarUI
365: .getInactiveComponentPainter();
366: if (normalPainter == null)
367: titleBarProps
368: .getNormalProperties()
369: .getShapedPanelProperties()
370: .getMap()
371: .removeValue(
372: ShapedPanelProperties.COMPONENT_PAINTER);
373: else
374: titleBarProps.getNormalProperties()
375: .getShapedPanelProperties()
376: .setComponentPainter(normalPainter);
377:
378: // Focused painter
379: ComponentPainter focusedPainter = titleBarUI
380: .getActiveComponentPainter();
381: if (focusedPainter == null)
382: titleBarProps
383: .getFocusedProperties()
384: .getShapedPanelProperties()
385: .getMap()
386: .removeValue(
387: ShapedPanelProperties.COMPONENT_PAINTER);
388: else
389: titleBarProps.getFocusedProperties()
390: .getShapedPanelProperties()
391: .setComponentPainter(focusedPainter);
392:
393: titleBarProps.setMinimumSizeProvider(
394: titleBarUI.getSizeDimensionProvider())
395: .getNormalProperties().setTitleVisible(
396: !titleBarUI.isRenderingTitle())
397: .setIconVisible(
398: !titleBarUI.isRenderingIcon());
399:
400: titleBarProps.getFocusedProperties()
401: .getComponentProperties().setInsets(
402: titleBarUI.getInsets());
403: titleBarProps.getNormalProperties()
404: .getComponentProperties().setInsets(
405: titleBarUI.getInsets());
406:
407: // Background colors
408: updateBackgroundColor(titleBarProps
409: .getNormalProperties()
410: .getComponentProperties(), titleBarUI
411: .getInactiveBackgroundColor());
412: updateBackgroundColor(titleBarProps
413: .getFocusedProperties()
414: .getComponentProperties(), titleBarUI
415: .getActiveBackgroundColor());
416: }
417:
418: {
419: // General
420: rootProps.setDragRectangleBorderWidth(3);
421: }
422: }
423: });
424: }
425:
426: private void updateBackgroundColor(ComponentProperties props,
427: Color color) {
428: if (color == null)
429: props.getMap().removeValue(
430: ComponentProperties.BACKGROUND_COLOR);
431: else
432: props.setBackgroundColor(color);
433: }
434: }
|