SimpleInternalFrame.java
001 /*
002  * Copyright (c) 2000-2006 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 package com.jgoodies.uif_lite.panel;
032 
033 import java.awt.*;
034 
035 import javax.swing.*;
036 import javax.swing.border.AbstractBorder;
037 
038 /**
039  * A <code>JPanel</code> subclass that has a drop shadow border and
040  * that provides a header with icon, title and tool bar.<p>
041  *
042  * This class can be used to replace the <code>JInternalFrame</code>,
043  * for use outside of a <code>JDesktopPane</code>.
044  * The <code>SimpleInternalFrame</code> is less flexible but often
045  * more usable; it avoids overlapping windows and scales well
046  * up to IDE size.
047  * Several customers have reported that they and their clients feel
048  * much better with both the appearance and the UI feel.<p>
049  *
050  * The SimpleInternalFrame provides the following bound properties:
051  <i>frameIcon, title, toolBar, content, selected.</i><p>
052  *
053  * By default the SimpleInternalFrame is in <i>selected</i> state.
054  * If you don't do anything, multiple simple internal frames will
055  * be displayed as selected.
056  *
057  @author Karsten Lentzsch
058  @version $Revision: 1.1 $
059  *
060  @see    javax.swing.JInternalFrame
061  @see    javax.swing.JDesktopPane
062  */
063 
064 public class SimpleInternalFrame extends JPanel {
065 
066     private JLabel        titleLabel;
067     private GradientPanel gradientPanel;
068     private JPanel        headerPanel;
069     private boolean       selected;
070 
071 
072     // Instance Creation ****************************************************
073 
074     /**
075      * Constructs a SimpleInternalFrame with the specified title.
076      * The title is intended to be non-blank, or in other words
077      * should contain non-space characters.
078      *
079      @param title       the initial title
080      */
081     public SimpleInternalFrame(String title) {
082         this(null, title, null, null);
083     }
084 
085 
086     /**
087      * Constructs a SimpleInternalFrame with the specified
088      * icon, and title.
089      *
090      @param icon        the initial icon
091      @param title       the initial title
092      */
093     public SimpleInternalFrame(Icon icon, String title) {
094         this(icon, title, null, null);
095     }
096 
097 
098     /**
099      * Constructs a SimpleInternalFrame with the specified
100      * title, tool bar, and content panel.
101      *
102      @param title       the initial title
103      @param bar         the initial tool bar
104      @param content     the initial content pane
105      */
106     public SimpleInternalFrame(String title, JToolBar bar, JComponent content) {
107         this(null, title, bar, content);
108     }
109 
110 
111     /**
112      * Constructs a SimpleInternalFrame with the specified
113      * icon, title, tool bar, and content panel.
114      *
115      @param icon        the initial icon
116      @param title       the initial title
117      @param bar         the initial tool bar
118      @param content     the initial content pane
119      */
120     public SimpleInternalFrame(
121         Icon icon,
122         String title,
123         JToolBar bar,
124         JComponent content) {
125         super(new BorderLayout());
126         this.selected = false;
127         this.titleLabel = new JLabel(title, icon, SwingConstants.LEADING);
128         JPanel top = buildHeader(titleLabel, bar);
129 
130         add(top, BorderLayout.NORTH);
131         if (content != null) {
132             setContent(content);
133         }
134         setBorder(new ShadowBorder());
135         setSelected(true);
136         updateHeader();
137     }
138 
139 
140     // Public API ***********************************************************
141 
142     /**
143      * Returns the frame's icon.
144      *
145      @return the frame's icon
146      */
147     public Icon getFrameIcon() {
148         return titleLabel.getIcon();
149     }
150 
151 
152     /**
153      * Sets a new frame icon.
154      *
155      @param newIcon   the icon to be set
156      */
157     public void setFrameIcon(Icon newIcon) {
158         Icon oldIcon = getFrameIcon();
159         titleLabel.setIcon(newIcon);
160         firePropertyChange("frameIcon", oldIcon, newIcon);
161     }
162 
163 
164     /**
165      * Returns the frame's title text.
166      
167      @return String   the current title text
168      */
169     public String getTitle() {
170         return titleLabel.getText();
171     }
172 
173 
174     /**
175      * Sets a new title text.
176      
177      @param newText  the title text tp be set
178      */
179     public void setTitle(String newText) {
180         String oldText = getTitle();
181         titleLabel.setText(newText);
182         firePropertyChange("title", oldText, newText);
183     }
184 
185 
186     /**
187      * Returns the current toolbar, null if none has been set before.
188      *
189      @return the current toolbar - if any
190      */
191     public JToolBar getToolBar() {
192         return headerPanel.getComponentCount() 1
193             (JToolBarheaderPanel.getComponent(1)
194             null;
195     }
196 
197 
198     /**
199      * Sets a new tool bar in the header.
200      *
201      @param newToolBar the tool bar to be set in the header
202      */
203     public void setToolBar(JToolBar newToolBar) {
204         JToolBar oldToolBar = getToolBar();
205         if (oldToolBar == newToolBar) {
206             return;
207         }
208         if (oldToolBar != null) {
209             headerPanel.remove(oldToolBar);
210         }
211         if (newToolBar != null) {
212             newToolBar.setBorder(BorderFactory.createEmptyBorder(0000));
213             headerPanel.add(newToolBar, BorderLayout.EAST);
214         }
215         updateHeader();
216         firePropertyChange("toolBar", oldToolBar, newToolBar);
217     }
218 
219 
220     /**
221      * Returns the content - null, if none has been set.
222      
223      @return the current content
224      */
225     public Component getContent() {
226         return hasContent() ? getComponent(1null;
227     }
228 
229 
230     /**
231      * Sets a new panel content; replaces any existing content, if existing.
232      
233      @param newContent   the panel's new content
234      */
235     public void setContent(Component newContent) {
236         Component oldContent = getContent();
237         if (hasContent()) {
238             remove(oldContent);
239         }
240         add(newContent, BorderLayout.CENTER);
241         firePropertyChange("content", oldContent, newContent);
242     }
243 
244 
245     /**
246      * Answers if the panel is currently selected (or in other words active)
247      * or not. In the selected state, the header background will be
248      * rendered differently.
249      *
250      @return boolean  a boolean, where true means the frame is selected
251      *                  (currently active) and false means it is not
252      */
253     public boolean isSelected() {
254         return selected;
255     }
256 
257 
258     /**
259      * This panel draws its title bar differently if it is selected,
260      * which may be used to indicate to the user that this panel
261      * has the focus, or should get more attention than other
262      * simple internal frames.
263      *
264      @param newValue  a boolean, where true means the frame is selected
265      *                  (currently active) and false means it is not
266      */
267     public void setSelected(boolean newValue) {
268         boolean oldValue = isSelected();
269         selected = newValue;
270         updateHeader();
271         firePropertyChange("selected", oldValue, newValue);
272     }
273 
274 
275     // Building *************************************************************
276 
277     /**
278      * Creates and answers the header panel, that consists of:
279      * an icon, a title label, a tool bar, and a gradient background.
280      *
281      @param label   the label to paint the icon and text
282      @param bar     the panel's tool bar
283      @return the panel's built header area
284      */
285     private JPanel buildHeader(JLabel label, JToolBar bar) {
286         gradientPanel =
287             new GradientPanel(new BorderLayout(), getHeaderBackground());
288         label.setOpaque(false);
289 
290         gradientPanel.add(label, BorderLayout.WEST);
291         gradientPanel.setBorder(BorderFactory.createEmptyBorder(3431));
292 
293         headerPanel = new JPanel(new BorderLayout());
294         headerPanel.add(gradientPanel, BorderLayout.CENTER);
295         setToolBar(bar);
296         headerPanel.setBorder(new RaisedHeaderBorder());
297         headerPanel.setOpaque(false);
298         return headerPanel;
299     }
300 
301     /**
302      * Updates the header.
303      */
304     private void updateHeader() {
305         gradientPanel.setBackground(getHeaderBackground());
306         gradientPanel.setOpaque(isSelected());
307         titleLabel.setForeground(getTextForeground(isSelected()));
308         headerPanel.repaint();
309     }
310 
311 
312     /**
313      * Updates the UI. In addition to the superclass behavior, we need
314      * to update the header component.
315      */
316     public void updateUI() {
317         super.updateUI();
318         if (titleLabel != null) {
319             updateHeader();
320         }
321     }
322 
323 
324     // Helper Code **********************************************************
325 
326     /**
327      * Checks and answers if the panel has a content component set.
328      *
329      @return true if the panel has a content, false if it's empty
330      */
331     private boolean hasContent() {
332         return getComponentCount() 1;
333     }
334     
335     /**
336      * Determines and answers the header's text foreground color.
337      * Tries to lookup a special color from the L&amp;F.
338      * In case it is absent, it uses the standard internal frame forground.
339      *
340      @param isSelected   true to lookup the active color, false for the inactive
341      @return the color of the foreground text
342      */
343     protected Color getTextForeground(boolean isSelected) {
344         Color c =
345             UIManager.getColor(
346                 isSelected
347                     "SimpleInternalFrame.activeTitleForeground"
348                     "SimpleInternalFrame.inactiveTitleForeground");
349         if (c != null) {
350             return c;
351         }
352         return UIManager.getColor(
353             isSelected
354                 "InternalFrame.activeTitleForeground"
355                 "Label.foreground");
356 
357     }
358 
359     /**
360      * Determines and answers the header's background color.
361      * Tries to lookup a special color from the L&amp;F.
362      * In case it is absent, it uses the standard internal frame background.
363      *
364      @return the color of the header's background
365      */
366     protected Color getHeaderBackground() {
367         Color c =
368             UIManager.getColor("SimpleInternalFrame.activeTitleBackground");
369         return c != null
370             ? c
371             : UIManager.getColor("InternalFrame.activeTitleBackground");
372     }
373 
374 
375     // Helper Classes *******************************************************
376 
377     // A custom border for the raised header pseudo 3D effect.
378     private static class RaisedHeaderBorder extends AbstractBorder {
379 
380         private static final Insets INSETS = new Insets(1110);
381 
382         public Insets getBorderInsets(Component c) { return INSETS; }
383 
384         public void paintBorder(Component c, Graphics g,
385             int x, int y, int w, int h) {
386 
387             g.translate(x, y);
388             g.setColor(UIManager.getColor("controlLtHighlight"));
389             g.fillRect(00,   w, 1);
390             g.fillRect(01,   1, h-1);
391             g.setColor(UIManager.getColor("controlShadow"));
392             g.fillRect(0, h-1, w, 1);
393             g.translate(-x, -y);
394         }
395     }
396 
397     // A custom border that has a shadow on the right and lower sides.
398     private static class ShadowBorder extends AbstractBorder {
399 
400         private static final Insets INSETS = new Insets(1133);
401 
402         public Insets getBorderInsets(Component c) { return INSETS; }
403 
404         public void paintBorder(Component c, Graphics g,
405             int x, int y, int w, int h) {
406 
407             Color shadow        = UIManager.getColor("controlShadow");
408             if (shadow == null) {
409                 shadow = Color.GRAY;
410             }
411             Color lightShadow   = new Color(shadow.getRed(),
412                                             shadow.getGreen(),
413                                             shadow.getBlue(),
414                                             170);
415             Color lighterShadow = new Color(shadow.getRed(),
416                                             shadow.getGreen(),
417                                             shadow.getBlue(),
418                                             70);
419             g.translate(x, y);
420 
421             g.setColor(shadow);
422             g.fillRect(00, w - 31);
423             g.fillRect(001, h - 3);
424             g.fillRect(w - 311, h - 3);
425             g.fillRect(1, h - 3, w - 31);
426             // Shadow line 1
427             g.setColor(lightShadow);
428             g.fillRect(w - 3011);
429             g.fillRect(0, h - 311);
430             g.fillRect(w - 211, h - 3);
431             g.fillRect(1, h - 2, w - 31);
432             // Shadow line2
433             g.setColor(lighterShadow);
434             g.fillRect(w - 2011);
435             g.fillRect(0, h - 211);
436             g.fillRect(w-2, h-211);
437             g.fillRect(w - 111, h - 2);
438             g.fillRect(1, h - 1, w - 21);
439             g.translate(-x, -y);
440         }
441     }
442 
443 }