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 }