/* * Copyright (c) 2007, 2012, 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. * * 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 com.sun.max.ins.gui; import java.awt.datatransfer.*; import java.awt.event.*; import com.sun.max.ins.*; import com.sun.max.unsafe.*; import com.sun.max.vm.stack.*; /** * A selectable, lightweight, label for basic kinds of data * about which little is known. */ public abstract class DataLabel extends InspectorLabel { protected DataLabel(Inspection inspection, String text) { super(inspection, text); } protected DataLabel(Inspection inspection, String text, String toolTipText) { this(inspection, text); setToolTipText(toolTipText); } public void refresh(boolean force) { // Values don't change unless explicitly set } public void redisplay() { // Default styles setFont(preference().style().primitiveDataFont()); } /** * A label that displays an unchanging boolean value as "true" or "false". */ public static final class BooleanAsText extends DataLabel { public BooleanAsText(Inspection inspection, boolean b) { super(inspection, b ? "true" : "false"); redisplay(); } } /** * A label that displays an unchanging byte value in decimal; a ToolTip shows the value in hex. */ public static final class ByteAsDecimal extends DataLabel { public ByteAsDecimal(Inspection inspection, byte b) { super(inspection, Byte.toString(b), "byte: " + intTo0xHex(Byte.valueOf(b).intValue())); redisplay(); } @Override public void redisplay() { setFont(preference().style().decimalDataFont()); } } /** * A label that displays an unchanging byte value in hex; a ToolTip shows the value in decimal. */ public static final class ByteAsHex extends DataLabel { public ByteAsHex(Inspection inspection, byte b) { super(inspection, intTo0xHex(Byte.valueOf(b).intValue()), "byte: " + Byte.toString(b)); redisplay(); } @Override public void redisplay() { setFont(preference().style().hexDataFont()); } } /** * A label that displays a changeable array of bytes in a bracketed string of hex pairs. */ public static class ByteArrayAsHex extends DataLabel { private byte[] bytes; public ByteArrayAsHex(Inspection inspection, byte[] bytes) { super(inspection, ""); this.bytes = bytes; redisplay(); } @Override public void redisplay() { setFont(preference().style().hexDataFont()); updateText(); } public void setValue(byte[] bytes) { this.bytes = bytes; updateText(); } private void updateText() { final String byteString = bytesToByteString(bytes); setText(byteString); setWrappedToolTipHtmlText(byteString); } } /** * A label that displays a changeable array of bytes as 8 bit characters. */ public static class ByteArrayAsUnicode extends DataLabel { private byte[] bytes; public ByteArrayAsUnicode(Inspection inspection, byte[] bytes) { super(inspection, ""); this.bytes = bytes; redisplay(); } @Override public void redisplay() { setFont(preference().style().hexDataFont()); updateText(); } protected void setValue(byte[] bytes) { this.bytes = bytes; updateText(); } private void updateText() { if (bytes != null && bytes.length > 0) { final StringBuilder result = new StringBuilder(100); String prefix = "["; for (int i = 0; i < bytes.length / 2; i++) { result.append(prefix); final int index = 2 * i; final char ch = (char) ((bytes[index + 1] * 256) + bytes[index]); result.append(Character.toString(ch)); prefix = " "; } result.append("]"); final String labelText = result.toString(); setText(labelText); setWrappedToolTipHtmlText(labelText); } } } /** * A label that displays a changeable array of bytes as 8 bit characters. */ public static class ByteArrayAsChar extends DataLabel { private byte[] bytes; public ByteArrayAsChar(Inspection inspection, byte[] bytes) { super(inspection, ""); this.bytes = bytes; redisplay(); } @Override public void redisplay() { setFont(preference().style().hexDataFont()); updateText(); } protected void setValue(byte[] bytes) { this.bytes = bytes; updateText(); } private void updateText() { if (bytes != null && bytes.length > 0) { final StringBuilder result = new StringBuilder(100); String prefix = "["; for (byte b : bytes) { result.append(prefix); final char ch = (char) b; result.append(Character.toString(ch)); prefix = " "; } result.append("]"); final String labelText = result.toString(); setText(labelText); setWrappedToolTipHtmlText(labelText); } } } /** * A label that displays an unchanging short value in decimal; a ToolTip displays the value in hex. */ public static final class ShortAsDecimal extends DataLabel { ShortAsDecimal(Inspection inspection, short n) { super(inspection, Short.toString(n), "short: " + intTo0xHex(Short.valueOf(n).intValue())); redisplay(); } @Override public void redisplay() { setFont(preference().style().decimalDataFont()); } } /** * A label that displays an unchanging char value as a textual character; a ToolTip displays the value in decimal and hex. */ public static final class CharAsText extends DataLabel { CharAsText(Inspection inspection, char c) { super(inspection, "'" + c + "'"); final int n = Character.getNumericValue(c); setToolTipText("char: " + Integer.toString(n) + ", " + intTo0xHex(n)); redisplay(); } @Override public void redisplay() { setFont(preference().style().charDataFont()); } } /** * A label that displays the decimal value of an unchanging char; a ToolTip displays the character and hex value. */ public static final class CharAsDecimal extends DataLabel { public CharAsDecimal(Inspection inspection, char c) { super(inspection, Integer.toString(Character.getNumericValue(c))); setToolTipText("char: '" + c + "', " + intTo0xHex(Character.getNumericValue(c))); redisplay(); } @Override public void redisplay() { setFont(preference().style().decimalDataFont()); } } /** * A label that displays the decimal value of an integer; a ToolTip displays the value in hex. */ public static class IntAsDecimal extends DataLabel { private int n; public IntAsDecimal(Inspection inspection, int n) { super(inspection, ""); this.n = n; updateText(); redisplay(); } public IntAsDecimal(Inspection inspection) { this(inspection, 0); } @Override public void redisplay() { setFont(preference().style().decimalDataFont()); } public void setValue(int n) { this.n = n; updateText(); } private void updateText() { setText(Integer.toString(n)); setWrappedToolTipHtmlText("int: " + intTo0xHex(n)); } } /** * A label that displays the hex value of an int; a ToolTip displays the value in decimal. */ public static class IntAsHex extends DataLabel { private int n; public IntAsHex(Inspection inspection, int n) { super(inspection, ""); this.n = n; updateText(); redisplay(); } @Override public void redisplay() { setFont(preference().style().hexDataFont()); } protected void setValue(int n) { this.n = n; updateText(); } private void updateText() { setText(intTo0xHex(n)); setToolTipText("int: " + Integer.toString(n)); } } public static class FloatAsText extends DataLabel { private float f; public FloatAsText(Inspection inspection, float f) { super(inspection, Float.toString(f), intTo0xHex(Float.floatToIntBits(f))); this.f = f; updateText(); redisplay(); } @Override public void redisplay() { // TODO: define a font for floats setFont(preference().style().hexDataFont()); } protected void updateText() { final String labelText = Float.toString(f); setText(labelText); setWrappedToolTipHtmlText(labelText); } protected void setValue(float f) { this.f = f; updateText(); } } /** * A label that displays the decimal value of a long; a ToolTip displays the value in hex. */ public static class LongAsDecimal extends DataLabel { long n; public LongAsDecimal(Inspection inspection, long n) { super(inspection, ""); this.n = n; updateText(); redisplay(); } public LongAsDecimal(Inspection inspection) { this(inspection, 0); } @Override public void redisplay() { setFont(preference().style().decimalDataFont()); } public void setValue(long n) { this.n = n; updateText(); } private void updateText() { setText(Long.toString(n)); setWrappedToolTipHtmlText("long: " + longTo0xHex(n)); } } /** * A label that displays the hex value of an unchanging long; a ToolTip displays the value in decimal. */ public static final class LongAsHex extends DataLabel { public LongAsHex(Inspection inspection, long n) { super(inspection, longTo0xHex(n), "long: " + Long.toString(n)); redisplay(); } @Override public void redisplay() { setFont(preference().style().hexDataFont()); } } public static class DoubleAsText extends DataLabel { private double f; public DoubleAsText(Inspection inspection, double f) { super(inspection, "", ""); this.f = f; updateText(); redisplay(); } @Override public void redisplay() { // TODO: define a font for doubles setFont(preference().style().hexDataFont()); } private void updateText() { final String labelText = Double.toString(f); setText(labelText); setWrappedToolTipHtmlText(labelText); } protected void setValue(double f) { this.f = f; updateText(); } } /** * A label that displays a memory address in hex; if a base address * is specified, then a ToolTip displays the offset from the base. */ public static class AddressAsHex extends DataLabel { protected Address address; private final Address origin; public AddressAsHex(Inspection inspection, Address address) { this(inspection, address, null); } public AddressAsHex(Inspection inspection, Address addr, Address origin) { super(inspection, addr.toHexString()); this.address = addr; this.origin = origin; enableDragSource(); addMouseListener(new InspectorMouseClickAdapter(inspection()) { @Override public void procedure(final MouseEvent mouseEvent) { switch (inspection().gui().getButton(mouseEvent)) { case MouseEvent.BUTTON3: { final InspectorPopupMenu menu = new InspectorPopupMenu("Address"); menu.add(actions().copyWord(address, "Copy address to clipboard")); menu.add(views().memory().makeViewAction(address, null)); if (vm().watchpointManager() != null) { menu.add(actions().setWordWatchpoint(address, null)); } menu.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); break; } case MouseEvent.BUTTON2: { changeBiasState(); break; } } } }); redisplay(); } protected AddressAsHex(Inspection inspection, Address address, Address origin, InspectorMouseClickAdapter mouseListener) { super(inspection, address.toHexString()); this.address = address; this.origin = origin; enableDragSource(); addMouseListener(mouseListener); redisplay(); } @Override public Transferable getTransferable() { return new InspectorTransferable.AddressTransferable(inspection(), address); } @Override public void redisplay() { setFont(preference().style().hexDataFont()); updateText(); } public void setValue(Address address) { this.address = address; updateText(); } protected void changeBiasState() { } protected String toolTipText() { if (origin == null) { return null; } final long position = address.minus(origin).toLong(); return "AsPosition: " + position + ", " + longTo0xHex(position); } private void updateText() { setText(address.toPaddedHexString('0')); setToolTipText(toolTipText()); } } public static class BiasedStackAddressAsHex extends AddressAsHex { boolean biased; final StackBias bias; public BiasedStackAddressAsHex(Inspection inspection, Address address, StackBias bias) { super(inspection, address, null); this.bias = bias; biased = true; } public BiasedStackAddressAsHex(Inspection inspection, StackBias bias) { this(inspection, Address.zero(), bias); } private boolean useBias() { return bias != null && !bias.equals(StackBias.NONE); } @Override protected void changeBiasState() { if (!useBias()) { return; } if (biased) { biased = false; setValue(bias.unbias(address.asPointer())); } else { biased = true; setValue(bias.bias(address.asPointer())); } } @Override protected String toolTipText() { if (useBias()) { return biased ? "Biased" : "Unbiased"; } return null; } } /** * A label that displays the textual name of an Enum value; a ToolTip displays * both the class name and the ordinal of the value. */ public static final class EnumAsText extends DataLabel { public EnumAsText(Inspection inspection, Enum e) { super(inspection, e.getClass().getSimpleName() + "." + e.name(), "Enum: " + e.getClass().getName() + "." + e.name() + " ord=" + e.ordinal()); redisplay(); } } public static final class Percent extends DataLabel { private long numerator; private long denominator; public Percent(Inspection inspection, long numerator, long denominator) { super(inspection, null); assert denominator != 0; this.numerator = numerator; this.denominator = denominator; redisplay(); } @Override public void redisplay() { setFont(preference().style().decimalDataFont()); updateText(); } public void setValue(int numerator, int denominator) { this.numerator = numerator; this.denominator = denominator; updateText(); } private void updateText() { final long percent = 100 * numerator / denominator; setText(Long.toString(percent) + "%"); setToolTipText(Long.toString(numerator) + " / " + denominator); } } }