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