001: /*
002: * Copyright (c) 2003 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: /*
032: * Source code changes (c) 2005 beck et al. projects
033: */
034:
035: package org.gui4j.core.swing;
036:
037: import java.awt.BorderLayout;
038: import java.awt.Color;
039: import java.awt.Component;
040: import java.awt.Dimension;
041: import java.awt.Font;
042: import java.awt.GradientPaint;
043: import java.awt.Graphics;
044: import java.awt.Graphics2D;
045: import java.awt.Insets;
046: import java.awt.LayoutManager;
047: import java.awt.Paint;
048: import java.awt.event.MouseListener;
049:
050: import javax.swing.BorderFactory;
051: import javax.swing.Icon;
052: import javax.swing.JComponent;
053: import javax.swing.JLabel;
054: import javax.swing.JPanel;
055: import javax.swing.JToolBar;
056: import javax.swing.SwingConstants;
057: import javax.swing.UIManager;
058: import javax.swing.border.AbstractBorder;
059:
060: /**
061: * A lightweight component derived from JPanel that features certain
062: * subcomponents that make it look similar to a frame or internal frame. It
063: * shows a titlebar above its content component. The title bar has an optional
064: * icon on the left, a title text and an optional toolbar on the right.
065: */
066: public class SimpleInternalFrame extends JPanel {
067: private String title;
068: private String infoText;
069:
070: private JLabel titleLabel;
071: private GradientPanel gradientPanel;
072: private JPanel headerPanel;
073: private boolean isSelected;
074:
075: // support for usage as Dockable in FlexDock (see Gui4jPortal)
076: private Icon tabIcon;
077: private String tabText;
078: private Listener listener;
079:
080: // Instance Creation ****************************************************
081:
082: /**
083: * Constructs a <code>SimpleInternalFrame</code> with an empty title.
084: */
085: public SimpleInternalFrame() {
086: this (null, "", null, null);
087: }
088:
089: /**
090: * Constructs a <code>SimpleInternalFrame</code> with the specified title.
091: *
092: * @param title
093: * the initial name
094: */
095: public SimpleInternalFrame(String title) {
096: this (null, title, null, null);
097: }
098:
099: /**
100: * Constructs a <code>SimpleInternalFrame</code> with the specified icon,
101: * and title.
102: *
103: * @param icon
104: * the initial icon
105: * @param title
106: * the initial name
107: */
108: public SimpleInternalFrame(Icon icon, String title) {
109: this (icon, title, null, null);
110: }
111:
112: /**
113: * Constructs a <code>SimpleInternalFrame</code> with the specified title,
114: * tool bar, and content panel.
115: *
116: * @param title
117: * the initial name
118: * @param bar
119: * the initial tool bar
120: * @param content
121: * the initial content pane
122: */
123: public SimpleInternalFrame(String title, JToolBar bar,
124: JComponent content) {
125: this (null, title, bar, content);
126: }
127:
128: /**
129: * Constructs a <code>SimpleInternalFrame</code> with the specified icon,
130: * title, tool bar, and content panel.
131: *
132: * @param icon
133: * the initial icon
134: * @param title
135: * the initial title
136: * @param bar
137: * the initial tool bar
138: * @param content
139: * the initial content pane
140: */
141: public SimpleInternalFrame(Icon icon, String title, JToolBar bar,
142: JComponent content) {
143: super (new BorderLayout());
144: this .isSelected = false;
145: this .title = title;
146: this .titleLabel = new JLabel(title, icon,
147: SwingConstants.LEADING);
148: JPanel top = buildHeader(titleLabel, bar);
149:
150: add(top, BorderLayout.NORTH);
151: if (content != null) {
152: setContent(content);
153: }
154: setBorder(new ShadowBorder());
155: setSelected(true);
156: updateHeader();
157:
158: }
159:
160: // Public API ***********************************************************
161:
162: public Listener getListener() {
163: return listener;
164: }
165:
166: public void setListener(Listener listener) {
167: this .listener = listener;
168: }
169:
170: /**
171: * Returns the frame's icon.
172: *
173: * @return the frame's icon
174: */
175: public Icon getFrameIcon() {
176: return titleLabel.getIcon();
177: }
178:
179: /**
180: * Sets a new frame icon.
181: *
182: * @param newIcon
183: * the icon to be set
184: */
185: public void setFrameIcon(Icon newIcon) {
186: Icon oldIcon = getFrameIcon();
187: titleLabel.setIcon(newIcon);
188: firePropertyChange("frameIcon", oldIcon, newIcon);
189: }
190:
191: public Icon getTabIcon() {
192: return tabIcon;
193: }
194:
195: public void setTabIcon(Icon tabIcon) {
196: this .tabIcon = tabIcon;
197: notifyListener();
198: }
199:
200: public String getTabText() {
201: if (tabText == null || tabText.length() == 0) {
202: return title;
203: }
204: return tabText;
205: }
206:
207: public void setTabText(String tabText) {
208: this .tabText = tabText;
209: notifyListener();
210: }
211:
212: /**
213: * Returns the frame's caption, consisting of its title and, if existent,
214: * its info text.
215: *
216: * @return String the current caption
217: */
218: public String getCaption() {
219: return titleLabel.getText();
220: }
221:
222: public String getInfoText() {
223: return infoText;
224: }
225:
226: public void setInfoText(String info) {
227: this .infoText = info;
228: updateCaption();
229: }
230:
231: public String getTitle() {
232: return title;
233: }
234:
235: public void setTitle(String title) {
236: this .title = title;
237: updateCaption();
238: notifyListener();
239: }
240:
241: /**
242: * Returns the current toolbar, null if none has been set before.
243: *
244: * @return the current toolbar - if any
245: */
246: public JToolBar getToolBar() {
247: return headerPanel.getComponentCount() > 1 ? (JToolBar) headerPanel
248: .getComponent(1)
249: : null;
250: }
251:
252: /**
253: * Sets a new tool bar in the header.
254: *
255: * @param newToolBar
256: * the tool bar to be set in the header
257: */
258: public void setToolBar(JToolBar newToolBar) {
259: JToolBar oldToolBar = getToolBar();
260: if (oldToolBar == newToolBar) {
261: return;
262: }
263: if (oldToolBar != null) {
264: headerPanel.remove(oldToolBar);
265: }
266: if (newToolBar != null) {
267: newToolBar.setBorder(BorderFactory.createEmptyBorder(0, 0,
268: 0, 0));
269: headerPanel.add(newToolBar, BorderLayout.EAST);
270: }
271: updateHeader();
272: firePropertyChange("toolBar", oldToolBar, newToolBar);
273: }
274:
275: /**
276: * Returns the content - null, if none has been set.
277: *
278: * @return the current content
279: */
280: public Component getContent() {
281: return hasContent() ? getComponent(1) : null;
282: }
283:
284: /**
285: * Sets a new panel content; replaces any existing content, if existing.
286: *
287: * @param newContent
288: * the panel's new content
289: */
290: public void setContent(Component newContent) {
291: Component oldContent = getContent();
292: if (hasContent()) {
293: remove(oldContent);
294: }
295: add(newContent, BorderLayout.CENTER);
296: firePropertyChange("content", oldContent, newContent);
297: }
298:
299: /**
300: * Answers if the panel is currently selected (or in other words active) or
301: * not. In the selected state, the header background will be rendered
302: * differently.
303: *
304: * @return boolean a boolean, where true means the frame is selected
305: * (currently active) and false means it is not
306: */
307: public boolean isSelected() {
308: return isSelected;
309: }
310:
311: /**
312: * This panel draws its title bar differently if it is selected, which may
313: * be used to indicate to the user that this panel has the focus, or should
314: * get more attention than other simple internal frames.
315: *
316: * @param newValue
317: * a boolean, where true means the frame is selected (currently
318: * active) and false means it is not
319: */
320: public void setSelected(boolean newValue) {
321: boolean oldValue = isSelected();
322: isSelected = newValue;
323: updateHeader();
324: firePropertyChange("selected", oldValue, newValue);
325: }
326:
327: public void addHeaderListener(MouseListener mouseListener) {
328: gradientPanel.addMouseListener(mouseListener);
329: }
330:
331: public void setToolTipText(String text) {
332: super .setToolTipText(text);
333: gradientPanel.setToolTipText(text);
334: }
335:
336: public void setFont(Font font) {
337: super .setFont(font);
338: if (titleLabel != null) {
339: titleLabel.setFont(font);
340: }
341: }
342:
343: // Building *************************************************************
344:
345: /**
346: * Creates and answers the header panel, that consists of: an icon, a title
347: * label, a tool bar, and a gradient background.
348: *
349: * @param label
350: * the label to paint the icon and text
351: * @param bar
352: * the panel's tool bar
353: * @return the panel's built header area
354: */
355: private JPanel buildHeader(JLabel label, JToolBar bar) {
356: gradientPanel = new GradientPanel(new BorderLayout(),
357: getHeaderBackground());
358: label.setOpaque(false);
359:
360: gradientPanel.add(label, BorderLayout.WEST);
361: gradientPanel.setBorder(BorderFactory.createEmptyBorder(3, 4,
362: 3, 1));
363:
364: headerPanel = new JPanel(new BorderLayout());
365: headerPanel.add(gradientPanel, BorderLayout.CENTER);
366: setToolBar(bar);
367: headerPanel.setBorder(new RaisedHeaderBorder());
368: headerPanel.setOpaque(false);
369: return headerPanel;
370: }
371:
372: /**
373: * Updates the header.
374: */
375: private void updateHeader() {
376: gradientPanel.setBackground(getHeaderBackground());
377: gradientPanel.setOpaque(isSelected());
378: titleLabel.setForeground(getTextForeground(isSelected()));
379: headerPanel.repaint();
380:
381: Dimension minSize = new Dimension(headerPanel.getMinimumSize());
382: minSize.height += 3; // border
383: setMinimumSize(minSize);
384: }
385:
386: /**
387: * Updates the UI. In addition to the superclass behavior, we need to update
388: * the header component.
389: */
390: public void updateUI() {
391: super .updateUI();
392: if (titleLabel != null) {
393: updateHeader();
394: }
395: }
396:
397: // Helper Code **********************************************************
398:
399: /**
400: * Checks and answers if the panel has a content component set.
401: *
402: * @return true if the panel has a content, false if it's empty
403: */
404: private boolean hasContent() {
405: return getComponentCount() > 1;
406: }
407:
408: /**
409: * Determines and answers the header's text foreground color. Tries to
410: * lookup a special color from the L&F. In case it is absent, it uses
411: * the standard internal frame forground.
412: *
413: * @param selected
414: * true to lookup the active color, false for the inactive
415: * @return the color of the foreground text
416: */
417: protected Color getTextForeground(boolean selected) {
418: Color c = UIManager
419: .getColor(selected ? "SimpleInternalFrame.activeTitleForeground"
420: : "SimpleInternalFrame.inactiveTitleForeground");
421: if (c != null) {
422: return c;
423: }
424: return UIManager
425: .getColor(selected ? "InternalFrame.activeTitleForeground"
426: : "Label.foreground");
427:
428: }
429:
430: /**
431: * Determines and answers the header's background color. Tries to lookup a
432: * special color from the L&F. In case it is absent, it uses the
433: * standard internal frame background.
434: *
435: * @return the color of the header's background
436: */
437: protected Color getHeaderBackground() {
438: Color c = UIManager
439: .getColor("SimpleInternalFrame.activeTitleBackground");
440: if (c != null)
441: return c;
442: c = UIManager.getColor("InternalFrame.activeTitleGradient");
443: return c != null ? c : UIManager
444: .getColor("InternalFrame.activeTitleBackground");
445: }
446:
447: private void updateCaption() {
448: String newCaption = title;
449: if (infoText != null) {
450: newCaption = newCaption + " (" + infoText + ")";
451: }
452:
453: String oldCaption = getCaption();
454: titleLabel.setText(newCaption);
455: firePropertyChange("title", oldCaption, newCaption);
456: }
457:
458: public Component getDragHandle() {
459: return gradientPanel;
460: }
461:
462: protected String paramString() {
463: return getCaption();
464: }
465:
466: private void notifyListener() {
467: if (listener != null) {
468: listener.propertiesChanged();
469: }
470: }
471:
472: // Nested Interface ****************************************
473:
474: public static interface Listener {
475: void propertiesChanged();
476: }
477:
478: // Helper Classes *******************************************************
479:
480: // A custom border for the raised header pseudo 3D effect.
481: private static class RaisedHeaderBorder extends AbstractBorder {
482:
483: private static final Insets INSETS = new Insets(1, 1, 1, 0);
484:
485: public Insets getBorderInsets(Component c) {
486: return INSETS;
487: }
488:
489: public void paintBorder(Component c, Graphics g, int x, int y,
490: int w, int h) {
491:
492: g.translate(x, y);
493: g.setColor(UIManager.getColor("controlLtHighlight"));
494: g.fillRect(0, 0, w, 1);
495: g.fillRect(0, 1, 1, h - 1);
496: g.setColor(UIManager.getColor("controlShadow"));
497: g.fillRect(0, h - 1, w, 1);
498: g.translate(-x, -y);
499: }
500: }
501:
502: // A panel with a horizontal gradient background.
503: private static class GradientPanel extends JPanel {
504:
505: private GradientPanel(LayoutManager lm, Color background) {
506: super (lm);
507: setBackground(background);
508: }
509:
510: public void paintComponent(Graphics g) {
511: super .paintComponent(g);
512: if (!isOpaque()) {
513: return;
514: }
515: Color control = UIManager.getColor("control");
516: int width = getWidth();
517: int height = getHeight();
518:
519: Graphics2D g2 = (Graphics2D) g;
520: Paint storedPaint = g2.getPaint();
521: g2.setPaint(new GradientPaint(0, 0, getBackground(), width,
522: 0, control));
523: g2.fillRect(0, 0, width, height);
524: g2.setPaint(storedPaint);
525: }
526: }
527:
528: }
|