comparison agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c70a245cad3a
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2000-2002 Sun Microsystems, Inc. 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 package sun.jvm.hotspot.ui;
26
27 import java.awt.event.*;
28 import javax.swing.*;
29 import javax.swing.event.*;
30 import java.math.*;
31 import java.util.*;
32
33 /** A JScrollBar which uses BigIntegers as the representation for the
34 minimum, maximum, unit increment, etc. Interaction with the
35 buttons and track is accurate to unit and block increments;
36 however, if the scale of the scrollbar (defined by
37 getMaximumHP().subtract(getMinimumHP())) is very large, each
38 interaction with the thumb will necessarily cause extremely large
39 motion of the value. */
40
41 public class HighPrecisionJScrollBar extends JScrollBar {
42 private BigInteger valueHP;
43 private BigInteger visibleHP;
44 private BigInteger minimumHP;
45 private BigInteger maximumHP;
46 private BigInteger unitIncrementHP;
47 private BigInteger blockIncrementHP;
48 private BigDecimal scaleFactor;
49 private BigInteger rangeHP;
50 // The underlying scrollbar runs a range from 0..BIG_RANGE-1
51 private static final int BIG_RANGE = 10000;
52 // Do we need to scale HP values up/down to fit in 0..BIG_RANGE-1?
53 private boolean down;
54 private java.util.List changeListeners = new ArrayList();
55 // Number of digits after decimal point to use when scaling between
56 // high and low precision
57 private static final int SCALE = 20;
58
59
60 // This is a hack to allow us to differentiate between clicks on the
61 // arrow and track since we can't get useful information from
62 // JScrollBars' AdjustmentListener (bug in design of BasicUI
63 // classes; FIXME: file RFE.)
64 private static final int UNIT_INCREMENT = 1;
65 private static final int BLOCK_INCREMENT = 2;
66 private static final int MINIMUM = 0;
67 private static final int MAXIMUM = 65536;
68 private boolean updating = false;
69 private int lastValueSeen = -1;
70
71 public HighPrecisionJScrollBar() {
72 super();
73 initialize();
74 installListener();
75 }
76
77 public HighPrecisionJScrollBar(int orientation) {
78 super(orientation);
79 initialize();
80 installListener();
81 }
82
83 /** value, minimum and maximum should be positive */
84 public HighPrecisionJScrollBar(int orientation, BigInteger value, BigInteger minimum, BigInteger maximum) {
85 super(orientation);
86 initialize(value, minimum, maximum);
87 installListener();
88 }
89
90 public BigInteger getValueHP() {
91 return valueHP;
92 }
93
94
95 /** NOTE: the real value will always be set to be (value mod
96 unitIncrement) == 0, subtracting off the mod of the passed value
97 if necessary. */
98
99 public void setValueHP(BigInteger value) {
100 if (value.compareTo(getMaximumHP()) > 0) {
101 value = getMaximumHP();
102 } else if (value.compareTo(getMinimumHP()) < 0) {
103 value = getMinimumHP();
104 }
105 valueHP = value.subtract(value.mod(unitIncrementHP));
106 int lpValue = toUnderlyingRange(this.valueHP);
107 if (getValueHP().add(getVisibleAmountHP()).compareTo(getMaximumHP()) >= 0 ) {
108 lpValue = BIG_RANGE - getVisibleAmount();
109 }
110 lastValueSeen = lpValue;
111 setValue(lpValue);
112 fireStateChanged();
113 }
114 public BigInteger getMinimumHP() {
115 return minimumHP;
116 }
117
118 public void setMinimumHP(BigInteger minimum) {
119 setRange(minimum, maximumHP);
120 updateScrollBarValues();
121 }
122
123 public BigInteger getMaximumHP() {
124 return maximumHP;
125 }
126
127 public void setMaximumHP(BigInteger maximum) {
128 setRange(minimumHP, maximum);
129 updateScrollBarValues();
130 }
131
132 public BigInteger getVisibleAmountHP() {
133 return visibleHP;
134 }
135
136 public void setVisibleAmountHP(BigInteger visibleAmount) {
137 this.visibleHP = visibleAmount;
138 // int lpVisAmt = toUnderlyingRange(visibleAmount);
139 // Make certain that visibleAmount value that are full range come out looking like full range
140 int lpVisAmt;
141 if (visibleAmount.compareTo(rangeHP) < 0) {
142 lpVisAmt = scaleToUnderlying(visibleAmount);
143 if (lpVisAmt == 0) {
144 lpVisAmt = 1;
145 }
146 setVisible(true);
147 } else {
148 lpVisAmt = BIG_RANGE;
149 setVisible(false);
150 }
151 setVisibleAmount(lpVisAmt);
152 }
153
154 public BigInteger getBlockIncrementHP() {
155 return blockIncrementHP;
156 }
157
158 public void setBlockIncrementHP(BigInteger blockIncrement) {
159 this.blockIncrementHP = blockIncrement;
160 // NOTE we do not forward this to the underlying scrollBar because of
161 // the earlier mentioned hack.
162 }
163
164 public BigInteger getUnitIncrementHP() {
165 return unitIncrementHP;
166 }
167
168 public void setUnitIncrementHP(BigInteger unitIncrement) {
169 this.unitIncrementHP = unitIncrement;
170 // NOTE we do not forward this to the underlying scrollBar because of
171 // the earlier mentioned hack.
172 }
173
174
175 public void addChangeListener(ChangeListener l) {
176 changeListeners.add(l);
177 }
178
179 public void removeChangeListener(ChangeListener l) {
180 changeListeners.remove(l);
181 }
182
183 //----------------------------------------------------------------------
184 // Programmatic access to scrollbar functionality
185 // (Causes change events to be sent)
186
187 public void scrollUpOrLeft() {
188 if (updating) return;
189 beginUpdate();
190 setValueHP(getValueHP().subtract(getUnitIncrementHP()));
191 endUpdate();
192 }
193
194 public void scrollDownOrRight() {
195 if (updating) return;
196 beginUpdate();
197 setValueHP(getValueHP().add(getUnitIncrementHP()));
198 endUpdate();
199 }
200
201 public void pageUpOrLeft() {
202 if (updating) return;
203 beginUpdate();
204 setValueHP(getValueHP().subtract(getBlockIncrementHP()));
205 endUpdate();
206 }
207
208 public void pageDownOrRight() {
209 if (updating) return;
210 beginUpdate();
211 setValueHP(getValueHP().add(getBlockIncrementHP()));
212 endUpdate();
213 }
214
215 //----------------------------------------------------------------------
216 // Internals only below this point
217 //
218
219 private void beginUpdate() {
220 updating = true;
221 }
222
223 private void endUpdate() {
224 updating = false;
225 }
226
227 private void initialize(BigInteger value, BigInteger minimum, BigInteger maximum) {
228 // Initialize the underlying scrollbar to the standard range values
229 // The increments are important and are how we differentiate arrow from track events
230 setMinimum(0);
231 setMaximum(BIG_RANGE - 1);
232 setValue(0);
233 setVisibleAmount(1);
234 setUnitIncrement(UNIT_INCREMENT);
235 setBlockIncrement(BLOCK_INCREMENT);
236
237 setUnitIncrementHP(new BigInteger(Integer.toString(getUnitIncrement())));
238 setBlockIncrementHP(new BigInteger(Integer.toString(getBlockIncrement())));
239
240 // Must set range and value first (it sets min/max)
241 setRange(minimum, maximum);
242
243 setVisibleAmountHP(new BigInteger(Integer.toString(getVisibleAmount())));
244 setValueHP(value);
245 }
246
247 private void initialize() {
248 BigInteger min = new BigInteger(Integer.toString(getMinimum()));
249 BigInteger max = new BigInteger(Integer.toString(getMaximum()));
250 initialize(min, min, max);
251 }
252
253 private void setRange(BigInteger minimum, BigInteger maximum) {
254 if (minimum.compareTo(maximum) > 0 ) {
255 throw new RuntimeException("Bad scrollbar range " + minimum + " > " + maximum);
256 }
257 minimumHP = minimum;
258 maximumHP = maximum;
259 rangeHP = maximum.subtract(minimum).add(BigInteger.ONE);
260 BigInteger range2 = new BigInteger(Integer.toString(BIG_RANGE));
261 if (rangeHP.compareTo(range2) >= 0 ) {
262 down = true;
263 scaleFactor = new BigDecimal(rangeHP, SCALE).divide(new BigDecimal(range2, SCALE), BigDecimal.ROUND_DOWN).max(new BigDecimal(BigInteger.ONE));
264 } else {
265 down = false;
266 scaleFactor = new BigDecimal(range2, SCALE).divide(new BigDecimal(rangeHP, SCALE), BigDecimal.ROUND_DOWN).max(new BigDecimal(BigInteger.ONE));
267 }
268 // FIXME: should put in original scaling algorithm (shifting by
269 // number of bits) as alternative when scale between low and high
270 // precision is very large
271 }
272
273 // A range update is complete. Rescale our computed values and
274 // inform the underlying scrollBar as needed.
275 private void updateScrollBarValues() {
276 setValueHP(getValueHP());
277 setVisibleAmountHP(getVisibleAmountHP());
278 setBlockIncrementHP(getBlockIncrementHP());
279 setUnitIncrementHP(getUnitIncrementHP());
280 }
281
282 private BigDecimal getScaleFactor() {
283 return scaleFactor;
284 }
285
286
287 // Value scaling routines
288 private BigInteger scaleToHP(int i) {
289 BigDecimal ib = new BigDecimal(Integer.toString(i));
290 if (down) return ib.multiply(getScaleFactor()).toBigInteger();
291 else return ib.divide(getScaleFactor(), BigDecimal.ROUND_DOWN).toBigInteger();
292 }
293
294 private int scaleToUnderlying(BigInteger i) {
295 BigDecimal d = new BigDecimal(i);
296 if (down) return d.divide(getScaleFactor(), BigDecimal.ROUND_DOWN).intValue();
297 else return d.multiply(getScaleFactor()).intValue();
298 }
299
300 // Range scaling routines
301 private BigInteger toHPRange(int i) {
302 return scaleToHP(i).add(minimumHP);
303 // return ib.shiftLeft(Math.max(2, maximumHP.bitLength() - 33));
304 }
305
306 private int toUnderlyingRange(BigInteger i) {
307 return scaleToUnderlying(i.subtract(minimumHP));
308 // return i.shiftRight(Math.max(2, maximumHP.bitLength() - 33)).intValue();
309 }
310
311 private void installListener() {
312 super.addAdjustmentListener(new AdjustmentListener() {
313 public void adjustmentValueChanged(AdjustmentEvent e) {
314 if (updating) {
315 return;
316 }
317 beginUpdate();
318 switch (e.getAdjustmentType()) {
319 case AdjustmentEvent.TRACK:
320 int val = e.getValue();
321 int diff = val - lastValueSeen;
322 int absDiff = Math.abs(diff);
323 // System.err.println("diff: " + diff + " absDiff: " + absDiff);
324 if (absDiff == UNIT_INCREMENT) {
325 if (diff > 0) {
326 // System.err.println("case 1");
327 setValueHP(getValueHP().add(getUnitIncrementHP()));
328 } else {
329 // System.err.println("case 2");
330 setValueHP(getValueHP().subtract(getUnitIncrementHP()));
331 }
332 } else if (absDiff == BLOCK_INCREMENT) {
333 if (diff > 0) {
334 // System.err.println("case 3");
335 setValueHP(getValueHP().add(getBlockIncrementHP()));
336 } else {
337 // System.err.println("case 4");
338 setValueHP(getValueHP().subtract(getBlockIncrementHP()));
339 }
340 } else {
341 // System.err.println("case 5");
342 // FIXME: seem to be getting spurious update events,
343 // with diff = 0, upon mouse down/up on the track
344 if (absDiff != 0) {
345 // Convert low-precision value to high precision
346 // (note we lose the low bits)
347 BigInteger i = null;
348 if (e.getValue() == getMinimum()) {
349 i = getMinimumHP();
350 } else if (e.getValue() >= getMaximum() - 1) {
351 i = getMaximumHP();
352 } else {
353 i = toHPRange(e.getValue());
354 }
355 setValueHP(i);
356 }
357 }
358 break;
359 default:
360 // Should not reach here, but leaving it a no-op in case
361 // we later get the other events (should revisit code in
362 // that case)
363 break;
364 }
365 endUpdate();
366 }
367 });
368 }
369
370 private void fireStateChanged() {
371 ChangeEvent e = null;
372 for (Iterator iter = changeListeners.iterator(); iter.hasNext(); ) {
373 ChangeListener l = (ChangeListener) iter.next();
374 if (e == null) {
375 e = new ChangeEvent(this);
376 }
377 l.stateChanged(e);
378 }
379 }
380
381 public static void main(String[] args) {
382 JFrame frame = new JFrame();
383 frame.setSize(300, 300);
384 // 32-bit version
385 /*
386 HighPrecisionJScrollBar hpsb =
387 new HighPrecisionJScrollBar(
388 JScrollBar.VERTICAL,
389 new BigInteger(1, new byte[] {
390 (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
391 new BigInteger(1, new byte[] {
392 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
393 new BigInteger(1, new byte[] {
394 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}));
395 hpsb.setUnitIncrementHP(new BigInteger(1, new byte[] {
396 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01}));
397 hpsb.setBlockIncrementHP(new BigInteger(1, new byte[] {
398 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10}));
399 */
400
401 // 64-bit version
402 HighPrecisionJScrollBar hpsb =
403 new HighPrecisionJScrollBar(
404 JScrollBar.VERTICAL,
405 new BigInteger(1, new byte[] {
406 (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00,
407 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
408 new BigInteger(1, new byte[] {
409 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
410 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
411 new BigInteger(1, new byte[] {
412 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
413 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}));
414 hpsb.setUnitIncrementHP(new BigInteger(1, new byte[] {
415 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
416 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01}));
417 hpsb.setBlockIncrementHP(new BigInteger(1, new byte[] {
418 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
419 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10}));
420 hpsb.addChangeListener(new ChangeListener() {
421 public void stateChanged(ChangeEvent e) {
422 HighPrecisionJScrollBar h = (HighPrecisionJScrollBar) e.getSource();
423 System.out.println("New value = 0x" + h.getValueHP().toString(16));
424 }
425 });
426 frame.getContentPane().add(hpsb);
427 frame.show();
428 }
429
430 }