001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.preferences.display;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Component;
007import java.util.ArrayList;
008import java.util.Arrays;
009import java.util.List;
010import java.util.Locale;
011
012import javax.swing.Box;
013import javax.swing.DefaultComboBoxModel;
014import javax.swing.DefaultListCellRenderer;
015import javax.swing.JLabel;
016import javax.swing.JList;
017import javax.swing.JPanel;
018import javax.swing.ListCellRenderer;
019
020import org.openstreetmap.josm.Main;
021import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
022import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
023import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
024import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
025import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
026import org.openstreetmap.josm.gui.widgets.JosmComboBox;
027import org.openstreetmap.josm.tools.GBC;
028import org.openstreetmap.josm.tools.I18n;
029import org.openstreetmap.josm.tools.LanguageInfo;
030
031/**
032 * Language preferences.
033 */
034public class LanguagePreference implements SubPreferenceSetting {
035
036    /**
037     * Factory used to create a new {@code LanguagePreference}.
038     */
039    public static class Factory implements PreferenceSettingFactory {
040        @Override
041        public PreferenceSetting createPreferenceSetting() {
042            return new LanguagePreference();
043        }
044    }
045
046    /** the combo box with the available locales */
047    private JosmComboBox<Locale> langCombo;
048
049    @Override
050    public void addGui(final PreferenceTabbedPane gui) {
051        LanguageComboBoxModel model = new LanguageComboBoxModel();
052        // Selecting the language BEFORE the JComboBox listens to model changes speed up initialization by ~35ms (see #7386)
053        // See https://stackoverflow.com/questions/3194958/fast-replacement-for-jcombobox-basiccomboboxui
054        model.selectLanguage(Main.pref.get("language"));
055        langCombo = new JosmComboBox<>(model);
056        langCombo.setRenderer(new LanguageCellRenderer());
057
058        LafPreference lafPreference = gui.getSetting(LafPreference.class);
059        final JPanel panel = lafPreference.panel;
060        panel.add(new JLabel(tr("Language")), GBC.std().insets(20, 0, 0, 0));
061        panel.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
062        panel.add(langCombo, GBC.eol().fill(GBC.HORIZONTAL));
063        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
064
065        TabPreferenceSetting tabPref = lafPreference.getTabPreferenceSetting(gui);
066        tabPref.registerSubTab(this, tabPref.getSubTab(lafPreference));
067    }
068
069    @Override
070    public boolean ok() {
071        if (langCombo.getSelectedItem() == null)
072            return Main.pref.put("language", null);
073        else
074            return Main.pref.put("language",
075                    LanguageInfo.getJOSMLocaleCode((Locale) langCombo.getSelectedItem()));
076    }
077
078    private static class LanguageComboBoxModel extends DefaultComboBoxModel<Locale> {
079        private final List<Locale> data = new ArrayList<>();
080
081        LanguageComboBoxModel() {
082            data.add(0, null);
083            data.addAll(Arrays.asList(I18n.getAvailableTranslations()));
084        }
085
086        public void selectLanguage(String language) {
087            setSelectedItem(null);
088            if (language != null) {
089                language = LanguageInfo.getJavaLocaleCode(language);
090                for (Locale locale: data) {
091                    if (locale == null) {
092                        continue;
093                    }
094                    if (locale.toString().equals(language)) {
095                        setSelectedItem(locale);
096                        return;
097                    }
098                }
099            }
100        }
101
102        @Override
103        public Locale getElementAt(int index) {
104            return data.get(index);
105        }
106
107        @Override
108        public int getSize() {
109            return data.size();
110        }
111    }
112
113    private static class LanguageCellRenderer implements ListCellRenderer<Locale> {
114        private final DefaultListCellRenderer dispatch;
115
116        /**
117         * Constructs a new {@code LanguageCellRenderer}.
118         */
119        LanguageCellRenderer() {
120            this.dispatch = new DefaultListCellRenderer();
121        }
122
123        @Override
124        public Component getListCellRendererComponent(JList<? extends Locale> list, Locale l,
125                int index, boolean isSelected, boolean cellHasFocus) {
126            return dispatch.getListCellRendererComponent(list,
127                    l == null
128                            ? tr("Default (Auto determined)")
129                            : LanguageInfo.getDisplayName(l),
130                    index, isSelected, cellHasFocus);
131        }
132    }
133
134    @Override
135    public boolean isExpert() {
136        return false;
137    }
138
139    @Override
140    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
141        return gui.getSetting(LafPreference.class).getTabPreferenceSetting(gui);
142    }
143}