/*
* 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.method;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.sun.max.gui.*;
import com.sun.max.ins.*;
import com.sun.max.ins.gui.*;
import com.sun.max.unsafe.*;
/**
* Dialog for entering information about areas in VM memory that are generally
* unknown to the VM and Inspector: starting location, size in bytes (optional), and
* a description useful for debugging.
* <br>
* The dialog works in two modes: one that includes address, size in bytes, and description
* fields and one that includes just address and description.
*/
public abstract class NativeLocationInputDialog extends InspectorDialog {
private AddressInputField.Hex addressInputField;
private AddressInputField.Decimal sizeInputField;
private JTextField descriptionInputField;
// Most recently entered and validated value in the address field; null if current entry is not valid.
private Address address;
// Most recently entered and validated value in the size field; -1 if current entry is not valid.
private long nBytes;
// Should the dialog display a size field?
private final boolean getSizeInput;
// Most recently entered value in the description field.
private String description;
/**
* When the dialog was created with a size parameter, this method gets called with the
* results when the dialog is complete and if all field values are valid.
*
* @param address valid address entered
* @param nBytes valid size in bytes entered
* @param description description entered
*/
public void entered(Address address, long nBytes, String description) {
}
/**
* When the dialog was created without a size parameter, this method gets called with the
* results when the dialog is complete and if all field values are valid.
*
* @param address valid address entered
* @param description description entered
*/
public void entered(Address address, String description) {
}
/**
* Creates a dialog for entering information about a region of otherwise unknown memory in the VM.
* Calls {@link #entered(Address, long, String)} when completed with valid values.
* <br>
* Override {@link #isValidAddress(Address)} for additional validation on the address field.
* <br>
* Override {@link #isValidSize(long)} for additional validation on the size field.
* <br>
* @param inspection
* @param frameTitle optional title to appear in the window frame of the dialog
* @param address initial value for the address input field
* @param nBytes initial value for the size input field
* @param description initial value for the description input field
*/
public NativeLocationInputDialog(Inspection inspection, String frameTitle, Address address, long nBytes, String description) {
super(inspection, frameTitle == null ? "Native Location Description" : frameTitle, true);
this.address = address == null ? Address.zero() : address;
this.nBytes = nBytes;
this.getSizeInput = true;
this.description = description;
createDialog();
}
/**
* Creates a dialog for entering information about a region of otherwise unknown memory in the VM.
* Calls {@link #entered(Address, String)} when completed with valid values.
* <br>
* Override {@link #isValidAddress(Address)} for additional validation on the address field.
* <br>
* @param inspection
* @param frameTitle optional title to appear in the window frame of the dialog
* @param address initial value for the address input field
* @param description initial value for the description input field
*/
public NativeLocationInputDialog(Inspection inspection, String frameTitle, Address address, String description) {
super(inspection, frameTitle == null ? "Native Location Description" : frameTitle, true);
this.address = address == null ? Address.zero() : address;
this.nBytes = -1;
this.getSizeInput = false;
this.description = description;
createDialog();
}
private void createDialog() {
final JPanel dialogPanel = new InspectorPanel(inspection(), new BorderLayout());
final JPanel fieldsPanel = new InspectorPanel(inspection(), new SpringLayout());
final JLabel addressFieldLabel = new JLabel("Address:", JLabel.TRAILING);
fieldsPanel.add(addressFieldLabel);
addressInputField = new AddressInputField.Hex(inspection(), address) {
@Override
public void update(Address address) {
if (isValidAddress(address)) {
NativeLocationInputDialog.this.address = address;
} else {
NativeLocationInputDialog.this.address = null;
}
}
};
addressFieldLabel.setLabelFor(addressInputField);
fieldsPanel.add(addressInputField);
if (getSizeInput) {
final JLabel sizeFieldLabel = new JLabel("Size:", JLabel.TRAILING);
fieldsPanel.add(sizeFieldLabel);
// Using an address entry field here for historical reasons, even though something simpler would do.
final Address initialSize = nBytes == -1 ? Address.zero() : Address.fromLong(nBytes);
sizeInputField = new AddressInputField.Decimal(inspection(), initialSize) {
@Override
public void update(Address address) {
final long nBytes = address.toLong();
if (isValidSize(nBytes)) {
NativeLocationInputDialog.this.nBytes = nBytes;
} else {
NativeLocationInputDialog.this.nBytes = -1;
}
}
};
sizeInputField.setRange(1, Integer.MAX_VALUE);
sizeFieldLabel.setLabelFor(sizeInputField);
fieldsPanel.add(sizeInputField);
}
final JLabel descriptionFieldLabel = new JLabel("Description:", JLabel.TRAILING);
fieldsPanel.add(descriptionFieldLabel);
descriptionInputField = new JTextField(description);
descriptionFieldLabel.setLabelFor(descriptionInputField);
fieldsPanel.add(descriptionInputField);
final int rows = getSizeInput ? 3 : 2;
final int cols = 2;
SpringUtilities.makeCompactGrid(fieldsPanel, rows, cols, 6, 6, 6, 6);
dialogPanel.add(fieldsPanel, BorderLayout.NORTH);
final JPanel buttonPanel = new InspectorPanel(inspection());
buttonPanel.add(new JButton(new AbstractAction("Cancel") {
public void actionPerformed(ActionEvent event) {
dispose();
}
}));
buttonPanel.add(new JButton(new EnterAction()));
dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
setContentPane(dialogPanel);
pack();
inspection().gui().moveToMiddle(this);
setVisible(true);
}
private String defaultTitle(Address address) {
return "native " + address;
}
protected boolean isValidAddress(Address address) {
return true;
}
protected boolean isValidSize(long nBytes) {
return true;
}
private final class EnterAction extends InspectorAction {
private EnterAction() {
super(inspection(), "OK");
}
@Override
protected void procedure() {
addressInputField.attemptUpdate();
if (NativeLocationInputDialog.this.address == null) {
gui().errorMessage("Invalid address");
return;
}
if (getSizeInput) {
sizeInputField.attemptUpdate();
if (NativeLocationInputDialog.this.nBytes == -1) {
gui().errorMessage("Invalid size");
return;
}
}
description = descriptionInputField.getText();
dispose();
if (getSizeInput) {
entered(address, nBytes, description);
} else {
entered(address, description);
}
}
}
}