1 /*
2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.awt;
26 
27 import sun.awt.AWTAccessor;
28 
29 import java.awt.event.AdjustmentEvent;
30 import java.awt.event.AdjustmentListener;
31 import java.awt.peer.ScrollPanePeer;
32 import java.io.Serializable;
33 
34 
35 /**
36  * This class represents the state of a horizontal or vertical
37  * scrollbar of a {@code ScrollPane}.  Objects of this class are
38  * returned by {@code ScrollPane} methods.
39  *
40  * @since       1.4
41  */
42 public class ScrollPaneAdjustable implements Adjustable, Serializable {
43 
44     /**
45      * The {@code ScrollPane} this object is a scrollbar of.
46      * @serial
47      */
48     private ScrollPane sp;
49 
50     /**
51      * Orientation of this scrollbar.
52      *
53      * @serial
54      * @see #getOrientation
55      * @see java.awt.Adjustable#HORIZONTAL
56      * @see java.awt.Adjustable#VERTICAL
57      */
58     private int orientation;
59 
60     /**
61      * The value of this scrollbar.
62      * {@code value} should be greater than {@code minimum}
63      * and less than {@code maximum}
64      *
65      * @serial
66      * @see #getValue
67      * @see #setValue
68      */
69     private int value;
70 
71     /**
72      * The minimum value of this scrollbar.
73      * This value can only be set by the {@code ScrollPane}.
74      * <p>
75      * <strong>ATTN:</strong> In current implementation
76      * {@code minimum} is always {@code 0}.  This field can
77      * only be altered via {@code setSpan} method and
78      * {@code ScrollPane} always calls that method with
79      * {@code 0} for the minimum.  {@code getMinimum} method
80      * always returns {@code 0} without checking this field.
81      *
82      * @serial
83      * @see #getMinimum
84      * @see #setSpan(int, int, int)
85      */
86     private int minimum;
87 
88     /**
89      * The maximum value of this scrollbar.
90      * This value can only be set by the {@code ScrollPane}.
91      *
92      * @serial
93      * @see #getMaximum
94      * @see #setSpan(int, int, int)
95      */
96     private int maximum;
97 
98     /**
99      * The size of the visible portion of this scrollbar.
100      * This value can only be set by the {@code ScrollPane}.
101      *
102      * @serial
103      * @see #getVisibleAmount
104      * @see #setSpan(int, int, int)
105      */
106     private int visibleAmount;
107 
108     /**
109      * The adjusting status of the {@code Scrollbar}.
110      * True if the value is in the process of changing as a result of
111      * actions being taken by the user.
112      *
113      * @see #getValueIsAdjusting
114      * @see #setValueIsAdjusting
115      * @since 1.4
116      */
117     private transient boolean isAdjusting;
118 
119     /**
120      * The amount by which the scrollbar value will change when going
121      * up or down by a line.
122      * This value should be a non negative integer.
123      *
124      * @serial
125      * @see #getUnitIncrement
126      * @see #setUnitIncrement
127      */
128     private int unitIncrement  = 1;
129 
130     /**
131      * The amount by which the scrollbar value will change when going
132      * up or down by a page.
133      * This value should be a non negative integer.
134      *
135      * @serial
136      * @see #getBlockIncrement
137      * @see #setBlockIncrement
138      */
139     private int blockIncrement = 1;
140 
141     @SuppressWarnings("serial") // Not statically typed as Serializable
142     private AdjustmentListener adjustmentListener;
143 
144     /**
145      * Error message for {@code AWTError} reported when one of
146      * the public but unsupported methods is called.
147      */
148     private static final String SCROLLPANE_ONLY =
149         "Can be set by scrollpane only";
150 
151 
152     /**
153      * Initialize JNI field and method ids.
154      */
initIDs()155     private static native void initIDs();
156 
157     static {
Toolkit.loadLibraries()158         Toolkit.loadLibraries();
159         if (!GraphicsEnvironment.isHeadless()) {
initIDs()160             initIDs();
161         }
AWTAccessor.setScrollPaneAdjustableAccessor(new AWTAccessor.ScrollPaneAdjustableAccessor() { public void setTypedValue(final ScrollPaneAdjustable adj, final int v, final int type) { adj.setTypedValue(v, type); } })162         AWTAccessor.setScrollPaneAdjustableAccessor(new AWTAccessor.ScrollPaneAdjustableAccessor() {
163             public void setTypedValue(final ScrollPaneAdjustable adj,
164                                       final int v, final int type) {
165                 adj.setTypedValue(v, type);
166             }
167         });
168     }
169 
170     /**
171      * JDK 1.1 serialVersionUID.
172      */
173     private static final long serialVersionUID = -3359745691033257079L;
174 
175 
176     /**
177      * Constructs a new object to represent specified scrollabar
178      * of the specified {@code ScrollPane}.
179      * Only ScrollPane creates instances of this class.
180      * @param sp           {@code ScrollPane}
181      * @param l            {@code AdjustmentListener} to add upon creation.
182      * @param orientation  specifies which scrollbar this object represents,
183      *                     can be either  {@code Adjustable.HORIZONTAL}
184      *                     or {@code Adjustable.VERTICAL}.
185      */
ScrollPaneAdjustable(ScrollPane sp, AdjustmentListener l, int orientation)186     ScrollPaneAdjustable(ScrollPane sp, AdjustmentListener l, int orientation) {
187         this.sp = sp;
188         this.orientation = orientation;
189         addAdjustmentListener(l);
190     }
191 
192     /**
193      * This is called by the scrollpane itself to update the
194      * {@code minimum}, {@code maximum} and
195      * {@code visible} values.  The scrollpane is the only one
196      * that should be changing these since it is the source of these
197      * values.
198      */
setSpan(int min, int max, int visible)199     void setSpan(int min, int max, int visible) {
200         // adjust the values to be reasonable
201         minimum = min;
202         maximum = Math.max(max, minimum + 1);
203         visibleAmount = Math.min(visible, maximum - minimum);
204         visibleAmount = Math.max(visibleAmount, 1);
205         blockIncrement = Math.max((int)(visible * .90), 1);
206         setValue(value);
207     }
208 
209     /**
210      * Returns the orientation of this scrollbar.
211      * @return    the orientation of this scrollbar, either
212      *            {@code Adjustable.HORIZONTAL} or
213      *            {@code Adjustable.VERTICAL}
214      */
getOrientation()215     public int getOrientation() {
216         return orientation;
217     }
218 
219     /**
220      * This method should <strong>NOT</strong> be called by user code.
221      * This method is public for this class to properly implement
222      * {@code Adjustable} interface.
223      *
224      * @throws AWTError Always throws an error when called.
225      */
setMinimum(int min)226     public void setMinimum(int min) {
227         throw new AWTError(SCROLLPANE_ONLY);
228     }
229 
getMinimum()230     public int getMinimum() {
231         // XXX: This relies on setSpan always being called with 0 for
232         // the minimum (which is currently true).
233         return 0;
234     }
235 
236     /**
237      * This method should <strong>NOT</strong> be called by user code.
238      * This method is public for this class to properly implement
239      * {@code Adjustable} interface.
240      *
241      * @throws AWTError Always throws an error when called.
242      */
setMaximum(int max)243     public void setMaximum(int max) {
244         throw new AWTError(SCROLLPANE_ONLY);
245     }
246 
getMaximum()247     public int getMaximum() {
248         return maximum;
249     }
250 
setUnitIncrement(int u)251     public synchronized void setUnitIncrement(int u) {
252         if (u != unitIncrement) {
253             unitIncrement = u;
254             if (sp.peer != null) {
255                 ScrollPanePeer peer = (ScrollPanePeer) sp.peer;
256                 peer.setUnitIncrement(this, u);
257             }
258         }
259     }
260 
getUnitIncrement()261     public int getUnitIncrement() {
262         return unitIncrement;
263     }
264 
setBlockIncrement(int b)265     public synchronized void setBlockIncrement(int b) {
266         blockIncrement = b;
267     }
268 
getBlockIncrement()269     public int getBlockIncrement() {
270         return blockIncrement;
271     }
272 
273     /**
274      * This method should <strong>NOT</strong> be called by user code.
275      * This method is public for this class to properly implement
276      * {@code Adjustable} interface.
277      *
278      * @throws AWTError Always throws an error when called.
279      */
setVisibleAmount(int v)280     public void setVisibleAmount(int v) {
281         throw new AWTError(SCROLLPANE_ONLY);
282     }
283 
getVisibleAmount()284     public int getVisibleAmount() {
285         return visibleAmount;
286     }
287 
288 
289     /**
290      * Sets the {@code valueIsAdjusting} property.
291      *
292      * @param b new adjustment-in-progress status
293      * @see #getValueIsAdjusting
294      * @since 1.4
295      */
setValueIsAdjusting(boolean b)296     public void setValueIsAdjusting(boolean b) {
297         if (isAdjusting != b) {
298             isAdjusting = b;
299             AdjustmentEvent e =
300                 new AdjustmentEvent(this,
301                         AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
302                         AdjustmentEvent.TRACK, value, b);
303             adjustmentListener.adjustmentValueChanged(e);
304         }
305     }
306 
307     /**
308      * Returns true if the value is in the process of changing as a
309      * result of actions being taken by the user.
310      *
311      * @return the value of the {@code valueIsAdjusting} property
312      * @see #setValueIsAdjusting
313      */
getValueIsAdjusting()314     public boolean getValueIsAdjusting() {
315         return isAdjusting;
316     }
317 
318     /**
319      * Sets the value of this scrollbar to the specified value.
320      * <p>
321      * If the value supplied is less than the current minimum or
322      * greater than the current maximum, then one of those values is
323      * substituted, as appropriate.
324      *
325      * @param v the new value of the scrollbar
326      */
setValue(int v)327     public void setValue(int v) {
328         setTypedValue(v, AdjustmentEvent.TRACK);
329     }
330 
331     /**
332      * Sets the value of this scrollbar to the specified value.
333      * <p>
334      * If the value supplied is less than the current minimum or
335      * greater than the current maximum, then one of those values is
336      * substituted, as appropriate. Also, creates and dispatches
337      * the AdjustmentEvent with specified type and value.
338      *
339      * @param v the new value of the scrollbar
340      * @param type the type of the scrolling operation occurred
341      */
setTypedValue(int v, int type)342     private void setTypedValue(int v, int type) {
343         v = Math.max(v, minimum);
344         v = Math.min(v, maximum - visibleAmount);
345 
346         if (v != value) {
347             value = v;
348             // Synchronously notify the listeners so that they are
349             // guaranteed to be up-to-date with the Adjustable before
350             // it is mutated again.
351             AdjustmentEvent e =
352                 new AdjustmentEvent(this,
353                         AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
354                         type, value, isAdjusting);
355             adjustmentListener.adjustmentValueChanged(e);
356         }
357     }
358 
getValue()359     public int getValue() {
360         return value;
361     }
362 
363     /**
364      * Adds the specified adjustment listener to receive adjustment
365      * events from this {@code ScrollPaneAdjustable}.
366      * If {@code l} is {@code null}, no exception is thrown
367      * and no action is performed.
368      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
369      * >AWT Threading Issues</a> for details on AWT's threading model.
370      *
371      * @param    l   the adjustment listener.
372      * @see      #removeAdjustmentListener
373      * @see      #getAdjustmentListeners
374      * @see      java.awt.event.AdjustmentListener
375      * @see      java.awt.event.AdjustmentEvent
376      */
addAdjustmentListener(AdjustmentListener l)377     public synchronized void addAdjustmentListener(AdjustmentListener l) {
378         if (l == null) {
379             return;
380         }
381         adjustmentListener = AWTEventMulticaster.add(adjustmentListener, l);
382     }
383 
384     /**
385      * Removes the specified adjustment listener so that it no longer
386      * receives adjustment events from this {@code ScrollPaneAdjustable}.
387      * If {@code l} is {@code null}, no exception is thrown
388      * and no action is performed.
389      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
390      * >AWT Threading Issues</a> for details on AWT's threading model.
391      *
392      * @param         l     the adjustment listener.
393      * @see           #addAdjustmentListener
394      * @see           #getAdjustmentListeners
395      * @see           java.awt.event.AdjustmentListener
396      * @see           java.awt.event.AdjustmentEvent
397      * @since         1.1
398      */
removeAdjustmentListener(AdjustmentListener l)399     public synchronized void removeAdjustmentListener(AdjustmentListener l){
400         if (l == null) {
401             return;
402         }
403         adjustmentListener = AWTEventMulticaster.remove(adjustmentListener, l);
404     }
405 
406     /**
407      * Returns an array of all the adjustment listeners
408      * registered on this {@code ScrollPaneAdjustable}.
409      *
410      * @return all of this {@code ScrollPaneAdjustable}'s
411      *         {@code AdjustmentListener}s
412      *         or an empty array if no adjustment
413      *         listeners are currently registered
414      *
415      * @see           #addAdjustmentListener
416      * @see           #removeAdjustmentListener
417      * @see           java.awt.event.AdjustmentListener
418      * @see           java.awt.event.AdjustmentEvent
419      * @since 1.4
420      */
getAdjustmentListeners()421     public synchronized AdjustmentListener[] getAdjustmentListeners() {
422         return AWTEventMulticaster.getListeners(adjustmentListener,
423                                                 AdjustmentListener.class);
424     }
425 
426     /**
427      * Returns a string representation of this scrollbar and its values.
428      * @return    a string representation of this scrollbar.
429      */
toString()430     public String toString() {
431         return getClass().getName() + "[" + paramString() + "]";
432     }
433 
434     /**
435      * Returns a string representing the state of this scrollbar.
436      * This method is intended to be used only for debugging purposes,
437      * and the content and format of the returned string may vary
438      * between implementations.  The returned string may be empty but
439      * may not be {@code null}.
440      *
441      * @return      the parameter string of this scrollbar.
442      */
paramString()443     public String paramString() {
444         return ((orientation == Adjustable.VERTICAL ? "vertical,"
445                                                     :"horizontal,")
446                 + "[0.."+maximum+"]"
447                 + ",val=" + value
448                 + ",vis=" + visibleAmount
449                 + ",unit=" + unitIncrement
450                 + ",block=" + blockIncrement
451                 + ",isAdjusting=" + isAdjusting);
452     }
453 }
454