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