mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2024-12-27 02:18:18 +08:00
368fa189d1
Handle also the case when the user closes the dialog without selecting an answer. Signed-off-by: Stefan Weil <sw@weilnetz.de>
649 lines
21 KiB
Java
649 lines
21 KiB
Java
// Copyright 2007 Google Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); You may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
|
// applicable law or agreed to in writing, software distributed under the
|
|
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
|
// OF ANY KIND, either express or implied. See the License for the specific
|
|
// language governing permissions and limitations under the License.
|
|
|
|
package com.google.scrollview.ui;
|
|
|
|
import com.google.scrollview.ScrollView;
|
|
import com.google.scrollview.events.SVEvent;
|
|
import com.google.scrollview.events.SVEventHandler;
|
|
import com.google.scrollview.events.SVEventType;
|
|
import com.google.scrollview.ui.SVMenuBar;
|
|
import com.google.scrollview.ui.SVPopupMenu;
|
|
|
|
import org.piccolo2d.PCamera;
|
|
import org.piccolo2d.PCanvas;
|
|
import org.piccolo2d.PLayer;
|
|
import org.piccolo2d.extras.swing.PScrollPane;
|
|
import org.piccolo2d.nodes.PImage;
|
|
import org.piccolo2d.nodes.PPath;
|
|
import org.piccolo2d.nodes.PText;
|
|
import org.piccolo2d.util.PPaintContext;
|
|
|
|
import java.awt.BasicStroke;
|
|
import java.awt.BorderLayout;
|
|
import java.awt.Color;
|
|
import java.awt.Font;
|
|
import java.awt.GraphicsEnvironment;
|
|
import java.awt.Rectangle;
|
|
import java.awt.TextArea;
|
|
import java.awt.geom.IllegalPathStateException;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JOptionPane;
|
|
import javax.swing.SwingUtilities;
|
|
import javax.swing.WindowConstants;
|
|
|
|
/**
|
|
* The SVWindow is the top-level ui class. It should get instantiated whenever
|
|
* the user intends to create a new window. It contains helper functions to draw
|
|
* on the canvas, add new menu items, show modal dialogs etc.
|
|
*
|
|
* @author wanke@google.com
|
|
*/
|
|
public class SVWindow extends JFrame {
|
|
/**
|
|
* Constants defining the maximum initial size of the window.
|
|
*/
|
|
private static final int MAX_WINDOW_X = 1000;
|
|
private static final int MAX_WINDOW_Y = 800;
|
|
|
|
/* Constant defining the (approx) height of the default message box*/
|
|
private static final int DEF_MESSAGEBOX_HEIGHT = 200;
|
|
|
|
/** Constant defining the "speed" at which to zoom in and out. */
|
|
public static final double SCALING_FACTOR = 2;
|
|
|
|
/** The top level layer we add our PNodes to (root node). */
|
|
PLayer layer;
|
|
|
|
/** The current color of the pen. It is used to draw edges, text, etc. */
|
|
Color currentPenColor;
|
|
|
|
/**
|
|
* The current color of the brush. It is used to draw the interior of
|
|
* primitives.
|
|
*/
|
|
Color currentBrushColor;
|
|
|
|
/** The system name of the current font we are using (e.g.
|
|
* "Times New Roman"). */
|
|
Font currentFont;
|
|
|
|
/** The stroke width to be used. */
|
|
// This really needs to be a fixed width stroke as the basic stroke is
|
|
// anti-aliased and gets too faint, but the piccolo fixed width stroke
|
|
// is too buggy and generates missing initial moveto in path definition
|
|
// errors with a IllegalPathStateException that cannot be caught because
|
|
// it is in the automatic repaint function. If we can fix the exceptions
|
|
// in piccolo, then we can use the following instead of BasicStroke:
|
|
// import edu.umd.cs.piccolox.util.PFixedWidthStroke;
|
|
// PFixedWidthStroke stroke = new PFixedWidthStroke(0.5f);
|
|
// Instead we use the BasicStroke and turn off anti-aliasing.
|
|
BasicStroke stroke = new BasicStroke(0.5f);
|
|
|
|
/**
|
|
* A unique representation for the window, also known by the client. It is
|
|
* used when sending messages from server to client to identify him.
|
|
*/
|
|
public int hash;
|
|
|
|
/**
|
|
* The total number of created Windows. If this ever reaches 0 (apart from the
|
|
* beginning), quit the server.
|
|
*/
|
|
public static int nrWindows = 0;
|
|
|
|
/**
|
|
* The Canvas, MessageBox, EventHandler, Menubar and Popupmenu associated with
|
|
* this window.
|
|
*/
|
|
private SVEventHandler svEventHandler = null;
|
|
private SVMenuBar svMenuBar = null;
|
|
private TextArea ta = null;
|
|
public SVPopupMenu svPuMenu = null;
|
|
public PCanvas canvas;
|
|
private int winSizeX;
|
|
private int winSizeY;
|
|
|
|
/** Set the brush to an RGB color */
|
|
public void brush(int red, int green, int blue) {
|
|
brush(red, green, blue, 255);
|
|
}
|
|
|
|
/** Set the brush to an RGBA color */
|
|
public void brush(int red, int green, int blue, int alpha) {
|
|
// If alpha is zero, use a null brush to save rendering time.
|
|
if (alpha == 0) {
|
|
currentBrushColor = null;
|
|
} else {
|
|
currentBrushColor = new Color(red, green, blue, alpha);
|
|
}
|
|
}
|
|
|
|
/** Erase all content from the window, but do not destroy it. */
|
|
public void clear() {
|
|
// Manipulation of Piccolo's scene graph should be done from Swings
|
|
// event dispatch thread since Piccolo is not thread safe. This code calls
|
|
// removeAllChildren() from that thread and releases the latch.
|
|
final java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
layer.removeAllChildren();
|
|
repaint();
|
|
latch.countDown();
|
|
}
|
|
});
|
|
try {
|
|
latch.await();
|
|
} catch (InterruptedException e) {
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start setting up a new polyline. The server will now expect
|
|
* polyline data until the polyline is complete.
|
|
*
|
|
* @param length number of coordinate pairs
|
|
*/
|
|
public void createPolyline(int length) {
|
|
ScrollView.polylineXCoords = new float[length];
|
|
ScrollView.polylineYCoords = new float[length];
|
|
ScrollView.polylineSize = length;
|
|
ScrollView.polylineScanned = 0;
|
|
}
|
|
|
|
/**
|
|
* Draw the now complete polyline.
|
|
*/
|
|
public void drawPolyline() {
|
|
int numCoords = ScrollView.polylineXCoords.length;
|
|
if (numCoords < 2) {
|
|
return;
|
|
}
|
|
PPath pn = PPath.createLine(ScrollView.polylineXCoords[0],
|
|
ScrollView.polylineYCoords[0],
|
|
ScrollView.polylineXCoords[1],
|
|
ScrollView.polylineYCoords[1]);
|
|
pn.reset();
|
|
pn.moveTo(ScrollView.polylineXCoords[0], ScrollView.polylineYCoords[0]);
|
|
for (int p = 1; p < numCoords; ++p) {
|
|
pn.lineTo(ScrollView.polylineXCoords[p], ScrollView.polylineYCoords[p]);
|
|
}
|
|
pn.closePath();
|
|
ScrollView.polylineSize = 0;
|
|
pn.setStrokePaint(currentPenColor);
|
|
pn.setPaint(null); // Don't fill the polygon - this is just a polyline.
|
|
pn.setStroke(stroke);
|
|
layer.addChild(pn);
|
|
}
|
|
|
|
/**
|
|
* Construct a new SVWindow and set it visible.
|
|
*
|
|
* @param name Title of the window.
|
|
* @param hash Unique internal representation. This has to be the same as
|
|
* defined by the client, as they use this to refer to the windows.
|
|
* @param posX X position of where to draw the window (upper left).
|
|
* @param posY Y position of where to draw the window (upper left).
|
|
* @param sizeX The width of the window.
|
|
* @param sizeY The height of the window.
|
|
* @param canvasSizeX The canvas width of the window.
|
|
* @param canvasSizeY The canvas height of the window.
|
|
*/
|
|
public SVWindow(String name, int hash, int posX, int posY, int sizeX,
|
|
int sizeY, int canvasSizeX, int canvasSizeY) {
|
|
super(name);
|
|
|
|
// Provide defaults for sizes.
|
|
if (sizeX <= 0) sizeX = canvasSizeX;
|
|
if (sizeY <= 0) sizeY = canvasSizeY;
|
|
if (canvasSizeX <= 0) canvasSizeX = sizeX;
|
|
if (canvasSizeY <= 0) canvasSizeY = sizeY;
|
|
|
|
// Avoid later division by zero.
|
|
if (sizeX <= 0) {
|
|
sizeX = 1;
|
|
canvasSizeX = sizeX;
|
|
}
|
|
if (sizeY <= 0) {
|
|
sizeY = 1;
|
|
canvasSizeY = sizeY;
|
|
}
|
|
|
|
// Initialize variables
|
|
nrWindows++;
|
|
this.hash = hash;
|
|
this.svEventHandler = new SVEventHandler(this);
|
|
this.currentPenColor = Color.BLACK;
|
|
this.currentBrushColor = Color.BLACK;
|
|
this.currentFont = new Font("Times New Roman", Font.PLAIN, 12);
|
|
|
|
// Determine the initial size and zoom factor of the window.
|
|
// If the window is too big, rescale it and zoom out.
|
|
int shrinkfactor = 1;
|
|
|
|
if (sizeX > MAX_WINDOW_X) {
|
|
shrinkfactor = (sizeX + MAX_WINDOW_X - 1) / MAX_WINDOW_X;
|
|
}
|
|
if (sizeY / shrinkfactor > MAX_WINDOW_Y) {
|
|
shrinkfactor = (sizeY + MAX_WINDOW_Y - 1) / MAX_WINDOW_Y;
|
|
}
|
|
winSizeX = sizeX / shrinkfactor;
|
|
winSizeY = sizeY / shrinkfactor;
|
|
double initialScalingfactor = 1.0 / shrinkfactor;
|
|
if (winSizeX > canvasSizeX || winSizeY > canvasSizeY) {
|
|
initialScalingfactor = Math.min(1.0 * winSizeX / canvasSizeX,
|
|
1.0 * winSizeY / canvasSizeY);
|
|
}
|
|
|
|
// Setup the actual window (its size, camera, title, etc.)
|
|
if (canvas == null) {
|
|
canvas = new PCanvas();
|
|
getContentPane().add(canvas, BorderLayout.CENTER);
|
|
}
|
|
|
|
layer = canvas.getLayer();
|
|
canvas.setBackground(Color.BLACK);
|
|
|
|
// Disable antialiasing to make the lines more visible.
|
|
canvas.setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING);
|
|
|
|
setLayout(new BorderLayout());
|
|
|
|
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
|
|
|
validate();
|
|
canvas.requestFocus();
|
|
|
|
// Manipulation of Piccolo's scene graph should be done from Swings
|
|
// event dispatch thread since Piccolo is not thread safe. This code calls
|
|
// initialize() from that thread once the PFrame is initialized, so you are
|
|
// safe to start working with Piccolo in the initialize() method.
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
repaint();
|
|
}
|
|
});
|
|
|
|
setSize(winSizeX, winSizeY);
|
|
setLocation(posX, posY);
|
|
setTitle(name);
|
|
|
|
// Add a Scrollpane to be able to scroll within the canvas
|
|
PScrollPane scrollPane = new PScrollPane(canvas);
|
|
getContentPane().add(scrollPane);
|
|
scrollPane.setWheelScrollingEnabled(false);
|
|
PCamera lc = canvas.getCamera();
|
|
lc.scaleViewAboutPoint(initialScalingfactor, 0, 0);
|
|
|
|
// Disable the default event handlers and add our own.
|
|
addWindowListener(svEventHandler);
|
|
canvas.removeInputEventListener(canvas.getPanEventHandler());
|
|
canvas.removeInputEventListener(canvas.getZoomEventHandler());
|
|
canvas.addInputEventListener(svEventHandler);
|
|
canvas.addKeyListener(svEventHandler);
|
|
|
|
// Make the window visible.
|
|
validate();
|
|
setVisible(true);
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenience function to add a message box to the window which can be used
|
|
* to output debug information.
|
|
*/
|
|
public void addMessageBox() {
|
|
if (ta == null) {
|
|
ta = new TextArea();
|
|
ta.setEditable(false);
|
|
getContentPane().add(ta, BorderLayout.SOUTH);
|
|
}
|
|
// We need to make the window bigger to accommodate the message box.
|
|
winSizeY += DEF_MESSAGEBOX_HEIGHT;
|
|
setSize(winSizeX, winSizeY);
|
|
}
|
|
|
|
/**
|
|
* Allows you to specify the thickness with which to draw lines, recantgles
|
|
* and ellipses.
|
|
* @param width The new thickness.
|
|
*/
|
|
public void setStrokeWidth(float width) {
|
|
// If this worked we wouldn't need the antialiased rendering off.
|
|
// stroke = new PFixedWidthStroke(width);
|
|
stroke = new BasicStroke(width);
|
|
}
|
|
|
|
/**
|
|
* Draw an ellipse at (x,y) with given width and height, using the
|
|
* current stroke, the current brush color to fill it and the
|
|
* current pen color for the outline.
|
|
*/
|
|
public void drawEllipse(int x, int y, int width, int height) {
|
|
PPath pn = PPath.createEllipse(x, y, width, height);
|
|
pn.setStrokePaint(currentPenColor);
|
|
pn.setStroke(stroke);
|
|
pn.setPaint(currentBrushColor);
|
|
layer.addChild(pn);
|
|
}
|
|
|
|
/**
|
|
* Draw the image with the given name at (x,y). Any image loaded stays in
|
|
* memory, so if you intend to redraw an image, you do not have to use
|
|
* createImage again.
|
|
*/
|
|
public void drawImage(PImage img, int xPos, int yPos) {
|
|
img.setX(xPos);
|
|
img.setY(yPos);
|
|
layer.addChild(img);
|
|
}
|
|
|
|
/**
|
|
* Draw a line from (x1,y1) to (x2,y2) using the current pen color and stroke.
|
|
*/
|
|
public void drawLine(int x1, int y1, int x2, int y2) {
|
|
PPath pn = PPath.createLine(x1, y1, x2, y2);
|
|
pn.setStrokePaint(currentPenColor);
|
|
pn.setPaint(null); // Null paint may render faster than the default.
|
|
pn.setStroke(stroke);
|
|
pn.moveTo(x1, y1);
|
|
pn.lineTo(x2, y2);
|
|
layer.addChild(pn);
|
|
}
|
|
|
|
/**
|
|
* Draw a rectangle given the two points (x1,y1) and (x2,y2) using the current
|
|
* stroke, pen color for the border and the brush to fill the
|
|
* interior.
|
|
*/
|
|
public void drawRectangle(int x1, int y1, int x2, int y2) {
|
|
|
|
if (x1 > x2) {
|
|
int t = x1;
|
|
x1 = x2;
|
|
x2 = t;
|
|
}
|
|
if (y1 > y2) {
|
|
int t = y1;
|
|
y1 = y2;
|
|
y2 = t;
|
|
}
|
|
|
|
PPath pn = PPath.createRectangle(x1, y1, x2 - x1, y2 - y1);
|
|
pn.setStrokePaint(currentPenColor);
|
|
pn.setStroke(stroke);
|
|
pn.setPaint(currentBrushColor);
|
|
layer.addChild(pn);
|
|
}
|
|
|
|
/**
|
|
* Draw some text at (x,y) using the current pen color and text attributes. If
|
|
* the current font does NOT support at least one character, it tries to find
|
|
* a font which is capable of displaying it and use that to render the text.
|
|
* Note: If the font says it can render a glyph, but in reality it turns out
|
|
* to be crap, there is nothing we can do about it.
|
|
*/
|
|
public void drawText(int x, int y, String text) {
|
|
int unreadableCharAt = -1;
|
|
char[] chars = text.toCharArray();
|
|
PText pt = new PText(text);
|
|
pt.setTextPaint(currentPenColor);
|
|
pt.setFont(currentFont);
|
|
|
|
// Check to see if every character can be displayed by the current font.
|
|
for (int i = 0; i < chars.length; i++) {
|
|
if (!currentFont.canDisplay(chars[i])) {
|
|
// Set to the first not displayable character.
|
|
unreadableCharAt = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Have to find some working font and use it for this text entry.
|
|
if (unreadableCharAt != -1) {
|
|
Font[] allfonts =
|
|
GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
|
|
for (int j = 0; j < allfonts.length; j++) {
|
|
if (allfonts[j].canDisplay(chars[unreadableCharAt])) {
|
|
Font tempFont =
|
|
new Font(allfonts[j].getFontName(), currentFont.getStyle(),
|
|
currentFont.getSize());
|
|
pt.setFont(tempFont);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pt.setX(x);
|
|
pt.setY(y);
|
|
layer.addChild(pt);
|
|
}
|
|
|
|
/** Set the pen color to an RGB value */
|
|
public void pen(int red, int green, int blue) {
|
|
pen(red, green, blue, 255);
|
|
}
|
|
|
|
/** Set the pen color to an RGBA value */
|
|
public void pen(int red, int green, int blue, int alpha) {
|
|
currentPenColor = new Color(red, green, blue, alpha);
|
|
}
|
|
|
|
/**
|
|
* Define how to display text. Note: underlined is not currently not supported
|
|
*/
|
|
public void textAttributes(String font, int pixelSize, boolean bold,
|
|
boolean italic, boolean underlined) {
|
|
|
|
// For legacy reasons convert "Times" to "Times New Roman"
|
|
if (font.equals("Times")) {
|
|
font = "Times New Roman";
|
|
}
|
|
|
|
int style = Font.PLAIN;
|
|
if (bold) {
|
|
style += Font.BOLD;
|
|
}
|
|
if (italic) {
|
|
style += Font.ITALIC;
|
|
}
|
|
currentFont = new Font(font, style, pixelSize);
|
|
}
|
|
|
|
/**
|
|
* Zoom the window to the rectangle given the two points (x1,y1)
|
|
* and (x2,y2), which must be greater than (x1,y1).
|
|
*/
|
|
public void zoomRectangle(int x1, int y1, int x2, int y2) {
|
|
if (x2 > x1 && y2 > y1) {
|
|
winSizeX = getWidth();
|
|
winSizeY = getHeight();
|
|
int width = x2 - x1;
|
|
int height = y2 - y1;
|
|
// Since piccolo doesn't do this well either, pad with a margin
|
|
// all the way around.
|
|
int wmargin = width / 2;
|
|
int hmargin = height / 2;
|
|
double scalefactor = Math.min(winSizeX / (2.0 * wmargin + width),
|
|
winSizeY / (2.0 * hmargin + height));
|
|
PCamera lc = canvas.getCamera();
|
|
lc.scaleView(scalefactor / lc.getViewScale());
|
|
lc.animateViewToPanToBounds(new Rectangle(x1 - hmargin, y1 - hmargin,
|
|
2 * wmargin + width,
|
|
2 * hmargin + height), 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flush buffers and update display.
|
|
*
|
|
* Only actually reacts if there are no more messages in the stack, to prevent
|
|
* the canvas from flickering.
|
|
*/
|
|
public void update() {
|
|
// TODO(rays) fix bugs in piccolo or use something else.
|
|
// The repaint function generates many
|
|
// exceptions for no good reason. We catch and ignore as many as we
|
|
// can here, but most of them are generated by the system repaints
|
|
// caused by resizing/exposing parts of the window etc, and they
|
|
// generate unwanted stack traces that have to be piped to /dev/null
|
|
// (on linux).
|
|
try {
|
|
repaint();
|
|
} catch (NullPointerException e) {
|
|
// Do nothing so the output isn't full of stack traces.
|
|
} catch (IllegalPathStateException e) {
|
|
// Do nothing so the output isn't full of stack traces.
|
|
}
|
|
}
|
|
|
|
/** Adds a checkbox entry to the menubar, c.f. SVMenubar.add(...) */
|
|
public void addMenuBarItem(String parent, String name, int id,
|
|
boolean checked) {
|
|
svMenuBar.add(parent, name, id, checked);
|
|
}
|
|
|
|
/** Adds a submenu to the menubar, c.f. SVMenubar.add(...) */
|
|
public void addMenuBarItem(String parent, String name) {
|
|
addMenuBarItem(parent, name, -1);
|
|
}
|
|
|
|
/** Adds a new entry to the menubar, c.f. SVMenubar.add(...) */
|
|
public void addMenuBarItem(String parent, String name, int id) {
|
|
if (svMenuBar == null) {
|
|
svMenuBar = new SVMenuBar(this);
|
|
|
|
}
|
|
svMenuBar.add(parent, name, id);
|
|
}
|
|
|
|
/** Add a message to the message box. */
|
|
public void addMessage(String message) {
|
|
if (ta != null) {
|
|
ta.append(message + "\n");
|
|
} else {
|
|
System.out.println(message + "\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method converts a string which might contain hexadecimal values to a
|
|
* string which contains the respective unicode counterparts.
|
|
*
|
|
* For example, Hall0x0094chen returns Hall<o umlaut>chen
|
|
* encoded as utf8.
|
|
*
|
|
* @param input The original string, containing 0x values
|
|
* @return The converted string which has the replaced unicode symbols
|
|
*/
|
|
private static String convertIntegerStringToUnicodeString(String input) {
|
|
StringBuffer sb = new StringBuffer(input);
|
|
Pattern numbers = Pattern.compile("0x[0-9a-fA-F]{4}");
|
|
Matcher matcher = numbers.matcher(sb);
|
|
|
|
while (matcher.find()) {
|
|
// Find the next match which resembles a hexadecimal value and convert it
|
|
// to
|
|
// its char value
|
|
char a = (char) (Integer.decode(matcher.group()).intValue());
|
|
|
|
// Replace the original with the new character
|
|
sb.replace(matcher.start(), matcher.end(), String.valueOf(a));
|
|
|
|
// Start again, since our positions have switched
|
|
matcher.reset();
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Show a modal input dialog. The answer by the dialog is then send to the
|
|
* client, together with the associated menu id, as SVET_POPUP
|
|
*
|
|
* @param msg The text that is displayed in the dialog.
|
|
* @param def The default value of the dialog.
|
|
* @param id The associated commandId
|
|
* @param evtype The event this is associated with (usually SVET_MENU
|
|
* or SVET_POPUP)
|
|
*/
|
|
public void showInputDialog(String msg, String def, int id,
|
|
SVEventType evtype) {
|
|
svEventHandler.timer.stop();
|
|
String tmp =
|
|
(String) JOptionPane.showInputDialog(this, msg, "",
|
|
JOptionPane.QUESTION_MESSAGE, null, null, def);
|
|
|
|
if (tmp != null) {
|
|
tmp = convertIntegerStringToUnicodeString(tmp);
|
|
SVEvent res = new SVEvent(evtype, this, id, tmp);
|
|
ScrollView.addMessage(res);
|
|
}
|
|
svEventHandler.timer.restart();
|
|
}
|
|
|
|
|
|
/**
|
|
* Shows a modal input dialog to the user. The return value is automatically
|
|
* sent to the client as SVET_INPUT event (with command id -1).
|
|
*
|
|
* @param msg The text of the dialog.
|
|
*/
|
|
public void showInputDialog(String msg) {
|
|
showInputDialog(msg, null, -1, SVEventType.SVET_INPUT);
|
|
}
|
|
|
|
/**
|
|
* Shows a dialog presenting "Yes" and "No" as answers and returns either a
|
|
* "y" or "n" to the client.
|
|
*
|
|
* Closing the dialog without answering is handled like "No".
|
|
*
|
|
* @param msg The text that is displayed in the dialog.
|
|
*/
|
|
public void showYesNoDialog(String msg) {
|
|
// res returns 0 on yes, 1 on no. Seems to be a bit counterintuitive
|
|
int res =
|
|
JOptionPane.showOptionDialog(this, msg, "", JOptionPane.YES_NO_OPTION,
|
|
JOptionPane.QUESTION_MESSAGE, null, null, null);
|
|
|
|
SVEvent e = new SVEvent(SVEventType.SVET_INPUT, this, 0, 0, 0, 0,
|
|
res == 0 ? "y" : "n");
|
|
ScrollView.addMessage(e);
|
|
}
|
|
|
|
/** Adds a submenu to the popup menu, c.f. SVPopupMenu.add(...) */
|
|
public void addPopupMenuItem(String parent, String name) {
|
|
if (svPuMenu == null) {
|
|
svPuMenu = new SVPopupMenu(this);
|
|
}
|
|
svPuMenu.add(parent, name, -1);
|
|
}
|
|
|
|
/** Adds a new menu entry to the popup menu, c.f. SVPopupMenu.add(...) */
|
|
public void addPopupMenuItem(String parent, String name, int cmdEvent,
|
|
String value, String desc) {
|
|
if (svPuMenu == null) {
|
|
svPuMenu = new SVPopupMenu(this);
|
|
}
|
|
svPuMenu.add(parent, name, cmdEvent, value, desc);
|
|
}
|
|
|
|
/** Destroys a window. */
|
|
public void destroy() {
|
|
ScrollView.addMessage(new SVEvent(SVEventType.SVET_DESTROY, this, 0,
|
|
"SVET_DESTROY"));
|
|
setVisible(false);
|
|
// dispose();
|
|
}
|
|
}
|