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