// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui.preferences;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import org.openstreetmap.josm.actions.ExpertToggleAction;
import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
import org.openstreetmap.josm.gui.help.HelpUtil;
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
import org.openstreetmap.josm.gui.util.GuiHelper;
import org.openstreetmap.josm.tools.GBC;
import org.openstreetmap.josm.tools.ImageProvider;
import org.openstreetmap.josm.tools.InputMapUtils;
import org.openstreetmap.josm.tools.WindowGeometry;
public class PreferenceDialog extends JDialog {
private final PreferenceTabbedPane tpPreferences = new PreferenceTabbedPane();
private boolean canceled;
/**
* Constructs a new {@code PreferenceDialog}.
* @param parent parent component
*/
public PreferenceDialog(Component parent) {
super(GuiHelper.getFrameForComponent(parent), tr("Preferences"), ModalityType.DOCUMENT_MODAL);
build();
this.setMinimumSize(new Dimension(600, 350));
// set the maximum width to the current screen. If the dialog is opened on a
// smaller screen than before, this will reset the stored preference.
this.setMaximumSize(GuiHelper.getScreenSize());
}
protected JPanel buildActionPanel() {
JPanel pnl = new JPanel(new GridBagLayout());
JCheckBox expert = new JCheckBox(tr("Expert mode"));
expert.setSelected(ExpertToggleAction.isExpert());
expert.addActionListener(e -> ExpertToggleAction.getInstance().actionPerformed(null));
JPanel btns = new JPanel(new FlowLayout(FlowLayout.CENTER));
btns.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
btns.add(new JButton(new OKAction()));
btns.add(new JButton(new CancelAction()));
btns.add(new JButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Action/Preferences"))));
pnl.add(expert, GBC.std().insets(5, 0, 0, 0));
pnl.add(btns, GBC.std().fill(GBC.HORIZONTAL));
return pnl;
}
protected final void build() {
Container c = getContentPane();
c.setLayout(new BorderLayout());
c.add(tpPreferences, BorderLayout.CENTER);
tpPreferences.buildGui();
tpPreferences.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
c.add(buildActionPanel(), BorderLayout.SOUTH);
addWindowListener(new WindowEventHandler());
InputMapUtils.addEscapeAction(getRootPane(), new CancelAction());
HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Action/Preferences"));
}
/**
* Replies the preferences tabbed pane.
* @return The preferences tabbed pane, or null if the dialog is not yet initialized.
* @since 5604
*/
public PreferenceTabbedPane getTabbedPane() {
return tpPreferences;
}
public boolean isCanceled() {
return canceled;
}
protected void setCanceled(boolean canceled) {
this.canceled = canceled;
}
@Override
public void setVisible(boolean visible) {
if (visible) {
// Make the pref window at most as large as the parent JOSM window
// Have to take window decorations into account or the windows will
// be too large
Insets i = this.getParent().getInsets();
Dimension p = this.getParent().getSize();
p = new Dimension(Math.min(p.width-i.left-i.right, 700),
Math.min(p.height-i.top-i.bottom, 800));
new WindowGeometry(
getClass().getName() + ".geometry",
WindowGeometry.centerInWindow(
getParent(),
p
)
).applySafe(this);
} else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
new WindowGeometry(this).remember(getClass().getName() + ".geometry");
}
super.setVisible(visible);
}
/**
* Select preferences tab by name.
* @param name preferences tab name (icon)
*/
public void selectPreferencesTabByName(String name) {
tpPreferences.selectTabByName(name);
}
/**
* Select preferences tab by class.
* @param clazz preferences tab class
*/
public void selectPreferencesTabByClass(Class<? extends TabPreferenceSetting> clazz) {
tpPreferences.selectTabByPref(clazz);
}
/**
* Select preferences sub-tab by class.
* @param clazz preferences sub-tab class
*/
public void selectSubPreferencesTabByClass(Class<? extends SubPreferenceSetting> clazz) {
tpPreferences.selectSubTabByPref(clazz);
}
class CancelAction extends AbstractAction {
CancelAction() {
putValue(NAME, tr("Cancel"));
new ImageProvider("cancel").getResource().attachImageIcon(this);
putValue(SHORT_DESCRIPTION, tr("Close the preferences dialog and discard preference updates"));
}
public void cancel() {
setCanceled(true);
setVisible(false);
tpPreferences.validationListeners.clear();
}
@Override
public void actionPerformed(ActionEvent evt) {
cancel();
}
}
class OKAction extends AbstractAction {
OKAction() {
putValue(NAME, tr("OK"));
new ImageProvider("ok").getResource().attachImageIcon(this);
putValue(SHORT_DESCRIPTION, tr("Save the preferences and close the dialog"));
}
@Override
public void actionPerformed(ActionEvent evt) {
for (ValidationListener listener: tpPreferences.validationListeners) {
if (!listener.validatePreferences())
return;
}
tpPreferences.savePreferences();
tpPreferences.validationListeners.clear();
setCanceled(false);
setVisible(false);
}
}
class WindowEventHandler extends WindowAdapter {
@Override
public void windowClosing(WindowEvent arg0) {
new CancelAction().cancel();
}
}
}