001 /*
002 * $Id: JXStatusBar.java 3249 2009-02-04 19:53:56Z kschaefe $
003 *
004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020 */
021
022 package org.jdesktop.swingx;
023
024
025 import java.awt.Insets;
026 import javax.swing.JComponent;
027 import org.jdesktop.swingx.plaf.StatusBarAddon;
028 import org.jdesktop.swingx.plaf.LookAndFeelAddons;
029 import org.jdesktop.swingx.plaf.StatusBarUI;
030
031 /**
032 * <p>A container for <code>JComponents</code> that is typically placed at
033 * the bottom of a form and runs the entire width of the form. There are 3
034 * important functions that <code>JXStatusBar</code> provides.
035 * First, <code>JXStatusBar</code> provides a hook for a pluggable look.
036 * There is a definite look associated with status bars on windows, for instance.
037 * By implementing a subclass of {@link JComponent}, we provide a way for the
038 * pluggable look and feel system to modify the look of the status bar.</p>
039 *
040 * <p>Second, <code>JXStatusBar</code> comes with its own layout manager. Each item is added to
041 * the <code>JXStatusBar</code> with a <code>JXStatusBar.Constraint</code>
042 * as the constraint argument. The <code>JXStatusBar.Constraint</code> contains
043 * an <code>Insets</code> object, as well as a <code>ResizeBehavior</code>,
044 * which can be FIXED or FILL. The resize behaviour applies to the width of
045 * components. All components added will maintain there preferred height, and the
046 * height of the <code>JXStatusBar</code> will be the height of the highest
047 * component plus insets.</p>
048 *
049 * <p>A constraint with <code>JXStatusBar.Constraint.ResizeBehavior.FIXED</code>
050 * will cause the component to occupy a fixed area on the <code>JXStatusBar</code>.
051 * The size of the area remains constant when the <code>JXStatusBar</code> is resized.
052 * A constraint with this behavior may also take a width value, see
053 * {@link JXStatusBar.Constraint#setFixedWidth(int)}. The width is a preferred
054 * minimum width. If the component preferred width is greater than the constraint
055 * width, the component width will apply.</p>
056 *
057 * <p>All components with constraint <code>JXStatusBar.Constraint.ResizeBehavior.FILL</code>
058 * will share equally any spare space in the <code>JXStatusBar</code>. Spare space
059 * is that left over after allowing for all FIXED component and the preferred
060 * width of FILL components, plus insets
061 *
062 * <p>Constructing a <code>JXStatusBar</code> is very straightforward:
063 * <pre><code>
064 * JXStatusBar bar = new JXStatusBar();
065 * JLabel statusLabel = new JLabel("Ready");
066 * JXStatusBar.Constraint c1 = new JXStatusBarConstraint()
067 * c1.setFixedWidth(100);
068 * bar.add(statusLabel, c1); // Fixed width of 100 with no inserts
069 * JXStatusBar.Constraint c2 = new JXStatusBarConstraint(
070 * JXStatusBar.Constraint.ResizeBehavior.FILL) // Fill with no inserts
071 * JProgressBar pbar = new JProgressBar();
072 * bar.add(pbar, c2); // Fill with no inserts - will use remaining space
073 * </code></pre></p>
074 *
075 * <p>Two common use cases for status bars include tracking application status and
076 * progress. <code>JXStatusBar</code> does not manage these tasks, but instead special components
077 * exist or can be created that do manage these tasks. For example, if your application
078 * has a TaskManager or some other repository of currently running jobs, you could
079 * easily create a TaskManagerProgressBar that tracks those jobs. This component
080 * could then be added to the <code>JXStatusBar</code> like any other component.</p>
081 *
082 * <h2>Client Properties</h2>
083 * <p>The BasicStatusBarUI.AUTO_ADD_SEPARATOR client property can be specified, which
084 * will disable the auto-adding of separators. In this case, you must add your own
085 * JSeparator components. To use:
086 * <pre><code>
087 * JXStatusBar sbar = new JXStatusBar();
088 * sbar.putClientProperty(BasicStatusBarUI.AUTO_ADD_SEPARATOR, false);
089 * sbar.add(comp1);
090 * sbar.add(new JSeparator(JSeparator.VERTICAL));
091 * sbar.add(comp2);
092 * sbar.add(comp3);
093 * </code></pre></p>
094 *
095 * @status REVIEWED
096 *
097 * @author pdoubleya
098 * @author rbair
099 * @author Karl George Schaefer
100 */
101 public class JXStatusBar extends JComponent {
102 /**
103 * @see #getUIClassID
104 * @see #readObject
105 */
106 public static final String uiClassID = "StatusBarUI";
107
108 //TODO how to handle UI delegate setting of primitive?
109 private boolean resizeHandleEnabled;
110
111 /**
112 * Initialization that would ideally be moved into various look and feel
113 * classes.
114 */
115 static {
116 LookAndFeelAddons.contribute(new StatusBarAddon());
117 }
118
119 /**
120 * Creates a new JXStatusBar
121 */
122 public JXStatusBar() {
123 super();
124 updateUI();
125 }
126
127 /**
128 * @param resizeHandleEnabled the resizeHandleEnabled to set
129 */
130 public void setResizeHandleEnabled(boolean resizeHandleEnabled) {
131 boolean oldValue = isResizeHandleEnabled();
132 this.resizeHandleEnabled = resizeHandleEnabled;
133 firePropertyChange("resizeHandleEnabled", oldValue, isResizeHandleEnabled());
134 }
135
136 /**
137 * @return the resizeHandleEnabled
138 */
139 public boolean isResizeHandleEnabled() {
140 return resizeHandleEnabled;
141 }
142
143 /**
144 * Returns the look and feel (L&F) object that renders this component.
145 *
146 * @return the StatusBarUI object that renders this component
147 */
148 public StatusBarUI getUI() {
149 return (StatusBarUI) ui;
150 }
151
152 /**
153 * Sets the look and feel (L&F) object that renders this component.
154 *
155 * @param ui
156 * the StatusBarUI L&F object
157 * @see javax.swing.UIDefaults#getUI
158 * @beaninfo
159 * bound: true
160 * hidden: true
161 * attribute: visualUpdate true
162 * description: The component's look and feel delegate.
163 */
164 public void setUI(StatusBarUI ui) {
165 super.setUI(ui);
166 }
167
168 /**
169 * Returns a string that specifies the name of the L&F class that renders
170 * this component.
171 *
172 * @return "StatusBarUI"
173 * @see javax.swing.JComponent#getUIClassID
174 * @see javax.swing.UIDefaults#getUI
175 * @beaninfo expert: true description: A string that specifies the name of
176 * the L&F class.
177 */
178 @Override
179 public String getUIClassID() {
180 return uiClassID;
181 }
182
183 /**
184 * Notification from the <code>UIManager</code> that the L&F has changed.
185 * Replaces the current UI object with the latest version from the
186 * <code>UIManager</code>.
187 *
188 * @see javax.swing.JComponent#updateUI
189 */
190 @Override
191 public void updateUI() {
192 setUI((StatusBarUI) LookAndFeelAddons
193 .getUI(this, StatusBarUI.class));
194 }
195
196 /**
197 * The constraint object to be used with the <code>JXStatusBar</code>. It takes
198 * a ResizeBehaviour, Insets and a Width. Width is only applicable for
199 * ResizeBehavior.FIXED. @see JXStatusBar class documentation.
200 */
201 public static class Constraint {
202 public static enum ResizeBehavior {FILL, FIXED}
203
204 private Insets insets;
205 private ResizeBehavior resizeBehavior;
206 private int fixedWidth = 0;
207
208 /**
209 * Creates a new Constraint with default FIXED behaviour and no insets.
210 */
211 public Constraint() {
212 this(ResizeBehavior.FIXED, null);
213 }
214
215 /**
216 * Creates a new Constraint with default FIXED behaviour and the given insets
217 *
218 * @param insets may be null. If null, an Insets with 0 values will be used.
219 */
220 public Constraint(Insets insets) {
221 this(ResizeBehavior.FIXED, insets);
222 }
223
224 /**
225 * Creates a new Constraint with default FIXED behaviour and the given fixed
226 * width.
227 *
228 * @param fixedWidth must be >= 0
229 */
230 public Constraint(int fixedWidth) {
231 this(fixedWidth, null);
232 }
233
234 /**
235 * Creates a new Constraint with default FIXED behaviour and the given fixed
236 * width, and using the given Insets.
237 *
238 * @param fixedWidth must be >= 0
239 * @param insets may be null. If null, an Insets with 0 values will be used.
240 */
241 public Constraint(int fixedWidth, Insets insets) {
242 if (fixedWidth < 0) {
243 throw new IllegalArgumentException("fixedWidth must be >= 0");
244 }
245 this.fixedWidth = fixedWidth;
246 this.insets = insets == null ? new Insets(0, 0, 0, 0) : (Insets)insets.clone();
247 this.resizeBehavior = ResizeBehavior.FIXED;
248 }
249
250 /**
251 * Creates a new Constraint with the specified resize behaviour and no insets
252 *
253 * @param resizeBehavior - either JXStatusBar.Constraint.ResizeBehavior.FIXED
254 * or JXStatusBar.Constraint.ResizeBehavior.FILL.
255 */
256 public Constraint(ResizeBehavior resizeBehavior) {
257 this(resizeBehavior, null);
258 }
259
260 /**
261 * Creates a new Constraint with the specified resize behavior and insets.
262 *
263 * @param resizeBehavior - either JXStatusBar.Constraint.ResizeBehavior.FIXED
264 * or JXStatusBar.Constraints.ResizeBehavior.FILL.
265 * @param insets may be null. If null, an Insets with 0 values will be used.
266 */
267 public Constraint(ResizeBehavior resizeBehavior, Insets insets) {
268 this.resizeBehavior = resizeBehavior;
269 this.insets = insets == null ? new Insets(0, 0, 0, 0) : (Insets)insets.clone();
270 }
271
272 /**
273 * Set the fixed width the component added with this
274 * constraint will occupy on the <code>JXStatusBar</code>. Only applies
275 * to ResizeBehavior.FIXED. Will be ignored for ResizeBehavior.FILL.
276 *
277 * @param width - minimum width component will occupy. If 0, the preferred
278 * width of the component will be used.
279 * The width specified must be >= 0
280 */
281 public void setFixedWidth(int width) {
282 if (width < 0) {
283 throw new IllegalArgumentException("width must be >= 0");
284 }
285 fixedWidth = resizeBehavior == ResizeBehavior.FIXED ? width : 0;
286 }
287
288 /**
289 * Returns the ResizeBehavior.
290 *
291 * @return ResizeBehavior
292 */
293 public ResizeBehavior getResizeBehavior() {
294 return resizeBehavior;
295 }
296
297 /**
298 * Returns the insets.
299 *
300 * @return insets
301 */
302 public Insets getInsets() {
303 return (Insets)insets.clone();
304 }
305
306 /**
307 * Get fixed width. Width is zero for resize behavior FILLED
308 * @return the width of this constraint
309 */
310 public int getFixedWidth() {
311 return fixedWidth;
312 }
313 }
314
315 }