blob: 790ac6d95eb6581d8f0f94041713a038aba8c636 [file] [log] [blame]
/*
* Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt.windows;
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.peer.ScrollPanePeer;
import sun.awt.PeerEvent;
import sun.util.logging.PlatformLogger;
class WScrollPanePeer extends WPanelPeer implements ScrollPanePeer {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WScrollPanePeer");
int scrollbarWidth;
int scrollbarHeight;
int prevx;
int prevy;
static {
initIDs();
}
static native void initIDs();
native void create(WComponentPeer parent);
native int getOffset(int orient);
WScrollPanePeer(Component target) {
super(target);
scrollbarWidth = _getVScrollbarWidth();
scrollbarHeight = _getHScrollbarHeight();
}
void initialize() {
super.initialize();
setInsets();
Insets i = getInsets();
setScrollPosition(-i.left,-i.top);
}
public void setUnitIncrement(Adjustable adj, int p) {
// The unitIncrement is grabbed from the target as needed.
}
public Insets insets() {
return getInsets();
}
private native void setInsets();
public native synchronized void setScrollPosition(int x, int y);
public int getHScrollbarHeight() {
return scrollbarHeight;
}
private native int _getHScrollbarHeight();
public int getVScrollbarWidth() {
return scrollbarWidth;
}
private native int _getVScrollbarWidth();
public Point getScrollOffset() {
int x = getOffset(Adjustable.HORIZONTAL);
int y = getOffset(Adjustable.VERTICAL);
return new Point(x, y);
}
/**
* The child component has been resized. The scrollbars must be
* updated with the new sizes. At the native level the sizes of
* the actual windows may not have changed yet, so the size
* information from the java-level is passed down and used.
*/
public void childResized(int width, int height) {
ScrollPane sp = (ScrollPane)target;
Dimension vs = sp.getSize();
setSpans(vs.width, vs.height, width, height);
setInsets();
}
native synchronized void setSpans(int viewWidth, int viewHeight,
int childWidth, int childHeight);
/**
* Called by ScrollPane's internal observer of the scrollpane's adjustables.
* This is called whenever a scroll position is changed in one
* of adjustables, whether it was modified externally or from the
* native scrollbars themselves.
*/
public void setValue(Adjustable adj, int v) {
Component c = getScrollChild();
if (c == null) {
return;
}
Point p = c.getLocation();
switch(adj.getOrientation()) {
case Adjustable.VERTICAL:
setScrollPosition(-(p.x), v);
break;
case Adjustable.HORIZONTAL:
setScrollPosition(v, -(p.y));
break;
}
}
private Component getScrollChild() {
ScrollPane sp = (ScrollPane)target;
Component child = null;
try {
child = sp.getComponent(0);
} catch (ArrayIndexOutOfBoundsException e) {
// do nothing. in this case we return null
}
return child;
}
/*
* Called from Windows in response to WM_VSCROLL/WM_HSCROLL message
*/
private void postScrollEvent(int orient, int type,
int pos, boolean isAdjusting)
{
Runnable adjustor = new Adjustor(orient, type, pos, isAdjusting);
WToolkit.executeOnEventHandlerThread(new ScrollEvent(target, adjustor));
}
/*
* Event that executes on the Java dispatch thread to move the
* scroll bar thumbs and paint the exposed area in one synchronous
* operation.
*/
class ScrollEvent extends PeerEvent {
ScrollEvent(Object source, Runnable runnable) {
super(source, runnable, 0L);
}
public PeerEvent coalesceEvents(PeerEvent newEvent) {
if (log.isLoggable(PlatformLogger.FINEST)) {
log.finest("ScrollEvent coalesced: " + newEvent);
}
if (newEvent instanceof ScrollEvent) {
return newEvent;
}
return null;
}
}
native void setTypedValue(ScrollPaneAdjustable adjustable, int newpos, int type);
/*
* Runnable for the ScrollEvent that performs the adjustment.
*/
class Adjustor implements Runnable {
int orient; // selects scrollbar
int type; // adjustment type
int pos; // new position (only used for absolute)
boolean isAdjusting; // isAdjusting status
Adjustor(int orient, int type, int pos, boolean isAdjusting) {
this.orient = orient;
this.type = type;
this.pos = pos;
this.isAdjusting = isAdjusting;
}
public void run() {
if (getScrollChild() == null) {
return;
}
ScrollPane sp = (ScrollPane)WScrollPanePeer.this.target;
ScrollPaneAdjustable adj = null;
// ScrollPaneAdjustable made public in 1.4, but
// get[HV]Adjustable can't be declared to return
// ScrollPaneAdjustable because it would break backward
// compatibility -- hence the cast
if (orient == Adjustable.VERTICAL) {
adj = (ScrollPaneAdjustable)sp.getVAdjustable();
} else if (orient == Adjustable.HORIZONTAL) {
adj = (ScrollPaneAdjustable)sp.getHAdjustable();
} else {
if (log.isLoggable(PlatformLogger.FINE)) {
log.fine("Assertion failed: unknown orient");
}
}
if (adj == null) {
return;
}
int newpos = adj.getValue();
switch (type) {
case AdjustmentEvent.UNIT_DECREMENT:
newpos -= adj.getUnitIncrement();
break;
case AdjustmentEvent.UNIT_INCREMENT:
newpos += adj.getUnitIncrement();
break;
case AdjustmentEvent.BLOCK_DECREMENT:
newpos -= adj.getBlockIncrement();
break;
case AdjustmentEvent.BLOCK_INCREMENT:
newpos += adj.getBlockIncrement();
break;
case AdjustmentEvent.TRACK:
newpos = this.pos;
break;
default:
if (log.isLoggable(PlatformLogger.FINE)) {
log.fine("Assertion failed: unknown type");
}
return;
}
// keep scroll position in acceptable range
newpos = Math.max(adj.getMinimum(), newpos);
newpos = Math.min(adj.getMaximum(), newpos);
// set value, this will synchronously fire an AdjustmentEvent
adj.setValueIsAdjusting(isAdjusting);
// Fix for 4075484 - consider type information when creating AdjustmentEvent
// We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK
// Instead, we call private method setTypedValue of ScrollPaneAdjustable.
// Because ScrollPaneAdjustable is in another package we should call it through native code.
setTypedValue(adj, newpos, type);
// Paint the exposed area right away. To do this - find
// the heavyweight ancestor of the scroll child.
Component hwAncestor = getScrollChild();
while (hwAncestor != null
&& !(hwAncestor.getPeer() instanceof WComponentPeer))
{
hwAncestor = hwAncestor.getParent();
}
if (log.isLoggable(PlatformLogger.FINE)) {
if (hwAncestor == null) {
log.fine("Assertion (hwAncestor != null) failed, " +
"couldn't find heavyweight ancestor of scroll pane child");
}
}
WComponentPeer hwPeer = (WComponentPeer)hwAncestor.getPeer();
hwPeer.paintDamagedAreaImmediately();
}
}
}