/* * Copyright (c) 2007, 2011, 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.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import javax.swing.*; import com.sun.max.ins.*; import com.sun.max.ins.view.*; import com.sun.max.program.*; import com.sun.max.tele.*; import com.sun.max.vm.value.*; /** * A label specialized for use in the {@link AbstractView}. * <br> * Labels can act as a source for drag and drop operations. */ public abstract class InspectorLabel extends JLabel implements InspectionHolder, TextSearchable, Prober { private static final int TRACE_VALUE = 2; /** * Support for labels that can act as a source for a drag and drop gesture. * */ private class InspectorLabelDragSource implements DragGestureListener, DragSourceListener { /** * The cursor set for the current drag action. */ private Cursor dragCursor = null; public InspectorLabelDragSource() { } public void dragGestureRecognized(DragGestureEvent dge) { Trace.line(TRACE_VALUE, InspectorLabel.this.tracePrefix() + "initiating drag=" + dge.getTriggerEvent()); Transferable transferable = getTransferable(); if (transferable != null) { if (transferable instanceof InspectorTransferable) { final InspectorTransferable inspectorTransferable = (InspectorTransferable) transferable; dragCursor = inspectorTransferable.getDragCursor(); } else { dragCursor = null; } Trace.line(TRACE_VALUE, tracePrefix() + "dragging=" + transferable); dge.startDrag(null, transferable, this); } } public void dragEnter(DragSourceDragEvent dsde) { Trace.line(TRACE_VALUE, tracePrefix() + "Drag Source: dragEnter "); dsde.getDragSourceContext().setCursor(dragCursor); } public void dragExit(DragSourceEvent dsde) { Trace.line(TRACE_VALUE, tracePrefix() + "Drag Source: dragExit"); dsde.getDragSourceContext().setCursor(null); } public void dragOver(DragSourceDragEvent dsde) { Trace.line(TRACE_VALUE, tracePrefix() + "Drag Source: dragOver"); } public void dropActionChanged(DragSourceDragEvent dsde) { Trace.line(TRACE_VALUE, tracePrefix() + "Drag Source: dropActionChanged"); } public void dragDropEnd(DragSourceDropEvent dsde) { Trace.line(TRACE_VALUE, tracePrefix() + "Drag Source: drop completed, success: " + dsde.getDropSuccess()); } } private final Inspection inspection; private boolean dragSourceEnabled = false; private final String tracePrefix; /** * An optional string that can be prepended to every label's text. */ private String textPrefix = ""; /** * An optional string that can be appended to every label's text. */ private String textSuffix = ""; /** * An optional string that can be prepended to every label tooltip text. */ private String toolTipPrefix = ""; /** * An optional string that can be appended to every label tooltip text. */ private String toolTipSuffix = ""; /** * Translates an int into hex text prefixed with "0x, e.g. "0x4ef". * * @param intValue an int * @return string describing the int as hex with "0x" prefix */ public static final String intTo0xHex(int intValue) { return "0x" + Integer.toHexString(intValue); } /** * Translates an integer into decimal text with plus/minus, e.g. "-2", "0", or "+3" * * @return integer as a decimal text string with a plus/minus prefix if not zero. */ public static final String intToPlusMinusDecimal(int intValue) { return (intValue >= 0 ? "+" : "") + Integer.toString(intValue); } /** * Translates an integer into decimal text, followed by prefixed hex equivalent, e.g. "22(0x16)" * * @return string describing the integer in both decimal and hex, with no "+" prefix. */ public static final String intToDecimalAndHex(int intValue) { return Integer.toString(intValue) + "(" + intTo0xHex(intValue) + ")"; } /** * Translates an integer into decimal text with plus/minus, followed by prefixed, unpadded * hex equivalent, e.g. "+22(0x16)" * * @return string describing the relative location in both decimal and hex, with a "+" prefix when non-negative */ public static final String intToPlusMinusDecimalAndHex(int intValue) { return intToPlusMinusDecimal(intValue) + "(" + intTo0xHex(intValue) + ")"; } /** * Translates a long into decimal text with plus/minus, e.g. "-2", "0", or "+3" * * @return long as a decimal text string with a plus/minus prefix if not zero. */ public static final String longToPlusMinusDecimal(long longValue) { return (longValue >= 0 ? "+" : "") + Long.toString(longValue); } /** * Translates a long into hex text prefixed with "0x, e.g. "0x4ef". * * @param longValue a long * @return string describing the long as hex with "0x" prefix */ public static final String longTo0xHex(long longValue) { return "0x" + Long.toHexString(longValue); } /** * Translates a long into decimal text, followed by prefixed hex equivalent, e.g. "22(0x16)" * * @return string describing the long in both decimal and hex, with no "+" prefix. */ public static final String longToDecimalAndHex(long longValue) { return Long.toString(longValue) + "(" + longTo0xHex(longValue) + ")"; } /** * Translates a sequence of bytes into space-separated text surrounded by brackets, e.g. "[0F FF A0]" */ public static final String bytesToByteString(byte[] bytes) { if (bytes == null) { return ""; } final StringBuilder result = new StringBuilder(100); String prefix = "["; for (byte b : bytes) { result.append(prefix); result.append(String.format("%02X", b)); prefix = " "; } result.append("]"); return result.toString(); } /** * Translates a VM {@code Value} into decimal text, followed by prefixed * hex equivalent, e.g. "+22(0x16)" * * @param value * @return string describing the value in both decimal and hex */ public static final String valueToDecimalAndHex(Value value) { return Long.toString(value.toLong()) + "(" + value.toWord().to0xHexString() + ")"; } public static final String valueToFloatText(Value value) { return Float.toString(Float.intBitsToFloat((int) (value.toLong() & 0xffffffffL))) + "f"; } public static final String valueToDoubleText(Value value) { return Double.toString(Double.longBitsToDouble(value.toLong())) + "d"; } /** * Translates a string that may legitimately contain the characters '<' and '>', * replacing every instance characters with HTML special character codes so that they * will be displayed correctly. Should not be used on any string that already contains * HTML tags, because the method does not discriminate. * * @param text a text string * @return a text string with all occurrences of '<' and '>' by HTML special character codes. */ public static final String htmlify(String text) { return text == null ? null : text.replaceAll("<", "<").replaceAll(">", ">"); } /** * A label for use in the Inspector, by default not opaque. * * @param text label text * @param toolTipText text for ToolTips */ public InspectorLabel(Inspection inspection, String text, String toolTipText) { super(text); this.inspection = inspection; String simpleName = getClass().getSimpleName(); if (simpleName.equals("")) { simpleName = "anonymous InspectorLabel"; } this.tracePrefix = "[" + simpleName + "] "; setToolTipText(toolTipText); setOpaque(false); } /** * A label for use in the Inspector. * @param text label text */ public InspectorLabel(Inspection inspection, String text) { this(inspection, text, null); } /** * A label for use in the Inspector. */ public InspectorLabel(Inspection inspection) { this(inspection, null, null); } public final Inspection inspection() { return inspection; } public final MaxVM vm() { return inspection.vm(); } public InspectorGUI gui() { return inspection.gui(); } public final InspectionFocus focus() { return inspection.focus(); } public final InspectionViews views() { return inspection.views(); } public final InspectionActions actions() { return inspection.actions(); } public final InspectionPreferences preference() { return inspection.preference(); } public String getSearchableText() { return getText(); } /** * Sets text to be prepended to every subsequently "wrapped" label text *. * @param textPrefix prefix for every text display. * @see #setWrappedText(String) */ public final void setTextPrefix(String textPrefix) { this.textPrefix = textPrefix == null ? "" : textPrefix; //redisplay(); } /** * Sets text to be appended to every subsequently "wrapped" label text, with an additional * space inserted between. * * @param textSuffix suffix for every text display. * @see #setWrappedText(String) */ public final void setTextSuffix(String textSuffix) { if (textSuffix != null && !textSuffix.equals("")) { this.textSuffix = " " + textSuffix; } else { this.textSuffix = ""; } //redisplay(); } /** * Sets the label's text to the specified string, wrapped * by an optional prefix and an optional suffix. * * @param text the text to be wrapped and set as the label's text. * @see #setTextPrefix(String) * @see #setTextSuffix(String) * @see #setText(String) */ public void setWrappedText(String text) { //System.out.println(" pre=" + textPrefix + " txt=" + text + " suf=" + textSuffix); super.setText(textPrefix + text + textSuffix); } /** * Sets the label's text to the specified string, but starting * with an {@code <html>} tag, and wrapped * by an optional prefix and an optional suffix. * Note that any text appearing in this context should be * filtered by {@link #htmlify(String)} so that angle bracket * characters will be rendered correctly. * * @param text the text to be wrapped and set as the label's text. * @see #setTextPrefix(String) * @see #setTextSuffix(String) * @see #setText(String) */ public void setWrappedHtmlText(String text) { //System.out.println("<html>" + " pre=" + textPrefix + " txt=" + text + " suf=" + textSuffix); super.setText("<html>" + textPrefix + text + textSuffix); //super.setText(textPrefix + text + textSuffix); } /** * Sets text to be prepended to every subsequently "wrapped" tooltip, with an additional * space inserted between. Be sure to set the prefix <i>before</i> an event (such as a * value change) that causes the tool tip text to be regenerated. * * @param toolTipPrefix prefix for every tooltip display. * @see #setWrappedToolTipHtmlText(String) */ public final void setToolTipPrefix(String toolTipPrefix) { if (toolTipPrefix != null && !toolTipPrefix.equals("")) { this.toolTipPrefix = toolTipPrefix + " "; } else { this.toolTipPrefix = ""; } //redisplay(); } /** * Sets text to be appended to every subsequently "wrapped" tooltip, with an additional * space inserted between. * * @param toolTipSuffix suffix for every tooltip display. * @see #setWrappedToolTipHtmlText(String) */ public final void setToolTipSuffix(String toolTipSuffix) { if (toolTipSuffix != null && !toolTipSuffix.equals("")) { this.toolTipSuffix = " " + toolTipSuffix; } else { this.toolTipSuffix = ""; } //redisplay(); } /** * Sets the label's tool tip text to the specified string, but starting * with an {@code <html>} tag, and wrapped * by an optional prefix and an optional suffix. * * @param toolTipText the text to be wrapped and set as the label's tool tip text. * @see #setToolTipPrefix(String) * @see #setToolTipSuffix(String) * @see #setToolTipText(String) */ public final void setWrappedToolTipHtmlText(String toolTipText) { //System.out.println("<html>" + toolTipPrefix + toolTipText + toolTipSuffix); super.setToolTipText("<html>" + toolTipPrefix + toolTipText + toolTipSuffix); } /** * @return the text string assigned to the label with all HTML tags removed. */ public final String getTextDeHtmlify() { return getText().replaceAll("\\<.*?\\>", ""); } /** * Enables support for this label to act as a <strong>source</strong> for drag * and drop operations (copy only, not move). * <br> * Once this has been called, attempts to drag from the label will cause the * method {@link #getTransferable()} to be called. * * @see #getTransferable() */ protected void enableDragSource() { Trace.line(TRACE_VALUE, tracePrefix() + "enable drag source"); if (!dragSourceEnabled) { DragSource dragSource = DragSource.getDefaultDragSource(); dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, new InspectorLabelDragSource()); dragSourceEnabled = true; } } /** * @return the dragSourceEnabled */ protected boolean isDragSourceEnabled() { return dragSourceEnabled; } /** * Creates something that can be copied, as the source of a drag and drop operation. * <br> * Will not be called by a drag gesture starting in the label * unless {@link #enableDragSource()} has been previously called. * <br> * An exception to the above occurs when the label is used as a cell renderer for an * {@link InspectorTable}. In that situation, the table's drag and drop mechanism may * call this method, whether or not {@link #enableDragSource()} has been called. * * @return something that can be dragged from this label; null if nothing can be dragged. * @see #enableDragSource() * @see InspectorTable */ public Transferable getTransferable() { return null; } /** * @return default prefix text for trace messages; identifies the class being traced. */ protected String tracePrefix() { return tracePrefix; } }