diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2000-2002 Sun Microsystems, Inc.  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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.ui;
+
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.math.*;
+import java.util.*;
+
+/** A JScrollBar which uses BigIntegers as the representation for the
+    minimum, maximum, unit increment, etc. Interaction with the
+    buttons and track is accurate to unit and block increments;
+    however, if the scale of the scrollbar (defined by
+    getMaximumHP().subtract(getMinimumHP())) is very large, each
+    interaction with the thumb will necessarily cause extremely large
+    motion of the value. */
+
+public class HighPrecisionJScrollBar extends JScrollBar {
+  private BigInteger valueHP;
+  private BigInteger visibleHP;
+  private BigInteger minimumHP;
+  private BigInteger maximumHP;
+  private BigInteger unitIncrementHP;
+  private BigInteger blockIncrementHP;
+  private BigDecimal scaleFactor;
+  private BigInteger rangeHP;
+  // The underlying scrollbar runs a range from 0..BIG_RANGE-1
+  private static final int BIG_RANGE = 10000;
+  // Do we need to scale HP values up/down to fit in 0..BIG_RANGE-1?
+  private boolean    down;
+  private java.util.List changeListeners = new ArrayList();
+  // Number of digits after decimal point to use when scaling between
+  // high and low precision
+  private static final int SCALE = 20;
+
+
+  // This is a hack to allow us to differentiate between clicks on the
+  // arrow and track since we can't get useful information from
+  // JScrollBars' AdjustmentListener (bug in design of BasicUI
+  // classes; FIXME: file RFE.)
+  private static final int UNIT_INCREMENT  = 1;
+  private static final int BLOCK_INCREMENT = 2;
+  private static final int MINIMUM = 0;
+  private static final int MAXIMUM = 65536;
+  private boolean updating = false;
+  private int lastValueSeen = -1;
+
+  public HighPrecisionJScrollBar() {
+    super();
+    initialize();
+    installListener();
+  }
+
+  public HighPrecisionJScrollBar(int orientation) {
+    super(orientation);
+    initialize();
+    installListener();
+  }
+
+  /** value, minimum and maximum should be positive */
+  public HighPrecisionJScrollBar(int orientation, BigInteger value, BigInteger minimum, BigInteger maximum) {
+    super(orientation);
+    initialize(value, minimum, maximum);
+    installListener();
+  }
+
+  public BigInteger getValueHP() {
+    return valueHP;
+  }
+
+
+  /** NOTE: the real value will always be set to be (value mod
+      unitIncrement) == 0, subtracting off the mod of the passed value
+      if necessary. */
+
+  public void setValueHP(BigInteger value) {
+    if (value.compareTo(getMaximumHP()) > 0) {
+      value = getMaximumHP();
+    } else if (value.compareTo(getMinimumHP()) < 0) {
+      value = getMinimumHP();
+    }
+    valueHP = value.subtract(value.mod(unitIncrementHP));
+    int lpValue = toUnderlyingRange(this.valueHP);
+    if (getValueHP().add(getVisibleAmountHP()).compareTo(getMaximumHP()) >= 0 ) {
+      lpValue = BIG_RANGE - getVisibleAmount();
+    }
+    lastValueSeen = lpValue;
+    setValue(lpValue);
+    fireStateChanged();
+  }
+  public BigInteger getMinimumHP() {
+    return minimumHP;
+  }
+
+  public void setMinimumHP(BigInteger minimum) {
+    setRange(minimum, maximumHP);
+    updateScrollBarValues();
+  }
+
+  public BigInteger getMaximumHP() {
+    return maximumHP;
+  }
+
+  public void setMaximumHP(BigInteger maximum) {
+    setRange(minimumHP, maximum);
+    updateScrollBarValues();
+  }
+
+  public BigInteger getVisibleAmountHP() {
+    return visibleHP;
+  }
+
+  public void setVisibleAmountHP(BigInteger visibleAmount) {
+    this.visibleHP = visibleAmount;
+    // int lpVisAmt = toUnderlyingRange(visibleAmount);
+    // Make certain that visibleAmount value that are full range come out looking like full range
+    int lpVisAmt;
+    if (visibleAmount.compareTo(rangeHP) < 0) {
+      lpVisAmt = scaleToUnderlying(visibleAmount);
+      if (lpVisAmt == 0) {
+        lpVisAmt = 1;
+      }
+      setVisible(true);
+    } else {
+      lpVisAmt = BIG_RANGE;
+      setVisible(false);
+    }
+    setVisibleAmount(lpVisAmt);
+  }
+
+  public BigInteger getBlockIncrementHP() {
+    return blockIncrementHP;
+  }
+
+  public void setBlockIncrementHP(BigInteger blockIncrement) {
+    this.blockIncrementHP = blockIncrement;
+    // NOTE we do not forward this to the underlying scrollBar because of
+    // the earlier mentioned hack.
+  }
+
+  public BigInteger getUnitIncrementHP() {
+    return unitIncrementHP;
+  }
+
+  public void setUnitIncrementHP(BigInteger unitIncrement) {
+    this.unitIncrementHP = unitIncrement;
+    // NOTE we do not forward this to the underlying scrollBar because of
+    // the earlier mentioned hack.
+  }
+
+
+  public void addChangeListener(ChangeListener l) {
+    changeListeners.add(l);
+  }
+
+  public void removeChangeListener(ChangeListener l) {
+    changeListeners.remove(l);
+  }
+
+  //----------------------------------------------------------------------
+  // Programmatic access to scrollbar functionality
+  // (Causes change events to be sent)
+
+  public void scrollUpOrLeft() {
+    if (updating) return;
+    beginUpdate();
+    setValueHP(getValueHP().subtract(getUnitIncrementHP()));
+    endUpdate();
+  }
+
+  public void scrollDownOrRight() {
+    if (updating) return;
+    beginUpdate();
+    setValueHP(getValueHP().add(getUnitIncrementHP()));
+    endUpdate();
+  }
+
+  public void pageUpOrLeft() {
+    if (updating) return;
+    beginUpdate();
+    setValueHP(getValueHP().subtract(getBlockIncrementHP()));
+    endUpdate();
+  }
+
+  public void pageDownOrRight() {
+    if (updating) return;
+    beginUpdate();
+    setValueHP(getValueHP().add(getBlockIncrementHP()));
+    endUpdate();
+  }
+
+  //----------------------------------------------------------------------
+  // Internals only below this point
+  //
+
+  private void beginUpdate() {
+    updating = true;
+  }
+
+  private void endUpdate() {
+    updating = false;
+  }
+
+  private void initialize(BigInteger value, BigInteger minimum, BigInteger maximum) {
+    // Initialize the underlying scrollbar to the standard range values
+    // The increments are important and are how we differentiate arrow from track events
+    setMinimum(0);
+    setMaximum(BIG_RANGE - 1);
+    setValue(0);
+    setVisibleAmount(1);
+    setUnitIncrement(UNIT_INCREMENT);
+    setBlockIncrement(BLOCK_INCREMENT);
+
+    setUnitIncrementHP(new BigInteger(Integer.toString(getUnitIncrement())));
+    setBlockIncrementHP(new BigInteger(Integer.toString(getBlockIncrement())));
+
+    // Must set range and value first (it sets min/max)
+    setRange(minimum, maximum);
+
+    setVisibleAmountHP(new BigInteger(Integer.toString(getVisibleAmount())));
+    setValueHP(value);
+  }
+
+  private void initialize() {
+    BigInteger min = new BigInteger(Integer.toString(getMinimum()));
+    BigInteger max = new BigInteger(Integer.toString(getMaximum()));
+    initialize(min, min, max);
+  }
+
+  private void setRange(BigInteger minimum, BigInteger maximum) {
+    if (minimum.compareTo(maximum) > 0 ) {
+      throw new RuntimeException("Bad scrollbar range " + minimum + " > " + maximum);
+    }
+    minimumHP = minimum;
+    maximumHP = maximum;
+    rangeHP = maximum.subtract(minimum).add(BigInteger.ONE);
+    BigInteger range2 = new BigInteger(Integer.toString(BIG_RANGE));
+    if (rangeHP.compareTo(range2) >= 0 ) {
+      down = true;
+      scaleFactor = new BigDecimal(rangeHP, SCALE).divide(new BigDecimal(range2, SCALE), BigDecimal.ROUND_DOWN).max(new BigDecimal(BigInteger.ONE));
+    } else {
+      down = false;
+      scaleFactor = new BigDecimal(range2, SCALE).divide(new BigDecimal(rangeHP, SCALE), BigDecimal.ROUND_DOWN).max(new BigDecimal(BigInteger.ONE));
+    }
+    // FIXME: should put in original scaling algorithm (shifting by
+    // number of bits) as alternative when scale between low and high
+    // precision is very large
+  }
+
+  // A range update is complete. Rescale our computed values and
+  // inform the underlying scrollBar as needed.
+  private void updateScrollBarValues() {
+    setValueHP(getValueHP());
+    setVisibleAmountHP(getVisibleAmountHP());
+    setBlockIncrementHP(getBlockIncrementHP());
+    setUnitIncrementHP(getUnitIncrementHP());
+  }
+
+  private BigDecimal getScaleFactor() {
+    return scaleFactor;
+  }
+
+
+  // Value scaling routines
+  private BigInteger scaleToHP(int i) {
+    BigDecimal ib = new BigDecimal(Integer.toString(i));
+    if (down) return ib.multiply(getScaleFactor()).toBigInteger();
+    else return ib.divide(getScaleFactor(), BigDecimal.ROUND_DOWN).toBigInteger();
+  }
+
+  private int scaleToUnderlying(BigInteger i) {
+    BigDecimal d = new BigDecimal(i);
+    if (down) return d.divide(getScaleFactor(), BigDecimal.ROUND_DOWN).intValue();
+    else return d.multiply(getScaleFactor()).intValue();
+  }
+
+  // Range scaling routines
+  private BigInteger toHPRange(int i) {
+    return scaleToHP(i).add(minimumHP);
+    // return ib.shiftLeft(Math.max(2, maximumHP.bitLength() - 33));
+  }
+
+  private int toUnderlyingRange(BigInteger i) {
+    return scaleToUnderlying(i.subtract(minimumHP));
+    // return i.shiftRight(Math.max(2, maximumHP.bitLength() - 33)).intValue();
+  }
+
+  private void installListener() {
+    super.addAdjustmentListener(new AdjustmentListener() {
+        public void adjustmentValueChanged(AdjustmentEvent e) {
+          if (updating) {
+            return;
+          }
+          beginUpdate();
+          switch (e.getAdjustmentType()) {
+          case AdjustmentEvent.TRACK:
+            int val = e.getValue();
+            int diff = val - lastValueSeen;
+            int absDiff = Math.abs(diff);
+            //            System.err.println("diff: " + diff + " absDiff: " + absDiff);
+            if (absDiff == UNIT_INCREMENT) {
+              if (diff > 0) {
+                //                System.err.println("case 1");
+                setValueHP(getValueHP().add(getUnitIncrementHP()));
+              } else {
+                //                System.err.println("case 2");
+                setValueHP(getValueHP().subtract(getUnitIncrementHP()));
+              }
+            } else if (absDiff == BLOCK_INCREMENT) {
+              if (diff > 0) {
+                //                System.err.println("case 3");
+                setValueHP(getValueHP().add(getBlockIncrementHP()));
+              } else {
+                //                System.err.println("case 4");
+                setValueHP(getValueHP().subtract(getBlockIncrementHP()));
+              }
+            } else {
+              //              System.err.println("case 5");
+              // FIXME: seem to be getting spurious update events,
+              // with diff = 0, upon mouse down/up on the track
+              if (absDiff != 0) {
+                // Convert low-precision value to high precision
+                // (note we lose the low bits)
+                BigInteger i = null;
+                if (e.getValue() == getMinimum()) {
+                  i = getMinimumHP();
+                } else if (e.getValue() >= getMaximum() - 1) {
+                  i = getMaximumHP();
+                } else {
+                  i = toHPRange(e.getValue());
+                }
+                setValueHP(i);
+              }
+            }
+            break;
+          default:
+            // Should not reach here, but leaving it a no-op in case
+            // we later get the other events (should revisit code in
+            // that case)
+            break;
+          }
+          endUpdate();
+        }
+      });
+  }
+
+  private void fireStateChanged() {
+    ChangeEvent e = null;
+    for (Iterator iter = changeListeners.iterator(); iter.hasNext(); ) {
+      ChangeListener l = (ChangeListener) iter.next();
+      if (e == null) {
+        e = new ChangeEvent(this);
+      }
+      l.stateChanged(e);
+    }
+  }
+
+  public static void main(String[] args) {
+    JFrame frame = new JFrame();
+    frame.setSize(300, 300);
+    // 32-bit version
+    /*
+    HighPrecisionJScrollBar hpsb =
+      new HighPrecisionJScrollBar(
+        JScrollBar.VERTICAL,
+        new BigInteger(1, new byte[] {
+          (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
+        new BigInteger(1, new byte[] {
+          (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
+        new BigInteger(1, new byte[] {
+          (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}));
+    hpsb.setUnitIncrementHP(new BigInteger(1, new byte[] {
+      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01}));
+    hpsb.setBlockIncrementHP(new BigInteger(1, new byte[] {
+      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10}));
+    */
+
+    // 64-bit version
+    HighPrecisionJScrollBar hpsb =
+      new HighPrecisionJScrollBar(
+        JScrollBar.VERTICAL,
+        new BigInteger(1, new byte[] {
+          (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+          (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
+        new BigInteger(1, new byte[] {
+          (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+          (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
+        new BigInteger(1, new byte[] {
+          (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+          (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}));
+    hpsb.setUnitIncrementHP(new BigInteger(1, new byte[] {
+      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01}));
+    hpsb.setBlockIncrementHP(new BigInteger(1, new byte[] {
+      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10}));
+    hpsb.addChangeListener(new ChangeListener() {
+        public void stateChanged(ChangeEvent e) {
+          HighPrecisionJScrollBar h = (HighPrecisionJScrollBar) e.getSource();
+          System.out.println("New value = 0x" + h.getValueHP().toString(16));
+        }
+      });
+    frame.getContentPane().add(hpsb);
+    frame.show();
+  }
+
+}