//
// MappingDialog.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.image.BufferedImage;
import java.awt.event.*;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.*;
import visad.*;
import visad.util.*;
/**
* MappingDialog is a dialog that lets the user create ScalarMaps.
*/
public class MappingDialog extends JDialog
implements ActionListener, ListSelectionListener, MouseListener
{
/**
* Flag whether user hit Done or Cancel button.
*/
private boolean Confirm = false;
/**
* ScalarMaps selected by the user.
*/
private ScalarMap[] ScalarMaps;
// -- GUI components --
private JComponent MathCanvas;
private JScrollPane MathCanvasView;
private JComponent CoordCanvas;
private JScrollPane CoordCanvasView;
private boolean CoordRefs;
private JList MathList;
private JComponent DisplayCanvas;
private DefaultListModel CurMaps;
private JList CurrentMaps;
private JScrollPane CurrentMapsView;
private JLabel description;
// -- State info --
/**
* Array of ScalarTypes.
*/
private ScalarType[] MathTypes;
/**
* Array of ScalarType names.
*/
private String[] Scalars;
/**
* Array of ScalarType widths.
*/
private int[] ScW;
/**
* Vector of MDTuples indicating ScalarType locations.
*/
private Vector[] ScP;
/**
* ScalarType height.
*/
private int ScH;
/**
* Width and height of MathType string.
*/
private Dimension StrSize;
/**
* Width and height of CoordinateSystem string.
*/
private Dimension CoordSize;
/**
* Flags marking whether each possible ScalarMap has been assigned.
*/
private boolean[][][] Maps;
/**
* String representation of each possible ScalarMap.
*/
private String[][][] CurMapLabel;
/**
* 11 pt monospaced font.
*/
private static final Font Mono = new Font("Monospaced", Font.PLAIN, 11);
/**
* Names of system intrinsic DisplayRealTypes.
*/
private static final String[][] MapNames = {
{"X Axis", "Y Axis", "Z Axis", "X Offset", "Y Offset", "Z Offset"},
{"Latitude", "Longitude", "Radius",
"Cyl Radius", "Cyl Azimuth", "Cyl Z Axis"},
{"Flow1 X", "Flow1 Y", "Flow1 Z", "Flow2 X", "Flow2 Y", "Flow2 Z"},
{"Flow1 Elevation", "Flow1 Azimuth", "Flow1 Radial",
"Flow2 Elevation", "Flow2 Azimuth", "Flow2 Radial"},
{"Red", "Green", "Blue", "RGB", "RGBA", "Alpha"},
{"Cyan", "Magenta", "Yellow", "CMY", "Animation", "Iso-contour"},
{"Hue", "Saturation", "Value", "HSV", "Select Value", "Select Range"},
{"", "Text", "", "", "Shape", ""}
};
/**
* List of system intrinsic DisplayRealTypes.
*/
private static final DisplayRealType[][] MapTypes = {
{Display.XAxis, Display.YAxis, Display.ZAxis,
Display.XAxisOffset, Display.YAxisOffset, Display.ZAxisOffset},
{Display.Latitude, Display.Longitude, Display.Radius,
Display.CylRadius, Display.CylAzimuth, Display.CylZAxis},
{Display.Flow1X, Display.Flow1Y, Display.Flow1Z,
Display.Flow2X, Display.Flow2Y, Display.Flow2Z},
{Display.Flow1Elevation, Display.Flow1Azimuth, Display.Flow1Radial,
Display.Flow2Elevation, Display.Flow2Azimuth, Display.Flow2Radial},
{Display.Red, Display.Green, Display.Blue,
Display.RGB, Display.RGBA, Display.Alpha},
{Display.Cyan, Display.Magenta, Display.Yellow,
Display.CMY, Display.Animation, Display.IsoContour},
{Display.Hue, Display.Saturation, Display.Value,
Display.HSV, Display.SelectValue, Display.SelectRange},
{null, Display.Text, null, null, Display.Shape, null}
};
/**
* Indices into MapTypes of alpha-related DisplayRealTypes.
*/
private static final Point[] AlphaMaps = {
new Point(4, 4), // RGBA
new Point(4, 5) // Alpha
};
/**
* Indices into MapTypes of 3D-related DisplayRealTypes.
*/
private static final Point[] ThreeDMaps = {
new Point(0, 2), // ZAxis
new Point(0, 5), // ZAxisOffset
new Point(1, 0), // Latitude
new Point(1, 5), // CylZAxis
new Point(2, 2), // Flow1Z
new Point(2, 5), // Flow2Z
new Point(3, 0), // Flow1Elevation
new Point(3, 3) // Flow2Elevation
};
/**
* Width of mapping arrays.
*/
private static final int MapWidth = MapTypes[0].length;
/**
* Height of mapping arrays.
*/
private static final int MapHeight = MapTypes.length;
/**
* display.gif image.
*/
private static Image DRT = null;
/**
* Whether DRT image has been initialized.
*/
private static boolean Inited = false;
/**
* Pre-loads the display.gif file, so it's ready
* when mapping dialog is requested.
*/
public static void initDialog() {
if (DRT == null) {
URL url = MappingDialog.class.getResource("display.gif");
DRT = Toolkit.getDefaultToolkit().getImage(url);
}
Inited = true;
}
/**
* Returns a human-readable list of CoordinateSystem dependencies.
*/
private static String prettyCoordSys(MathType type) {
String s = "";
if (type instanceof FunctionType) s = s + pcsFunction((FunctionType) type);
else if (type instanceof SetType) s = s + pcsSet((SetType) type);
else if (type instanceof TupleType) s = s + pcsTuple((TupleType) type);
return s;
}
/**
* prettyCoordSys helper method.
*/
private static String pcsFunction(FunctionType mathType) {
String s = "";
// extract domain
RealTupleType domain = mathType.getDomain();
s = s + pcsTuple((TupleType) domain);
// extract range
MathType range = mathType.getRange();
s = s + prettyCoordSys(range);
return s;
}
/**
* prettyCoordSys helper method.
*/
private static String pcsSet(SetType mathType) {
// extract domain
RealTupleType domain = mathType.getDomain();
return pcsTuple((TupleType) domain);
}
/**
* prettyCoordSys helper method.
*/
private static String pcsTuple(TupleType mathType) {
String s = "";
if (mathType instanceof RealTupleType) {
RealTupleType rtt = (RealTupleType) mathType;
CoordinateSystem cs = rtt.getCoordinateSystem();
if (cs != null) {
RealTupleType ref = cs.getReference();
if (ref != null) {
s = s + rtt.prettyString() + " ==> " + ref.prettyString() + "\n";
}
}
}
else {
// extract components
for (int j=0; j width) width = w;
pos = nextPos;
numLines++;
}
while (pos < typeString.length());
StrSize = new Dimension(width, (ScH + 2) * numLines + 10);
// get starting line position for each line of MathType string
int[] mathLines = new int[numLines];
pos = -1;
for (int i=0; i width) width = w;
pos = nextPos;
numLines++;
}
while (pos < coordString.length() - 1);
CoordSize = new Dimension(width, (ScH + 2) * numLines + 10);
// get starting line position for each line of CoordinateSystem string
int[] coordLines = new int[numLines];
pos = -1;
for (int i=0; i= 0) {
for (int i=0; i maxMCHeight) prefMCHeight = maxMCHeight;
MathCanvasView.setPreferredSize(new Dimension(0, prefMCHeight));
MathCanvasView.setBackground(Color.white);
JScrollBar horiz = MathCanvasView.getHorizontalScrollBar();
JScrollBar verti = MathCanvasView.getVerticalScrollBar();
horiz.setBlockIncrement(5 * ScH + 10);
horiz.setUnitIncrement(ScH+2);
verti.setBlockIncrement(5 * ScH + 10);
verti.setUnitIncrement(ScH+2);
topPanel.add(Box.createRigidArea(new Dimension(5, 0)));
JPanel whitePanel = new JPanel();
whitePanel.setBackground(Color.white);
whitePanel.setLayout(new BoxLayout(whitePanel, BoxLayout.X_AXIS));
whitePanel.add(MathCanvasView);
topPanel.add(whitePanel);
topPanel.add(Box.createRigidArea(new Dimension(5, 0)));
// set up description label
description = new JLabel(" ");
JPanel descPanel = new JPanel();
descPanel.setLayout(new BoxLayout(descPanel, BoxLayout.X_AXIS));
contentPane.add(descPanel);
contentPane.add(Box.createRigidArea(new Dimension(0, 15)));
descPanel.add(description);
// set up lower panel
JPanel lowerPanel = new JPanel();
lowerPanel.setLayout(new BoxLayout(lowerPanel, BoxLayout.X_AXIS));
contentPane.add(lowerPanel);
contentPane.add(Box.createRigidArea(new Dimension(0, 5)));
// set up far-left-side panel
JPanel flsPanel = new JPanel();
flsPanel.setLayout(new BoxLayout(flsPanel, BoxLayout.Y_AXIS));
lowerPanel.add(Box.createRigidArea(new Dimension(5, 0)));
lowerPanel.add(flsPanel);
// only do CoordSys stuff if there are CoordinateSystem references
if (CoordRefs) {
// draw the pretty-print CoordinateSystem references to an Image (slow!)
final BufferedImage csImg = new BufferedImage(
CoordSize.width, CoordSize.height, BufferedImage.TYPE_INT_RGB);
g = csImg.getGraphics();
g.setFont(Mono);
g.setColor(Color.white);
g.fillRect(0, 0, CoordSize.width, CoordSize.height);
g.setColor(Color.black);
for (int i=0; i= 0) {
for (int i=0; i maxCCHeight) prefCCHeight = maxCCHeight;
CoordCanvasView.setPreferredSize(new Dimension(0, prefCCHeight));
CoordCanvasView.setBackground(Color.white);
horiz = CoordCanvasView.getHorizontalScrollBar();
verti = CoordCanvasView.getVerticalScrollBar();
horiz.setBlockIncrement(5 * ScH + 10);
horiz.setUnitIncrement(ScH + 2);
verti.setBlockIncrement(5 * ScH + 10);
verti.setUnitIncrement(ScH + 2);
topPanel2.add(Box.createRigidArea(new Dimension(5, 0)));
JPanel whitePanel2 = new JPanel();
whitePanel2.setBackground(Color.white);
whitePanel2.setLayout(new BoxLayout(whitePanel2, BoxLayout.X_AXIS));
whitePanel2.add(CoordCanvasView);
topPanel2.add(whitePanel2);
topPanel2.add(Box.createRigidArea(new Dimension(5, 0)));
}
// set up left-side panel
JPanel lsPanel = new JPanel();
lsPanel.setLayout(new BoxLayout(lsPanel, BoxLayout.Y_AXIS));
lowerPanel.add(Box.createRigidArea(new Dimension(5, 0)));
lowerPanel.add(lsPanel);
// begin set up "current mappings" list
CurMaps = new DefaultListModel();
int num = MathTypes.length;
CurMaps.ensureCapacity(num * MapWidth * MapHeight);
CurrentMaps = new JList(CurMaps);
// set up "map from" list
Maps = new boolean[num][MapHeight][MapWidth];
CurMapLabel = new String[num][MapHeight][MapWidth];
for (int i=0; i " + MapNames[j][k];
if (startMaps != null) {
for (int m=0; m= 0) {
for (int col=0; col screen.width - pad) w = screen.width - pad;
if (h > screen.height - pad) h = screen.height - pad;
return new Dimension(w, h);
}
/**
* Displays the dialog in the center of the screen.
*/
public void display() {
pack();
Util.centerWindow(this);
setVisible(true);
}
/**
* Gets the mappings selected by the user.
*/
public ScalarMap[] getMaps() {
return ScalarMaps;
}
/**
* Gets whether the user pressed the Ok button.
*/
public boolean okPressed() {
return Confirm;
}
/**
* Recursive quick-sort routine for alphabetizing scalars.
*/
private void sort(int lo0, int hi0) {
if (hi0 < lo0) return;
int lo = lo0;
int hi = hi0;
String mid = Scalars[(lo0 + hi0) / 2].toLowerCase();
while (lo <= hi) {
while (lo < hi0 && Scalars[lo].toLowerCase().compareTo(mid) < 0) ++lo;
while (hi > lo0 && Scalars[hi].toLowerCase().compareTo(mid) > 0) --hi;
if (lo <= hi) {
// MathTypes[lo] <-> MathTypes[hi]
ScalarType st = MathTypes[lo];
MathTypes[lo] = MathTypes[hi];
MathTypes[hi] = st;
// Scalars[lo] <-> Scalars[hi]
String s = Scalars[lo];
Scalars[lo] = Scalars[hi];
Scalars[hi] = s;
// ScW[lo] <-> ScW[hi]
int i = ScW[lo];
ScW[lo] = ScW[hi];
ScW[hi] = i;
// ScP[lo] <-> ScP[hi]
Vector v = ScP[lo];
ScP[lo] = ScP[hi];
ScP[hi] = v;
lo++;
hi--;
}
}
if (lo0 < hi) sort(lo0, hi);
if (lo < hi0) sort(lo, hi0);
}
/**
* Clears a box in the "map to" canvas.
*/
void eraseBox(int col, int row, Graphics g) {
int x = 40 * col;
int y = 40 * row;
g.setColor(Color.black);
for (int i=0; i<40; i+=2) {
g.drawLine(x, y + i, x + i, y);
g.drawLine(x + i, y + 38, x + 38, y + i);
}
}
/**
* Highlights a box in the "map to" canvas.
*/
void highlightBox(int col, int row, Graphics g) {
int x = 40 * col;
int y = 40 * row;
final int n1 = 11;
final int n2 = 29;
g.setColor(Color.blue);
g.drawRect(x, y, 39, 39);
g.drawLine(x, y + n1, x + n1, y);
g.drawLine(x, y + n2, x + n2, y);
g.drawLine(x + n1, y + 39, x + 39, y + n1);
g.drawLine(x + n2, y + 39, x + 39, y + n2);
g.drawLine(x + n2, y, x + 39, y + n1);
g.drawLine(x + n1, y, x + 39, y + n2);
g.drawLine(x, y + n1, x + n2, y + 39);
g.drawLine(x, y + n2, x + n1, y + 39);
}
/**
* Clears all maps from the current mappings list.
*/
private void clearAll() {
CurrentMaps.clearSelection(); // work-around for nasty swing bug
CurMaps.removeAllElements();
for (int i=0; i= 0) setType = setType.substring(index + 1);
int dim = set.getDimension();
s = setType + "(" + dim + ")";
}
desc = desc + ": Unit=" + u + "; Set=" + s;
}
else {
desc = desc + " (text)";
}
description.setText(desc);
}
/**
* Handles button press events.
*/
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
synchronized (Lock) {
if (cmd.equals("all")) { // clear all
if (CurMaps.getSize() > 0) {
clearAll();
// update components
Graphics g = DisplayCanvas.getGraphics();
DisplayCanvas.paint(g);
g.dispose();
CurrentMaps.repaint();
CurrentMapsView.validate();
}
}
else if (cmd.equals("sel")) { // clear selected
int[] ndx = CurrentMaps.getSelectedIndices();
int len = ndx.length;
for (int x=len-1; x>=0; x--) {
String s = (String) CurMaps.getElementAt(ndx[x]);
boolean looking = true;
for (int i=0; i 0) {
// update components
Graphics g = DisplayCanvas.getGraphics();
DisplayCanvas.paint(g);
g.dispose();
CurrentMaps.repaint();
CurrentMapsView.validate();
}
}
else if (cmd.equals("detect")) {
ScalarMap[] maps = DataUtility.guessMaps(Types, Allow3D);
if (CurMaps.getSize() > 0) clearAll();
if (maps != null) {
for (int i=0; i " + MapNames[j][k] + ") is not valid.",
"Illegal mapping", JOptionPane.ERROR_MESSAGE);
}
}
}
}
}
if (okay) {
Confirm = true;
setVisible(false);
}
}
else if (cmd.equals("cancel")) setVisible(false);
}
}
/**
* Handles list selection change events.
*/
public void valueChanged(ListSelectionEvent e) {
synchronized (Lock) {
if (!e.getValueIsAdjusting()) {
if ((JList) e.getSource() == MathList) {
Graphics g = DisplayCanvas.getGraphics();
DisplayCanvas.paint(g);
g.dispose();
int i = MathList.getSelectedIndex();
MDTuple tuple = (MDTuple) ScP[i].elementAt(0);
Rectangle r = new Rectangle(tuple.x, tuple.y, ScW[i], ScH);
MathList.ensureIndexIsVisible(i);
if (tuple.b) CoordCanvas.scrollRectToVisible(r);
else MathCanvas.scrollRectToVisible(r);
MathCanvas.repaint();
if (CoordRefs) CoordCanvas.repaint();
updateDescriptionLabel(i);
}
}
}
}
/**
* Handles mouse clicks in the MathType window and "map to" canvas.
*/
public void mousePressed(MouseEvent e) {
synchronized (Lock) {
Component c = e.getComponent();
if (c == MathCanvas) {
Point p = e.getPoint();
for (int i=0; i= 0 && row >= 0 && col >= 0 &&
row < MapHeight && col < MapWidth && !Illegal[row][col])
{
Maps[ndx][row][col] = !Maps[ndx][row][col];
if (Maps[ndx][row][col]) {
CurMaps.addElement(CurMapLabel[ndx][row][col]);
}
else {
CurrentMaps.clearSelection();
CurMaps.removeElement(CurMapLabel[ndx][row][col]);
}
// redraw DisplayCanvas
Graphics g = DisplayCanvas.getGraphics();
g.setClip(40 * col, 40 * row, 41, 41);
DisplayCanvas.paint(g);
g.dispose();
// redraw CurrentMaps
CurrentMaps.repaint();
CurrentMapsView.validate();
}
}
else if (c == CoordCanvas) {
Point p = e.getPoint();
for (int i=0; i
Ads help maintain this website.