//
// SpreadSheet.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.ss;
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.rmi.*;
import java.rmi.registry.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import visad.*;
import visad.data.Form;
import visad.data.netcdf.Plain;
import visad.data.tiff.TiffForm;
import visad.data.visad.VisADForm;
import visad.formula.*;
import visad.util.*;
/**
* SpreadSheet is a user interface for VisAD that supports
* multiple 3-D displays (FancySSCells).
*/
public class SpreadSheet extends GUIFrame implements AdjustmentListener,
DisplayListener, KeyListener, ItemListener, MouseListener,
MouseMotionListener, SSCellListener
{
/**
* Starting width of the application, in percentage of screen size.
*/
protected static final int WIDTH_PERCENT = 60;
/**
* Starting width of the application, in percentage of screen size.
*/
protected static final int HEIGHT_PERCENT = 80;
/**
* Minimum VisAD display width, including display border.
*/
protected static final int MIN_VIS_WIDTH = 120;
/**
* Minimum VisAD display height, including display border.
*/
protected static final int MIN_VIS_HEIGHT = 120;
/**
* Default VisAD display width.
*/
protected static final int DEFAULT_VIS_WIDTH = 250;
/**
* Default VisAD display height.
*/
protected static final int DEFAULT_VIS_HEIGHT = 250;
/**
* Spreadsheet cell letter order.
*/
protected static final String Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* Vertical cell label's width.
*/
protected static final int LABEL_WIDTH = 30;
/**
* Horizontal cell label's height.
*/
protected static final int LABEL_HEIGHT = 20;
/**
* Whether connection status messages are printed about clones.
*/
protected static final boolean SHOW_CONNECT_MESSAGES = true;
/**
* Header for first line of spreadsheet files.
*/
protected static final String SSFileHeader =
"# VisAD Visualization SpreadSheet spreadsheet file";
/**
* Argument classes for constructing an SSCell.
*/
protected static final Class[] cellArgs = {
String.class, FormulaManager.class, RemoteServer.class,
boolean.class, String.class, Frame.class
};
/**
* Constructor used to create SSCells for SpreadSheets.
*/
protected static Constructor cellConstructor;
/**
* Whether Java3D is possible on this JVM.
*/
protected static boolean Possible3D;
/**
* Whether Java3D is enabled on this JVM.
*/
protected static boolean CanDo3D;
/**
* Whether the HDF-5 native library is present on this JVM.
*/
protected static boolean CanDoHDF5;
/**
* Whether this JVM supports saving JPEG images with JPEGImageEncoder.
*/
protected static boolean CanDoJPEG;
/**
* Whether this JVM supports JPython scripting.
*/
protected static boolean CanDoPython;
/**
* Whether spreadsheet should have toolbar buttons.
*/
protected static boolean BugFix;
/**
* File dialog.
*/
protected JFileChooser SSFileDialog;
/**
* Base title.
*/
protected String bTitle;
/**
* Number of display columns.
*/
protected int NumVisX;
/**
* Number of display rows.
*/
protected int NumVisY;
/**
* Formula manager.
*/
protected FormulaManager fm;
/**
* Server name, if any.
*/
protected String serverName;
/**
* Server address for a cloned sheet, if any.
*/
protected String cloneAddress;
/**
* Server for spreadsheet cells, if any.
*/
protected RemoteServerImpl rsi = null;
/**
* Whether spreadsheet is a clone of another spreadsheet.
*/
protected boolean IsRemote = false;
/**
* Whether spreadsheet is a slaved clone of another spreadsheet.
*/
protected boolean IsSlave = false;
/**
* ID number for this collaborative spreadsheet.
*/
protected double CollabID = 0;
/**
* Row and column information needed for spreadsheet cloning.
*/
protected RemoteDataReference RemoteColRow;
/**
* Remote clone's copy of CanDo3D.
*/
protected RemoteDataReference RemoteCanDo3D;
/**
* Flag marking whether spreadsheet's cells
* automatically switch dimensions when needed.
*/
protected boolean AutoSwitch = true;
/**
* Flag marking whether spreadsheet's cells
* automatically detect mappings.
*/
protected boolean AutoDetect = true;
/**
* Flag marking whether spreadsheet's cells
* automatically show controls.
*/
protected boolean AutoShowControls = true;
/**
* Panel that contains actual VisAD displays.
*/
protected Panel DisplayPanel;
/**
* Panel containing the scrolling pane.
*/
protected JPanel ScrollPanel;
/**
* Scrolling pane, in case sheet gets too small.
*/
protected ScrollPane SCPane;
/**
* View port for horizontal cell labels.
*/
protected JViewport HorizLabels;
/**
* View port for vertical cell labels.
*/
protected JViewport VertLabels;
/**
* Array of panels for horizontal labels.
*/
protected JPanel[] HorizLabel;
/**
* Array of panels for vertical labels.
*/
protected JPanel[] VertLabel;
/**
* Array of horizontal yellow sizing boxes.
*/
protected JComponent[] HorizDrag;
/**
* Array of vertical yellow sizing boxes.
*/
protected JComponent[] VertDrag;
/**
* Panel containing horizontal labels and sizing boxes.
*/
protected JPanel HorizPanel;
/**
* Panel containing vertical labels and sizing boxes.
*/
protected JPanel VertPanel;
/**
* Array of spreadsheet cells.
*/
protected FancySSCell[][] DisplayCells = null;
/**
* Formula bar.
*/
protected JComboBox FormulaBox;
/**
* Formula editor.
*/
protected ComboBoxEditor FormulaEditor;
/**
* Formula text field.
*/
protected JTextField FormulaText;
/**
* Formula action listener.
*/
protected ActionListener FormulaListener;
/**
* Tool bar.
*/
protected JToolBar Toolbar;
/**
* Submenus.
*/
protected JMenu FileExport;
/**
* Menu items.
*/
protected JMenuItem FileSave1, FileSave2, FileSave3, FileSave4, FileSave5,
FileSnap, EditPaste, EditClear, CellDel, CellPrint, CellEdit, CellReset,
CellShow, LayAddCol, LayDelCol, LayDelRow;
/**
* Checkbox menu items.
*/
protected JCheckBoxMenuItem CellDim3D3D, CellDim2D2D, CellDim2D3D,
AutoSwitchBox, AutoDetectBox, AutoShowBox;
/**
* Toolbar buttons.
*/
protected JButton ToolSave, ToolPaste, Tool3D, Tool2D, ToolJ2D, ToolMap,
ToolShow, ToolReset, FormulaAdd, FormulaDel;
/**
* Column of currently selected cell.
*/
protected int CurX = 0;
/**
* Row of currently selected cell.
*/
protected int CurY = 0;
/**
* Contents of clipboard.
*/
protected String Clipboard = null;
/**
* Current spreadsheet file.
*/
protected File CurrentFile = null;
/**
* Object for preventing simultaneous GUI manipulation.
*/
protected Object Lock = new Object();
/**
* Waits the specified number of milliseconds.
*/
public static void snooze(long ms) {
try {
Thread.sleep(ms);
}
catch (InterruptedException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
}
/**
* Gateway into VisAD Visualization SpreadSheet user interface.
*/
public static void main(String[] argv) {
String usage = "\n" +
"Usage: java [-mx###m] visad.ss.SpreadSheet [cols rows]\n" +
" [-file filename] [-gui] [-no3d] [-debug] [-bugfix]\n" +
" [-server name] [-client address] [-slave address]\n\n" +
"###\n" +
" Maximum megabytes of memory to use.\n" +
"cols\n" +
" Number of columns in this SpreadSheet.\n" +
"rows\n" +
" Number of rows in this SpreadSheet.\n" +
"-file filename\n" +
" Load the given filename at launch. If file is a\n" +
" spreadsheet file, the layout is configured accordingly.\n" +
" If file is data, it is loaded into cell A1.\n" +
"-gui\n" +
" Pop up an options window so that the user can\n" +
" select SpreadSheet settings graphically.\n" +
"-no3d\n" +
" Disable Java3D.\n" +
"-debug\n" +
" Print stack traces for all errors.\n" +
"-bugfix\n" +
" Disable toolbar. For some systems, will prevent\n" +
" lockups on spreadsheet start.\n" +
"-server name\n" +
" Initialize this SpreadSheet as an RMI server\n" +
" with the given name.\n" +
"-client address\n" +
" Initialize this SpreadSheet as a clone of\n" +
" the server at the given RMI address.\n" +
"-slave address\n" +
" Initialize this SpreadSheet as a slaved clone\n" +
" of the server at the given RMI address.";
int cols = 2;
int rows = 2;
String dfile = null;
String servname = null;
String clonename = null;
boolean guiOptions = false;
int len = argv.length;
if (len > 0) {
int ix = 0;
// parse command line flags
while (ix < len) {
if (argv[ix].charAt(0) == '-') {
if (argv[ix].equals("-file")) {
if (ix < len - 1) dfile = argv[++ix];
}
else if (argv[ix].equals("-server")) {
if (clonename != null) {
System.out.println("A spreadsheet cannot be both a server " +
"and a clone!");
System.out.println(usage);
System.exit(3);
}
else if (ix < len - 1) servname = argv[++ix];
else {
System.out.println("You must specify a server name after " +
"the '-server' flag!");
System.out.println(usage);
System.exit(4);
}
}
else if (argv[ix].equals("-client") || argv[ix].equals("-slave")) {
if (servname != null) {
System.out.println("A spreadsheet cannot be both a server " +
"and a clone!");
System.out.println(usage);
System.exit(3);
}
else if (ix < len - 1) {
clonename = argv[ix + 1];
if (argv[ix].equals("-slave")) clonename = "slave:" + clonename;
ix++;
}
else {
System.out.println("You must specify a server after " +
"the '" + argv[ix] + "' flag!");
System.out.println(usage);
System.exit(5);
}
}
else if (argv[ix].equals("-gui")) guiOptions = true;
else if (argv[ix].equals("-bugfix")) BugFix = true;
else if (argv[ix].equals("-no3d")) BasicSSCell.disable3D();
else if (argv[ix].equals("-debug")) {
BasicSSCell.DEBUG = true;
FormulaVar.DEBUG = true;
}
else {
// unknown flag
if (!argv[ix].equals("-help")) {
System.out.println("Unknown option: " + argv[ix]);
}
System.out.println(usage);
System.exit(1);
}
}
else {
// parse number of rows and columns
boolean success = true;
if (ix < len - 1) {
try {
cols = Integer.parseInt(argv[ix]);
rows = Integer.parseInt(argv[ix + 1]);
ix++;
if (rows < 1 || cols < 1 || cols > Letters.length()) {
success = false;
}
}
catch (NumberFormatException exc) {
success = false;
}
if (!success) {
System.out.println("Invalid number of columns and rows: " +
argv[ix] + " x " + argv[ix + 1]);
System.out.println(usage);
System.exit(2);
}
}
else {
System.out.println("Unknown option: " + argv[ix]);
System.out.println(usage);
System.exit(1);
}
}
ix++;
}
}
final SpreadSheet ss = new SpreadSheet(WIDTH_PERCENT, HEIGHT_PERCENT,
cols, rows, servname, clonename, "VisAD SpreadSheet", null, guiOptions);
if (dfile != null) {
File f = new File(dfile);
String line = null;
try {
BufferedReader fin = new BufferedReader(new FileReader(f));
line = fin.readLine();
fin.close();
}
catch (IOException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
System.out.println("Could not read file " + dfile);
}
if (line != null) {
final boolean ssfile = line.equals(SSFileHeader);
final String filename = dfile;
Util.invoke(false, BasicSSCell.DEBUG, new Runnable() {
public void run() {
try {
if (ssfile) {
// file is a spreadsheet file
ss.openFile(filename);
}
else {
// file is a data file
ss.DisplayCells[0][0].addDataSource(filename);
}
}
catch (Exception exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
System.out.println("Could not load file " + filename +
" into the SpreadSheet");
}
}
});
}
}
}
// --- CONSTRUCTORS ---
/**
* Constructor with option selection dialog at default values.
*/
public SpreadSheet() {
this(WIDTH_PERCENT, HEIGHT_PERCENT, 2, 2, null, null,
"VisAD SpreadSheet", null, true);
}
/**
* Constructor with default formula manager and no option selection dialog.
*/
public SpreadSheet(int sWidth, int sHeight, int cols, int rows,
String server, String clone, String sTitle)
{
this(sWidth, sHeight, cols, rows, server, clone, sTitle, null, false);
}
/**
* Constructor with no option selection dialog.
*/
public SpreadSheet(int sWidth, int sHeight, int cols, int rows,
String server, String clone, String sTitle, FormulaManager fm)
{
this(sWidth, sHeight, cols, rows, server, clone, sTitle, fm, false);
}
/**
* Main constructor.
*/
public SpreadSheet(int sWidth, int sHeight, int cols, int rows,
String server, String clone, String sTitle, FormulaManager fm,
boolean chooseOptions)
{
super(true);
bTitle = sTitle;
NumVisX = cols;
NumVisY = rows;
this.fm = fm;
Possible3D = BasicSSCell.possible3D();
CanDo3D = BasicSSCell.canDo3D();
MappingDialog.initDialog();
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
quitProgram();
}
});
setBackground(Color.white);
// parse clone address
boolean slave = clone != null && clone.startsWith("slave:");
if (slave) clone = clone.substring(6);
if (clone != null) {
int slash = clone.lastIndexOf("/");
if (slash < 0) slash = clone.lastIndexOf(":");
server = clone.substring(slash + 1);
clone = clone.substring(0, slash);
}
serverName = server;
cloneAddress = clone;
IsSlave = slave;
// test whether HDF-5 native library is present
CanDoHDF5 = Util.canDoHDF5();
if (!CanDoHDF5 && BasicSSCell.DEBUG) {
System.err.println("Warning: HDF-5 library not found");
}
// test whether JPEG codec is present
CanDoJPEG = Util.canDoJPEG();
if (!CanDoJPEG && BasicSSCell.DEBUG) {
System.err.println("Warning: JPEG codec not found");
}
// test whether JPython is present
CanDoPython = Util.canDoPython();
if (!CanDoPython && BasicSSCell.DEBUG) {
System.err.println("Warning: JPython not found");
}
// create file chooser dialog
SSFileDialog = new JFileChooser(System.getProperty("user.dir"));
SSFileDialog.addChoosableFileFilter(
new ExtensionFileFilter("ss", "SpreadSheet files"));
if (chooseOptions) {
// get settings from option selection dialog
getOptions(NumVisX, NumVisY, serverName, cloneAddress, IsSlave);
}
clone = cloneAddress == null ? null : cloneAddress + "/" + serverName;
server = cloneAddress == null ? serverName : null;
// determine information for spreadsheet cloning
RemoteServer rs = null;
String[][] cellNames = null;
if (clone != null) {
// CLIENT: initialize
// connect to server
boolean success = true;
if (SHOW_CONNECT_MESSAGES) {
System.out.print("Connecting to " + clone + " ");
}
// connection loop
while (cellNames == null && success) {
// wait a second before trying to connect
snooze(1000);
if (SHOW_CONNECT_MESSAGES) System.out.print(".");
try {
// look up server
rs = (RemoteServer) Naming.lookup("//" + clone);
// determine whether server supports Java3D
RemoteCanDo3D = rs.getDataReference("CanDo3D");
Real bit = (Real) RemoteCanDo3D.getData();
if (bit.getValue() == 0) {
CanDo3D = false;
BasicSSCell.disable3D();
}
// extract cell name information
RemoteColRow = rs.getDataReference("ColRow");
cellNames = getNewCellNames();
}
catch (UnmarshalException exc) {
// fatal RMI error, probably a version difference; display error box
if (BasicSSCell.DEBUG) exc.printStackTrace();
displayErrorMessage("Unable to clone the spreadsheet at " + clone +
". The server is using an incompatible version of Java", null,
"Failed to clone spreadsheet");
success = false;
}
catch (MalformedURLException exc) {
// server name is invalid; display error box
if (BasicSSCell.DEBUG) exc.printStackTrace();
displayErrorMessage("Unable to clone the spreadsheet at " + clone +
". The server name is not valid", null,
"Failed to clone spreadsheet");
success = false;
}
catch (VisADException exc) {
// fatal error of some other type; display error box
if (BasicSSCell.DEBUG) exc.printStackTrace();
displayErrorMessage("Unable to clone the spreadsheet at " + clone +
". An error occurred while downloading the necessary data", exc,
"Failed to clone spreadsheet");
success = false;
}
catch (NotBoundException exc) {
// server is not ready yet; try again
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
catch (NullPointerException exc) {
// server is not ready yet; try again
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
catch (RemoteException exc) {
// server is not ready yet; try again
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
}
if (success) {
if (SHOW_CONNECT_MESSAGES) System.out.println(" done");
bTitle = bTitle + " [" + (IsSlave ? "slaved" : "collaborative") +
" mode: " + clone + "]";
IsRemote = true;
}
else {
if (SHOW_CONNECT_MESSAGES) System.out.println(" failed");
IsSlave = false;
rs = null;
}
}
// set up the content pane
JPanel pane = new JPanel();
pane.setBackground(Color.white);
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
setContentPane(pane);
// set up file menu
addMenuItem("File", "Import data...", "loadDataSet", 'i');
FileExport = addSubMenu("File", "Export data", 'e', false);
FileSave1 = addMenuItem("Export data", "netCDF...",
"exportDataSetNetcdf", 'n', true);
FileSave3 = addMenuItem("Export data", "HDF-5...",
"exportDataSetHDF5", 'h', CanDoHDF5);
FileSave4 = addMenuItem("Export data", "TIFF...",
"exportDataSetTIFF", 't', true);
FileSave2 = addMenuItem("Export data", "Serialized...",
"exportDataSetSerial", 's', true);
FileSave5 = addMenuItem("Export data", "Binary...",
"exportDataSetBinary", 'b', true);
addMenuSeparator("File");
FileSnap = addMenuItem("File", "Take JPEG snapshot...",
"captureImageJPEG", 'j', false);
addMenuSeparator("File");
addMenuItem("File", "Exit", "quitProgram", 'x');
// set up edit menu
addMenuItem("Edit", "Cut", "cutCell", 't', !IsRemote);
addMenuItem("Edit", "Copy", "copyCell", 'c', !IsRemote);
EditPaste = addMenuItem("Edit", "Paste", "pasteCell", 'p', false);
EditClear = addMenuItem("Edit", "Clear", "clearCell", 'l', false);
// set up setup menu
addMenuItem("Setup", "New spreadsheet file", "newFile", 'n');
addMenuItem("Setup", "Open spreadsheet file...", "openFile", 'o',
!IsRemote);
addMenuItem("Setup", "Save spreadsheet file", "saveFile", 's', !IsRemote);
addMenuItem("Setup", "Save spreadsheet file as...", "saveAsFile", 'a',
!IsRemote);
// set up cell menu
CellDim3D3D = new JCheckBoxMenuItem("3-D (Java3D)", CanDo3D);
addMenuItem("Cell", CellDim3D3D, "setDim3D", '3', CanDo3D);
CellDim2D2D = new JCheckBoxMenuItem("2-D (Java2D)", !CanDo3D);
addMenuItem("Cell", CellDim2D2D, "setDimJ2D", 'j', true);
CellDim2D3D = new JCheckBoxMenuItem("2-D (Java3D)", false);
addMenuItem("Cell", CellDim2D3D, "setDim2D", '2', CanDo3D);
addMenuSeparator("Cell");
addMenuItem("Cell", "Add data object", "formulaAdd", 'a');
CellDel = addMenuItem("Cell", "Delete data object",
"formulaDel", 'd', false);
addMenuSeparator("Cell");
CellPrint = addMenuItem("Cell", "Print cell...",
"printCurrentCell", 'p', false);
addMenuSeparator("Cell");
CellEdit = addMenuItem("Cell", "Edit mappings...",
"createMappings", 'e', false);
CellReset = addMenuItem("Cell", "Reset orientation",
"resetOrientation", 'r', false);
CellShow = addMenuItem("Cell", "Show controls",
"showControls", 's', false);
// set up layout menu
LayAddCol = addMenuItem("Layout", "Add column", "addColumn", 'c');
addMenuItem("Layout", "Add row", "addRow", 'r');
LayDelCol = addMenuItem("Layout", "Delete column",
"deleteColumn", 'l', NumVisX > 1);
LayDelRow = addMenuItem("Layout", "Delete row",
"deleteRow", 'w', NumVisY > 1);
addMenuSeparator("Layout");
addMenuItem("Layout", "Tile cells", "tileCells", 't');
// set up options menu
if (!CanDo3D) AutoSwitch = false;
AutoSwitchBox = new JCheckBoxMenuItem("Auto-switch to 3-D",
AutoSwitch && !IsRemote);
addMenuItem("Options", AutoSwitchBox,
"optionsSwitch", '3', CanDo3D && !IsRemote);
AutoDetectBox = new JCheckBoxMenuItem("Auto-detect mappings",
AutoDetect && !IsRemote);
addMenuItem("Options", AutoDetectBox, "optionsDetect", 'm', !IsRemote);
AutoShowBox = new JCheckBoxMenuItem("Auto-display controls",
AutoShowControls && !IsSlave);
addMenuItem("Options", AutoShowBox, "optionsDisplay", 'c', !IsSlave);
// set up toolbar
if (!BugFix) {
Toolbar = new JToolBar();
Toolbar.setBackground(Color.lightGray);
Toolbar.setBorder(new EtchedBorder());
Toolbar.setFloatable(false);
pane.add(Toolbar);
// file menu toolbar icons
addToolbarButton("open", "Import data", "loadDataSet", true, Toolbar);
ToolSave = addToolbarButton("save", "Export data to netCDF",
"exportDataSetNetcdf", false, Toolbar);
Toolbar.addSeparator();
// edit menu toolbar icons
addToolbarButton("cut", "Cut", "cutCell", !IsRemote, Toolbar);
addToolbarButton("copy", "Copy", "copyCell", !IsRemote, Toolbar);
ToolPaste = addToolbarButton("paste", "Paste",
"pasteCell", false, Toolbar);
Toolbar.addSeparator();
// cell menu toolbar icons
Tool3D = addToolbarButton("3d", "3-D (Java3D)",
"setDim3D", false, Toolbar);
ToolJ2D = addToolbarButton("j2d", "2-D (Java2D)",
"setDimJ2D", CanDo3D, Toolbar);
Tool2D = addToolbarButton("2d", "2-D (Java3D)",
"setDim2D", CanDo3D, Toolbar);
Toolbar.addSeparator();
ToolMap = addToolbarButton("mappings", "Edit mappings",
"createMappings", false, Toolbar);
ToolReset = addToolbarButton("reset", "Reset orientation",
"resetOrientation", false, Toolbar);
ToolShow = addToolbarButton("show", "Show controls",
"showControls", false, Toolbar);
Toolbar.addSeparator();
// layout menu toolbar icon
addToolbarButton("tile", "Tile cells", "tileCells", true, Toolbar);
Toolbar.add(Box.createHorizontalGlue());
// HACK - limit toolbar height
Toolbar.setMaximumSize(new Dimension(Toolbar.getMaximumSize().width,
Toolbar.getPreferredSize().height));
}
// set up formula bar
JPanel formulaPanel = new JPanel();
formulaPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, 25));
formulaPanel.setBackground(Color.lightGray);
formulaPanel.setLayout(new BoxLayout(formulaPanel, BoxLayout.X_AXIS));
formulaPanel.setBorder(new EtchedBorder());
pane.add(formulaPanel);
pane.add(Box.createRigidArea(new Dimension(0, 6)));
if (!BugFix) {
FormulaAdd = addToolbarButton("add", "Add data",
"formulaAdd", true, formulaPanel);
FormulaDel = addToolbarButton("del", "Remove data",
"formulaDel", true, formulaPanel);
}
FormulaBox = new JComboBox();
formulaPanel.add(FormulaBox);
FormulaBox.setLightWeightPopupEnabled(false);
FormulaBox.setEditable(true);
FormulaEditor = FormulaBox.getEditor();
FormulaListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newItem = ((String) FormulaEditor.getItem()).trim();
try {
int id = 0;
int type = BasicSSCell.UNKNOWN_SOURCE;
boolean notify = true;
int index1 = newItem.indexOf("d", 2);
int index2 = newItem.indexOf(":");
if (index1 > 0 && index2 > 0 && index1 < index2) {
String cellName = newItem.substring(0, index1);
BasicSSCell ssCell = BasicSSCell.getSSCellByName(cellName);
int dataId = 0;
try {
dataId = Integer.parseInt(newItem.substring(index1 + 1, index2));
}
catch (NumberFormatException exc) {
if (BasicSSCell.DEBUG && BasicSSCell.DEBUG_LEVEL >= 3) {
exc.printStackTrace();
}
}
if (ssCell == DisplayCells[CurX][CurY] && dataId > 0) {
// user is 'editing' the data object
String varName = newItem.substring(0, index2);
String source = ssCell.getDataSource(varName);
if (source != null) {
ssCell.removeData(varName);
String oldItem = null;
for (int i=0; i 0) {
for (int j=0; j 0) {
for (int j=0; j= 0) {
String sX = line.substring(eq + 1, x).trim();
String sY = line.substring(x + 1).trim();
try {
sizeX = Integer.parseInt(sX);
sizeY = Integer.parseInt(sY);
}
catch (NumberFormatException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
}
}
// cell dimension
if (keyword.equalsIgnoreCase("dimension") ||
keyword.equalsIgnoreCase("dimensions") ||
keyword.equalsIgnoreCase("dim"))
{
int x = line.indexOf("x", eq);
if (x >= 0) {
String sX = line.substring(eq + 1, x).trim();
String sY = line.substring(x + 1).trim();
try {
dimX = Integer.parseInt(sX);
dimY = Integer.parseInt(sY);
}
catch (NumberFormatException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
}
}
// column widths
if (keyword.equalsIgnoreCase("columns") ||
keyword.equalsIgnoreCase("column") ||
keyword.equalsIgnoreCase("column widths") ||
keyword.equalsIgnoreCase("column_widths") ||
keyword.equalsIgnoreCase("columnwidths") ||
keyword.equalsIgnoreCase("column width") ||
keyword.equalsIgnoreCase("column_width") ||
keyword.equalsIgnoreCase("columnwidth"))
{
StringTokenizer ln = new StringTokenizer(line.substring(eq + 1));
int nt = ln.countTokens();
for (int z=0; z= MIN_VIS_WIDTH) colWidths.add(new Integer(cw));
}
}
// rows heights
if (keyword.equalsIgnoreCase("rows") ||
keyword.equalsIgnoreCase("row") ||
keyword.equalsIgnoreCase("row heights") ||
keyword.equalsIgnoreCase("row_heights") ||
keyword.equalsIgnoreCase("rowheights") ||
keyword.equalsIgnoreCase("row height") ||
keyword.equalsIgnoreCase("row_height") ||
keyword.equalsIgnoreCase("rowheight"))
{
StringTokenizer ln = new StringTokenizer(line.substring(eq + 1));
int nt = ln.countTokens();
for (int z=0; z= MIN_VIS_WIDTH) rowHeights.add(new Integer(rh));
}
}
// auto switch
if (keyword.equalsIgnoreCase("auto switch") ||
keyword.equalsIgnoreCase("auto_switch") ||
keyword.equalsIgnoreCase("auto-switch") ||
keyword.equalsIgnoreCase("autoswitch"))
{
String val = line.substring(eq + 1).trim();
if (val.equalsIgnoreCase("false") ||
val.equalsIgnoreCase("F"))
{
autoSwitch = false;
}
}
// auto detect
if (keyword.equalsIgnoreCase("auto detect") ||
keyword.equalsIgnoreCase("auto_detect") ||
keyword.equalsIgnoreCase("auto-detect") ||
keyword.equalsIgnoreCase("autodetect"))
{
String val = line.substring(eq + 1).trim();
if (val.equalsIgnoreCase("false") ||
val.equalsIgnoreCase("F"))
{
autoDetect = false;
}
}
// auto show
if (keyword.equalsIgnoreCase("auto show") ||
keyword.equalsIgnoreCase("auto_show") ||
keyword.equalsIgnoreCase("auto-show") ||
keyword.equalsIgnoreCase("autoshow"))
{
String val = line.substring(eq + 1).trim();
if (val.equalsIgnoreCase("false") ||
val.equalsIgnoreCase("F"))
{
autoShow = false;
}
}
}
gotGlobal = true;
}
}
// make sure cell dimensions are valid
if (dimX < 1 || dimY < 1) {
displayErrorMessage("The file " + file + " has an invalid " +
"global dimension entry", null, "VisAD SpreadSheet error");
// reset auto-switch, auto-detect and auto-show
setAutoSwitch(origSwitch);
setAutoDetect(origDetect);
setAutoShowControls(origShow);
return;
}
// create label width and height arrays
len = colWidths.size();
int[] cw = new int[dimX];
for (int i=0; i 0 && sizeY > 0) setSize(sizeX, sizeY);
// reconstruct spreadsheet cells and labels
NumVisX = dimX;
NumVisY = dimY;
reconstructSpreadsheet(cellNames, cw, rh, null);
synchColRow();
// set each cell's string
for (int j=0; j 0) {
// re-layout horizontal spreadsheet labels
JPanel[] newLabels = new JPanel[NumVisX + 1];
for (int i=0; i NumVisX - 1) selectCell(NumVisX - 1, CurY);
reconstructHoriz(newLabels, newDrag, fcells);
if (letter == last) LayAddCol.setEnabled(true);
if (NumVisX == 1) LayDelCol.setEnabled(false);
}
return true;
}
/**
* Deletes a row from the spreadsheet.
*/
public synchronized boolean deleteRow() {
// make sure at least one row will be left
if (NumVisY == 1) {
displayErrorMessage("This is the last row", null, "Cannot delete row");
return false;
}
// make sure no cells are dependent on rows about to be deleted
for (int i=0; i NumVisY - 1) selectCell(CurX, NumVisY - 1);
reconstructVert(newLabels, newDrag, fcells);
if (NumVisY == 1) LayDelRow.setEnabled(false);
}
return true;
}
/**
* Resizes all cells to exactly fill the entire pane, if possible.
*/
public void tileCells() {
Dimension paneSize = SCPane.getSize();
int w = paneSize.width - SCPane.getVScrollbarWidth() - 5 * NumVisX;
int h = paneSize.height - SCPane.getHScrollbarHeight() - 5 * NumVisY;
int wx = w / NumVisX;
int hy = h / NumVisY;
if (wx < MIN_VIS_WIDTH) wx = MIN_VIS_WIDTH;
if (hy < MIN_VIS_HEIGHT) hy = MIN_VIS_HEIGHT;
Dimension hSize = new Dimension(wx, LABEL_HEIGHT);
Dimension vSize = new Dimension(LABEL_WIDTH, hy);
for (int i=0; i 0) FormulaBox.removeAllItems();
String[] varNames = DisplayCells[CurX][CurY].getVariableNames();
int len = varNames.length;
for (int i=0; i 0;
CellDel.setEnabled(b);
if (!BugFix) FormulaDel.setEnabled(b);
}
});
}
/**
* Updates dimension checkbox menu items and toolbar buttons.
*/
protected void refreshDisplayMenuItems() {
Util.invoke(false, BasicSSCell.DEBUG, new Runnable() {
public void run() {
// update dimension check marks
int dim = DisplayCells[CurX][CurY].getDimension();
boolean j3d3d = (dim == BasicSSCell.JAVA3D_3D);
boolean j2d2d = (dim == BasicSSCell.JAVA2D_2D);
boolean j3d2d = (dim == BasicSSCell.JAVA3D_2D);
CellDim3D3D.setState(j3d3d);
CellDim2D2D.setState(j2d2d);
CellDim2D3D.setState(j3d2d);
if (!BugFix) {
Tool3D.setEnabled(!j3d3d && CanDo3D);
Tool2D.setEnabled(!j3d2d && CanDo3D);
ToolJ2D.setEnabled(!j2d2d);
}
}
});
}
// --- COLLABORATION ---
/**
* Determines whether or not the last remote event was from the server.
*/
private double getColRowID() {
TupleIface t = null;
Real id = null;
try {
t = (TupleIface) RemoteColRow.getData();
id = (Real) t.getComponent(0);
return id.getValue();
}
catch (NullPointerException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
catch (VisADException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
catch (RemoteException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
return Float.NaN;
}
/**
* Gets the latest remote row and column information.
*/
private String[][] getNewCellNames() {
// extract new row and column information
TupleIface t = null;
TupleIface tc = null;
RealTuple tr = null;
try {
t = (TupleIface) RemoteColRow.getData();
tc = (TupleIface) t.getComponent(1);
tr = (RealTuple) t.getComponent(2);
}
catch (NullPointerException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
catch (VisADException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
catch (RemoteException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
if (tc == null || tr == null) return null;
int collen = -1;
int rowlen = -1;
try {
collen = tc.getDimension();
rowlen = tr.getDimension();
}
catch (RemoteException exc) {
if (BasicSSCell.DEBUG) exc.printStackTrace();
}
if (rowlen < 1 || collen < 1) return null;
String[] colNames = new String[collen];
int[] rowNames = new int[rowlen];
String[][] cellNames = new String[collen][rowlen];
for (int i=0; i 0) FormulaText.getCaret().moveDot(pos - 1);
}
else {
// left arrow pressed; move caret left
if (pos > 0) FormulaText.getCaret().setDot(pos - 1);
}
}
else if (keyCode == KeyEvent.VK_RIGHT) {
int pos = FormulaText.getCaretPosition();
if (shiftHeld) {
// shift + right arrow pressed; alter selection right
if (pos < FormulaText.getText().length()) {
FormulaText.getCaret().moveDot(pos + 1);
}
}
else {
// right arrow pressed; move caret right
if (pos < FormulaText.getText().length()) {
FormulaText.getCaret().setDot(pos + 1);
}
}
}
else if (keyCode == KeyEvent.VK_HOME) {
if (shiftHeld) {
// shift + home pressed; select to beginning of text
FormulaText.getCaret().moveDot(0);
}
else {
// home pressed; move to beginning of text
FormulaText.getCaret().setDot(0);
}
}
else if (keyCode == KeyEvent.VK_END) {
if (shiftHeld) {
// shift + end pressed; select to end of text
FormulaText.getCaret().moveDot(FormulaText.getText().length());
}
else {
// end pressed; move to end of text
FormulaText.getCaret().setDot(FormulaText.getText().length());
}
}
else commandKey = false;
}
/**
* BIG HAMMER HACK.
*/
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SHIFT) shiftHeld = false;
}
/**
* BIG HAMMER HACK.
*/
public void keyTyped(KeyEvent e) {
char key = e.getKeyChar();
if (!commandKey && !e.isActionKey() && key >= 32) {
int start = FormulaText.getSelectionStart();
int end = FormulaText.getSelectionEnd();
String text = FormulaText.getText();
FormulaText.setText(text.substring(0, start) +
key + text.substring(end));
FormulaText.getCaret().setDot(start + 1);
}
e.consume();
}
/**
* Old x value used with cell resizing logic.
*/
private int oldX;
/**
* Old y value used with cell resizing logic.
*/
private int oldY;
/**
* Handles mouse presses.
*/
public void mousePressed(MouseEvent e) {
Component c = e.getComponent();
for (int j=0; j= NumVisX) x = NumVisX - 1;
if (y >= NumVisY) y = NumVisY - 1;
// update borders of all cells
for (int j=0; j
Ads help maintain this website.