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