View Javadoc

1   /*
2    * $Id: StatusBar.java 178 2010-10-31 18:01:20Z roland $
3    * Copyright (C) 2007 Roland Krueger
4    * 
5    * Author: Roland Krueger (www.rolandkrueger.info)
6    *
7    * This file is part of RoKlib.
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public License
11   * as published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful, but
15   * WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22   * USA
23   */
24  package info.rolandkrueger.roklib.ui.swing;
25  
26  import java.awt.GridLayout;
27  import java.util.ArrayList;
28  import java.util.Timer;
29  import java.util.TimerTask;
30  
31  import javax.swing.JLabel;
32  import javax.swing.JPanel;
33  import javax.swing.border.EmptyBorder;
34  import javax.swing.border.EtchedBorder;
35  
36  /**
37   * This class represents a status bar that can be used to display status
38   * messages in a windowed application. The area of a status bar is divided into
39   * two parts. The bar's left half is used as display for general messages. Here,
40   * all types of messages can be displayed by the application. If desired, the
41   * right half of a status bar can be filled with specialized message fields.
42   * Such fields can be used to show the status of a some special part of the
43   * application. In a client-server application, it is conceivable to show the
44   * server address a client is connected to in such a field, for example. These
45   * specialized message fields are added to a status bar with
46   * {@link StatusBar#addElement(String, String)}.<br>
47   * <br>
48   * It is possible to display messages in the message area of a status bar that
49   * will be shown for a certain predefined period of time. This is done with
50   * {@link StatusBar#setTimedMessage(String)}. If the delay of a timed message -
51   * which can be defined through the constructor
52   * {@link StatusBar#StatusBar(long)} or with
53   * {@link StatusBar#setMessageDelay(long)} - has elapsed, the timed message is
54   * replaced by the ready message as provided by
55   * {@link StatusBar#setReadyMessage(String)}.<br>
56   * <br>
57   * <b>Example:</b> The following code will create a status bar as sketched
58   * below: <blockquote>
59   * 
60   * <pre>
61   * StatusBar bar = new StatusBar ();
62   * bar.setReadyMessage ("Ready.");
63   * bar.addElement      ("Msg. field 1",     "Help text for message field 1.");
64   * bar.addElement      ("Other msg. field", "Help text for the other message field.");
65   * 
66   * +-------------------------------+--------------+------------------+
67   * | Ready.                        | Msg. field 1 | Other msg. field |
68   * +-------------------------------+--------------+------------------+
69   * </pre>
70   * 
71   * </blockquote>
72   * 
73   * @author Roland Krueger
74   */
75  public class StatusBar extends JPanel implements HoverListener
76  {
77    private static final long serialVersionUID = 1777229355563005791L;
78  
79    private JLabel mInfoLabel;
80    private JPanel mElementsPanel;
81    private Timer mTimer;
82    private long mDelay;
83    private String mReadyText = "";
84    private String mCurrentMessage = "";
85    private ArrayList<BarElement> mElements;
86  
87    /**
88     * Default constructor. The duration of displaying a timed message is set to 2
89     * seconds.
90     * 
91     * @see StatusBar#setTimedMessage(String)
92     */
93    public StatusBar ()
94    {
95      this (2000);
96    }
97  
98    /**
99     * Constructs a {@link StatusBar} with the specified delay for timed messages.
100    * 
101    * @see StatusBar#setTimedMessage(String)
102    * @param messageDelay
103    *          delay in milliseconds for timed messages
104    */
105   public StatusBar (long messageDelay)
106   {
107     mInfoLabel = new JLabel ();
108     setLayout (new GridLayout ());
109     mInfoLabel.setBorder (new EtchedBorder (EtchedBorder.LOWERED));
110     add (mInfoLabel);
111     mDelay = messageDelay;
112     mTimer = new Timer ();
113     mElementsPanel = new JPanel ();
114     mElements = new ArrayList<BarElement> ();
115     mElementsPanel.setLayout (new GridLayout ());
116     setBorder (new EmptyBorder (1, 1, 1, 1));
117   }
118 
119   public void hoverStarted (Hoverable source)
120   {
121     if (source.getHoverText () == null) return;
122     mInfoLabel.setText (source.getHoverText ());
123   }
124 
125   public void hoverEnded (Hoverable source)
126   {
127     mInfoLabel.setText (mCurrentMessage);
128   }
129 
130   /**
131    * Sets the ready message for this status bar. This message will be displayed
132    * in the message area if no other message is currently being shown.
133    * 
134    * @param msg
135    *          the ready message for this status bar.
136    */
137   public void setReadyMessage (String msg)
138   {
139     mReadyText = msg;
140     mCurrentMessage = msg;
141     mInfoLabel.setText (msg);
142   }
143 
144   /**
145    * A timed message will be displayed in the message area for a certain amount
146    * of time. This time can be configured either through the constructor
147    * {@link StatusBar#StatusBar(long)} or through method
148    * {@link StatusBar#setMessageDelay(long)}. After the delay has elapsed, the
149    * status bar's ready message is displayed again.
150    * 
151    * @param msg
152    *          the message to be displayed for some time
153    */
154   public void setTimedMessage (String msg)
155   {
156     mCurrentMessage = msg;
157     mInfoLabel.setText (msg);
158 
159     mTimer.schedule (new TimerTask ()
160     {
161       public void run ()
162       {
163         mCurrentMessage = mReadyText;
164         mInfoLabel.setText (mCurrentMessage);
165       }
166     }, mDelay);
167   }
168 
169   /**
170    * Sets the amount of time in milliseconds of how long a timed message will be
171    * displayed.
172    * 
173    * @see StatusBar#setTimedMessage(String)
174    * @param delay
175    *          the amount of time in milliseconds of how long a timed message
176    *          will be displayed
177    */
178   public void setMessageDelay (long delay)
179   {
180     mDelay = delay;
181   }
182 
183   /**
184    * Adds a specialized message field to the right half of the status bar. The
185    * specified <code>text</code> will be displayed in that field. The given
186    * <code>helpText</code> will be displayed in the general message area while
187    * the mouse cursor hovers over the specialized message field. Both of these
188    * text messages can be changed with
189    * {@link StatusBar#setElementText(int, String)} and
190    * {@link StatusBar#setElementHelpText(int, String)}, respectively. The
191    * <code>int</code> value that is returned by this method is the
192    * identification number of the new specialized message field. This number is
193    * needed for the first parameter of the <code>setElement*</code> methods and
194    * indicates the field that is meant to be changed.
195    * 
196    * @see StatusBar#setElementHelpText(int, String)
197    * @see StatusBar#setElementText(int, String)
198    * @param text
199    *          the text that will be displayed in the text area
200    * @param helpText
201    *          help text for the text area that will be displayed in the general
202    *          text area when the mouse hovers over the new text area
203    * @return an identification number that is needed to refer to the newly added
204    *         text area
205    */
206   public int addElement (String text, String helpText)
207   {
208     BarElement element = new BarElement (text, helpText);
209     element.addHoverListener (this);
210     if (mElements.size () == 0)
211     {
212       // rearrange layout if the first separate element is added
213       removeAll ();
214       setLayout (new GridLayout (1, 2));
215       add (mInfoLabel);
216       add (mElementsPanel);
217     }
218     mElementsPanel.add (element);
219     mElements.add (element);
220     return mElements.indexOf (element);
221   }
222 
223   /**
224    * Sets the text displayed by the spezialized message area with the given
225    * identification number.
226    * 
227    * @param elementNr
228    *          identification number as provided by
229    *          {@link StatusBar#addElement(String, String)} which refers to the
230    *          message field that is to be changed by this method
231    * @param text
232    *          the text to be displayed by the message field
233    * @throws ArrayIndexOutOfBoundsException
234    *           if the message field denoted by <code>elementNr</code> does not
235    *           exist
236    */
237   public void setElementText (int elementNr, String text)
238   {
239     if (elementNr > mElements.size () || elementNr < 0)
240       throw new ArrayIndexOutOfBoundsException ();
241     mElements.get (elementNr).setText (text);
242   }
243 
244   /**
245    * Sets the help text that belongs to the spezialized message area with the
246    * given identification number.
247    * 
248    * @param elementNr
249    *          identification number as provided by
250    *          {@link StatusBar#addElement(String, String)} which refers to the
251    *          message field that is to be changed by this method
252    * @param helpText
253    *          the text to be displayed by the message field
254    * @throws ArrayIndexOutOfBoundsException
255    *           if the message field denoted by <code>elementNr</code> does not
256    *           exist
257    */
258   public void setElementHelpText (int elementNr, String helpText)
259   {
260     if (elementNr >= mElements.size () || elementNr < 0)
261       throw new ArrayIndexOutOfBoundsException ();
262     mElements.get (elementNr).setHelpText (helpText);
263   }
264 
265   /**
266    * This class represents a single display area of a status bar.
267    * 
268    * @author Roland Krueger
269    */
270   private class BarElement extends JLabel implements Hoverable
271   {
272     private static final long serialVersionUID = 9159375387417999283L;
273 
274     private String mHelpText;
275     private HoverManager mHoverManager;
276 
277     public BarElement (String text, String helpText)
278     {
279       super (text);
280       setHelpText (helpText);
281       mHoverManager = new HoverManager (this);
282       addMouseListener (mHoverManager);
283       setBorder (new EtchedBorder (EtchedBorder.LOWERED));
284     }
285 
286     public BarElement (String text)
287     {
288       this (text, "");
289     }
290 
291     public void setText (String text)
292     {
293       super.setText (text);
294     }
295 
296     public void setHelpText (String helpText)
297     {
298       mHelpText = helpText;
299       setToolTipText (helpText);
300     }
301 
302     public String getHoverText ()
303     {
304       return mHelpText;
305     }
306 
307     public boolean addHoverListener (HoverListener listener)
308     {
309       return mHoverManager.addHoverListener (listener);
310     }
311   }
312 }