001: /*
002: * Copyright 1996-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.motif;
027:
028: import java.awt.*;
029: import java.awt.event.AdjustmentEvent;
030: import java.awt.peer.ScrollPanePeer;
031: import sun.awt.DebugHelper;
032: import sun.awt.PeerEvent;
033:
034: class MScrollPanePeer extends MPanelPeer implements ScrollPanePeer {
035: private static final DebugHelper dbg = DebugHelper
036: .create(MScrollPanePeer.class);
037:
038: final static int UNIT_INCREMENT = 0;
039: final static int BLOCK_INCREMENT = 1;
040:
041: boolean ignore;
042:
043: native void create(MComponentPeer parent);
044:
045: static {
046: initIDs();
047: }
048:
049: /**
050: * Initialize JNI field and method IDs
051: */
052: private static native void initIDs();
053:
054: MScrollPanePeer(Component target) {
055: init(target);
056: scrollPaneInit();
057: }
058:
059: MScrollPanePeer(Component target, Object arg) {
060: init(target, arg);
061: scrollPaneInit();
062: }
063:
064: void scrollPaneInit() {
065: ignore = false;
066: ScrollPane sp = (ScrollPane) target;
067: Adjustable vadj, hadj;
068: if ((vadj = sp.getVAdjustable()) != null) {
069: pSetIncrement(Adjustable.VERTICAL, UNIT_INCREMENT, vadj
070: .getUnitIncrement());
071: }
072: if ((hadj = sp.getHAdjustable()) != null) {
073: pSetIncrement(Adjustable.HORIZONTAL, UNIT_INCREMENT, hadj
074: .getUnitIncrement());
075: }
076: super .pSetScrollbarBackground(sp.getBackground());
077: }
078:
079: public void setScrollChild(MComponentPeer child) {
080: pSetScrollChild(child);
081: }
082:
083: public void setBackground(Color c) {
084: super .setBackground(c);
085: pSetScrollbarBackground(c);
086: }
087:
088: public void setForeground(Color c) {
089: super .setForeground(c);
090: pSetInnerForeground(c);
091: }
092:
093: native void pSetScrollChild(MComponentPeer child);
094:
095: native void pSetIncrement(int orient, int type, int incr);
096:
097: native int pGetScrollbarSpace(int orient);
098:
099: native int pGetBlockIncrement(int orient);
100:
101: native Insets pInsets(int w, int h, int childw, int childh);
102:
103: native int pGetShadow();
104:
105: public int getHScrollbarHeight() {
106: ScrollPane sp = (ScrollPane) target;
107: if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) {
108: return 0;
109: } else {
110: return pGetScrollbarSpace(Adjustable.HORIZONTAL);
111: }
112: }
113:
114: public int getVScrollbarWidth() {
115: ScrollPane sp = (ScrollPane) target;
116: if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) {
117: return 0;
118: } else {
119: return pGetScrollbarSpace(Adjustable.VERTICAL);
120: }
121: }
122:
123: public Insets insets() {
124: ScrollPane sp = (ScrollPane) target;
125: Dimension d = sp.size();
126: Dimension cd;
127: Component c = getScrollChild();
128: if (c != null) {
129: cd = c.size();
130: } else {
131: cd = new Dimension(0, 0);
132: }
133: return pInsets(d.width, d.height, cd.width, cd.height);
134: }
135:
136: public void setUnitIncrement(Adjustable adj, int u) {
137: ScrollPane sp = (ScrollPane) target;
138: if (sp.getScrollbarDisplayPolicy() != ScrollPane.SCROLLBARS_NEVER) {
139: pSetIncrement(adj.getOrientation(), UNIT_INCREMENT, u);
140: }
141: }
142:
143: public void setValue(Adjustable adj, int v) {
144: if (!ignore) {
145: Point p;
146: Component c = getScrollChild();
147: if (c == null) {
148: return;
149: }
150: p = c.getLocation();
151: switch (adj.getOrientation()) {
152: case Adjustable.VERTICAL:
153: setScrollPosition(-(p.x), v);
154: break;
155: case Adjustable.HORIZONTAL:
156: setScrollPosition(v, -(p.y));
157: break;
158: }
159: }
160: }
161:
162: public native void setScrollPosition(int x, int y);
163:
164: public void childResized(int w, int h) {
165: // REMIND AIM: May need to revisit this...
166: if (((ScrollPane) target).getScrollbarDisplayPolicy() != ScrollPane.SCROLLBARS_NEVER) {
167: ScrollPane sp = (ScrollPane) target;
168: Adjustable vAdj = sp.getVAdjustable();
169: Adjustable hAdj = sp.getHAdjustable();
170: pSetIncrement(Scrollbar.VERTICAL, UNIT_INCREMENT, vAdj
171: .getUnitIncrement());
172: pSetIncrement(Scrollbar.HORIZONTAL, UNIT_INCREMENT, hAdj
173: .getUnitIncrement());
174: pSetIncrement(Scrollbar.VERTICAL, BLOCK_INCREMENT, vAdj
175: .getBlockIncrement());
176: pSetIncrement(Scrollbar.HORIZONTAL, BLOCK_INCREMENT, hAdj
177: .getBlockIncrement());
178: }
179:
180: }
181:
182: // NOTE: This method may be called by privileged threads.
183: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
184: private void postScrollEvent(int orient, int type, int pos,
185: boolean isAdjusting) {
186: Runnable adjustor = new Adjustor(orient, type, pos, isAdjusting);
187: MToolkit.executeOnEventHandlerThread(new ScrollEvent(target,
188: adjustor));
189: }
190:
191: /**
192: * This is used to change the adjustable on dispatch thread to
193: * represent a change made in the native scrollbar. Since the
194: * change was reflected immediately at the native level,
195: * notification from the adjustable is temporarily ignored.
196: */
197: class ScrollEvent extends PeerEvent {
198: ScrollEvent(Object source, Runnable runnable) {
199: super (source, runnable, 0L);
200: }
201:
202: public PeerEvent coalesceEvents(PeerEvent newEvent) {
203: if (dbg.on)
204: dbg.println("ScrollEvent coalesced " + newEvent);
205: if (newEvent instanceof ScrollEvent) {
206: return newEvent;
207: }
208: return null;
209: }
210: }
211:
212: native void setTypedValue(ScrollPaneAdjustable adjustable,
213: int value, int type);
214:
215: /**
216: * Runnable for the ScrollEvent that performs the adjustment.
217: */
218: class Adjustor implements Runnable {
219: int orient; // selects scrollbar
220: int type; // adjustment type
221: int pos; // new position (only used for absolute)
222: boolean isAdjusting; // isAdjusting status
223:
224: Adjustor(int orient, int type, int pos, boolean isAdjusting) {
225: this .orient = orient;
226: this .type = type;
227: this .pos = pos;
228: this .isAdjusting = isAdjusting;
229: }
230:
231: public void run() {
232: ScrollPane sp = (ScrollPane) MScrollPanePeer.this .target;
233: ScrollPaneAdjustable adj = null;
234:
235: // ScrollPaneAdjustable made public in 1.4, but
236: // get[HV]Adjustable can't be declared to return
237: // ScrollPaneAdjustable because it would break backward
238: // compatibility -- hence the cast
239:
240: if (orient == Adjustable.VERTICAL) {
241: adj = (ScrollPaneAdjustable) sp.getVAdjustable();
242: } else if (orient == Adjustable.HORIZONTAL) {
243: adj = (ScrollPaneAdjustable) sp.getHAdjustable();
244: } else {
245: if (dbg.on)
246: dbg.assertion(false);
247: }
248:
249: if (adj == null) {
250: return;
251: }
252:
253: int newpos = adj.getValue();
254: switch (type) {
255: case AdjustmentEvent.UNIT_DECREMENT:
256: newpos -= adj.getUnitIncrement();
257: break;
258: case AdjustmentEvent.UNIT_INCREMENT:
259: newpos += adj.getUnitIncrement();
260: break;
261: case AdjustmentEvent.BLOCK_DECREMENT:
262: newpos -= adj.getBlockIncrement();
263: break;
264: case AdjustmentEvent.BLOCK_INCREMENT:
265: newpos += adj.getBlockIncrement();
266: break;
267: case AdjustmentEvent.TRACK:
268: newpos = this .pos;
269: break;
270: default:
271: if (dbg.on)
272: dbg.assertion(false);
273: return;
274: }
275:
276: // keep scroll position in acceptable range
277: newpos = Math.max(adj.getMinimum(), newpos);
278: newpos = Math.min(adj.getMaximum(), newpos);
279:
280: // set value; this will synchronously fire an AdjustmentEvent
281: try {
282: MScrollPanePeer.this .ignore = true;
283: adj.setValueIsAdjusting(isAdjusting);
284:
285: // Fix for 4075484 - consider type information when creating AdjustmentEvent
286: // We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK
287: // Instead, we call private method setTypedValue of ScrollPaneAdjustable.
288: // Because ScrollPaneAdjustable is in another package we should call it through native code.
289: setTypedValue(adj, newpos, type);
290: } finally {
291: MScrollPanePeer.this .ignore = false;
292: }
293: }
294: } // class Adjustor
295:
296: private Component getScrollChild() {
297: ScrollPane sp = (ScrollPane) target;
298: Component child = null;
299: try {
300: child = sp.getComponent(0);
301: } catch (ArrayIndexOutOfBoundsException e) {
302: // do nothing. in this case we return null
303: }
304: return child;
305: }
306:
307: final static int MARGIN = 1;
308: final static int SCROLLBAR = 16;
309: int hsbSpace;
310: int vsbSpace;
311: int vval;
312: int hval;
313: int vmax;
314: int hmax;
315:
316: /*
317: * Print the native component by rendering the Motif look ourselves.
318: * ToDo(aim): needs to query native motif for more accurate size and
319: * color information.
320: */
321: public void print(Graphics g) {
322: ScrollPane sp = (ScrollPane) target;
323: Dimension d = sp.size();
324: Color bg = sp.getBackground();
325: Color fg = sp.getForeground();
326: Point p = sp.getScrollPosition();
327: Component c = getScrollChild();
328: Dimension cd;
329: if (c != null) {
330: cd = c.size();
331: } else {
332: cd = new Dimension(0, 0);
333: }
334: int sbDisplay = sp.getScrollbarDisplayPolicy();
335: int vvis, hvis, vmin, hmin, vmax, hmax, vval, hval;
336:
337: switch (sbDisplay) {
338: case ScrollPane.SCROLLBARS_NEVER:
339: hsbSpace = vsbSpace = 0;
340: break;
341: case ScrollPane.SCROLLBARS_ALWAYS:
342: hsbSpace = vsbSpace = SCROLLBAR;
343: break;
344: case ScrollPane.SCROLLBARS_AS_NEEDED:
345: hsbSpace = (cd.width <= (d.width - 2 * MARGIN) ? 0
346: : SCROLLBAR);
347: vsbSpace = (cd.height <= (d.height - 2 * MARGIN) ? 0
348: : SCROLLBAR);
349:
350: if (hsbSpace == 0 && vsbSpace != 0) {
351: hsbSpace = (cd.width <= (d.width - SCROLLBAR - 2 * MARGIN) ? 0
352: : SCROLLBAR);
353: }
354: if (vsbSpace == 0 && hsbSpace != 0) {
355: vsbSpace = (cd.height <= (d.height - SCROLLBAR - 2 * MARGIN) ? 0
356: : SCROLLBAR);
357: }
358: }
359:
360: vvis = hvis = vmin = hmin = vmax = hmax = vval = hval = 0;
361:
362: if (vsbSpace > 0) {
363: vmin = 0;
364: vvis = d.height - (2 * MARGIN) - hsbSpace;
365: vmax = Math.max(cd.height - vvis, 0);
366: vval = p.y;
367: }
368: if (hsbSpace > 0) {
369: hmin = 0;
370: hvis = d.width - (2 * MARGIN) - vsbSpace;
371: hmax = Math.max(cd.width - hvis, 0);
372: hval = p.x;
373: }
374:
375: // need to be careful to add the margins back in here because
376: // we're drawing the margin border, after all!
377: int w = d.width - vsbSpace;
378: int h = d.height - hsbSpace;
379:
380: g.setColor(bg);
381: g.fillRect(0, 0, d.width, d.height);
382:
383: if (hsbSpace > 0) {
384: int sbw = d.width - vsbSpace;
385: g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1,
386: SCROLLBAR - 3);
387: Graphics ng = g.create();
388: try {
389: ng.translate(0, d.height - (SCROLLBAR - 2));
390: drawScrollbar(ng, bg, SCROLLBAR - 2, sbw, hmin, hmax,
391: hval, hvis, true);
392: } finally {
393: ng.dispose();
394: }
395: }
396: if (vsbSpace > 0) {
397: int sbh = d.height - hsbSpace;
398: g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3,
399: sbh - 1);
400: Graphics ng = g.create();
401: try {
402: ng.translate(d.width - (SCROLLBAR - 2), 0);
403: drawScrollbar(ng, bg, SCROLLBAR - 2, sbh, vmin, vmax,
404: vval, vvis, false);
405: } finally {
406: ng.dispose();
407: }
408: }
409:
410: draw3DRect(g, bg, 0, 0, w - 1, h - 1, false);
411:
412: target.print(g);
413: sp.printComponents(g);
414: }
415:
416: /**
417: * @see ContainerPeer#restack
418: */
419: public void restack() {
420: // Since ScrollPane can only have one child its restacking does nothing.
421: // Also, it is dangerous, since SP child is actually not a child of SP widget
422: // but the child of SP content widget.
423: }
424: }
|