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 javax.swing.event.ChangeEvent;
016: import javax.swing.event.ChangeListener;
017: import javax.swing.event.EventListenerList;
018: import java.util.EventListener;
019:
020: /**
021: * Paging implementation of SBoundedRangeModel
022: *
023: * @author <a href="mailto:armin.haaf@mercatis.de">Armin Haaf</a>
024: */
025: public class SPagingBoundedRangeModel implements SBoundedRangeModel {
026:
027: /**
028: * Only one <code>ChangeEvent</code> is needed per model instance since the
029: * event's only (read-only) state is the source property. The source
030: * of events generated here is always "this".
031: */
032: protected transient ChangeEvent changeEvent = null;
033:
034: /**
035: * The listeners waiting for model changes.
036: */
037: protected EventListenerList listenerList = new EventListenerList();
038:
039: protected int value = 0;
040: protected int extent = 0;
041: protected int min = 0;
042: protected int max = 100;
043: protected boolean isAdjusting = false;
044:
045: /**
046: * indicates if we should fire event immediately when they arise, or if we
047: * should collect them for a later delivery
048: */
049: private boolean delayEvents = false;
050:
051: /**
052: * got a delayed Event?
053: */
054: protected boolean gotDelayedEvent = false;
055:
056: public SPagingBoundedRangeModel() {
057: super ();
058: }
059:
060: public SPagingBoundedRangeModel(int value, int extent, int min,
061: int max) {
062: setRangeProperties(value, extent, min, max, false);
063: }
064:
065: /**
066: * Returns the model's current value.
067: *
068: * @return the model's current value
069: * @see #setValue
070: * @see javax.swing.BoundedRangeModel#getValue
071: */
072: public int getValue() {
073: return value;
074: }
075:
076: /**
077: * Returns the model's extent.
078: *
079: * @return the model's extent
080: * @see #setExtent
081: * @see javax.swing.BoundedRangeModel#getExtent
082: */
083: public int getExtent() {
084: return extent;
085: }
086:
087: /**
088: * Returns the model's minimum.
089: *
090: * @return the model's minimum
091: * @see #setMinimum
092: * @see javax.swing.BoundedRangeModel#getMinimum
093: */
094: public int getMinimum() {
095: return min;
096: }
097:
098: /**
099: * Returns the model's maximum.
100: *
101: * @return the model's maximum
102: * @see #setMaximum
103: * @see javax.swing.BoundedRangeModel#getMaximum
104: */
105: public int getMaximum() {
106: return max;
107: }
108:
109: /**
110: * Sets the current value of the model. For a slider, that
111: * determines where the knob appears. Ensures that the new
112: * value, <I>n</I> falls within the model's constraints:
113: * <pre>
114: * minimum <= value <= maximum
115: * </pre>
116: *
117: * @see javax.swing.BoundedRangeModel#setValue
118: */
119: public void setValue(int n) {
120: n = Math.min(n, Integer.MAX_VALUE - extent);
121:
122: int newValue = Math.max(n, min);
123: if (newValue + extent > max) {
124: newValue = max - extent;
125: }
126: setRangeProperties(newValue, extent, min, max, isAdjusting);
127: }
128:
129: /**
130: * Sets the extent to <I>n</I> after ensuring that <I>n</I>
131: * is greater than or equal to zero and falls within the model's
132: * constraints:
133: * <pre>
134: * minimum <= value <= maximum
135: * </pre>
136: *
137: * @see javax.swing.BoundedRangeModel#setExtent
138: */
139: public void setExtent(int n) {
140: int newExtent = Math.max(0, n);
141: if (value + newExtent > max) {
142: newExtent = max - value;
143: }
144: setRangeProperties(value, newExtent, min, max, isAdjusting);
145: }
146:
147: /**
148: * Sets the minimum to <I>n</I> after ensuring that <I>n</I>
149: * that the other three properties obey the model's constraints:
150: * <pre>
151: * minimum <= value <= maximum
152: * </pre>
153: *
154: * @see #getMinimum
155: * @see javax.swing.BoundedRangeModel#setMinimum
156: */
157: public void setMinimum(int n) {
158: int newMax = Math.max(n, max);
159: int newValue = Math.max(n, value);
160: int newExtent = Math.min(newMax - newValue, extent);
161: setRangeProperties(newValue, newExtent, n, newMax, isAdjusting);
162: }
163:
164: /**
165: * Sets the maximum to <I>n</I> after ensuring that <I>n</I>
166: * that the other three properties obey the model's constraints:
167: * <pre>
168: * minimum <= value <= maximum
169: * </pre>
170: *
171: * @see javax.swing.BoundedRangeModel#setMaximum
172: */
173: public void setMaximum(int n) {
174: int newMin = Math.min(n, min);
175: int newExtent = Math.min(n - newMin, extent);
176: int newValue = Math.min(n - newExtent, value);
177: setRangeProperties(newValue, newExtent, newMin, n, isAdjusting);
178: }
179:
180: /**
181: * Sets the <code>valueIsAdjusting</code> property.
182: *
183: * @see #getValueIsAdjusting
184: * @see #setValue
185: * @see javax.swing.BoundedRangeModel#setValueIsAdjusting
186: */
187: public void setValueIsAdjusting(boolean b) {
188: setRangeProperties(value, extent, min, max, b);
189: }
190:
191: /**
192: * Returns true if the value is in the process of changing
193: * as a result of actions being taken by the user.
194: *
195: * @return the value of the <code>valueIsAdjusting</code> property
196: * @see #setValue
197: * @see javax.swing.BoundedRangeModel#getValueIsAdjusting
198: */
199: public boolean getValueIsAdjusting() {
200: return isAdjusting;
201: }
202:
203: /**
204: * Sets all of the <code>BoundedRangeModel</code> properties after forcing
205: * the arguments to obey the usual constraints:
206: * <pre>
207: * minimum <= value <= maximum
208: * </pre>
209: * <p/>
210: * At most, one <code>ChangeEvent</code> is generated.
211: *
212: * @see javax.swing.BoundedRangeModel#setRangeProperties
213: * @see #setValue
214: * @see #setExtent
215: * @see #setMinimum
216: * @see #setMaximum
217: * @see #setValueIsAdjusting
218: */
219: public void setRangeProperties(int newValue, int newExtent,
220: int newMin, int newMax, boolean adjusting) {
221: if (newMin > newMax) {
222: newMin = newMax;
223: }
224: if (newValue > newMax) {
225: newMax = newValue;
226: }
227: if (newValue < newMin) {
228: newMin = newValue;
229: }
230: if (newExtent < 0) {
231: newExtent = 0;
232: }
233: if ((newExtent + newValue) > newMax) {
234: newExtent = newMax - newValue;
235: }
236:
237: boolean isChange = (newValue != value) || (newExtent != extent)
238: || (newMin != min) || (newMax != max)
239: || (adjusting != isAdjusting);
240:
241: if (isChange) {
242: value = newValue;
243: extent = newExtent;
244: min = newMin;
245: max = newMax;
246: isAdjusting = adjusting;
247:
248: fireStateChanged();
249: }
250: }
251:
252: public boolean getDelayEvents() {
253: return delayEvents;
254: }
255:
256: public void setDelayEvents(boolean b) {
257: delayEvents = b;
258: }
259:
260: /**
261: * Adds a <code>ChangeListener</code>. The change listeners are run each
262: * time any one of the Bounded Range model properties changes.
263: *
264: * @param l the ChangeListener to add
265: * @see #removeChangeListener
266: * @see javax.swing.BoundedRangeModel#addChangeListener
267: */
268: public void addChangeListener(ChangeListener l) {
269: listenerList.add(ChangeListener.class, l);
270: }
271:
272: /**
273: * Removes a <code>ChangeListener</code>.
274: *
275: * @param l the <code>ChangeListener</code> to remove
276: * @see #addChangeListener
277: * @see javax.swing.BoundedRangeModel#removeChangeListener
278: */
279: public void removeChangeListener(ChangeListener l) {
280: listenerList.remove(ChangeListener.class, l);
281: }
282:
283: /**
284: * Returns an array of all the change listeners
285: * registered on this <code>DefaultBoundedRangeModel</code>.
286: *
287: * @return all of this model's <code>ChangeListener</code>s
288: * or an empty
289: * array if no change listeners are currently registered
290: * @see #addChangeListener
291: * @see #removeChangeListener
292: * @since 1.4
293: */
294: public ChangeListener[] getChangeListeners() {
295: return listenerList.getListeners(ChangeListener.class);
296: }
297:
298: /**
299: * Runs each <code>ChangeListener</code>'s <code>componentChanged</code> method.
300: *
301: * @see #setRangeProperties
302: * @see EventListenerList
303: */
304: protected void fireStateChanged() {
305: if (delayEvents) {
306: gotDelayedEvent = true;
307: } else {
308: Object[] listeners = listenerList.getListenerList();
309: for (int i = listeners.length - 2; i >= 0; i -= 2) {
310: if (listeners[i] == ChangeListener.class) {
311: if (changeEvent == null) {
312: changeEvent = new ChangeEvent(this );
313: }
314: ((ChangeListener) listeners[i + 1])
315: .stateChanged(changeEvent);
316: }
317: }
318: }
319: }
320:
321: /**
322: * Returns a string that displays all of the
323: * <code>BoundedRangeModel</code> properties.
324: */
325: public String toString() {
326: String modelString = "value=" + getValue() + ", " + "extent="
327: + getExtent() + ", " + "min=" + getMinimum() + ", "
328: + "max=" + getMaximum() + ", " + "adj="
329: + getValueIsAdjusting();
330:
331: return getClass().getName() + "[" + modelString + "]";
332: }
333:
334: /**
335: * Returns an array of all the objects currently registered as
336: * <code><em>Foo</em>Listener</code>s
337: * upon this model.
338: * <code><em>Foo</em>Listener</code>s
339: * are registered using the <code>add<em>Foo</em>Listener</code> method.
340: * <p/>
341: * You can specify the <code>listenerType</code> argument
342: * with a class literal, such as <code><em>Foo</em>Listener.class</code>.
343: * For example, you can query a <code>DefaultBoundedRangeModel</code>
344: * instance <code>m</code>
345: * for its change listeners
346: * with the following code:
347: * <p/>
348: * <pre>ChangeListener[] cls = (ChangeListener[])(m.getListeners(ChangeListener.class));</pre>
349: * <p/>
350: * If no such listeners exist,
351: * this method returns an empty array.
352: *
353: * @param listenerType the type of listeners requested;
354: * this parameter should specify an interface
355: * that descends from <code>java.util.EventListener</code>
356: * @return an array of all objects registered as
357: * <code><em>Foo</em>Listener</code>s
358: * on this model,
359: * or an empty array if no such
360: * listeners have been added
361: * @throws ClassCastException if <code>listenerType</code> doesn't
362: * specify a class or interface that implements
363: * <code>java.util.EventListener</code>
364: * @see #getChangeListeners
365: * @since 1.3
366: */
367: public EventListener[] getListeners(Class listenerType) {
368: return listenerList.getListeners(listenerType);
369: }
370:
371: /**
372: * fire event with isValueIsAdjusting true
373: */
374: public void fireDelayedIntermediateEvents() {
375: }
376:
377: public void fireDelayedFinalEvents() {
378: if (!delayEvents && gotDelayedEvent) {
379: fireStateChanged();
380: gotDelayedEvent = false;
381: }
382: }
383:
384: }// SPagingBoundedRangeModel
|