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