source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java@ 4840

Last change on this file since 4840 was 4840, checked in by bastiK, 12 years ago

expert mode rework:

  • toggling of expert mode does not require restart
  • checkbox at a more prominent places (MainMenu > View and in the preference dialog at the bottom)
  • Property svn:eol-style set to native
File size: 13.7 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui.preferences;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Font;
8import java.awt.GridBagLayout;
9import java.awt.ScrollPane;
10import java.awt.event.MouseWheelEvent;
11import java.awt.event.MouseWheelListener;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.HashMap;
15import java.util.Iterator;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.Map;
19
20import javax.swing.BorderFactory;
21import javax.swing.JComponent;
22import javax.swing.JLabel;
23import javax.swing.JOptionPane;
24import javax.swing.JPanel;
25import javax.swing.JScrollPane;
26import javax.swing.JTabbedPane;
27import javax.swing.SwingUtilities;
28
29import org.openstreetmap.josm.Main;
30import org.openstreetmap.josm.actions.ExpertToggleAction;
31import org.openstreetmap.josm.actions.ExpertToggleAction.ExpertModeChangeListener;
32import org.openstreetmap.josm.gui.preferences.advanced.AdvancedPreference;
33import org.openstreetmap.josm.plugins.PluginDownloadTask;
34import org.openstreetmap.josm.plugins.PluginHandler;
35import org.openstreetmap.josm.plugins.PluginInformation;
36import org.openstreetmap.josm.tools.BugReportExceptionHandler;
37import org.openstreetmap.josm.tools.GBC;
38import org.openstreetmap.josm.tools.I18n;
39import org.openstreetmap.josm.tools.ImageProvider;
40
41/**
42 * The preference settings.
43 *
44 * @author imi
45 */
46public class PreferenceTabbedPane extends JTabbedPane implements MouseWheelListener, ExpertModeChangeListener {
47 /**
48 * Allows PreferenceSettings to do validation of entered values when ok was pressed.
49 * If data is invalid then event can return false to cancel closing of preferences dialog.
50 *
51 */
52 public interface ValidationListener {
53 /**
54 *
55 * @return True if preferences can be saved
56 */
57 boolean validatePreferences();
58 }
59
60 private class TabData {
61 public String icon;
62 public JComponent tab;
63 public String toolTip;
64 public boolean isExpert;
65 }
66
67 // all created tabs
68 private final List<TabData> tabs = new ArrayList<TabData>();
69 private final static Collection<PreferenceSettingFactory> settingsFactory = new LinkedList<PreferenceSettingFactory>();
70 private final List<PreferenceSetting> settings = new ArrayList<PreferenceSetting>();
71
72 // some common tabs
73 public final JPanel display = createPreferenceTab("display", tr("Display Settings"), tr("Various settings that influence the visual representation of the whole program."));
74 public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."),false);
75 public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
76 public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
77 public final JPanel plugins = createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
78
79 public final javax.swing.JTabbedPane displaycontent = new javax.swing.JTabbedPane();
80 public final javax.swing.JTabbedPane mapcontent = new javax.swing.JTabbedPane();
81
82 List<ValidationListener> validationListeners = new ArrayList<ValidationListener>();
83
84 /**
85 * Add validation listener to currently open preferences dialog. Calling to removeValidationListener is not necessary, all listeners will
86 * be automatically removed when dialog is closed
87 * @param validationListener
88 */
89 public void addValidationListener(ValidationListener validationListener) {
90 validationListeners.add(validationListener);
91 }
92
93 /**
94 * Construct a JPanel for the preference settings. Layout is GridBagLayout
95 * and a centered title label and the description are added. The panel
96 * will be shown inside a {@link ScrollPane}
97 * @param icon The name of the icon.
98 * @param title The title of this preference tab.
99 * @param desc A description in one sentence for this tab. Will be displayed
100 * italic under the title.
101 * @return The created panel ready to add other controls.
102 */
103 public JPanel createPreferenceTab(String icon, String title, String desc) {
104 return createPreferenceTab(icon, title, desc, false);
105 }
106
107 public JPanel createPreferenceTab(String icon, String title, String desc, boolean inScrollPane) {
108 return createPreferenceTab(icon, title, desc, inScrollPane, false);
109 }
110
111 /**
112 * Construct a JPanel for the preference settings. Layout is GridBagLayout
113 * and a centered title label and the description are added.
114 * @param icon The name of the icon.
115 * @param title The title of this preference tab.
116 * @param desc A description in one sentence for this tab. Will be displayed
117 * italic under the title.
118 * @param inScrollPane if <code>true</code> the added tab will show scroll bars
119 * if the panel content is larger than the available space
120 * @return The created panel ready to add other controls.
121 */
122 public JPanel createPreferenceTab(String icon, String title, String desc, boolean inScrollPane, boolean isExpert) {
123 JPanel p = new JPanel(new GridBagLayout());
124 p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
125 p.add(new JLabel(title), GBC.eol().insets(0,5,0,10).anchor(GBC.NORTHWEST));
126
127 JLabel descLabel = new JLabel("<html>"+desc+"</html>");
128 descLabel.setFont(descLabel.getFont().deriveFont(Font.ITALIC));
129 p.add(descLabel, GBC.eol().insets(5,0,5,20).fill(GBC.HORIZONTAL));
130
131 JComponent tab = p;
132 if (inScrollPane) {
133 JScrollPane sp = new JScrollPane(p);
134 tab = sp;
135 }
136 TabData data = new TabData();
137 data.icon = icon;
138 data.tab = tab;
139 data.isExpert = isExpert;
140 data.toolTip = "<html>"+desc+"</html>";
141 tabs.add(data);
142 return p;
143 }
144
145 public void selectTabByName(String name) {
146 for (TabData data : tabs) {
147 if (data.icon.equals(name)) {
148 Component c = data.tab;
149 if (c != null) {
150 setSelectedComponent(c);
151 }
152 return;
153 }
154 }
155 }
156
157 protected PluginPreference getPluginPreference() {
158 for (PreferenceSetting setting: settings) {
159 if (setting instanceof PluginPreference)
160 return (PluginPreference) setting;
161 }
162 return null;
163 }
164
165 public void savePreferences() {
166 if(Main.applet)
167 return;
168 // create a task for downloading plugins if the user has activated, yet not downloaded,
169 // new plugins
170 //
171 final PluginPreference preference = getPluginPreference();
172 final List<PluginInformation> toDownload = preference.getPluginsScheduledForUpdateOrDownload();
173 final PluginDownloadTask task;
174 if (! toDownload.isEmpty()) {
175 task = new PluginDownloadTask(this, toDownload, tr("Download plugins"));
176 } else {
177 task = null;
178 }
179
180 // this is the task which will run *after* the plugins are downloaded
181 //
182 final Runnable continuation = new Runnable() {
183 public void run() {
184 boolean requiresRestart = false;
185 if (task != null && !task.isCanceled()) {
186 if (!task.getDownloadedPlugins().isEmpty()) {
187 requiresRestart = true;
188 }
189 }
190
191 for (PreferenceSetting setting : settings) {
192 if (setting.ok()) {
193 requiresRestart = true;
194 }
195 }
196
197 // build the messages. We only display one message, including the status
198 // information from the plugin download task and - if necessary - a hint
199 // to restart JOSM
200 //
201 StringBuilder sb = new StringBuilder();
202 sb.append("<html>");
203 if (task != null && !task.isCanceled()) {
204 sb.append(PluginPreference.buildDownloadSummary(task));
205 }
206 if (requiresRestart) {
207 sb.append(tr("You have to restart JOSM for some settings to take effect."));
208 }
209 sb.append("</html>");
210
211 // display the message, if necessary
212 //
213 if ((task != null && !task.isCanceled()) || requiresRestart) {
214 JOptionPane.showMessageDialog(
215 Main.parent,
216 sb.toString(),
217 tr("Warning"),
218 JOptionPane.WARNING_MESSAGE
219 );
220 }
221 Main.parent.repaint();
222 }
223 };
224
225 if (task != null) {
226 // if we have to launch a plugin download task we do it asynchronously, followed
227 // by the remaining "save preferences" activites run on the Swing EDT.
228 //
229 Main.worker.submit(task);
230 Main.worker.submit(
231 new Runnable() {
232 public void run() {
233 SwingUtilities.invokeLater(continuation);
234 }
235 }
236 );
237 } else {
238 // no need for asynchronous activities. Simply run the remaining "save preference"
239 // activities on this thread (we are already on the Swing EDT
240 //
241 continuation.run();
242 }
243 }
244
245 /**
246 * If the dialog is closed with Ok, the preferences will be stored to the preferences-
247 * file, otherwise no change of the file happens.
248 */
249 public PreferenceTabbedPane() {
250 super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
251 super.addMouseWheelListener(this);
252 ExpertToggleAction.addExpertModeChangeListener(this);
253 }
254
255 public void buildGui() {
256 for (PreferenceSettingFactory factory : settingsFactory) {
257 PreferenceSetting setting = factory.createPreferenceSetting();
258 if (setting != null) {
259 settings.add(setting);
260 }
261 }
262
263 display.add(displaycontent, GBC.eol().fill(GBC.BOTH));
264 map.add(mapcontent, GBC.eol().fill(GBC.BOTH));
265 for (Iterator<PreferenceSetting> it = settings.iterator(); it.hasNext();) {
266 try {
267 PreferenceSetting settings = it.next();
268 settings.addGui(this);
269 } catch (SecurityException e) {
270 it.remove();
271 } catch (Throwable e) {
272 /* allow to change most settings even if e.g. a plugin fails */
273 BugReportExceptionHandler.handleException(e);
274 }
275 }
276 addGUITabs(false);
277 }
278
279 private void addGUITabs(boolean clear) {
280 boolean expert = Main.main.menu.expert.isSelected();
281 Component sel = getSelectedComponent();
282 if (clear) {
283 removeAll();
284 }
285 for (TabData data : tabs) {
286 if (expert || !data.isExpert) {
287 addTab(null, ImageProvider.get("preferences", data.icon), data.tab, data.toolTip);
288 }
289 }
290 try {
291 setSelectedComponent(sel);
292 } catch (IllegalArgumentException e) {}
293 }
294
295 @Override
296 public void expertChanged(boolean isExpert) {
297 addGUITabs(true);
298 }
299
300 public List<PreferenceSetting> getSettings() {
301 return settings;
302 }
303
304 @SuppressWarnings("unchecked")
305 public <T> T getSetting(Class<? extends T> clazz) {
306 for (PreferenceSetting setting:settings) {
307 if (clazz.isAssignableFrom(setting.getClass()))
308 return (T)setting;
309 }
310 return null;
311 }
312
313 static {
314 // order is important!
315 settingsFactory.add(new DrawingPreference.Factory());
316 settingsFactory.add(new ColorPreference.Factory());
317 settingsFactory.add(new LafPreference.Factory());
318 settingsFactory.add(new LanguagePreference.Factory());
319 settingsFactory.add(new ServerAccessPreference.Factory());
320 settingsFactory.add(new ProjectionPreference.Factory());
321 settingsFactory.add(new MapPaintPreference.Factory());
322 settingsFactory.add(new TaggingPresetPreference.Factory());
323 settingsFactory.add(new BackupPreference.Factory());
324 if(!Main.applet) {
325 settingsFactory.add(new PluginPreference.Factory());
326 }
327 settingsFactory.add(Main.toolbar);
328 settingsFactory.add(new AudioPreference.Factory());
329 settingsFactory.add(new ShortcutPreference.Factory());
330 settingsFactory.add(new ValidatorPreference.Factory());
331 settingsFactory.add(new RemoteControlPreference.Factory());
332 settingsFactory.add(new ImageryPreference.Factory());
333
334 PluginHandler.getPreferenceSetting(settingsFactory);
335
336 // always the last: advanced tab
337 settingsFactory.add(new AdvancedPreference.Factory());
338 }
339
340 /**
341 * This mouse wheel listener reacts when a scroll is carried out over the
342 * tab strip and scrolls one tab/down or up, selecting it immediately.
343 */
344 public void mouseWheelMoved(MouseWheelEvent wev) {
345 // Ensure the cursor is over the tab strip
346 if(super.indexAtLocation(wev.getPoint().x, wev.getPoint().y) < 0)
347 return;
348
349 // Get currently selected tab
350 int newTab = super.getSelectedIndex() + wev.getWheelRotation();
351
352 // Ensure the new tab index is sound
353 newTab = newTab < 0 ? 0 : newTab;
354 newTab = newTab >= super.getTabCount() ? super.getTabCount() - 1 : newTab;
355
356 // select new tab
357 super.setSelectedIndex(newTab);
358 }
359}
Note: See TracBrowser for help on using the repository browser.