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 }