org.jdesktop.swingx.JXDialog Maven / Gradle / Ivy
/*
* $Id: JXDialog.java 4172 2012-04-17 14:54:00Z kschaefe $
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jdesktop.swingx;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Window;
import java.util.Locale;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.plaf.basic.BasicOptionPaneUI;
import org.jdesktop.beans.JavaBean;
import org.jdesktop.swingx.action.BoundAction;
import org.jdesktop.swingx.plaf.LookAndFeelAddons;
import org.jdesktop.swingx.plaf.UIManagerExt;
/**
* First cut for enhanced Dialog. The idea is to have a pluggable content
* from which the dialog auto-configures all its "dialogueness".
*
*
* - accepts a content and configures itself from content's properties -
* replaces the execute action from the appropriate action in content's action map (if any)
* and set's its title from the content's name.
*
- registers stand-in actions for close/execute with the dialog's RootPane
*
- registers keyStrokes for esc/enter to trigger the close/execute actions
*
- takes care of building the button panel using the close/execute actions.
*
*
*
* - TODO: add link to forum discussion, wiki summary?
*
- PENDING: add support for vetoing the close.
*
- PENDING: add complete set of constructors
*
- PENDING: add windowListener to delegate to close action
*
*
* @author Jeanette Winzenburg
* @author Karl Schaefer
*/
@JavaBean
public class JXDialog extends JDialog {
static {
// Hack to enforce loading of SwingX framework ResourceBundle
LookAndFeelAddons.getAddon();
}
public static final String EXECUTE_ACTION_COMMAND = "execute";
public static final String CLOSE_ACTION_COMMAND = "close";
public static final String UIPREFIX = "XDialog.";
protected JComponent content;
/**
* Creates a non-modal dialog with the given component as
* content and without specified owner. A shared, hidden frame will be
* set as the owner of the dialog.
*
* @param content the component to show and to auto-configure from.
*/
public JXDialog(JComponent content) {
super();
setContent(content);
}
/**
* Creates a non-modal dialog with the given component as content and the
* specified Frame
as owner.
*
* @param frame the owner
* @param content the component to show and to auto-configure from.
*/
public JXDialog(Frame frame, JComponent content) {
super(frame);
setContent(content);
}
/**
* Creates a non-modal dialog with the given component as content and the
* specified Dialog
as owner.
*
* @param dialog the owner
* @param content the component to show and to auto-configure from.
*/
public JXDialog(Dialog dialog, JComponent content) {
super(dialog);
setContent(content);
}
/**
* Creates a non-modal dialog with the given component as content and the
* specified Window
as owner.
*
* @param window the owner
* @param content the component to show and to auto-configure from.
*/
public JXDialog(Window window, JComponent content) {
super(window);
setContentPane(content);
}
/**
* {@inheritDoc}
*/
@Override
protected JXRootPane createRootPane() {
return new JXRootPane();
}
/**
* {@inheritDoc}
*/
@Override
public JXRootPane getRootPane() {
return (JXRootPane) super.getRootPane();
}
/**
* Sets the status bar property on the underlying {@code JXRootPane}.
*
* @param statusBar
* the {@code JXStatusBar} which is to be the status bar
* @see #getStatusBar()
* @see JXRootPane#setStatusBar(JXStatusBar)
*/
public void setStatusBar(JXStatusBar statusBar) {
getRootPane().setStatusBar(statusBar);
}
/**
* Returns the value of the status bar property from the underlying
* {@code JXRootPane}.
*
* @return the {@code JXStatusBar} which is the current status bar
* @see #setStatusBar(JXStatusBar)
* @see JXRootPane#getStatusBar()
*/
public JXStatusBar getStatusBar() {
return getRootPane().getStatusBar();
}
/**
* Sets the tool bar property on the underlying {@code JXRootPane}.
*
* @param toolBar
* the {@code JToolBar} which is to be the tool bar
* @see #getToolBar()
* @see JXRootPane#setToolBar(JToolBar)
*/
public void setToolBar(JToolBar toolBar) {
getRootPane().setToolBar(toolBar);
}
/**
* Returns the value of the tool bar property from the underlying
* {@code JXRootPane}.
*
* @return the {@code JToolBar} which is the current tool bar
* @see #setToolBar(JToolBar)
* @see JXRootPane#getToolBar()
*/
public JToolBar getToolBar() {
return getRootPane().getToolBar();
}
/**
* PENDING: widen access - this could be public to make the content really
* pluggable?
*
* @param content
*/
private void setContent(JComponent content) {
if (this.content != null) {
throw new IllegalStateException("content must not be set more than once");
}
initActions();
Action contentCloseAction = content.getActionMap().get(CLOSE_ACTION_COMMAND);
if (contentCloseAction != null) {
putAction(CLOSE_ACTION_COMMAND, contentCloseAction);
}
Action contentExecuteAction = content.getActionMap().get(EXECUTE_ACTION_COMMAND);
if (contentExecuteAction != null) {
putAction(EXECUTE_ACTION_COMMAND, contentExecuteAction);
}
this.content = content;
build();
setTitleFromContent();
}
/**
* Infers and sets this dialog's title from the the content.
* Does nothing if content is null.
*
* Here: uses the content's name as title.
*/
protected void setTitleFromContent() {
if (content == null) return;
setTitle(content.getName());
}
/**
* pre: content != null.
*
*/
private void build() {
JComponent contentBox = new Box(BoxLayout.PAGE_AXIS);
contentBox.add(content);
JComponent buttonPanel = createButtonPanel();
contentBox.add(buttonPanel);
contentBox.setBorder(BorderFactory.createEmptyBorder(14, 14, 14, 14));
// content.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
// fieldPanel.setAlignmentX();
// buttonPanel.setAlignmentX(Component.RIGHT_ALIGNMENT);
add(contentBox);
}
/**
* {@inheritDoc}
*
* Overridden to check if content is available.
* PENDING: doesn't make sense - the content is immutable and guaranteed
* to be not null.
*/
@Override
public void setVisible(boolean visible) {
if (content == null) throw
new IllegalStateException("content must be built before showing the dialog");
super.setVisible(visible);
}
//------------------------ dynamic locale support
/**
* {@inheritDoc}
*
* Overridden to set the content's Locale and then updated
* this dialog's internal state.
*
*
*/
@Override
public void setLocale(Locale l) {
/*
* NOTE: this is called from super's constructor as one of the
* first methods (prior to setting the rootPane!). So back out
*
*/
if (content != null) {
content.setLocale(l);
updateLocaleState(l);
}
super.setLocale(l);
}
/**
* Updates this dialog's locale-dependent state.
*
* Here: updates title and actions.
*
*
*
* @see #setLocale(Locale)
*/
protected void updateLocaleState(Locale locale) {
setTitleFromContent();
for (Object key : getRootPane().getActionMap().allKeys()) {
if (key instanceof String) {
Action contentAction = content.getActionMap().get(key);
Action rootPaneAction = getAction(key);
if ((!rootPaneAction.equals(contentAction))) {
String keyString = getUIString((String) key, locale);
if (!key.equals(keyString)) {
rootPaneAction.putValue(Action.NAME, keyString);
}
}
}
}
}
/**
* The callback method executed when closing the dialog.
* Here: calls dispose.
*
*/
public void doClose() {
dispose();
}
private void initActions() {
Action defaultAction = createCloseAction();
putAction(CLOSE_ACTION_COMMAND, defaultAction);
putAction(EXECUTE_ACTION_COMMAND, defaultAction);
}
private Action createCloseAction() {
String actionName = getUIString(CLOSE_ACTION_COMMAND);
BoundAction action = new BoundAction(actionName,
CLOSE_ACTION_COMMAND);
action.registerCallback(this, "doClose");
return action;
}
/**
* create the dialog button controls.
*
*
* @return panel containing button controls
*/
protected JComponent createButtonPanel() {
// PENDING: this is a hack until we have a dedicated ButtonPanel!
JPanel panel = new JPanel(new BasicOptionPaneUI.ButtonAreaLayout(true, 6))
{
@Override
public Dimension getMaximumSize() {
return getPreferredSize();
}
};
panel.setBorder(BorderFactory.createEmptyBorder(9, 0, 0, 0));
Action executeAction = getAction(EXECUTE_ACTION_COMMAND);
Action closeAction = getAction(CLOSE_ACTION_COMMAND);
JButton defaultButton = new JButton(executeAction);
panel.add(defaultButton);
getRootPane().setDefaultButton(defaultButton);
if (executeAction != closeAction) {
JButton b = new JButton(closeAction);
panel.add(b);
getRootPane().setCancelButton(b);
}
return panel;
}
/**
* convenience wrapper to access rootPane's actionMap.
* @param key
* @param action
*/
private void putAction(Object key, Action action) {
getRootPane().getActionMap().put(key, action);
}
/**
* convenience wrapper to access rootPane's actionMap.
*
* @param key
* @return root pane's ActionMap
*/
private Action getAction(Object key) {
return getRootPane().getActionMap().get(key);
}
/**
* Returns a potentially localized value from the UIManager. The given key
* is prefixed by this component|s UIPREFIX
before doing the
* lookup. The lookup respects this table's current locale
* property. Returns the key, if no value is found.
*
* @param key the bare key to look up in the UIManager.
* @return the value mapped to UIPREFIX + key or key if no value is found.
*/
protected String getUIString(String key) {
return getUIString(key, getLocale());
}
/**
* Returns a potentially localized value from the UIManager for the
* given locale. The given key
* is prefixed by this component's UIPREFIX
before doing the
* lookup. Returns the key, if no value is found.
*
* @param key the bare key to look up in the UIManager.
* @param locale the locale use for lookup
* @return the value mapped to UIPREFIX + key in the given locale,
* or key if no value is found.
*/
protected String getUIString(String key, Locale locale) {
String text = UIManagerExt.getString(UIPREFIX + key, locale);
return text != null ? text : key;
}
}