1 /*
2  * Copyright (c) 1996, 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 sun.awt.windows;
26 
27 import java.awt.*;
28 import java.awt.event.AdjustmentEvent;
29 import java.awt.peer.ScrollPanePeer;
30 
31 import sun.awt.AWTAccessor;
32 import sun.awt.PeerEvent;
33 
34 import sun.util.logging.PlatformLogger;
35 
36 final class WScrollPanePeer extends WPanelPeer implements ScrollPanePeer {
37 
38     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WScrollPanePeer");
39 
40     int scrollbarWidth;
41     int scrollbarHeight;
42     int prevx;
43     int prevy;
44 
45     static {
initIDs()46         initIDs();
47     }
48 
initIDs()49     static native void initIDs();
50     @Override
create(WComponentPeer parent)51     native void create(WComponentPeer parent);
getOffset(int orient)52     native int getOffset(int orient);
53 
WScrollPanePeer(Component target)54     WScrollPanePeer(Component target) {
55         super(target);
56         scrollbarWidth = _getVScrollbarWidth();
57         scrollbarHeight = _getHScrollbarHeight();
58     }
59 
60     @Override
initialize()61     void initialize() {
62         super.initialize();
63         setInsets();
64         Insets i = getInsets();
65         setScrollPosition(-i.left,-i.top);
66     }
67 
68     @Override
setUnitIncrement(Adjustable adj, int p)69     public void setUnitIncrement(Adjustable adj, int p) {
70         // The unitIncrement is grabbed from the target as needed.
71     }
72 
73     @Override
insets()74     public Insets insets() {
75         return getInsets();
76     }
setInsets()77     private native void setInsets();
78 
79     @Override
setScrollPosition(int x, int y)80     public native synchronized void setScrollPosition(int x, int y);
81 
82     @Override
getHScrollbarHeight()83     public int getHScrollbarHeight() {
84         return scrollbarHeight;
85     }
_getHScrollbarHeight()86     private native int _getHScrollbarHeight();
87 
88     @Override
getVScrollbarWidth()89     public int getVScrollbarWidth() {
90         return scrollbarWidth;
91     }
_getVScrollbarWidth()92     private native int _getVScrollbarWidth();
93 
getScrollOffset()94     public Point getScrollOffset() {
95         int x = getOffset(Adjustable.HORIZONTAL);
96         int y = getOffset(Adjustable.VERTICAL);
97         return new Point(x, y);
98     }
99 
100     /**
101      * The child component has been resized.  The scrollbars must be
102      * updated with the new sizes.  At the native level the sizes of
103      * the actual windows may not have changed yet, so the size
104      * information from the java-level is passed down and used.
105      */
106     @Override
childResized(int width, int height)107     public void childResized(int width, int height) {
108         ScrollPane sp = (ScrollPane)target;
109         Dimension vs = sp.getSize();
110         setSpans(vs.width, vs.height, width, height);
111         setInsets();
112     }
113 
setSpans(int viewWidth, int viewHeight, int childWidth, int childHeight)114     native synchronized void setSpans(int viewWidth, int viewHeight,
115                                       int childWidth, int childHeight);
116 
117     /**
118      * Called by ScrollPane's internal observer of the scrollpane's adjustables.
119      * This is called whenever a scroll position is changed in one
120      * of adjustables, whether it was modified externally or from the
121      * native scrollbars themselves.
122      */
123     @Override
setValue(Adjustable adj, int v)124     public void setValue(Adjustable adj, int v) {
125         Component c = getScrollChild();
126         if (c == null) {
127             return;
128         }
129 
130         Point p = c.getLocation();
131         switch(adj.getOrientation()) {
132         case Adjustable.VERTICAL:
133             setScrollPosition(-(p.x), v);
134             break;
135         case Adjustable.HORIZONTAL:
136             setScrollPosition(v, -(p.y));
137             break;
138         }
139     }
140 
getScrollChild()141     private Component getScrollChild() {
142         ScrollPane sp = (ScrollPane)target;
143         Component child = null;
144         try {
145             child = sp.getComponent(0);
146         } catch (ArrayIndexOutOfBoundsException e) {
147             // do nothing.  in this case we return null
148         }
149         return child;
150     }
151 
152     /*
153      * Called from Windows in response to WM_VSCROLL/WM_HSCROLL message
154      */
postScrollEvent(int orient, int type, int pos, boolean isAdjusting)155     private void postScrollEvent(int orient, int type,
156                                  int pos, boolean isAdjusting)
157     {
158         Runnable adjustor = new Adjustor(orient, type, pos, isAdjusting);
159         WToolkit.executeOnEventHandlerThread(new ScrollEvent(target, adjustor));
160     }
161 
162     /*
163      * Event that executes on the Java dispatch thread to move the
164      * scroll bar thumbs and paint the exposed area in one synchronous
165      * operation.
166      */
167     class ScrollEvent extends PeerEvent {
ScrollEvent(Object source, Runnable runnable)168         ScrollEvent(Object source, Runnable runnable) {
169             super(source, runnable, 0L);
170         }
171 
172         @Override
coalesceEvents(PeerEvent newEvent)173         public PeerEvent coalesceEvents(PeerEvent newEvent) {
174             if (log.isLoggable(PlatformLogger.Level.FINEST)) {
175                 log.finest("ScrollEvent coalesced: " + newEvent);
176             }
177             if (newEvent instanceof ScrollEvent) {
178                 return newEvent;
179             }
180             return null;
181         }
182     }
183 
184     /*
185      * Runnable for the ScrollEvent that performs the adjustment.
186      */
187     class Adjustor implements Runnable {
188         int orient;             // selects scrollbar
189         int type;               // adjustment type
190         int pos;                // new position (only used for absolute)
191         boolean isAdjusting;    // isAdjusting status
192 
Adjustor(int orient, int type, int pos, boolean isAdjusting)193         Adjustor(int orient, int type, int pos, boolean isAdjusting) {
194             this.orient = orient;
195             this.type = type;
196             this.pos = pos;
197             this.isAdjusting = isAdjusting;
198         }
199 
200         @Override
run()201         public void run() {
202             if (getScrollChild() == null) {
203                 return;
204             }
205             ScrollPane sp = (ScrollPane)WScrollPanePeer.this.target;
206             ScrollPaneAdjustable adj = null;
207 
208             // ScrollPaneAdjustable made public in 1.4, but
209             // get[HV]Adjustable can't be declared to return
210             // ScrollPaneAdjustable because it would break backward
211             // compatibility -- hence the cast
212 
213             if (orient == Adjustable.VERTICAL) {
214                 adj = (ScrollPaneAdjustable)sp.getVAdjustable();
215             } else if (orient == Adjustable.HORIZONTAL) {
216                 adj = (ScrollPaneAdjustable)sp.getHAdjustable();
217             } else {
218                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
219                     log.fine("Assertion failed: unknown orient");
220                 }
221             }
222 
223             if (adj == null) {
224                 return;
225             }
226 
227             int newpos = adj.getValue();
228             switch (type) {
229               case AdjustmentEvent.UNIT_DECREMENT:
230                   newpos -= adj.getUnitIncrement();
231                   break;
232               case AdjustmentEvent.UNIT_INCREMENT:
233                   newpos += adj.getUnitIncrement();
234                   break;
235               case AdjustmentEvent.BLOCK_DECREMENT:
236                   newpos -= adj.getBlockIncrement();
237                   break;
238               case AdjustmentEvent.BLOCK_INCREMENT:
239                   newpos += adj.getBlockIncrement();
240                   break;
241               case AdjustmentEvent.TRACK:
242                   newpos = this.pos;
243                   break;
244               default:
245                   if (log.isLoggable(PlatformLogger.Level.FINE)) {
246                       log.fine("Assertion failed: unknown type");
247                   }
248                   return;
249             }
250 
251             // keep scroll position in acceptable range
252             newpos = Math.max(adj.getMinimum(), newpos);
253             newpos = Math.min(adj.getMaximum(), newpos);
254 
255             // set value, this will synchronously fire an AdjustmentEvent
256             adj.setValueIsAdjusting(isAdjusting);
257 
258             // Fix for 4075484 - consider type information when creating AdjustmentEvent
259             // We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK
260             // Instead, we call private method setTypedValue of ScrollPaneAdjustable.
261             AWTAccessor.getScrollPaneAdjustableAccessor().setTypedValue(adj,
262                                                                         newpos,
263                                                                         type);
264 
265             // Paint the exposed area right away.  To do this - find
266             // the heavyweight ancestor of the scroll child.
267             Component hwAncestor = getScrollChild();
268             while (hwAncestor != null
269                    && !(hwAncestor.getPeer() instanceof WComponentPeer))
270             {
271                 hwAncestor = hwAncestor.getParent();
272             }
273             if (log.isLoggable(PlatformLogger.Level.FINE)) {
274                 if (hwAncestor == null) {
275                     log.fine("Assertion (hwAncestor != null) failed, " +
276                              "couldn't find heavyweight ancestor of scroll pane child");
277                 }
278             }
279             WComponentPeer hwPeer = (WComponentPeer)hwAncestor.getPeer();
280             hwPeer.paintDamagedAreaImmediately();
281         }
282     }
283 
284 }
285