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 }