001 /*
002 * $Id: JXDialog.java,v 1.6 2006/05/14 08:12:15 dmouse Exp $
003 *
004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020 */
021 package org.jdesktop.swingx;
022
023 import java.awt.Dimension;
024 import java.awt.Frame;
025 import java.awt.event.KeyEvent;
026
027 import javax.swing.Action;
028 import javax.swing.BorderFactory;
029 import javax.swing.Box;
030 import javax.swing.BoxLayout;
031 import javax.swing.InputMap;
032 import javax.swing.JButton;
033 import javax.swing.JComponent;
034 import javax.swing.JDialog;
035 import javax.swing.JPanel;
036 import javax.swing.KeyStroke;
037 import javax.swing.UIManager;
038 import javax.swing.plaf.basic.BasicOptionPaneUI;
039
040 import org.jdesktop.swingx.action.BoundAction;
041 import org.jdesktop.swingx.plaf.LookAndFeelAddons;
042
043 /**
044 * First cut for enhanced Dialog.
045 *
046 * <ul>
047 * <li> registers stand-in actions for close/execute with the dialog's RootPane
048 * <li> registers keyStrokes for esc/enter to trigger the close/execute actions
049 * <li> takes care of building the button panel using the close/execute actions.
050 * <li> accepts a content and configures itself from content's properties -
051 * replaces the execute action from the appropriate action in content's action map (if any)
052 * and set's its title from the content's name.
053 * </ul>
054 *
055 *
056 * PENDING: add support for vetoing the close.
057 * PENDING: add complete set of constructors
058 * PENDING: add windowListener to delegate to close action
059 *
060 * @author Jeanette Winzenburg
061 */
062 public class JXDialog extends JDialog {
063
064 static {
065 // Hack to enforce loading of SwingX framework ResourceBundle
066 LookAndFeelAddons.getAddon();
067 }
068
069 public static final String EXECUTE_ACTION_COMMAND = "execute";
070 public static final String CLOSE_ACTION_COMMAND = "close";
071 public static final String UIPREFIX = "XDialog.";
072
073 JComponent content;
074
075 public JXDialog(Frame frame, JComponent content) {
076 super(frame);
077 setContent(content);
078 }
079
080 private void setContent(JComponent content) {
081 if (this.content != null) {
082 throw new IllegalStateException("content must not be set more than once");
083 }
084 initActions();
085 Action contentCloseAction = content.getActionMap().get(CLOSE_ACTION_COMMAND);
086 if (contentCloseAction != null) {
087 putAction(CLOSE_ACTION_COMMAND, contentCloseAction);
088 }
089 Action contentExecuteAction = content.getActionMap().get(EXECUTE_ACTION_COMMAND);
090 if (contentExecuteAction != null) {
091 putAction(EXECUTE_ACTION_COMMAND, contentExecuteAction);
092 }
093 this.content = content;
094 build();
095 setTitle(content.getName());
096 }
097
098 /**
099 * pre: content != null.
100 *
101 */
102 private void build() {
103 JComponent contentBox = new Box(BoxLayout.PAGE_AXIS);
104 contentBox.add(content);
105 JComponent buttonPanel = createButtonPanel();
106 contentBox.add(buttonPanel);
107 contentBox.setBorder(BorderFactory.createEmptyBorder(14, 14, 14, 14));
108 // content.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
109
110 // fieldPanel.setAlignmentX();
111 // buttonPanel.setAlignmentX(Component.RIGHT_ALIGNMENT);
112 add(contentBox);
113
114 }
115
116 // /**
117 // *
118 // */
119 // private void locate() {
120 // GraphicsConfiguration gc =
121 // GraphicsEnvironment.getLocalGraphicsEnvironment().
122 // getDefaultScreenDevice().getDefaultConfiguration();
123 // Rectangle bounds = gc.getBounds();
124 // int x = bounds.x+bounds.width/3;
125 // int y = bounds.y+bounds.height/3;
126 //
127 // setLocation(x, y);
128 // }
129
130 public void setVisible(boolean visible) {
131 if (content == null) throw
132 new IllegalStateException("content must be built before showing the dialog");
133 super.setVisible(visible);
134 }
135
136 public void doClose() {
137 dispose();
138 }
139
140 private void initActions() {
141 // PENDING: factor a common dialog containing the following
142 Action defaultAction = createCloseAction();
143 putAction(CLOSE_ACTION_COMMAND, defaultAction);
144 putAction(EXECUTE_ACTION_COMMAND, defaultAction);
145 }
146
147 private Action createCloseAction() {
148 String actionName = getUIString(CLOSE_ACTION_COMMAND);
149 BoundAction action = new BoundAction(actionName,
150 CLOSE_ACTION_COMMAND);
151 action.registerCallback(this, "doClose");
152 return action;
153 }
154
155 /**
156 * create the dialog button controls.
157 *
158 *
159 * @return panel containing button controls
160 */
161 protected JComponent createButtonPanel() {
162 // PENDING: this is a hack until we have a dedicated ButtonPanel!
163 JPanel panel = new JPanel(new BasicOptionPaneUI.ButtonAreaLayout(true, 6))
164 {
165 public Dimension getMaximumSize() {
166 return getPreferredSize();
167 }
168 };
169
170 panel.setBorder(BorderFactory.createEmptyBorder(9, 0, 0, 0));
171 Action findAction = getAction(EXECUTE_ACTION_COMMAND);
172 Action closeAction = getAction(CLOSE_ACTION_COMMAND);
173
174 JButton findButton;
175 panel.add(findButton = new JButton(findAction));
176 panel.add(new JButton(closeAction));
177
178
179 KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false);
180 KeyStroke escapeKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
181
182 InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
183 inputMap.put(enterKey, EXECUTE_ACTION_COMMAND);
184 inputMap.put(escapeKey, CLOSE_ACTION_COMMAND);
185
186 getRootPane().setDefaultButton(findButton);
187 return panel;
188 }
189
190 /**
191 * convenience wrapper to access rootPane's actionMap.
192 * @param key
193 * @param action
194 */
195 private void putAction(Object key, Action action) {
196 getRootPane().getActionMap().put(key, action);
197 }
198
199 /**
200 * convenience wrapper to access rootPane's actionMap.
201 *
202 * @param key
203 * @return root pane's <code>ActionMap</code>
204 */
205 private Action getAction(Object key) {
206 return getRootPane().getActionMap().get(key);
207 }
208 /**
209 * tries to find a String value from the UIManager, prefixing the
210 * given key with the UIPREFIX.
211 *
212 * TODO: move to utilities?
213 *
214 * @param key
215 * @return the String as returned by the UIManager or key if the returned
216 * value was null.
217 */
218 private String getUIString(String key) {
219 String text = UIManager.getString(UIPREFIX + key);
220 return text != null ? text : key;
221 }
222
223
224 }