001 /* 002 * $Id: JXTaskPane.java,v 1.8 2006/05/14 08:12:18 dmouse Exp $ 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 package org.jdesktop.swingx; 022 023 import java.awt.BorderLayout; 024 import java.awt.Component; 025 import java.awt.Container; 026 import java.awt.LayoutManager; 027 import java.beans.PropertyChangeEvent; 028 import java.beans.PropertyChangeListener; 029 030 import javax.swing.Action; 031 import javax.swing.Icon; 032 import javax.swing.JComponent; 033 import javax.swing.JPanel; 034 import javax.swing.UIManager; 035 036 import org.jdesktop.swingx.plaf.JXTaskPaneAddon; 037 import org.jdesktop.swingx.plaf.LookAndFeelAddons; 038 import org.jdesktop.swingx.plaf.TaskPaneUI; 039 040 /** 041 * <code>JXTaskPane</code> is a container for tasks and other 042 * arbitrary components. 043 * 044 * <p> 045 * Several <code>JXTaskPane</code>s are usually grouped together within a 046 * {@link org.jdesktop.swingx.JXTaskPaneContainer}. However it is not mandatory 047 * to use a JXTaskPaneContainer as the parent for JXTaskPane. The JXTaskPane can 048 * be added to any other container. See 049 * {@link org.jdesktop.swingx.JXTaskPaneContainer} to understand the benefits of 050 * using it as the parent container. 051 * 052 * <p> 053 * <code>JXTaskPane</code> provides control to expand and 054 * collapse the content area in order to show or hide the task list. It can have an 055 * <code>icon</code>, a <code>title</code> and can be marked as 056 * <code>special</code>. Marking a <code>JXTaskPane</code> as 057 * <code>special</code> ({@link #setSpecial(boolean)} is only a hint for 058 * the pluggable UI which will usually paint it differently (by example by 059 * using another color for the border of the pane). 060 * 061 * <p> 062 * When the JXTaskPane is expanded or collapsed, it will be 063 * animated with a fade effect. The animated can be disabled on a per 064 * component basis through {@link #setAnimated(boolean)}. 065 * 066 * To disable the animation for all newly created <code>JXTaskPane</code>, 067 * use the UIManager property: 068 * <code>UIManager.put("TaskPane.animate", Boolean.FALSE);</code>. 069 * 070 * <p> 071 * Example: 072 * <pre> 073 * <code> 074 * JXFrame frame = new JXFrame(); 075 * 076 * // a container to put all JXTaskPane together 077 * JXTaskPaneContainer taskPaneContainer = new JXTaskPaneContainer(); 078 * 079 * // create a first taskPane with common actions 080 * JXTaskPane actionPane = new JXTaskPane(); 081 * actionPane.setTitle("Files and Folders"); 082 * actionPane.setSpecial(true); 083 * 084 * // actions can be added, an hyperlink will be created 085 * Action renameSelectedFile = createRenameFileAction(); 086 * actionPane.add(renameSelectedFile); 087 * actionPane.add(createDeleteFileAction()); 088 * 089 * // add this taskPane to the taskPaneContainer 090 * taskPaneContainer.add(actionPane); 091 * 092 * // create another taskPane, it will show details of the selected file 093 * JXTaskPane details = new JXTaskPane(); 094 * details.setTitle("Details"); 095 * 096 * // add standard components to the details taskPane 097 * JLabel searchLabel = new JLabel("Search:"); 098 * JTextField searchField = new JTextField(""); 099 * details.add(searchLabel); 100 * details.add(searchField); 101 * 102 * taskPaneContainer.add(details); 103 * 104 * // put the action list on the left 105 * frame.add(taskPaneContainer, BorderLayout.EAST); 106 * 107 * // and a file browser in the middle 108 * frame.add(fileBrowser, BorderLayout.CENTER); 109 * 110 * frame.pack(). 111 * frame.setVisible(true); 112 * </code> 113 * </pre> 114 * 115 * @see org.jdesktop.swingx.JXTaskPaneContainer 116 * @see org.jdesktop.swingx.JXCollapsiblePane 117 * @author <a href="mailto:fred@L2FProd.com">Frederic Lavigne</a> 118 * 119 * @javabean.attribute 120 * name="isContainer" 121 * value="Boolean.TRUE" 122 * rtexpr="true" 123 * 124 * @javabean.attribute 125 * name="containerDelegate" 126 * value="getContentPane" 127 * 128 * @javabean.class 129 * name="JXTaskPane" 130 * shortDescription="JXTaskPane is a container for tasks and other arbitrary components." 131 * stopClass="java.awt.Component" 132 * 133 * @javabean.icons 134 * mono16="JXTaskPane16-mono.gif" 135 * color16="JXTaskPane16.gif" 136 * mono32="JXTaskPane32-mono.gif" 137 * color32="JXTaskPane32.gif" 138 */ 139 public class JXTaskPane extends JPanel implements 140 JXCollapsiblePane.JCollapsiblePaneContainer { 141 142 /** 143 * JXTaskPane pluggable UI key <i>swingx/TaskPaneUI</i> 144 */ 145 public final static String uiClassID = "swingx/TaskPaneUI"; 146 147 // ensure at least the default ui is registered 148 static { 149 LookAndFeelAddons.contribute(new JXTaskPaneAddon()); 150 } 151 152 /** 153 * Used when generating PropertyChangeEvents for the "expanded" property 154 */ 155 public static final String EXPANDED_CHANGED_KEY = "expanded"; 156 157 /** 158 * Used when generating PropertyChangeEvents for the "scrollOnExpand" property 159 */ 160 public static final String SCROLL_ON_EXPAND_CHANGED_KEY = "scrollOnExpand"; 161 162 /** 163 * Used when generating PropertyChangeEvents for the "title" property 164 */ 165 public static final String TITLE_CHANGED_KEY = "title"; 166 167 /** 168 * Used when generating PropertyChangeEvents for the "icon" property 169 */ 170 public static final String ICON_CHANGED_KEY = "icon"; 171 172 /** 173 * Used when generating PropertyChangeEvents for the "special" property 174 */ 175 public static final String SPECIAL_CHANGED_KEY = "special"; 176 177 /** 178 * Used when generating PropertyChangeEvents for the "animated" property 179 */ 180 public static final String ANIMATED_CHANGED_KEY = "animated"; 181 182 private String title; 183 private Icon icon; 184 private boolean special; 185 private boolean expanded = true; 186 private boolean scrollOnExpand; 187 188 private JXCollapsiblePane collapsePane; 189 190 /** 191 * Creates a new empty <code>JXTaskPane</code>. 192 */ 193 public JXTaskPane() { 194 collapsePane = new JXCollapsiblePane(); 195 super.setLayout(new BorderLayout(0, 0)); 196 super.addImpl(collapsePane, BorderLayout.CENTER, -1); 197 198 updateUI(); 199 setFocusable(true); 200 setOpaque(false); 201 202 // disable animation if specified in UIManager 203 setAnimated(!Boolean.FALSE.equals(UIManager.get("TaskPane.animate"))); 204 205 // listen for animation events and forward them to registered listeners 206 collapsePane.addPropertyChangeListener( 207 JXCollapsiblePane.ANIMATION_STATE_KEY, new PropertyChangeListener() { 208 public void propertyChange(PropertyChangeEvent evt) { 209 JXTaskPane.this.firePropertyChange(evt.getPropertyName(), evt 210 .getOldValue(), evt.getNewValue()); 211 } 212 }); 213 } 214 215 /** 216 * Returns the contentPane object for this JXTaskPane. 217 * @return the contentPane property 218 */ 219 public Container getContentPane() { 220 return collapsePane.getContentPane(); 221 } 222 223 /** 224 * Notification from the <code>UIManager</code> that the L&F has changed. 225 * Replaces the current UI object with the latest version from the <code>UIManager</code>. 226 * 227 * @see javax.swing.JComponent#updateUI 228 */ 229 @Override 230 public void updateUI() { 231 // collapsePane is null when updateUI() is called by the "super()" 232 // constructor 233 if (collapsePane == null) { 234 return; 235 } 236 setUI((TaskPaneUI)LookAndFeelAddons.getUI(this, TaskPaneUI.class)); 237 } 238 239 /** 240 * Sets the L&F object that renders this component. 241 * 242 * @param ui the <code>TaskPaneUI</code> L&F object 243 * @see javax.swing.UIDefaults#getUI 244 * 245 * @beaninfo bound: true hidden: true description: The UI object that 246 * implements the taskpane group's LookAndFeel. 247 */ 248 public void setUI(TaskPaneUI ui) { 249 super.setUI(ui); 250 } 251 252 /** 253 * Returns the name of the L&F class that renders this component. 254 * 255 * @return the string {@link #uiClassID} 256 * @see javax.swing.JComponent#getUIClassID 257 * @see javax.swing.UIDefaults#getUI 258 */ 259 @Override 260 public String getUIClassID() { 261 return uiClassID; 262 } 263 264 /** 265 * Returns the title currently displayed in the border of this pane. 266 * 267 * @return the title currently displayed in the border of this pane 268 */ 269 public String getTitle() { 270 return title; 271 } 272 273 /** 274 * Sets the title to be displayed in the border of this pane. 275 * 276 * @param title the title to be displayed in the border of this pane 277 * @javabean.property 278 * bound="true" 279 * preferred="true" 280 */ 281 public void setTitle(String title) { 282 String old = this.title; 283 this.title = title; 284 firePropertyChange(TITLE_CHANGED_KEY, old, title); 285 } 286 287 /** 288 * Returns the icon currently displayed in the border of this pane. 289 * 290 * @return the icon currently displayed in the border of this pane 291 */ 292 public Icon getIcon() { 293 return icon; 294 } 295 296 /** 297 * Sets the icon to be displayed in the border of this pane. Some pluggable 298 * UIs may impose size constraints for the icon. A size of 16x16 pixels is 299 * the recommended icon size. 300 * 301 * @param icon the icon to be displayed in the border of this pane 302 * @javabean.property 303 * bound="true" 304 * preferred="true" 305 */ 306 public void setIcon(Icon icon) { 307 Icon old = this.icon; 308 this.icon = icon; 309 firePropertyChange(ICON_CHANGED_KEY, old, icon); 310 } 311 312 /** 313 * Returns true if this pane is "special". 314 * 315 * @return true if this pane is "special" 316 * @see #setSpecial(boolean) 317 */ 318 public boolean isSpecial() { 319 return special; 320 } 321 322 /** 323 * Sets this pane to be "special" or not. Marking a <code>JXTaskPane</code> 324 * as <code>special</code> is only a hint for the pluggable UI which will 325 * usually paint it differently (by example by using another color for the 326 * border of the pane). 327 * 328 * <p> 329 * Usually the first JXTaskPane in a JXTaskPaneContainer is marked as special 330 * because it contains the default set of actions which can be executed given 331 * the current context. 332 * 333 * @param special 334 * true if this pane is "special", false otherwise 335 * @javabean.property bound="true" preferred="true" 336 */ 337 public void setSpecial(boolean special) { 338 if (this.special != special) { 339 this.special = special; 340 firePropertyChange(SPECIAL_CHANGED_KEY, !special, special); 341 } 342 } 343 344 /** 345 * Should this group be scrolled to be visible on expand. 346 * 347 * @param scrollOnExpand true to scroll this group to be 348 * visible if this group is expanded. 349 * 350 * @see #setExpanded(boolean) 351 * 352 * @javabean.property 353 * bound="true" 354 * preferred="true" 355 */ 356 public void setScrollOnExpand(boolean scrollOnExpand) { 357 if (this.scrollOnExpand != scrollOnExpand) { 358 this.scrollOnExpand = scrollOnExpand; 359 firePropertyChange(SCROLL_ON_EXPAND_CHANGED_KEY, 360 !scrollOnExpand, scrollOnExpand); 361 } 362 } 363 364 /** 365 * Should this group scroll to be visible after 366 * this group was expanded. 367 * 368 * @return true if we should scroll false if nothing 369 * should be done. 370 */ 371 public boolean isScrollOnExpand() { 372 return scrollOnExpand; 373 } 374 375 /** 376 * Expands or collapses this group. 377 * 378 * @param expanded true to expand the group, false to collapse it 379 * @javabean.property 380 * bound="true" 381 * preferred="true" 382 */ 383 public void setExpanded(boolean expanded) { 384 if (this.expanded != expanded) { 385 this.expanded = expanded; 386 collapsePane.setCollapsed(!expanded); 387 firePropertyChange(EXPANDED_CHANGED_KEY, !expanded, expanded); 388 } 389 } 390 391 /** 392 * Returns true if this taskpane is expanded, false if it is collapsed. 393 * 394 * @return true if this taskpane is expanded, false if it is collapsed. 395 */ 396 public boolean isExpanded() { 397 return expanded; 398 } 399 400 /** 401 * Enables or disables animation during expand/collapse transition. 402 * 403 * @param animated 404 * @javabean.property 405 * bound="true" 406 * preferred="true" 407 */ 408 public void setAnimated(boolean animated) { 409 if (isAnimated() != animated) { 410 collapsePane.setAnimated(animated); 411 firePropertyChange(ANIMATED_CHANGED_KEY, !isAnimated(), isAnimated()); 412 } 413 } 414 415 /** 416 * Returns true if this taskpane is animated during expand/collapse 417 * transition. 418 * 419 * @return true if this taskpane is animated during expand/collapse 420 * transition. 421 */ 422 public boolean isAnimated() { 423 return collapsePane.isAnimated(); 424 } 425 426 /** 427 * Adds an action to this <code>JXTaskPane</code>. Returns a 428 * component built from the action. The returned component has been 429 * added to the <code>JXTaskPane</code>. 430 * 431 * @param action 432 * @return a component built from the action 433 */ 434 public Component add(Action action) { 435 Component c = ((TaskPaneUI)ui).createAction(action); 436 add(c); 437 return c; 438 } 439 440 /** 441 * @see JXCollapsiblePane.JCollapsiblePaneContainer 442 */ 443 public Container getValidatingContainer() { 444 return getParent(); 445 } 446 447 /** 448 * Overriden to redirect call to the content pane. 449 */ 450 @Override 451 protected void addImpl(Component comp, Object constraints, int index) { 452 getContentPane().add(comp, constraints, index); 453 } 454 455 /** 456 * Overriden to redirect call to the content pane. 457 */ 458 @Override 459 public void setLayout(LayoutManager mgr) { 460 if (collapsePane != null) { 461 getContentPane().setLayout(mgr); 462 } 463 } 464 465 /** 466 * Overriden to redirect call to the content pane 467 */ 468 @Override 469 public void remove(Component comp) { 470 getContentPane().remove(comp); 471 } 472 473 /** 474 * Overriden to redirect call to the content pane. 475 */ 476 @Override 477 public void remove(int index) { 478 getContentPane().remove(index); 479 } 480 481 /** 482 * Overriden to redirect call to the content pane. 483 */ 484 @Override 485 public void removeAll() { 486 getContentPane().removeAll(); 487 } 488 489 /** 490 * @see JComponent#paramString() 491 */ 492 @Override 493 protected String paramString() { 494 return super.paramString() 495 + ",title=" 496 + getTitle() 497 + ",icon=" 498 + getIcon() 499 + ",expanded=" 500 + String.valueOf(isExpanded()) 501 + ",special=" 502 + String.valueOf(isSpecial()) 503 + ",scrollOnExpand=" 504 + String.valueOf(isScrollOnExpand()) 505 + ",ui=" + getUI(); 506 } 507 508 }