001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings;
014:
015: import org.wings.plaf.ButtonCG;
016: import org.wings.plaf.CheckBoxCG;
017: import org.wings.plaf.ClickableCG;
018: import org.wings.plaf.RadioButtonCG;
019: import org.wings.plaf.ToggleButtonCG;
020: import org.wings.style.Selector;
021: import org.wings.style.CSSStyleSheet;
022: import org.wings.style.CSSAttributeSet;
023: import org.wings.style.CSSProperty;
024:
025: import javax.swing.event.ChangeEvent;
026: import javax.swing.event.ChangeListener;
027: import javax.swing.event.EventListenerList;
028: import java.awt.*;
029: import java.awt.event.ItemEvent;
030: import java.awt.event.ItemListener;
031:
032: /**
033: * Base class for elements with icon and text like {@link SAbstractButton} and {@link SClickable}.
034: *
035: * It supports 7 different icon states.
036: *
037: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>
038: */
039: public abstract class SAbstractIconTextCompound extends SComponent
040: implements ItemSelectable {
041: public static final int ICON_COUNT = 7;
042: public static final int DISABLED_ICON = 0;
043: public static final int DISABLED_SELECTED_ICON = 1;
044: public static final int ENABLED_ICON = 2;
045: public static final int SELECTED_ICON = 3;
046: public static final int ROLLOVER_ICON = 4;
047: public static final int ROLLOVER_SELECTED_ICON = 5;
048: public static final int PRESSED_ICON = 6;
049:
050: /**
051: * A Pseudo selector for buttons in selected state
052: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
053: */
054: public static final Selector SELECTOR_SELECTED = new Selector(
055: "selected");
056:
057: private SButtonModel model;
058:
059: /**
060: * The button model's <code>changeListener</code>.
061: */
062: protected ChangeListener changeListener = null;
063:
064: protected transient ChangeEvent changeEvent = null;
065:
066: /**
067: * the text the button is showing
068: */
069: private String text;
070:
071: /**
072: * The icon to be displayed
073: */
074: private SIcon icon;
075:
076: private SIcon disabledIcon;
077:
078: private SIcon selectedIcon;
079:
080: private SIcon pressedIcon;
081:
082: private SIcon disabledSelectedIcon;
083:
084: private SIcon rolloverIcon;
085:
086: private SIcon rolloverSelectedIcon;
087:
088: private int verticalTextPosition = SConstants.CENTER;
089:
090: private int horizontalTextPosition = SConstants.RIGHT;
091:
092: private int iconTextGap = 4;
093:
094: private boolean delayEvents = false;
095: private boolean delayedEvent = false;
096:
097: /**
098: * Create a button with given text.
099: *
100: * @param text the button text
101: */
102: public SAbstractIconTextCompound(String text) {
103: setText(text);
104: model = new SDefaultButtonModel();
105: }
106:
107: /**
108: * Creates a new submit button
109: */
110: public SAbstractIconTextCompound() {
111: this (null);
112: }
113:
114: public SButtonModel getModel() {
115: return model;
116: }
117:
118: public void setModel(SButtonModel model) {
119: if (model == null)
120: throw new IllegalArgumentException("null not allowed");
121: reloadIfChange(this .model, model);
122: this .model = model;
123: }
124:
125: /**
126: * Returns the selected items or null if no items are selected.
127: */
128: public Object[] getSelectedObjects() {
129: return model.isSelected() ? new Object[] { this } : null;
130: }
131:
132: /**
133: * Returns an array of all the <code>ItemListener</code>s added
134: * to this SAbstractIconTextCompound with addItemListener().
135: *
136: * @return all of the <code>ItemListener</code>s added or an empty
137: * array if no listeners have been added
138: */
139: public ItemListener[] getItemListeners() {
140: return (ItemListener[]) (getListeners(ItemListener.class));
141: }
142:
143: /**
144: * Adds a ItemListener to the button.
145: *
146: * @see #removeItemListener(ItemListener)
147: */
148: public void addItemListener(ItemListener il) {
149: addEventListener(ItemListener.class, il);
150: }
151:
152: /**
153: * Remove the given itemListener from list of
154: * item listeners.
155: *
156: * @see #addItemListener(ItemListener)
157: */
158: public void removeItemListener(ItemListener il) {
159: removeEventListener(ItemListener.class, il);
160: }
161:
162: /**
163: * Returns an array of all the <code>ChangeListener</code>s added
164: * to this SAbstractIconTextCompound with addChangeListener().
165: *
166: * @return all of the <code>ChangeListener</code>s added or an empty
167: * array if no listeners have been added
168: */
169: public ChangeListener[] getChangeListeners() {
170: return (ChangeListener[]) (getListeners(ChangeListener.class));
171: }
172:
173: /**
174: * Adds a <code>ChangeListener</code> to the button.
175: *
176: * @param l the listener to be added
177: */
178: public void addChangeListener(ChangeListener l) {
179: addEventListener(ChangeListener.class, l);
180: }
181:
182: /**
183: * Removes a ChangeListener from the button.
184: *
185: * @param l the listener to be removed
186: */
187: public void removeChangeListener(ChangeListener l) {
188: removeEventListener(ChangeListener.class, l);
189: }
190:
191: /**
192: * Notifies all listeners that have registered interest for
193: * notification on this event type. The event instance
194: * is lazily created using the parameters passed into
195: * the fire method.
196: *
197: * @see EventListenerList
198: */
199: protected void fireStateChanged() {
200: // Guaranteed to return a non-null array
201: Object[] listeners = getListenerList();
202: // Process the listeners last to first, notifying
203: // those that are interested in this event
204: for (int i = listeners.length - 2; i >= 0; i -= 2) {
205: if (listeners[i] == ChangeListener.class) {
206: // Lazily create the event:
207: if (changeEvent == null)
208: changeEvent = new ChangeEvent(this );
209: ((ChangeListener) listeners[i + 1])
210: .stateChanged(changeEvent);
211: }
212: }
213: }
214:
215: public void setHorizontalTextPosition(int textPosition) {
216: reloadIfChange(this .horizontalTextPosition, textPosition);
217: horizontalTextPosition = textPosition;
218:
219: }
220:
221: public int getHorizontalTextPosition() {
222: return horizontalTextPosition;
223: }
224:
225: public void setVerticalTextPosition(int textPosition) {
226: reloadIfChange(this .verticalTextPosition, textPosition);
227: verticalTextPosition = textPosition;
228: }
229:
230: public int getVerticalTextPosition() {
231: return verticalTextPosition;
232: }
233:
234: public void setIconTextGap(int gap) {
235: reloadIfChange(this .iconTextGap, gap);
236: iconTextGap = gap;
237: }
238:
239: public int getIconTextGap() {
240: return iconTextGap;
241: }
242:
243: /**
244: * Sets the icon for the compound.
245: *
246: * @param i the icon.
247: */
248: public void setIcon(SIcon i) {
249: if (isDifferent(icon, i)) {
250: // do reload if previous icon was null
251: if (isUpdatePossible() && icon != null) {
252: if (SButton.class.isAssignableFrom(getClass()))
253: update(((ButtonCG) getCG()).getIconUpdate(
254: (SButton) this , i));
255: else if (SCheckBox.class.isAssignableFrom(getClass()))
256: update(((CheckBoxCG) getCG()).getIconUpdate(
257: (SCheckBox) this , i));
258: else if (SRadioButton.class
259: .isAssignableFrom(getClass()))
260: update(((RadioButtonCG) getCG()).getIconUpdate(
261: (SRadioButton) this , i));
262: else if (SToggleButton.class
263: .isAssignableFrom(getClass()))
264: update(((ToggleButtonCG) getCG()).getIconUpdate(
265: (SToggleButton) this , i));
266: else if (SClickable.class.isAssignableFrom(getClass()))
267: update(((ClickableCG) getCG()).getIconUpdate(
268: (SClickable) this , i));
269: else
270: reload();
271: } else {
272: reload();
273: }
274: icon = i;
275: }
276: }
277:
278: /**
279: * Returns the icon of the Compound.
280: *
281: * @see #setIcon(SIcon)
282: */
283: public SIcon getIcon() {
284: return icon;
285: }
286:
287: /**
288: * Sets the icon that is displayed when the compound is pressed with the mouse.
289: *
290: * @param icon to be shown when mouse button is pressed.
291: */
292: public void setPressedIcon(SIcon icon) {
293: reloadIfChange(pressedIcon, icon);
294: pressedIcon = icon;
295: }
296:
297: /**
298: * Returns the icon that is displayed when a compound is pressed with the mouse.
299: *
300: * @see #setPressedIcon(SIcon)
301: */
302: public SIcon getPressedIcon() {
303: return pressedIcon;
304: }
305:
306: /**
307: * Sets the icon that is displayed as rollOver effect (meaning the icon
308: * shown when the mouse is just positioned over the compound).
309: *
310: * @param icon rollOver icon for unselected compound.
311: */
312: public void setRolloverIcon(SIcon icon) {
313: reloadIfChange(rolloverIcon, icon);
314: rolloverIcon = icon;
315: }
316:
317: /**
318: * Returns the icon that is displayed as rollOver effect (meaning the icon
319: * shown when the mouse is just positioned over the compound).
320: *
321: * @see #setRolloverIcon(SIcon)
322: */
323: public SIcon getRolloverIcon() {
324: return rolloverIcon;
325: }
326:
327: /**
328: * Sets the icon that is displayed as rollover effect of a selected compound
329: * (meaning the icon shown when the mouse is just positioned over the selected compound).
330: *
331: * @param icon rollOver icon for selected compound.
332: */
333: public void setRolloverSelectedIcon(SIcon icon) {
334: reloadIfChange(rolloverSelectedIcon, icon);
335: rolloverSelectedIcon = icon;
336: }
337:
338: /**
339: * Returns the the rollOver icon of a selected compound.
340: *
341: * @see #setRolloverSelectedIcon(SIcon)
342: */
343: public SIcon getRolloverSelectedIcon() {
344: return rolloverSelectedIcon;
345: }
346:
347: /**
348: * Sets the icon that is displayed when a compound is selected.
349: *
350: * @param icon to be shown for a selected compound.
351: */
352: public void setSelectedIcon(SIcon icon) {
353: reloadIfChange(selectedIcon, icon);
354: selectedIcon = icon;
355: }
356:
357: /**
358: * Returns the icon of a selected compound.
359: *
360: * @see #setSelectedIcon(SIcon)
361: */
362: public SIcon getSelectedIcon() {
363: return selectedIcon;
364: }
365:
366: /**
367: * Sets the Icon that is displayed when a selected compound is disabled .
368: *
369: * @param icon to be shown for a selected compound that is disabled.
370: */
371: public void setDisabledSelectedIcon(SIcon icon) {
372: reloadIfChange(disabledSelectedIcon, icon);
373: disabledSelectedIcon = icon;
374: }
375:
376: /**
377: * Returns the icon of a selected compound that is disabled.
378: *
379: * @see #setDisabledSelectedIcon(SIcon)
380: */
381: public SIcon getDisabledSelectedIcon() {
382: return disabledSelectedIcon;
383: }
384:
385: /**
386: * Sets the icon that is displayed when a compound is disabled.
387: *
388: * @param icon to be shown for a disabled compound.
389: */
390: public void setDisabledIcon(SIcon icon) {
391: reloadIfChange(disabledIcon, icon);
392: disabledIcon = icon;
393: }
394:
395: /**
396: * Returns the the icon of a compound that is disabled.
397: *
398: * @see #setDisabledIcon(SIcon)
399: */
400: public SIcon getDisabledIcon() {
401: // Creates disabled icon only for SImageIcons not for SURLIcons
402: /*
403: if(disabledIcon == null) {
404: if(icon != null && icon instanceof SImageIcon)
405: disabledIcon = new SImageIcon(GrayFilter.createDisabledImage(((SImageIcon)icon).getImage()));
406: }
407: */
408: return disabledIcon;
409: }
410:
411: /**
412: * Return the background color.
413: *
414: * @return the background color
415: */
416: public Color getSelectionBackground() {
417: return dynamicStyles == null
418: || dynamicStyles.get(SELECTOR_SELECTED) == null ? null
419: : CSSStyleSheet
420: .getBackground((CSSAttributeSet) dynamicStyles
421: .get(SELECTOR_SELECTED));
422: }
423:
424: /**
425: * Set the foreground color.
426: *
427: * @param color the new foreground color
428: */
429: public void setSelectionBackground(Color color) {
430: setAttribute(SELECTOR_SELECTED, CSSProperty.BACKGROUND_COLOR,
431: CSSStyleSheet.getAttribute(color));
432: }
433:
434: /**
435: * Return the foreground color.
436: *
437: * @return the foreground color
438: */
439: public Color getSelectionForeground() {
440: return dynamicStyles == null
441: || dynamicStyles.get(SELECTOR_SELECTED) == null ? null
442: : CSSStyleSheet
443: .getForeground((CSSAttributeSet) dynamicStyles
444: .get(SELECTOR_SELECTED));
445: }
446:
447: /**
448: * Set the foreground color.
449: *
450: * @param color the new foreground color
451: */
452: public void setSelectionForeground(Color color) {
453: setAttribute(SELECTOR_SELECTED, CSSProperty.COLOR,
454: CSSStyleSheet.getAttribute(color));
455: }
456:
457: /**
458: * Set the font.
459: *
460: * @param font the new font
461: */
462: public void setSelectionFont(SFont font) {
463: setAttributes(SELECTOR_SELECTED, CSSStyleSheet
464: .getAttributes(font));
465: }
466:
467: /**
468: * Return the font.
469: *
470: * @return the font
471: */
472: public SFont getSelectionFont() {
473: return dynamicStyles == null
474: || dynamicStyles.get(SELECTOR_SELECTED) == null ? null
475: : CSSStyleSheet.getFont((CSSAttributeSet) dynamicStyles
476: .get(SELECTOR_SELECTED));
477: }
478:
479: /**
480: * Sets the label of the button.
481: */
482: public void setText(String t) {
483: if (isDifferent(text, t)) {
484: // do reload if previous text was null
485: if (isUpdatePossible() && text != null) {
486: if (SButton.class.isAssignableFrom(getClass()))
487: update(((ButtonCG) getCG()).getTextUpdate(
488: (SButton) this , t));
489: else if (SCheckBox.class.isAssignableFrom(getClass()))
490: update(((CheckBoxCG) getCG()).getTextUpdate(
491: (SCheckBox) this , t));
492: else if (SRadioButton.class
493: .isAssignableFrom(getClass()))
494: update(((RadioButtonCG) getCG()).getTextUpdate(
495: (SRadioButton) this , t));
496: else if (SToggleButton.class
497: .isAssignableFrom(getClass()))
498: update(((ToggleButtonCG) getCG()).getTextUpdate(
499: (SToggleButton) this , t));
500: else if (SClickable.class.isAssignableFrom(getClass()))
501: update(((ClickableCG) getCG()).getTextUpdate(
502: (SClickable) this , t));
503: else
504: reload();
505: } else {
506: reload();
507: }
508: text = t;
509: }
510: }
511:
512: /**
513: * Return the text of the button.
514: *
515: * @return the text
516: */
517: public String getText() {
518: return text;
519: }
520:
521: public boolean isSelected() {
522: return model.isSelected();
523: }
524:
525: /**
526: * Toggle the selection. If the new selection
527: * is different to the old selection
528: * an {@link ItemEvent} is raised.
529: */
530: public void setSelected(boolean selected) {
531: if (model.isSelected() != selected) {
532: model.setSelected(selected);
533:
534: if (!delayEvents) {
535: fireStateChanged();
536: fireItemStateChanged(new ItemEvent(this ,
537: ItemEvent.ITEM_STATE_CHANGED, this , model
538: .isSelected() ? ItemEvent.SELECTED
539: : ItemEvent.DESELECTED));
540: delayedEvent = false;
541: } else
542: delayedEvent = true;
543:
544: reload();
545: }
546: }
547:
548: /**
549: * Sets the proper icons for buttonstatus enabled resp. disabled.
550: */
551: public void setIcons(SIcon[] icons) {
552: setIcon(icons[ENABLED_ICON]);
553: setDisabledIcon(icons[DISABLED_ICON]);
554: setDisabledSelectedIcon(icons[DISABLED_SELECTED_ICON]);
555: setRolloverIcon(icons[ROLLOVER_ICON]);
556: setRolloverSelectedIcon(icons[ROLLOVER_SELECTED_ICON]);
557: setPressedIcon(icons[PRESSED_ICON]);
558: setSelectedIcon(icons[SELECTED_ICON]);
559: }
560:
561: protected final void delayEvents(boolean b) {
562: delayEvents = b;
563: }
564:
565: protected final boolean shouldDelayEvents() {
566: return delayEvents;
567: }
568:
569: /**
570: * Reports a selection change.
571: *
572: * @param ie report this event to all listeners
573: * @see java.awt.event.ItemListener
574: * @see java.awt.ItemSelectable
575: */
576: protected void fireItemStateChanged(ItemEvent ie) {
577: if (ie == null)
578: return;
579:
580: // Guaranteed to return a non-null array
581: Object[] listeners = getListenerList();
582: // Process the listeners last to first, notifying
583: // those that are interested in this event
584: for (int i = listeners.length - 2; i >= 0; i -= 2) {
585: if (listeners[i] == ItemListener.class) {
586: ((ItemListener) listeners[i + 1]).itemStateChanged(ie);
587: }
588: }
589: }
590:
591: public void fireIntermediateEvents() {
592: }
593:
594: public void fireFinalEvents() {
595: super .fireFinalEvents();
596: if (delayedEvent) {
597: fireStateChanged();
598: fireItemStateChanged(new ItemEvent(this ,
599: ItemEvent.ITEM_STATE_CHANGED, this , model
600: .isSelected() ? ItemEvent.SELECTED
601: : ItemEvent.DESELECTED));
602: delayedEvent = false;
603: }
604: }
605: }
|