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