/*
* This file is part of Caliph & Emir.
*
* Caliph & Emir is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Caliph & Emir 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with Caliph & Emir; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright statement:
* --------------------
* (c) 2005 by Werner Klieber (werner@klieber.info)
* http://caliph-emir.sourceforge.net
*/
package at.wklieber.tools;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* Provides a reusable window that presents a message and
* choice buttons to the user. A modal dialog is used.
* Since a thread is used to set the dialog to visible,
* when the client calls ask() it will not block.
* <p/>
* The client may implement ActionListener, which has:
* public void actionPerformed(ActionEvent evt)
* if user response notification is desired.
*/
public class MessageBox implements Runnable,
ActionListener, WindowListener, KeyListener {
//---------- Private Fields ------------------------------
private ActionListener listener;
private JDialog dialog;
private String closeWindowCommand = "CloseRequested";
private String title;
private Frame frame;
private boolean frameNotProvided;
private JPanel buttonPanel = null;
private Canvas imageCanvas;
//---------- Initialization ------------------------------
/**
* This convenience constructor is used to delare the
* listener that will be notified when a button is clicked.
* The listener must implement ActionListener.
*/
public MessageBox(ActionListener listener) {
this();
this.listener = listener;
}
/**
* This constructor is used for no listener, such as for
* a simple okay dialog.
*/
public MessageBox() {
}
// Unit test. Shows only simple features.
public static void main(String args[]) {
MessageBox box = new MessageBox();
box.setTitle("Test MessageBox");
box.useImageCanvas("LightBulb.gif");
box.askYesNo("Tell me now.\nDo you like Java?");
}
/**
* print a Messagebox with a title, the message and an ok button
*/
public static void displayMessage(String title, String message) {
MessageBox box = new MessageBox();
box.setTitle(title);
//box.useImageCanvas("LightBulb.gif");
box.askOkay(message);
}
/**
* print a Messagebox with a title, the message and an cancel button
*/
public static void displayCancelMessage(String title, String message) {
MessageBox box = new MessageBox();
box.setTitle(title);
//box.useImageCanvas("LightBulb.gif");
//Dialog returnValue = box.getDialog();
box.askCancel(message);
//box.getDialog();
}
//---------- Runnable Implementation ---------------------
/**
* This prevents the caller from blocking on ask(), which
* if this class is used on an awt event thread would
* cause a deadlock.
*/
//public void run() {
// dialog.setVisible(true);
//}
//---------- ActionListener Implementation ---------------
public void actionPerformed(ActionEvent evt) {
String command = evt.getActionCommand();
if (dialog != null) {
dialog.setVisible(false);
dialog.dispose();
}
if (frameNotProvided) frame.dispose();
if (listener != null) {
listener.actionPerformed(evt);
}
}
//---------- WindowListener Implementatons ---------------
public void windowClosing(WindowEvent evt) {
// User clicked on X or chose Close selection
fireCloseRequested();
}
public Dialog getDialog() {
return dialog;
}
public void windowClosed(WindowEvent evt) {
}
public void windowDeiconified(WindowEvent evt) {
}
public void windowIconified(WindowEvent evt) {
}
public void windowOpened(WindowEvent evt) {
}
public void windowActivated(WindowEvent evt) {
}
public void windowDeactivated(WindowEvent evt) {
}
//---------- KeyListener Implementation ------------------
public void keyTyped(KeyEvent evt) {
}
public void keyPressed(KeyEvent evt) {
if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) {
fireCloseRequested();
}
}
public void keyReleased(KeyEvent evt) {
}
private void fireCloseRequested() {
ActionEvent event = new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, closeWindowCommand);
actionPerformed(event);
}
//---------- Public Methods ------------------------------
/**
* This set the listener to be notified of button clicks
* and WindowClosing events.
*/
public void setActionListener(ActionListener listener) {
this.listener = listener;
}
public void setTitle(String title) {
this.title = title;
}
/**
* If a Frame is provided then it is used to instantiate
* the modal Dialog. Otherwise a temporary Frame is used.
* Providing a Frame will have the effect of putting the
* focus back on that Frame when the MessageBox is closed
* or a button is clicked.
*/
public void setFrame(Frame frame) { // Optional
this.frame = frame;
}
/**
* Sets the ActionCommand used in the ActionEvent when the
* user attempts to close the window. The window may be
* closed by clicking on "X", choosing Close from the
* window menu, or pressing the Escape key. The default
* command is "CloseRequested", which is just what a Close
* choice button would probably have as a command.
*/
public void setCloseWindowCommand(String command) {
closeWindowCommand = command;
}
/**
* This is handy for providing a small image that will be
* displayed to the left of the message.
*/
public void useImageCanvas(Canvas imageCanvas) {
this.imageCanvas = imageCanvas;
}
/**
* This loads the image from the specified @param fileName,
* which must be in the same directory as this class.
* For example @param fileName might be "LightBulb.gif".
*/
public void useImageCanvas(String fileName) {
try {
//ImageCanvas imageCanvas = new ImageCanvas(MessageBox.class, fileName);
//useImageCanvas(imageCanvas);
} catch (Exception ex) {
print("MessageBox.helpfulHint() - Cannot load image " + fileName);
ex.printStackTrace();
}
}
/**
* The @param label will be used for the button and the
*
* @param command will be returned to the listener.
*/
public void addChoice(String label, String command) {
if (buttonPanel == null) {
buttonPanel = new JPanel();
}
Button button = new Button(label);
button.setActionCommand(command);
button.addActionListener(this);
button.addKeyListener(this);
buttonPanel.add(button);
buttonPanel.repaint();
}
/**
* A convenience method that assumes the command is the
* same as the label.
*/
public void addChoice(String label) {
addChoice(label, label);
}
/**
* One of the "ask" methods must be the last call when
* using a MessageBox. This is the simplest "ask" method.
* It presents the provided @param message.
*/
public void ask(String message) {
if (frame == null) {
frame = new Frame();
frameNotProvided = true;
} else {
frameNotProvided = false;
}
if (buttonPanel == null) {
buttonPanel = new JPanel();
}
dialog = new JDialog(frame, true); // Modal
dialog.addWindowListener(this);
dialog.addKeyListener(this);
dialog.setTitle(title);
dialog.getContentPane().setLayout(new BorderLayout(5, 5));
JPanel messagePanel = createMultiLinePanel(message);
if (imageCanvas == null) {
dialog.getContentPane().add("Center", messagePanel);
} else {
JPanel centerPanel = new JPanel();
centerPanel.add(imageCanvas);
centerPanel.add(messagePanel);
dialog.getContentPane().add("Center", centerPanel);
}
//buttonPanel.setLayout();
dialog.getContentPane().add("South", buttonPanel);
dialog.getContentPane().repaint();
dialog.pack();
enforceMinimumSize(dialog, 200, 100);
centerWindow(dialog);
Toolkit.getDefaultToolkit().beep();
dialog.validate();
dialog.repaint();
// Start a new thread to show the dialog
//Thread thread = new Thread(this);
//thread.start();
dialog.setVisible(true);
}
/**
* Same as ask(String message) except adds an "Okay" button.
*/
public void askOkay(String message) {
addChoice("Okay");
ask(message);
}
/**
* Same as ask(String message) except adds "Yes" and "No"
* buttons.
*/
public void askYesNo(String message) {
addChoice("Yes");
addChoice("No");
ask(message);
}
/**
* Same as ask(String message) except adds "Cancel"
* buttons.
*/
public void askCancel(String message) {
addChoice("Cancel");
ask(message);
}
//---------- Private Methods -----------------------------
private JPanel createMultiLinePanel(String message) {
JPanel mainPanel = new JPanel();
GridBagLayout gbLayout = new GridBagLayout();
mainPanel.setLayout(gbLayout);
addMultilineString(message, mainPanel);
return mainPanel;
}
// There are a variaty of ways to do this....
private void addMultilineString(String message,
Container container) {
GridBagConstraints constraints = getDefaultConstraints();
constraints.gridwidth = GridBagConstraints.REMAINDER;
// Insets() args are top, left, bottom, right
constraints.insets = new Insets(0, 0, 0, 0);
GridBagLayout gbLayout = (GridBagLayout) container.getLayout();
while (message.length() > 0) {
int newLineIndex = message.indexOf('\n');
String line;
if (newLineIndex >= 0) {
line = message.substring(0, newLineIndex);
message = message.substring(newLineIndex + 1);
} else {
line = message;
message = "";
}
Label label = new Label(line);
gbLayout.setConstraints(label, constraints);
container.add(label);
}
}
private GridBagConstraints getDefaultConstraints() {
GridBagConstraints constraints = new GridBagConstraints();
constraints.weightx = 1.0;
constraints.weighty = 1.0;
constraints.gridheight = 1; // One row high
// Insets() args are top, left, bottom, right
constraints.insets = new Insets(4, 4, 4, 4);
// fill of NONE means do not change size
constraints.fill = GridBagConstraints.NONE;
// WEST means align left
constraints.anchor = GridBagConstraints.WEST;
return constraints;
}
private void centerWindow(Window win) {
Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
// If larger than screen, reduce window width or height
if (screenDim.width < win.getSize().width) {
win.setSize(screenDim.width, win.getSize().height);
}
if (screenDim.height < win.getSize().height) {
win.setSize(win.getSize().width, screenDim.height);
}
// Center Frame, Dialogue or Window on screen
int x = (screenDim.width - win.getSize().width) / 2;
int y = (screenDim.height - win.getSize().height) / 2;
win.setLocation(x, y);
}
private void enforceMinimumSize(Component comp,
int minWidth, int minHeight) {
if (comp.getSize().width < minWidth) {
comp.setSize(minWidth, comp.getSize().height);
}
if (comp.getSize().height < minHeight) {
comp.setSize(comp.getSize().width, minHeight);
}
}
//--- Std
private static void print(String text) {
System.out.println(text);
}
public void run() {
}
} // End class