001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.Component; 008import java.awt.Container; 009import java.awt.Dimension; 010import java.awt.FlowLayout; 011import java.awt.GridBagLayout; 012import java.awt.Insets; 013import java.awt.event.ActionEvent; 014import java.awt.event.WindowAdapter; 015import java.awt.event.WindowEvent; 016 017import javax.swing.AbstractAction; 018import javax.swing.BorderFactory; 019import javax.swing.JButton; 020import javax.swing.JCheckBox; 021import javax.swing.JDialog; 022import javax.swing.JPanel; 023 024import org.openstreetmap.josm.actions.ExpertToggleAction; 025import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction; 026import org.openstreetmap.josm.gui.help.HelpUtil; 027import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener; 028import org.openstreetmap.josm.gui.util.GuiHelper; 029import org.openstreetmap.josm.tools.GBC; 030import org.openstreetmap.josm.tools.ImageProvider; 031import org.openstreetmap.josm.tools.InputMapUtils; 032import org.openstreetmap.josm.tools.WindowGeometry; 033 034public class PreferenceDialog extends JDialog { 035 036 private final PreferenceTabbedPane tpPreferences = new PreferenceTabbedPane(); 037 private boolean canceled; 038 039 /** 040 * Constructs a new {@code PreferenceDialog}. 041 * @param parent parent component 042 */ 043 public PreferenceDialog(Component parent) { 044 super(GuiHelper.getFrameForComponent(parent), tr("Preferences"), ModalityType.DOCUMENT_MODAL); 045 build(); 046 this.setMinimumSize(new Dimension(600, 350)); 047 // set the maximum width to the current screen. If the dialog is opened on a 048 // smaller screen than before, this will reset the stored preference. 049 this.setMaximumSize(GuiHelper.getScreenSize()); 050 } 051 052 protected JPanel buildActionPanel() { 053 JPanel pnl = new JPanel(new GridBagLayout()); 054 055 JCheckBox expert = new JCheckBox(tr("Expert mode")); 056 expert.setSelected(ExpertToggleAction.isExpert()); 057 expert.addActionListener(e -> ExpertToggleAction.getInstance().actionPerformed(null)); 058 059 JPanel btns = new JPanel(new FlowLayout(FlowLayout.CENTER)); 060 btns.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 061 btns.add(new JButton(new OKAction())); 062 btns.add(new JButton(new CancelAction())); 063 btns.add(new JButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Action/Preferences")))); 064 pnl.add(expert, GBC.std().insets(5, 0, 0, 0)); 065 pnl.add(btns, GBC.std().fill(GBC.HORIZONTAL)); 066 return pnl; 067 } 068 069 protected final void build() { 070 Container c = getContentPane(); 071 c.setLayout(new BorderLayout()); 072 c.add(tpPreferences, BorderLayout.CENTER); 073 tpPreferences.buildGui(); 074 tpPreferences.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 075 c.add(buildActionPanel(), BorderLayout.SOUTH); 076 077 addWindowListener(new WindowEventHandler()); 078 079 InputMapUtils.addEscapeAction(getRootPane(), new CancelAction()); 080 HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Action/Preferences")); 081 } 082 083 /** 084 * Replies the preferences tabbed pane. 085 * @return The preferences tabbed pane, or null if the dialog is not yet initialized. 086 * @since 5604 087 */ 088 public PreferenceTabbedPane getTabbedPane() { 089 return tpPreferences; 090 } 091 092 public boolean isCanceled() { 093 return canceled; 094 } 095 096 protected void setCanceled(boolean canceled) { 097 this.canceled = canceled; 098 } 099 100 @Override 101 public void setVisible(boolean visible) { 102 if (visible) { 103 // Make the pref window at most as large as the parent JOSM window 104 // Have to take window decorations into account or the windows will 105 // be too large 106 Insets i = this.getParent().getInsets(); 107 Dimension p = this.getParent().getSize(); 108 p = new Dimension(Math.min(p.width-i.left-i.right, 700), 109 Math.min(p.height-i.top-i.bottom, 800)); 110 new WindowGeometry( 111 getClass().getName() + ".geometry", 112 WindowGeometry.centerInWindow( 113 getParent(), 114 p 115 ) 116 ).applySafe(this); 117 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775 118 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 119 } 120 super.setVisible(visible); 121 } 122 123 /** 124 * Select preferences tab by name. 125 * @param name preferences tab name (icon) 126 */ 127 public void selectPreferencesTabByName(String name) { 128 tpPreferences.selectTabByName(name); 129 } 130 131 /** 132 * Select preferences tab by class. 133 * @param clazz preferences tab class 134 */ 135 public void selectPreferencesTabByClass(Class<? extends TabPreferenceSetting> clazz) { 136 tpPreferences.selectTabByPref(clazz); 137 } 138 139 /** 140 * Select preferences sub-tab by class. 141 * @param clazz preferences sub-tab class 142 */ 143 public void selectSubPreferencesTabByClass(Class<? extends SubPreferenceSetting> clazz) { 144 tpPreferences.selectSubTabByPref(clazz); 145 } 146 147 class CancelAction extends AbstractAction { 148 CancelAction() { 149 putValue(NAME, tr("Cancel")); 150 new ImageProvider("cancel").getResource().attachImageIcon(this); 151 putValue(SHORT_DESCRIPTION, tr("Close the preferences dialog and discard preference updates")); 152 } 153 154 public void cancel() { 155 setCanceled(true); 156 setVisible(false); 157 tpPreferences.validationListeners.clear(); 158 } 159 160 @Override 161 public void actionPerformed(ActionEvent evt) { 162 cancel(); 163 } 164 } 165 166 class OKAction extends AbstractAction { 167 OKAction() { 168 putValue(NAME, tr("OK")); 169 new ImageProvider("ok").getResource().attachImageIcon(this); 170 putValue(SHORT_DESCRIPTION, tr("Save the preferences and close the dialog")); 171 } 172 173 @Override 174 public void actionPerformed(ActionEvent evt) { 175 for (ValidationListener listener: tpPreferences.validationListeners) { 176 if (!listener.validatePreferences()) 177 return; 178 } 179 180 tpPreferences.savePreferences(); 181 tpPreferences.validationListeners.clear(); 182 setCanceled(false); 183 setVisible(false); 184 } 185 } 186 187 class WindowEventHandler extends WindowAdapter { 188 @Override 189 public void windowClosing(WindowEvent arg0) { 190 new CancelAction().cancel(); 191 } 192 } 193}