// License: GPL. Copyright 2007 by Immanuel Scholz and others
package org.openstreetmap.josm.gui.preferences;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.ScrollPane;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.plugins.PluginDownloadTask;
import org.openstreetmap.josm.plugins.PluginHandler;
import org.openstreetmap.josm.plugins.PluginInformation;
import org.openstreetmap.josm.tools.BugReportExceptionHandler;
import org.openstreetmap.josm.tools.GBC;
import org.openstreetmap.josm.tools.I18n;
import org.openstreetmap.josm.tools.ImageProvider;
/**
* The preference settings.
*
* @author imi
*/
public class PreferenceTabbedPane extends JTabbedPane implements MouseWheelListener {
@SuppressWarnings("unused")
static private final Logger logger = Logger.getLogger(PreferenceTabbedPane.class.getName());
private final static Collection<PreferenceSettingFactory> settingsFactory = new LinkedList<PreferenceSettingFactory>();
private final List<PreferenceSetting> settings = new ArrayList<PreferenceSetting>();
// some common tabs
public final JPanel display = createPreferenceTab("display", tr("Display Settings"), tr("Various settings that influence the visual representation of the whole program."));
public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."),false);
public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
public final JPanel plugins = createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
public final javax.swing.JTabbedPane displaycontent = new javax.swing.JTabbedPane();
public final javax.swing.JTabbedPane mapcontent = new javax.swing.JTabbedPane();
/**
* Construct a JPanel for the preference settings. Layout is GridBagLayout
* and a centered title label and the description are added. The panel
* will be shown inside a {@link ScrollPane}
* @param icon The name of the icon.
* @param title The title of this preference tab.
* @param desc A description in one sentence for this tab. Will be displayed
* italic under the title.
* @return The created panel ready to add other controls.
*/
public JPanel createPreferenceTab(String icon, String title, String desc) {
return createPreferenceTab(icon, title, desc, false);
}
/**
* Construct a JPanel for the preference settings. Layout is GridBagLayout
* and a centered title label and the description are added.
* @param icon The name of the icon.
* @param title The title of this preference tab.
* @param desc A description in one sentence for this tab. Will be displayed
* italic under the title.
* @param inScrollPane if <code>true</code> the added tab will show scroll bars
* if the panel content is larger than the available space
* @return The created panel ready to add other controls.
*/
public JPanel createPreferenceTab(String icon, String title, String desc, boolean inScrollPane) {
JPanel p = new JPanel(new GridBagLayout());
p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
p.add(new JLabel(title), GBC.eol().insets(0,5,0,10).anchor(GBC.NORTHWEST));
JLabel descLabel = new JLabel("<html>"+desc+"</html>");
descLabel.setFont(descLabel.getFont().deriveFont(Font.ITALIC));
p.add(descLabel, GBC.eol().insets(5,0,5,20).fill(GBC.HORIZONTAL));
JComponent tab = p;
if (inScrollPane) {
JScrollPane sp = new JScrollPane(p);
tab = sp;
}
addTab(null, ImageProvider.get("preferences", icon), tab);
setToolTipTextAt(getTabCount()-1, "<html>"+desc+"</html>");
return p;
}
protected PluginPreference getPluginPreference() {
for (PreferenceSetting setting: settings) {
if (setting instanceof PluginPreference)
return (PluginPreference) setting;
}
return null;
}
public void savePreferences() {
// create a task for downloading plugins if the user has activated, yet not downloaded,
// new plugins
//
final PluginPreference preference = getPluginPreference();
final List<PluginInformation> toDownload = preference.getPluginsScheduledForUpdateOrDownload();
final PluginDownloadTask task;
if (! toDownload.isEmpty()) {
task = new PluginDownloadTask(this, toDownload, tr("Download plugins"));
} else {
task = null;
}
// this is the task which will run *after* the plugins are downloaded
//
final Runnable continuation = new Runnable() {
public void run() {
boolean requiresRestart = false;
if (task != null && !task.isCanceled()) {
if (!task.getDownloadedPlugins().isEmpty()) {
requiresRestart = true;
}
}
for (PreferenceSetting setting : settings) {
if (setting.ok()) {
requiresRestart = true;
}
}
// build the messages. We only display one message, including the status
// information from the plugin download task and - if necessary - a hint
// to restart JOSM
//
StringBuffer sb = new StringBuffer();
sb.append("<html>");
if (task != null && !task.isCanceled()) {
sb.append(PluginPreference.buildDownloadSummary(task));
}
if (requiresRestart) {
sb.append(tr("You have to restart JOSM for some settings to take effect."));
}
sb.append("</html>");
// display the message, if necessary
//
if ((task != null && !task.isCanceled()) || requiresRestart) {
JOptionPane.showMessageDialog(
Main.parent,
sb.toString(),
tr("Warning"),
JOptionPane.WARNING_MESSAGE
);
}
Main.parent.repaint();
}
};
if (task != null) {
// if we have to launch a plugin download task we do it asynchronously, followed
// by the remaining "save preferences" activites run on the Swing EDT.
//
Main.worker.submit(task);
Main.worker.submit(
new Runnable() {
public void run() {
SwingUtilities.invokeLater(continuation);
}
}
);
} else {
// no need for asynchronous activities. Simply run the remaining "save preference"
// activities on this thread (we are already on the Swing EDT
//
continuation.run();
}
}
/**
* If the dialog is closed with Ok, the preferences will be stored to the preferences-
* file, otherwise no change of the file happens.
*/
public PreferenceTabbedPane() {
super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
super.addMouseWheelListener(this);
}
public void buildGui() {
for (PreferenceSettingFactory factory:settingsFactory) {
// logger.info("creating settings: " + factory);
PreferenceSetting setting = factory.createPreferenceSetting();
if (setting != null) {
settings.add(factory.createPreferenceSetting());
}
}
display.add(displaycontent, GBC.eol().fill(GBC.BOTH));
map.add(mapcontent, GBC.eol().fill(GBC.BOTH));
for (Iterator<PreferenceSetting> it = settings.iterator(); it.hasNext();) {
try {
PreferenceSetting settings = it.next();
//logger.info("adding gui: " + settings);
settings.addGui(this);
} catch (SecurityException e) {
it.remove();
} catch (Throwable e) {
/* allow to change most settings even if e.g. a plugin fails */
BugReportExceptionHandler.handleException(e);
}
}
}
public List<PreferenceSetting> getSettings() {
return settings;
}
@SuppressWarnings("unchecked")
public <T> T getSetting(Class<? extends T> clazz) {
for (PreferenceSetting setting:settings) {
if (clazz.isAssignableFrom(setting.getClass()))
return (T)setting;
}
return null;
}
static {
// order is important!
settingsFactory.add(new DrawingPreference.Factory());
settingsFactory.add(new ColorPreference.Factory());
settingsFactory.add(new LafPreference.Factory());
settingsFactory.add(new LanguagePreference.Factory());
settingsFactory.add(new ServerAccessPreference.Factory());
settingsFactory.add(new ProjectionPreference.Factory());
settingsFactory.add(new MapPaintPreference.Factory());
settingsFactory.add(new TaggingPresetPreference.Factory());
settingsFactory.add(new PluginPreference.Factory());
settingsFactory.add(Main.toolbar);
settingsFactory.add(new AudioPreference.Factory());
settingsFactory.add(new ShortcutPreference.Factory());
PluginHandler.getPreferenceSetting(settingsFactory);
// always the last: advanced tab
settingsFactory.add(new AdvancedPreference.Factory());
}
/**
* This mouse wheel listener reacts when a scroll is carried out over the
* tab strip and scrolls one tab/down or up, selecting it immediately.
*/
public void mouseWheelMoved(MouseWheelEvent wev) {
// Ensure the cursor is over the tab strip
if(super.indexAtLocation(wev.getPoint().x, wev.getPoint().y) < 0)
return;
// Get currently selected tab
int newTab = super.getSelectedIndex() + wev.getWheelRotation();
// Ensure the new tab index is sound
newTab = newTab < 0 ? 0 : newTab;
newTab = newTab >= super.getTabCount() ? super.getTabCount() - 1 : newTab;
// select new tab
super.setSelectedIndex(newTab);
}
}