View Javadoc

1   package com.melloware.jukes.gui.view.component;
2   
3   import java.awt.BorderLayout;
4   import java.awt.Color;
5   import java.awt.Component;
6   import java.awt.GradientPaint;
7   import java.awt.Graphics;
8   import java.awt.Graphics2D;
9   import java.awt.Insets;
10  import java.awt.LayoutManager;
11  import java.awt.Paint;
12  
13  import javax.swing.BorderFactory;
14  import javax.swing.Icon;
15  import javax.swing.JComponent;
16  import javax.swing.JLabel;
17  import javax.swing.JPanel;
18  import javax.swing.JToolBar;
19  import javax.swing.SwingConstants;
20  import javax.swing.UIManager;
21  import javax.swing.border.AbstractBorder;
22  
23  import com.jgoodies.looks.LookUtils;
24  
25  /**
26   * A <code>JPanel</code> subclass that has a drop shadow border and
27   * that provides a header with icon, title and tool bar.<p>
28   *
29   * This class can be used to replace the <code>JInternalFrame</code>,
30   * for use outside of a <code>JDesktopPane</code>.
31   * The <code>SimpleInternalFrame</code> is less flexible but often
32   * more usable; it avoids overlapping windows and scales well
33   * up to IDE size.
34   * Several customers have reported that they and their clients feel
35   * much better with both the appearance and the UI feel.<p>
36   *
37   * The SimpleInternalFrame provides the following bound properties:
38   * <i>frameIcon, title, toolBar, headerToolbar, content, selected.</i><p>
39   *
40   * By default the SimpleInternalFrame is in <i>selected</i> state.
41   * If you don't do anything, multiple simple internal frames will
42   * be displayed as selected.
43   * <p>
44   * Copyright (c) 1999-2007 Melloware, Inc. <http://www.melloware.com>
45   * @author Emil A. Lefkof III <info@melloware.com>
46   * @version 4.0
47   *
48   * @see    javax.swing.JInternalFrame
49   * @see    javax.swing.JDesktopPane
50   */
51  @SuppressWarnings("PMD")
52  public class ComplexInternalFrame
53      extends JPanel {
54      
55      private boolean isSelected;
56      private GradientPanel gradientPanel;
57      private JLabel titleLabel;
58      private JPanel headerPanel;
59  
60  
61      /**
62       * Constructs a <code>SimpleInternalFrame</code> with the specified title.
63       *
64       * @param title       the initial title
65       */
66      public ComplexInternalFrame(String title) {
67          this(null, title, null, null);
68      }
69  
70      /**
71       * Constructs a <code>SimpleInternalFrame</code> with the specified
72       * icon, and title.
73       *
74       * @param icon        the initial icon
75       * @param title       the initial title
76       */
77      public ComplexInternalFrame(Icon icon, String title) {
78          this(icon, title, null, null);
79      }
80  
81      /**
82       * Constructs a <code>SimpleInternalFrame</code> with the specified
83       * title, tool bar, and content panel.
84       *
85       * @param title       the initial title
86       * @param bar         the initial tool bar
87       * @param content     the initial content pane
88       */
89      public ComplexInternalFrame(String title, JToolBar bar, JComponent content) {
90          this(null, title, bar, content);
91      }
92  
93      /**
94       * Constructs a <code>SimpleInternalFrame</code> with the specified
95       * icon, title, tool bar, and content panel.
96       *
97       * @param icon        the initial icon
98       * @param title       the initial title
99       * @param bar         the initial tool bar
100      * @param content     the initial content pane
101      */
102     public ComplexInternalFrame(Icon icon, String title, JToolBar bar, JComponent content) {
103         super(new BorderLayout());
104         this.isSelected = false;
105         this.titleLabel = new JLabel(title, icon, SwingConstants.LEADING);
106         JPanel top = buildHeader(titleLabel, bar);
107 
108         add(top, BorderLayout.NORTH);
109         if (content != null) {
110             setContent(content);
111         }
112         setBorder(new ShadowBorder());
113         setSelected(true);
114         updateHeader();
115     }
116 
117     /**
118      * Returns the content - null, if none has been set.
119      *
120      * @return the current content
121      */
122     public Component getContent() {
123         return hasContent() ? getComponent(1) : null;
124     }
125 
126 
127     /**
128      * Returns the frame's icon.
129      *
130      * @return the frame's icon
131      */
132     public Icon getFrameIcon() {
133         return titleLabel.getIcon();
134     }
135 
136     /**
137      * Returns the current toolbar, null if none has been set before.
138      *
139      * @return the current toolbar - if any
140      */
141     public JToolBar getHeaderToolBar() {
142         return (gradientPanel.getComponentCount() > 1) ? (JToolBar)gradientPanel.getComponent(1) : null;
143     }
144 
145     /**
146      * Returns the frame's title text.
147      *
148      * @return String   the current title text
149      */
150     public String getTitle() {
151         return titleLabel.getText();
152     }
153 
154     /**
155      * Returns the current toolbar, null if none has been set before.
156      *
157      * @return the current toolbar - if any
158      */
159     public JToolBar getToolBar() {
160         return (headerPanel.getComponentCount() > 1) ? (JToolBar)headerPanel.getComponent(1) : null;
161     }
162 
163     /**
164      * Sets a new panel content; replaces any existing content, if existing.
165      *
166      * @param newContent   the panel's new content
167      */
168     public void setContent(Component newContent) {
169         Component oldContent = getContent();
170         if (hasContent()) {
171             remove(oldContent);
172         }
173         add(newContent, BorderLayout.CENTER);
174         firePropertyChange("content", oldContent, newContent);
175     }
176 
177     /**
178      * Sets a new frame icon.
179      *
180      * @param newIcon   the icon to be set
181      */
182     public void setFrameIcon(Icon newIcon) {
183         Icon oldIcon = getFrameIcon();
184         titleLabel.setIcon(newIcon);
185         firePropertyChange("frameIcon", oldIcon, newIcon);
186     }
187 
188     public void setHeaderToolBar(JToolBar toolBar) {
189         final JToolBar oldToolBar = getHeaderToolBar();
190         if (oldToolBar != null) {
191             gradientPanel.remove(oldToolBar);
192         }
193         if (toolBar != null) {
194             toolBar.setBorderPainted(false);
195             toolBar.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
196             toolBar.setOpaque(false);
197             gradientPanel.add(toolBar, BorderLayout.EAST);
198         }
199         updateHeader();
200         firePropertyChange("headerToolBar", oldToolBar, toolBar);
201     }
202 
203     /**
204      * This panel draws its title bar differently if it is selected,
205      * which may be used to indicate to the user that this panel
206      * has the focus, or should get more attention than other
207      * simple internal frames.
208      *
209      * @param newValue  a boolean, where true means the frame is selected
210      *                  (currently active) and false means it is not
211      */
212     public void setSelected(boolean newValue) {
213         boolean oldValue = isSelected();
214         isSelected = newValue;
215         updateHeader();
216         firePropertyChange("selected", oldValue, newValue);
217     }
218 
219     /**
220      * Sets a new title text.
221      *
222      * @param newText  the title text tp be set
223      */
224     public void setTitle(String newText) {
225         String oldText = getTitle();
226         titleLabel.setText(newText);
227         firePropertyChange("title", oldText, newText);
228     }
229 
230     /**
231      * Sets a new tool bar in the header.
232      *
233      * @param newToolBar the tool bar to be set in the header
234      */
235     public void setToolBar(JToolBar newToolBar) {
236         final JToolBar oldToolBar = getToolBar();
237 
238         if (oldToolBar != null) {
239             headerPanel.remove(oldToolBar);
240         }
241         if (newToolBar != null) {
242             newToolBar.setOpaque(true);
243             newToolBar.setBackground(UIManager.getColor("control"));
244             newToolBar.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
245             headerPanel.add(newToolBar, BorderLayout.EAST);
246         }
247         updateHeader();
248         firePropertyChange("toolBar", oldToolBar, newToolBar);
249     }
250 
251     /**
252      * Answers if the panel is currently selected (or in other words active)
253      * or not. In the selected state, the header background will be
254      * rendered differently.
255      *
256      * @return boolean  a boolean, where true means the frame is selected
257      *                  (currently active) and false means it is not
258      */
259     public boolean isSelected() {
260         return isSelected;
261     }
262 
263     /**
264      * Updates the UI. In addition to the superclass behavior, we need
265      * to update the header component.
266      */
267     public void updateUI() {
268         super.updateUI();
269         if (titleLabel != null) {
270             updateHeader();
271         }
272     }
273 
274     /**
275      * Determines and answers the header's background color.
276      * Tries to lookup a special color from the L&amp;F.
277      * In case it is absent, it uses the standard internal frame background.
278      *
279      * @return the color of the header's background
280      */
281     protected Color getHeaderBackground() {
282         Color c = UIManager.getColor("SimpleInternalFrame.activeTitleBackground");
283         if (c != null) {
284             return c;
285         }
286         if (LookUtils.IS_LAF_WINDOWS_XP_ENABLED) {
287             c = UIManager.getColor("InternalFrame.activeTitleGradient");
288         }
289         return (c == null) ? UIManager.getColor("InternalFrame.activeTitleBackground") : c;
290     }
291 
292     /**
293      * Determines and answers the header's text foreground color.
294      * Tries to lookup a special color from the L&amp;F.
295      * In case it is absent, it uses the standard internal frame forground.
296      *
297      * @param selected   true to lookup the active color, false for the inactive
298      * @return the color of the foreground text
299      */
300     protected Color getTextForeground(boolean selected) {
301         Color c = UIManager.getColor(selected ? "SimpleInternalFrame.activeTitleForeground"
302                                               : "SimpleInternalFrame.inactiveTitleForeground");
303         if (c != null) {
304             return c;
305         }
306         return UIManager.getColor(selected ? "InternalFrame.activeTitleForeground" : "Label.foreground");
307 
308     }
309 
310 
311     /**
312      * Creates and answers the header panel, that consists of:
313      * an icon, a title label, a tool bar, and a gradient background.
314      *
315      * @param label   the label to paint the icon and text
316      * @param bar     the panel's tool bar
317      * @return the panel's built header area
318      */
319     private JPanel buildHeader(JLabel label, JToolBar bar) {
320         gradientPanel = new GradientPanel(new BorderLayout(), getHeaderBackground());
321         label.setOpaque(false);
322 
323         gradientPanel.add(label, BorderLayout.WEST);
324         gradientPanel.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 1));
325 
326         headerPanel = new JPanel(new BorderLayout());
327         headerPanel.add(gradientPanel, BorderLayout.CENTER);
328         setToolBar(bar);
329         headerPanel.setBorder(new RaisedHeaderBorder());
330         headerPanel.setOpaque(false);
331         return headerPanel;
332     }
333 
334     // Helper Code **********************************************************
335 
336     /**
337      * Checks and answers if the panel has a content component set.
338      *
339      * @return true if the panel has a content, false if it's empty
340      */
341     private boolean hasContent() {
342         return getComponentCount() > 1;
343     }
344 
345     /**
346      * Updates the header.
347      */
348     private void updateHeader() {
349         gradientPanel.setBackground(getHeaderBackground());
350         gradientPanel.setOpaque(isSelected());
351         titleLabel.setForeground(getTextForeground(isSelected()));
352         headerPanel.repaint();
353     }
354 
355     // A panel with a horizontal gradient background.
356     private static class GradientPanel
357         extends JPanel {
358 
359         private GradientPanel(LayoutManager lm, Color background) {
360             super(lm);
361             setBackground(background);
362         }
363 
364         public void paintComponent(Graphics g) {
365             super.paintComponent(g);
366             if (!isOpaque()) {
367                 return;
368             }
369             Color control = UIManager.getColor("control");
370             int width = getWidth();
371             int height = getHeight();
372 
373             Graphics2D g2 = (Graphics2D)g;
374             Paint storedPaint = g2.getPaint();
375             g2.setPaint(new GradientPaint(0, 0, getBackground(), width, 0, control));
376             g2.fillRect(0, 0, width, height);
377             g2.setPaint(storedPaint);
378         }
379     }
380 
381 
382     // A custom border for the raised header pseudo 3D effect.
383     private static class RaisedHeaderBorder
384         extends AbstractBorder {
385 
386         private static final Insets INSETS = new Insets(1, 1, 1, 0);
387 
388         public Insets getBorderInsets(Component c) {
389             return INSETS;
390         }
391 
392         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
393 
394             g.translate(x, y);
395             g.setColor(UIManager.getColor("controlLtHighlight"));
396             g.fillRect(0, 0, w, 1);
397             g.fillRect(0, 1, 1, h - 1);
398             g.setColor(UIManager.getColor("controlShadow"));
399             g.fillRect(0, h - 1, w, 1);
400             g.translate(-x, -y);
401         }
402     }
403 
404     // A custom border that has a shadow on the right and lower sides.
405     private static class ShadowBorder
406         extends AbstractBorder {
407 
408         private static final Insets INSETS = new Insets(1, 1, 3, 3);
409 
410         public Insets getBorderInsets(Component c) {
411             return INSETS;
412         }
413 
414         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
415 
416             Color shadow = UIManager.getColor("controlShadow");
417             if (shadow == null) {
418                 shadow = Color.GRAY;
419             }
420             Color lightShadow = new Color(shadow.getRed(), shadow.getGreen(), shadow.getBlue(), 170);
421             Color lighterShadow = new Color(shadow.getRed(), shadow.getGreen(), shadow.getBlue(), 70);
422             g.translate(x, y);
423 
424             g.setColor(shadow);
425             g.fillRect(0, 0, w - 3, 1);
426             g.fillRect(0, 0, 1, h - 3);
427             g.fillRect(w - 3, 1, 1, h - 3);
428             g.fillRect(1, h - 3, w - 3, 1);
429             // Shadow line 1
430             g.setColor(lightShadow);
431             g.fillRect(w - 3, 0, 1, 1);
432             g.fillRect(0, h - 3, 1, 1);
433             g.fillRect(w - 2, 1, 1, h - 3);
434             g.fillRect(1, h - 2, w - 3, 1);
435             // Shadow line2
436             g.setColor(lighterShadow);
437             g.fillRect(w - 2, 0, 1, 1);
438             g.fillRect(0, h - 2, 1, 1);
439             g.fillRect(w - 2, h - 2, 1, 1);
440             g.fillRect(w - 1, 1, 1, h - 2);
441             g.fillRect(1, h - 1, w - 2, 1);
442             g.translate(-x, -y);
443         }
444     }
445 
446 }