001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package nextapp.echo2.app.list;
031:
032: import java.util.EventListener;
033:
034: import nextapp.echo2.app.Border;
035: import nextapp.echo2.app.Color;
036: import nextapp.echo2.app.Component;
037: import nextapp.echo2.app.Extent;
038: import nextapp.echo2.app.Font;
039: import nextapp.echo2.app.Insets;
040: import nextapp.echo2.app.event.ActionEvent;
041: import nextapp.echo2.app.event.ActionListener;
042: import nextapp.echo2.app.event.ChangeEvent;
043: import nextapp.echo2.app.event.ChangeListener;
044: import nextapp.echo2.app.event.ListDataEvent;
045: import nextapp.echo2.app.event.ListDataListener;
046:
047: /**
048: * An abstract base class for list components.
049: */
050: public abstract class AbstractListComponent extends Component {
051:
052: public static final String INPUT_ACTION = "action";
053:
054: public static final String PROPERTY_ACTION_COMMAND = "actionCommand";
055:
056: public static final String ACTION_LISTENERS_CHANGED_PROPERTY = "actionListeners";
057: public static final String LIST_DATA_CHANGED_PROPERTY = "listData";
058: public static final String LIST_MODEL_CHANGED_PROPERTY = "listModel";
059: public static final String LIST_CELL_RENDERER_CHANGED_PROPERTY = "listCellRenderer";
060: public static final String SELECTION_MODEL_CHANGED_PROPERTY = "listSelectionModel";
061: public static final String SELECTION_CHANGED_PROPERTY = "listSelectionChanged";
062:
063: public static final String PROPERTY_BORDER = "border";
064: public static final String PROPERTY_DISABLED_BACKGROUND = "disabledBackground";
065: public static final String PROPERTY_DISABLED_BORDER = "disabledBorder";
066: public static final String PROPERTY_DISABLED_FONT = "disabledFont";
067: public static final String PROPERTY_DISABLED_FOREGROUND = "disabledForeground";
068: public static final String PROPERTY_HEIGHT = "height";
069: public static final String PROPERTY_INSETS = "insets";
070: public static final String PROPERTY_ROLLOVER_BACKGROUND = "rolloverBackground";
071: public static final String PROPERTY_ROLLOVER_ENABLED = "rolloverEnabled";
072: public static final String PROPERTY_ROLLOVER_FONT = "rolloverFont";
073: public static final String PROPERTY_ROLLOVER_FOREGROUND = "rolloverForeground";
074: public static final String PROPERTY_TOOL_TIP_TEXT = "toolTipText";
075: public static final String PROPERTY_WIDTH = "width";
076:
077: public static final DefaultListCellRenderer DEFAULT_LIST_CELL_RENDERER = new DefaultListCellRenderer();
078:
079: /**
080: * Local handler for list selection events.
081: */
082: private ChangeListener changeHandler = new ChangeListener() {
083:
084: /**
085: * @see nextapp.echo2.app.event.ChangeListener#stateChanged(nextapp.echo2.app.event.ChangeEvent)
086: */
087: public void stateChanged(ChangeEvent e) {
088: firePropertyChange(SELECTION_CHANGED_PROPERTY, null, null);
089: }
090: };
091:
092: /**
093: * Local handler of <code>ListDataEvent</code>s.
094: */
095: private ListDataListener listDataHandler = new ListDataListener() {
096:
097: /**
098: * @see nextapp.echo2.app.event.ListDataListener#contentsChanged(nextapp.echo2.app.event.ListDataEvent)
099: */
100: public void contentsChanged(ListDataEvent e) {
101: firePropertyChange(LIST_DATA_CHANGED_PROPERTY, null, null);
102: }
103:
104: /**
105: * @see nextapp.echo2.app.event.ListDataListener#intervalAdded(nextapp.echo2.app.event.ListDataEvent)
106: */
107: public void intervalAdded(ListDataEvent e) {
108: firePropertyChange(LIST_DATA_CHANGED_PROPERTY, null, null);
109: }
110:
111: /**
112: * @see nextapp.echo2.app.event.ListDataListener#intervalRemoved(nextapp.echo2.app.event.ListDataEvent)
113: */
114: public void intervalRemoved(ListDataEvent e) {
115: firePropertyChange(LIST_DATA_CHANGED_PROPERTY, null, null);
116: }
117: };
118:
119: private ListCellRenderer listCellRenderer = DEFAULT_LIST_CELL_RENDERER;
120: private ListModel model;
121: private ListSelectionModel selectionModel;
122:
123: /**
124: * Creates a new <code>AbstractListComponent</code> with default models.
125: */
126: public AbstractListComponent() {
127: this (null, null);
128: }
129:
130: /**
131: * Creates a new <code>AbstractListComponent</code> with the specified
132: * models.
133: *
134: * @param model the list data model
135: * @param selectionModel the selection model
136: */
137: public AbstractListComponent(ListModel model,
138: ListSelectionModel selectionModel) {
139: super ();
140: if (model == null) {
141: model = new DefaultListModel();
142: }
143: if (selectionModel == null) {
144: selectionModel = new DefaultListSelectionModel();
145: }
146: setModel(model);
147: setSelectionModel(selectionModel);
148: }
149:
150: /**
151: * Adds an <code>ActionListener</code> to the list component.
152: * The <code>ActionListener</code> will be invoked when the user
153: * selects an item.
154: *
155: * @param l the <code>ActionListener</code> to add
156: */
157: public void addActionListener(ActionListener l) {
158: getEventListenerList().addListener(ActionListener.class, l);
159: // Notification of action listener changes is provided due to
160: // existence of hasActionListeners() method.
161: firePropertyChange(ACTION_LISTENERS_CHANGED_PROPERTY, null, l);
162: }
163:
164: /**
165: * Fires an action event to all listeners.
166: */
167: private void fireActionEvent() {
168: if (!hasEventListenerList()) {
169: return;
170: }
171: EventListener[] listeners = getEventListenerList()
172: .getListeners(ActionListener.class);
173: ActionEvent e = null;
174: for (int i = 0; i < listeners.length; ++i) {
175: if (e == null) {
176: e = new ActionEvent(
177: this ,
178: (String) getRenderProperty(PROPERTY_ACTION_COMMAND));
179: }
180: ((ActionListener) listeners[i]).actionPerformed(e);
181: }
182: }
183:
184: /**
185: * Returns the action command which will be provided in
186: * <code>ActionEvent</code>s fired by this
187: * <code>AbstractListComponent</code>.
188: *
189: * @return the action command
190: */
191: public String getActionCommand() {
192: return (String) getProperty(PROPERTY_ACTION_COMMAND);
193: }
194:
195: /**
196: * Returns the <code>Border</code> surrounding the list component.
197: *
198: * @return the border
199: */
200: public Border getBorder() {
201: return (Border) getProperty(PROPERTY_BORDER);
202: }
203:
204: /**
205: * Returns the <code>ListCellRenderer</code> used to render items.
206: *
207: * @return the renderer
208: */
209: public ListCellRenderer getCellRenderer() {
210: return listCellRenderer;
211: }
212:
213: /**
214: * Returns the background color displayed when the component is
215: * disabled.
216: *
217: * @return the color
218: */
219: public Color getDisabledBackground() {
220: return (Color) getProperty(PROPERTY_DISABLED_BACKGROUND);
221: }
222:
223: /**
224: * Returns the border displayed when the component is
225: * disabled.
226: *
227: * @return the border
228: */
229: public Border getDisabledBorder() {
230: return (Border) getProperty(PROPERTY_DISABLED_BORDER);
231: }
232:
233: /**
234: * Returns the font displayed when the component is
235: * disabled.
236: *
237: * @return the font
238: */
239: public Font getDisabledFont() {
240: return (Font) getProperty(PROPERTY_DISABLED_FONT);
241: }
242:
243: /**
244: * Returns the foreground color displayed when the component is
245: * disabled.
246: *
247: * @return the color
248: */
249: public Color getDisabledForeground() {
250: return (Color) getProperty(PROPERTY_DISABLED_FOREGROUND);
251: }
252:
253: /**
254: * Returns the height.
255: * This property only supports <code>Extent</code>s with
256: * fixed (i.e., not percent) units.
257: *
258: * @return the height
259: */
260: public Extent getHeight() {
261: return (Extent) getProperty(PROPERTY_HEIGHT);
262: }
263:
264: /**
265: * Returns the inset margin around between the list components border and content.
266: *
267: * @return the inset margin
268: */
269: public Insets getInsets() {
270: return (Insets) getProperty(PROPERTY_INSETS);
271: }
272:
273: /**
274: * Returns the model.
275: *
276: * @return the model
277: */
278: public ListModel getModel() {
279: return model;
280: }
281:
282: /**
283: * Returns the rollover background.
284: *
285: * @return the rollover background
286: */
287: public Color getRolloverBackground() {
288: return (Color) getProperty(PROPERTY_ROLLOVER_BACKGROUND);
289: }
290:
291: /**
292: * Returns the rollover font.
293: *
294: * @return the rollover font
295: */
296: public Font getRolloverFont() {
297: return (Font) getProperty(PROPERTY_ROLLOVER_FONT);
298: }
299:
300: /**
301: * Returns the rollover foreground.
302: *
303: * @return the rollover foreground
304: */
305: public Color getRolloverForeground() {
306: return (Color) getProperty(PROPERTY_ROLLOVER_FOREGROUND);
307: }
308:
309: /**
310: * Returns the selection model.
311: *
312: * @return the selection model
313: */
314: public ListSelectionModel getSelectionModel() {
315: return selectionModel;
316: }
317:
318: /**
319: * Returns the tool tip text (displayed when the mouse cursor is hovered
320: * over the component).
321: *
322: * @return the tool tip text
323: */
324: public String getToolTipText() {
325: return (String) getProperty(PROPERTY_TOOL_TIP_TEXT);
326: }
327:
328: /**
329: * Returns the width.
330: * This property supports <code>Extent</code>s with
331: * fixed or percentile units.
332: *
333: * @return the width
334: */
335: public Extent getWidth() {
336: return (Extent) getProperty(PROPERTY_WIDTH);
337: }
338:
339: /**
340: * Determines the any <code>ActionListener</code>s are registered.
341: *
342: * @return true if any action listeners are registered
343: */
344: public boolean hasActionListeners() {
345: return hasEventListenerList()
346: && getEventListenerList().getListenerCount(
347: ActionListener.class) != 0;
348: }
349:
350: /**
351: * Determines if rollover effects are enabled.
352: *
353: * @return true if rollover effects are enabled
354: */
355: public boolean isRolloverEnabled() {
356: Boolean value = (Boolean) getProperty(PROPERTY_ROLLOVER_ENABLED);
357: return value == null ? false : value.booleanValue();
358: }
359:
360: /**
361: * This component does not support children.
362: *
363: * @see nextapp.echo2.app.Component#isValidChild(nextapp.echo2.app.Component)
364: */
365: public boolean isValidChild(Component child) {
366: return false;
367: }
368:
369: /**
370: * @see nextapp.echo2.app.Component#processInput(java.lang.String, java.lang.Object)
371: */
372: public void processInput(String inputName, Object inputValue) {
373: super .processInput(inputName, inputValue);
374:
375: if (SELECTION_CHANGED_PROPERTY.equals(inputName)) {
376: int[] selectedIndices = (int[]) inputValue;
377: ListSelectionModel selectionModel = getSelectionModel();
378: selectionModel.clearSelection();
379: for (int i = 0; i < selectedIndices.length; ++i) {
380: selectionModel.setSelectedIndex(selectedIndices[i],
381: true);
382: }
383: } else if (INPUT_ACTION.equals(inputName)) {
384: fireActionEvent();
385: }
386: }
387:
388: /**
389: * Removes an <code>ActionListener</code> from the list component.
390: *
391: * @param l the <code>ActionListener</code> to remove
392: */
393: public void removeActionListener(ActionListener l) {
394: if (!hasEventListenerList()) {
395: return;
396: }
397: getEventListenerList().removeListener(ActionListener.class, l);
398: // Notification of action listener changes is provided due to
399: // existence of hasActionListeners() method.
400: firePropertyChange(ACTION_LISTENERS_CHANGED_PROPERTY, l, null);
401: }
402:
403: /**
404: * Sets the action command which will be provided in
405: * <code>ActionEvent</code>s fired by this
406: * <code>AbstractListComponent</code>.
407: *
408: * @param newValue the new action command
409: */
410: public void setActionCommand(String newValue) {
411: setProperty(PROPERTY_ACTION_COMMAND, newValue);
412: }
413:
414: /**
415: * Sets the <code>Border</code> surrounding the list component.
416: *
417: * @param newValue the new <code>Border</code>
418: */
419: public void setBorder(Border newValue) {
420: setProperty(PROPERTY_BORDER, newValue);
421: }
422:
423: /**
424: * Sets the renderer for items.
425: * The renderer may not be null (use <code>DEFAULT_LIST_CELL_RENDERER</code>
426: * for default behavior).
427: *
428: * @param newValue the new renderer
429: */
430: public void setCellRenderer(ListCellRenderer newValue) {
431: if (newValue == null) {
432: throw new IllegalArgumentException(
433: "Cell Renderer may not be null.");
434: }
435: ListCellRenderer oldValue = listCellRenderer;
436: listCellRenderer = newValue;
437: firePropertyChange(LIST_CELL_RENDERER_CHANGED_PROPERTY,
438: oldValue, newValue);
439: }
440:
441: /**
442: * Sets the background color displayed when the component is disabled.
443: *
444: * @param newValue the new <code>Color</code>
445: */
446: public void setDisabledBackground(Color newValue) {
447: setProperty(PROPERTY_DISABLED_BACKGROUND, newValue);
448: }
449:
450: /**
451: * Sets the border displayed when the component is disabled.
452: *
453: * @param newValue the new border
454: */
455: public void setDisabledBorder(Border newValue) {
456: setProperty(PROPERTY_DISABLED_BORDER, newValue);
457: }
458:
459: /**
460: * Sets the font displayed when the component is disabled.
461: *
462: * @param newValue the new <code>Font</code>
463: */
464: public void setDisabledFont(Font newValue) {
465: setProperty(PROPERTY_DISABLED_FONT, newValue);
466: }
467:
468: /**
469: * Sets the foreground color displayed when the component is disabled.
470: *
471: * @param newValue the new <code>Color</code>
472: */
473: public void setDisabledForeground(Color newValue) {
474: setProperty(PROPERTY_DISABLED_FOREGROUND, newValue);
475: }
476:
477: /**
478: * Sets the height.
479: * This property only supports <code>Extent</code>s with
480: * fixed (i.e., not percent) units.
481: *
482: * @param newValue the new height
483: */
484: public void setHeight(Extent newValue) {
485: setProperty(PROPERTY_HEIGHT, newValue);
486: }
487:
488: /**
489: * Sets the inset margin around between the list components border and content.
490: *
491: * @param newValue the new inset margin
492: */
493: public void setInsets(Insets newValue) {
494: setProperty(PROPERTY_INSETS, newValue);
495: }
496:
497: /**
498: * Sets the model.
499: * The model may not be null.
500: *
501: * @param newValue the new model
502: */
503: public void setModel(ListModel newValue) {
504: if (newValue == null) {
505: throw new IllegalArgumentException("Model may not be null.");
506: }
507: ListModel oldValue = model;
508: if (oldValue != null) {
509: oldValue.removeListDataListener(listDataHandler);
510: }
511: newValue.addListDataListener(listDataHandler);
512: model = newValue;
513: firePropertyChange(LIST_MODEL_CHANGED_PROPERTY, oldValue,
514: newValue);
515: }
516:
517: /**
518: * Sets the rollover background.
519: *
520: * @param newValue the new rollover background
521: */
522: public void setRolloverBackground(Color newValue) {
523: setProperty(PROPERTY_ROLLOVER_BACKGROUND, newValue);
524: }
525:
526: /**
527: * Sets whether rollover effects are enabled.
528: *
529: * @param newValue the new rollover enabled state
530: */
531: public void setRolloverEnabled(boolean newValue) {
532: setProperty(PROPERTY_ROLLOVER_ENABLED, new Boolean(newValue));
533: }
534:
535: /**
536: * Sets the rollover font.
537: *
538: * @param newValue the new rollover font
539: */
540: public void setRolloverFont(Font newValue) {
541: setProperty(PROPERTY_ROLLOVER_FONT, newValue);
542: }
543:
544: /**
545: * Sets the rollover foreground.
546: *
547: * @param newValue the new rollover foreground
548: */
549: public void setRolloverForeground(Color newValue) {
550: setProperty(PROPERTY_ROLLOVER_FOREGROUND, newValue);
551: }
552:
553: /**
554: * Sets the selection model.
555: * The selection model may not be null.
556: *
557: * @param newValue the new selection model
558: */
559: public void setSelectionModel(ListSelectionModel newValue) {
560: if (newValue == null) {
561: throw new IllegalArgumentException(
562: "Selection model may not be null.");
563: }
564: ListSelectionModel oldValue = selectionModel;
565: if (oldValue != null) {
566: oldValue.removeChangeListener(changeHandler);
567: }
568: newValue.addChangeListener(changeHandler);
569: selectionModel = newValue;
570: firePropertyChange(SELECTION_MODEL_CHANGED_PROPERTY, oldValue,
571: newValue);
572: }
573:
574: /**
575: * Sets the tool tip text (displayed when the mouse cursor is hovered
576: * over the component).
577: *
578: * @param newValue the new tool tip text
579: */
580: public void setToolTipText(String newValue) {
581: setProperty(PROPERTY_TOOL_TIP_TEXT, newValue);
582: }
583:
584: /**
585: * Sets the width.
586: * This property supports <code>Extent</code>s with
587: * fixed or percentile units.
588: *
589: * @param newValue the new width
590: */
591: public void setWidth(Extent newValue) {
592: setProperty(PROPERTY_WIDTH, newValue);
593: }
594: }
|