/*
* RapidMiner
*
* Copyright (C) 2001-2011 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.tools.dialogs;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.LinkedList;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.rapidminer.gui.ApplicationFrame;
import com.rapidminer.gui.tools.ResourceAction;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.gui.tools.components.FixedWidthLabel;
import com.rapidminer.tools.I18N;
/** Dialog that provides some helper methods to create buttons. Automatically registers accelerators
* and action listeners. Override {@link #ok()}, {@link #cancel()} and {@link #close()} to customize
* the behaviour.
*
* The user can query if the ok button was pressed ({@link #wasConfirmed}).
* @author Simon Fischer
*/
public class ButtonDialog extends JDialog {
private static final long serialVersionUID = 1L;
private String key = null;
protected boolean wasConfirmed = false;
public static final int NORMAL = 1;
public static final int NARROW = 2;
public static final int LARGE = 3;
public static final int HUGE = 9;
public static final int MESSAGE = 4;
public static final int MESSAGE_EXTENDED = 5;
public static final int DEFAULT_SIZE = 8;
public static final int GAP = 6;
protected static final Insets INSETS = new Insets(GAP, GAP, GAP, GAP);
protected FixedWidthLabel infoTextLabel = null;
/**
* Arguments which will replace the place holder in the
* I18n-Properties message. The first argument will replace
* <code>{0}</code>, the second <code>{1}</code> and so on.
*/
protected final Object[] arguments;
private Component centerComponent;
private final LinkedList<ChangeListener> listeners = new LinkedList<ChangeListener>();
/**
* The key will be used for the properties gui.dialog.-key-.title and
* gui.dialog.-key-.icon
*/
public ButtonDialog(String key, Object ... arguments) {
super(ApplicationFrame.getApplicationFrame(), I18N.getMessage(I18N.getGUIBundle(), "gui.dialog." + key + ".title", arguments), false);
this.arguments = arguments;
configure(key);
pack();
}
/**
* The key will be used for the properties gui.dialog.-key-.title and
* gui.dialog.-key-.icon
*/
public ButtonDialog(String key, boolean modal, Object ... arguments) {
super(ApplicationFrame.getApplicationFrame(), I18N.getMessage(I18N.getGUIBundle(), "gui.dialog." + key + ".title", arguments), modal);
this.arguments = arguments;
configure(key);
pack();
}
/**
* The key will be used for the properties gui.dialog.-key-.title and
* gui.dialog.-key-.icon
*/
public ButtonDialog(String key, ModalityType type, Object ... arguments) {
super(ApplicationFrame.getApplicationFrame(), I18N.getMessage(I18N.getGUIBundle(), "gui.dialog." + key + ".title", arguments), type);
this.arguments = arguments;
configure(key);
pack();
}
/**
* @param key Key for the message in the I18n-GUI-properties file
* @param arguments Arguments which will replace the place holder in the
* I18n-Properties message. The first argument will replace
* <code>{0}</code>, the second <code>{1}</code> and so on.
* @deprecated
*/
@Deprecated
public ButtonDialog(Dialog owner, String key, boolean modal, Object... arguments ) {
this(key, modal, arguments);
// super(owner, I18N.getMessage(I18N.getGUIBundle(), "gui.dialog." + key + ".title"), modal);
// this.arguments = arguments;
// configure(key);
}
/**
* @param key Key for the message in the I18n-GUI-properties file
* @param arguments Arguments which will replace the place holder in the
* I18n-Properties message. The first argument will replace
* <code>{0}</code>, the second <code>{1}</code> and so on.
* @deprecated
*/
@Deprecated
public ButtonDialog(Dialog owner, String key, Object... arguments ) {
this(key, arguments);
// super(owner, I18N.getMessage(I18N.getGUIBundle(), "gui.dialog." + key + ".title"));
// this.arguments = arguments;
// configure(key);
}
/**
* @param key Key for the message in the I18n-GUI-properties file
* @param arguments Arguments which will replace the place holder in the
* I18n-Properties message. The first argument will replace
* <code>{0}</code>, the second <code>{1}</code> and so on.
* @deprecated
*/
@Deprecated
public ButtonDialog(Frame owner, String key, boolean modal, Object... arguments ) {
this(key, modal, arguments);
// super(owner, I18N.getMessage(I18N.getGUIBundle(), "gui.dialog." + key + ".title"), modal);
// this.arguments = arguments;
// configure(key);
}
/**
* @param key Key for the message in the I18n-GUI-properties file
* @param arguments Arguments which will replace the place holder in the
* I18n-Properties message. The first argument will replace
* <code>{0}</code>, the second <code>{1}</code> and so on.
* @deprecated
*/
@Deprecated
public ButtonDialog(Frame owner, String key, Object... arguments ) {
this(key, arguments);
// super(owner, I18N.getMessage(I18N.getGUIBundle(), "gui.dialog." + key + ".title"));
// this.arguments = arguments;
// configure(key);
}
private void configure(String key) {
this.key = key;
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
protected final String getKey() {
return "gui.dialog." + key;
}
/**
* Returns the internationalized info text for this dialog.
* Argument formation is already applied.
*/
protected String getInfoText() {
return I18N.getMessage(I18N.getGUIBundle(), getKey() + ".message", this.arguments);
}
protected Icon getInfoIcon() {
return SwingTools.createIcon("48/" + I18N.getMessage(I18N.getGUIBundle(), getKey() + ".icon"));
}
/**
* Returns the internationalized title for this dialog.
* Argument formation is already applied.
*/
protected String getDialogTitle() {
return I18N.getMessage(I18N.getGUIBundle(), getKey() + ".title", this.arguments);
}
private JPanel makeInfoPanel() {
return makeInfoPanel(getInfoText(), getInfoIcon());
}
private JPanel makeInfoPanel(String message, Icon icon) {
JLabel infoIcon = new JLabel(icon);
infoIcon.setVerticalAlignment(SwingConstants.TOP);
JPanel infoPanel = new JPanel(new BorderLayout(20, 0));
infoPanel.setBorder(BorderFactory.createEmptyBorder(12, 16, 16, 4));
infoPanel.add(infoIcon, BorderLayout.WEST);
int width;
if (centerComponent!= null) {
width = (int) centerComponent.getPreferredSize().getWidth() - 88; // icon plus padding
if (width < 420) {
width = 420;
}
} else {
width = 420;
}
infoTextLabel = new FixedWidthLabel(width, message);
infoPanel.add(infoTextLabel, BorderLayout.CENTER);
return infoPanel;
}
protected void layoutDefault(JComponent centerComponent, int size, Collection<AbstractButton> buttons) {
layoutDefault(centerComponent, size, buttons.toArray(new AbstractButton[buttons.size()]));
}
protected void layoutDefault(JComponent centerComponent, Collection<AbstractButton> buttons) {
layoutDefault(centerComponent, DEFAULT_SIZE, buttons.toArray(new AbstractButton[buttons.size()]));
}
protected void layoutDefault(JComponent centerComponent, AbstractButton ... buttons) {
layoutDefault(centerComponent, DEFAULT_SIZE, buttons);
}
protected void layoutDefault(JComponent centerComponent, int size, AbstractButton ... buttons) {
layoutDefault(centerComponent, makeButtonPanel(buttons), size);
}
protected void layoutDefault(final JComponent centerComponent, JPanel buttonPanel) {
layoutDefault(centerComponent, buttonPanel, DEFAULT_SIZE);
}
protected void layoutDefault(final JComponent centerComponent, JPanel buttonPanel, int size) {
this.centerComponent = centerComponent;
setTitle(getDialogTitle());
setLayout(new BorderLayout());
add(makeInfoPanel(), BorderLayout.NORTH);
if (centerComponent != null) {
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.setBorder(BorderFactory.createEmptyBorder(0, GAP, 0, GAP));
centerPanel.add(centerComponent, BorderLayout.CENTER);
add(centerPanel, BorderLayout.CENTER);
}
add(buttonPanel, BorderLayout.SOUTH);
this.addComponentListener(new ComponentListener() {
@Override
public void componentHidden(ComponentEvent e) {}
@Override
public void componentMoved(ComponentEvent e) {}
@Override
public void componentResized(ComponentEvent e) {
if ((infoTextLabel != null) && (centerComponent != null)) {
infoTextLabel.setWidth(centerComponent.getWidth() - 88);
}
}
@Override
public void componentShown(ComponentEvent e) {}
});
switch (size) {
case DEFAULT_SIZE:
break;
default:
setPreferredSize(getDefaultSize(size));
break;
}
pack();
setDefaultLocation();
}
protected void setDefaultLocation() {
setLocationRelativeTo(ApplicationFrame.getApplicationFrame());
}
protected void setDefaultSize() {
setDefaultSize(NORMAL);
}
protected Dimension getDefaultSize(int size) {
switch (size) {
case NARROW:
return new Dimension(360, 540);
case NORMAL:
return new Dimension(720, 540);
case LARGE:
return new Dimension(800, 600);
case HUGE:
return new Dimension(1000,760);
case MESSAGE:
return new Dimension(600, 200);
case MESSAGE_EXTENDED:
return new Dimension(600, 400);
default:
return new Dimension(420, 300);
}
}
protected void setDefaultSize(int size) {
if (size != DEFAULT_SIZE) {
setPreferredSize(getDefaultSize(size));
}
pack();
}
protected JPanel makeButtonPanel(Collection<AbstractButton> buttons) {
return makeButtonPanel(buttons.toArray(new AbstractButton[buttons.size()]));
}
protected JPanel makeButtonPanel(AbstractButton ... buttons) {
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, GAP, GAP));
for (AbstractButton button : buttons) {
if (button != null) {
buttonPanel.add(button);
}
}
return buttonPanel;
}
/** Will be default button. */
protected JButton makeOkButton() {
return makeOkButton("ok");
}
protected JButton makeOkButton(String i18nKey) {
Action okAction = new ResourceAction(i18nKey) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
wasConfirmed = true;
ok();
}
};
JButton button = new JButton(okAction);
getRootPane().setDefaultButton(button);
return button;
}
/** Will listen to ESCAPE. */
protected JButton makeCancelButton() {
return makeCancelButton("cancel");
}
protected JButton makeCancelButton(String i18nKey) {
Action cancelAction = new ResourceAction(i18nKey) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
wasConfirmed = false;
cancel();
}
};
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "CANCEL");
getRootPane().getActionMap().put("CANCEL", cancelAction);
return new JButton(cancelAction);
}
/** Will be default button and listen to ESCAPE. */
protected JButton makeCloseButton() {
Action Action = new ResourceAction("close") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
wasConfirmed = false;
close();
}
};
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "CLOSE");
getRootPane().getActionMap().put("CLOSE", Action);
JButton button = new JButton(Action);
getRootPane().setDefaultButton(button);
return button;
}
protected void cancel() {
dispose();
}
protected void ok() {
dispose();
}
protected void close() {
dispose();
}
/** Returns true iff the user pressed the generated ok button. */
public boolean wasConfirmed() {
return wasConfirmed;
}
protected void setConfirmed(boolean b) {
this.wasConfirmed = b;
}
public static TitledBorder createTitledBorder(String title) {
TitledBorder border = new TitledBorder(createBorder(), title) {
private static final long serialVersionUID = 3113821577644055057L;
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
super.paintBorder(c, g, x - EDGE_SPACING, y, width + 2 * EDGE_SPACING, height);
}
};
return border;
}
public static Border createBorder() {
return BorderFactory.createMatteBorder(1, 1, 1, 1, Color.LIGHT_GRAY);
}
public static GridLayout createGridLayout(int rows, int columns) {
return new GridLayout(rows, columns, GAP, GAP);
}
public void addChangeListener(ChangeListener l) {
listeners.add(l);
}
public void removeChangeListener(ChangeListener l) {
listeners.remove(l);
}
protected void fireStateChanged() {
ChangeEvent e = new ChangeEvent(this);
for (ChangeListener l : listeners) {
l.stateChanged(e);
}
}
}