001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.preferences.plugin;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.FlowLayout;
007import java.awt.GridBagConstraints;
008import java.awt.GridBagLayout;
009import java.awt.Insets;
010import java.util.EnumMap;
011import java.util.Locale;
012import java.util.Map;
013
014import javax.swing.ButtonGroup;
015import javax.swing.JLabel;
016import javax.swing.JPanel;
017import javax.swing.JRadioButton;
018import javax.swing.event.ChangeEvent;
019import javax.swing.event.ChangeListener;
020
021import org.openstreetmap.josm.Main;
022import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
023import org.openstreetmap.josm.gui.widgets.JosmTextField;
024import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
025import org.openstreetmap.josm.plugins.PluginHandler;
026
027/**
028 * A panel for configuring whether JOSM shall update plugins at startup.
029 *
030 */
031public class PluginUpdatePolicyPanel extends JPanel {
032
033    private enum Policy {
034        ASK("ask"),
035        ALWAYS("always"),
036        NEVER("never");
037
038        private String preferenceValue;
039        Policy(String preferenceValue) {
040            this.preferenceValue = preferenceValue;
041        }
042
043        public String getPreferencesValue() {
044            return preferenceValue;
045        }
046
047        static Policy fromPreferenceValue(String preferenceValue) {
048            if (preferenceValue == null) return null;
049            preferenceValue = preferenceValue.trim().toLowerCase(Locale.ENGLISH);
050            for (Policy p: Policy.values()) {
051                if (p.getPreferencesValue().equals(preferenceValue))
052                    return p;
053            }
054            return null;
055        }
056    }
057
058    private transient Map<Policy, JRadioButton> rbVersionBasedUpatePolicy;
059    private transient Map<Policy, JRadioButton> rbTimeBasedUpatePolicy;
060    private JosmTextField tfUpdateInterval;
061    private JLabel lblUpdateInterval;
062
063    protected JPanel buildVersionBasedUpdatePolicyPanel() {
064        JPanel pnl = new JPanel(new GridBagLayout());
065        GridBagConstraints gc = new GridBagConstraints();
066        gc.anchor = GridBagConstraints.NORTHWEST;
067        gc.fill = GridBagConstraints.HORIZONTAL;
068        gc.weightx = 1.0;
069
070        ButtonGroup bgVersionBasedUpdatePolicy = new ButtonGroup();
071        rbVersionBasedUpatePolicy = new EnumMap<>(Policy.class);
072        JRadioButton btn = new JRadioButton(tr("Ask before updating"));
073        rbVersionBasedUpatePolicy.put(Policy.ASK, btn);
074        bgVersionBasedUpdatePolicy.add(btn);
075
076        btn = new JRadioButton(tr("Always update without asking"));
077        rbVersionBasedUpatePolicy.put(Policy.ALWAYS, btn);
078        bgVersionBasedUpdatePolicy.add(btn);
079
080        btn = new JRadioButton(tr("Never update"));
081        rbVersionBasedUpatePolicy.put(Policy.NEVER, btn);
082        bgVersionBasedUpdatePolicy.add(btn);
083
084        JMultilineLabel lbl = new JMultilineLabel(
085                tr("Please decide whether JOSM shall automatically update active plugins at startup after an update of JOSM itself."));
086        gc.gridy = 0;
087        pnl.add(lbl, gc);
088        for (Policy p: Policy.values()) {
089            gc.gridy++;
090            pnl.add(rbVersionBasedUpatePolicy.get(p), gc);
091        }
092        return pnl;
093    }
094
095    protected JPanel buildUpdateIntervalPanel() {
096        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
097        pnl.add(lblUpdateInterval = new JLabel(tr("Update interval (in days):")));
098        pnl.add(tfUpdateInterval = new JosmTextField(5));
099        lblUpdateInterval.setLabelFor(tfUpdateInterval);
100        SelectAllOnFocusGainedDecorator.decorate(tfUpdateInterval);
101        return pnl;
102    }
103
104    protected JPanel buildTimeBasedUpdatePolicyPanel() {
105        JPanel pnl = new JPanel(new GridBagLayout());
106        GridBagConstraints gc = new GridBagConstraints();
107        gc.anchor = GridBagConstraints.NORTHWEST;
108        gc.fill = GridBagConstraints.HORIZONTAL;
109        gc.weightx = 1.0;
110
111        TimeBasedPolicyChangeListener changeListener = new TimeBasedPolicyChangeListener();
112
113        ButtonGroup bgTimeBasedUpdatePolicy = new ButtonGroup();
114        rbTimeBasedUpatePolicy = new EnumMap<>(Policy.class);
115        JRadioButton btn = new JRadioButton(tr("Ask before updating"));
116        btn.addChangeListener(changeListener);
117        rbTimeBasedUpatePolicy.put(Policy.ASK, btn);
118        bgTimeBasedUpdatePolicy.add(btn);
119
120        btn = new JRadioButton(tr("Always update without asking"));
121        btn.addChangeListener(changeListener);
122        rbTimeBasedUpatePolicy.put(Policy.ALWAYS, btn);
123        bgTimeBasedUpdatePolicy.add(btn);
124
125        btn = new JRadioButton(tr("Never update"));
126        btn.addChangeListener(changeListener);
127        rbTimeBasedUpatePolicy.put(Policy.NEVER, btn);
128        bgTimeBasedUpdatePolicy.add(btn);
129
130        JMultilineLabel lbl = new JMultilineLabel(
131                tr("Please decide whether JOSM shall automatically update active plugins after a certain period of time."));
132        gc.gridy = 0;
133        pnl.add(lbl, gc);
134        for (Policy p: Policy.values()) {
135            gc.gridy++;
136            pnl.add(rbTimeBasedUpatePolicy.get(p), gc);
137        }
138        gc.gridy++;
139        pnl.add(buildUpdateIntervalPanel(), gc);
140        return pnl;
141    }
142
143    protected final void build() {
144        setLayout(new GridBagLayout());
145        GridBagConstraints gc = new GridBagConstraints();
146        gc.anchor = GridBagConstraints.NORTHWEST;
147        gc.fill = GridBagConstraints.HORIZONTAL;
148        gc.weightx = 1.0;
149        gc.insets = new Insets(5, 5, 10, 5);
150
151        add(buildVersionBasedUpdatePolicyPanel(), gc);
152        gc.gridy = 1;
153        add(buildTimeBasedUpdatePolicyPanel(), gc);
154
155        gc.gridy = 2;
156        gc.weighty = 1.0;
157        gc.fill = GridBagConstraints.BOTH;
158        add(new JPanel(), gc);
159    }
160
161    /**
162     * Constructs a new {@code PluginUpdatePolicyPanel}.
163     */
164    public PluginUpdatePolicyPanel() {
165        build();
166        initFromPreferences();
167    }
168
169    /**
170     * Loads the relevant preference values from the JOSM preferences
171     *
172     */
173    public final void initFromPreferences() {
174        String pref = Main.pref.get("pluginmanager.version-based-update.policy", "ask");
175        Policy p = Policy.fromPreferenceValue(pref);
176        if (p == null) {
177            p = Policy.ASK;
178        }
179        rbVersionBasedUpatePolicy.get(p).setSelected(true);
180
181        pref = Main.pref.get("pluginmanager.time-based-update.policy", "ask");
182        p = Policy.fromPreferenceValue(pref);
183        if (p == null) {
184            p = Policy.ASK;
185        }
186        rbTimeBasedUpatePolicy.get(p).setSelected(true);
187
188        pref = Main.pref.get("pluginmanager.warntime", null);
189        int days = 0;
190        if (pref != null) {
191            // remove legacy preference
192            Main.pref.put("pluginmanager.warntime", null);
193            pref = pref.trim();
194            try {
195                days = Integer.parseInt(pref);
196            } catch (NumberFormatException e) {
197                // ignore - load from preference pluginmanager.time-based-update.interval
198                if (Main.isTraceEnabled()) {
199                    Main.trace(e.getMessage());
200                }
201            }
202            if (days <= 0) {
203                days = PluginHandler.DEFAULT_TIME_BASED_UPDATE_INTERVAL;
204            }
205        }
206        if (days == 0) {
207            days = Main.pref.getInteger("pluginmanager.time-based-update.interval", PluginHandler.DEFAULT_TIME_BASED_UPDATE_INTERVAL);
208        }
209        tfUpdateInterval.setText(Integer.toString(days));
210    }
211
212    /**
213     * Remebers the update policy preference settings on the JOSM preferences
214     */
215    public void rememberInPreferences() {
216
217        // remember policy for version based update
218        //
219        for (Policy p: Policy.values()) {
220            if (rbVersionBasedUpatePolicy.get(p).isSelected()) {
221                Main.pref.put("pluginmanager.version-based-update.policy", p.getPreferencesValue());
222                break;
223            }
224        }
225
226        // remember policy for time based update
227        //
228        for (Policy p: Policy.values()) {
229            if (rbTimeBasedUpatePolicy.get(p).isSelected()) {
230                Main.pref.put("pluginmanager.time-based-update.policy", p.getPreferencesValue());
231                break;
232            }
233        }
234
235        // remember update interval
236        //
237        int days = 0;
238        try {
239            days = Integer.parseInt(tfUpdateInterval.getText().trim());
240            if (days <= 0) {
241                days = PluginHandler.DEFAULT_TIME_BASED_UPDATE_INTERVAL;
242            }
243        } catch (NumberFormatException e) {
244            days = PluginHandler.DEFAULT_TIME_BASED_UPDATE_INTERVAL;
245        }
246        Main.pref.putInteger("pluginmanager.time-based-update.interval", days);
247    }
248
249    class TimeBasedPolicyChangeListener implements ChangeListener {
250        @Override
251        public void stateChanged(ChangeEvent e) {
252            lblUpdateInterval.setEnabled(!rbTimeBasedUpatePolicy.get(Policy.NEVER).isSelected());
253            tfUpdateInterval.setEnabled(!rbTimeBasedUpatePolicy.get(Policy.NEVER).isSelected());
254        }
255    }
256
257}