diff --git a/README.md b/README.md index c13ccef..8a0280a 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,24 @@ colorPicker.addColorListener(colorModel -> System.out.println(colorModel.getColo This creates a color picker component with expert controls and opacity settings. If the user selects a color, the color listener will be notified. +### :globe_with_meridians: Localization + +The color picker supports localization. You can set the locale by passing it to the constructor: + +```java +ColorPicker colorPicker = new ColorPicker(true, true, Locale.FRENCH); +// or +ColorPickerDialog.showDialog(null, Color.GREEN, Locale.FRENCH); +``` + +Currently, the following languages are supported: +- English +- Español +- Français +- Deutsch +- Português +- Русский + ## :hammer: Building Please use Maven to build and test the project. diff --git a/src/main/java/com/bric/colorpicker/ColorPicker.java b/src/main/java/com/bric/colorpicker/ColorPicker.java index bba96ff..008c6ed 100644 --- a/src/main/java/com/bric/colorpicker/ColorPicker.java +++ b/src/main/java/com/bric/colorpicker/ColorPicker.java @@ -41,6 +41,7 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.util.Locale; import java.util.ResourceBundle; import javax.swing.ButtonGroup; import javax.swing.JComponent; @@ -102,27 +103,32 @@ public class ColorPicker extends JPanel { private static final String MODE_CONTROLS_VISIBLE_PROPERTY = "mode controls visible"; /** - * The localized STRINGS used in this (and related) panel(s). + * Path to the localization bundle */ - private static final ResourceBundle strings = ResourceBundle.getBundle("com.bric.colorpicker.resources.ColorPicker"); + private static final String LOCALIZATION_BUNDLE_PATH = "com.bric.colorpicker.resources.ColorPicker"; + /** + * The localized STRINGS used in this (and related) panel(s). + */ + private final ResourceBundle strings; private final ColorModel colorModel = new ColorModel(); private final ModeModel modeModel = new ModeModel(); private final ColorSlider slider = new ColorSlider(); - private final Option alphaOption = new AlphaOption(); - private final Option hueOption = new HueOption(); - private final Option saturationOption = new SaturationOption(); - private final Option brightnessOption = new BrightnessOption(); - private final Option redOption = new RedOption(); - private final Option greenOption = new GreenOption(); - private final Option blueOption = new BlueOption(); - private final ColorSwatch preview = new ColorSwatch(50); - private final JLabel hexLabel = new JLabel(strings.getObject("hexLabel").toString()); + private final Option alphaOption; + private final Option hueOption; + private final Option saturationOption; + private final Option brightnessOption; + private final Option redOption; + private final Option greenOption; + private final Option blueOption; private final HexField hexField = new HexField(); private final JPanel expertControls = new JPanel(new GridBagLayout()); private final ColorPickerPanel colorPanel = new ColorPickerPanel(); private final OpacitySlider opacitySlider = new OpacitySlider(); - private final JLabel opacityLabel = new JLabel(strings.getObject("opacityLabel").toString()); + + private final ColorSwatch preview; + private final JLabel hexLabel; + private final JLabel opacityLabel; /** * Create a new {@code ColorPicker} with all controls visible except opacity. @@ -131,6 +137,14 @@ public ColorPicker() { this(true, false); } + /** + * Create a new {@code ColorPicker} with all controls visible except opacity with the active local + * @param local the current active local of the app + */ + public ColorPicker(Locale local) { + this(true, false, local); + } + /** * Create a new {@code ColorPicker}. * @@ -142,9 +156,25 @@ public ColorPicker() { * @param includeOpacity whether the opacity controls will be shown */ public ColorPicker(boolean showExpertControls, boolean includeOpacity) { + this(showExpertControls, includeOpacity, null); + } + + /** + * Create a new {@code ColorPicker}. + * + * @param showExpertControls the labels/spinners/buttons on the right side of a + * {@code ColorPicker} are optional. This boolean will control whether they + * are shown or not. + *

It may be that your users will never need or want numeric control when + * they choose their colors, so hiding this may simplify your interface. + * @param includeOpacity whether the opacity controls will be shown + * @param locale the current active local of the app + */ + public ColorPicker(boolean showExpertControls, boolean includeOpacity, Locale locale) { super(new GridBagLayout()); - initNames(); + if(locale == null) strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH); + else strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH, locale); GridBagConstraints constraints = new GridBagConstraints(); @@ -159,7 +189,7 @@ public ColorPicker(boolean showExpertControls, boolean includeOpacity) { ButtonGroup buttonGroup = new ButtonGroup(); Option[] options = { - hueOption, saturationOption, brightnessOption, redOption, greenOption, blueOption + hueOption = new HueOption(locale), saturationOption = new SaturationOption(locale), brightnessOption = new BrightnessOption(locale), redOption = new RedOption(locale), greenOption = new GreenOption(locale), blueOption = new BlueOption(locale) }; for (int optionIndex = 0; optionIndex < options.length; optionIndex++) { @@ -173,6 +203,7 @@ public ColorPicker(boolean showExpertControls, boolean includeOpacity) { constraints.insets = new Insets(normalInsets.top + 10, normalInsets.left, normalInsets.bottom, normalInsets.right); constraints.anchor = GridBagConstraints.LINE_END; constraints.fill = GridBagConstraints.NONE; + this.hexLabel = new JLabel(strings.getObject("hexLabel").toString()); optionsPanel.add(hexLabel, constraints); constraints.gridx++; @@ -180,6 +211,7 @@ public ColorPicker(boolean showExpertControls, boolean includeOpacity) { constraints.fill = GridBagConstraints.HORIZONTAL; optionsPanel.add(hexField, constraints); + alphaOption = new AlphaOption(locale); alphaOption.addTo(optionsPanel, constraints); constraints.gridx = 0; @@ -214,6 +246,7 @@ public ColorPicker(boolean showExpertControls, boolean includeOpacity) { constraints.weighty = 0; constraints.insets = normalInsets; constraints.anchor = GridBagConstraints.CENTER; + this.opacityLabel = new JLabel(strings.getObject("opacityLabel").toString()); add(opacityLabel, constraints); constraints.gridx++; @@ -231,6 +264,7 @@ public ColorPicker(boolean showExpertControls, boolean includeOpacity) { constraints.weightx = 1; constraints.anchor = GridBagConstraints.PAGE_START; constraints.insets = new Insets(normalInsets.top, normalInsets.left + 8, normalInsets.bottom + 10, normalInsets.right + 8); + this.preview = new ColorSwatch(50, locale); expertControls.add(preview, constraints); constraints.gridy++; @@ -239,6 +273,8 @@ public ColorPicker(boolean showExpertControls, boolean includeOpacity) { constraints.insets = new Insets(normalInsets.top, normalInsets.left, 0, normalInsets.right); expertControls.add(optionsPanel, constraints); + initNames(); + initializeColorPanel(); initializeSlider(); initializePreview(); diff --git a/src/main/java/com/bric/colorpicker/ColorPickerDialog.java b/src/main/java/com/bric/colorpicker/ColorPickerDialog.java index e5acd42..68f41e8 100644 --- a/src/main/java/com/bric/colorpicker/ColorPickerDialog.java +++ b/src/main/java/com/bric/colorpicker/ColorPickerDialog.java @@ -31,6 +31,7 @@ import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.Locale; import java.util.ResourceBundle; import javax.swing.JComponent; import javax.swing.JDialog; @@ -44,7 +45,7 @@ */ public class ColorPickerDialog extends JDialog { - private static final ResourceBundle STRINGS = ResourceBundle.getBundle("com.bric.colorpicker.resources.ColorPickerDialog"); + private static final String LOCALIZATION_BUNDLE_PATH = "com.bric.colorpicker.resources.ColorPickerDialog"; public static final JComponent[] LEFT_COMPONENTS = new JComponent[0]; private ColorPicker colorPicker; @@ -56,13 +57,25 @@ public ColorPickerDialog() { } public ColorPickerDialog(Frame owner, Color color, boolean includeOpacity) { - super(owner); - initialize(owner, color, includeOpacity); + this(owner, color, includeOpacity, null); } public ColorPickerDialog(Dialog owner, Color color, boolean includeOpacity) { + this(owner, color, includeOpacity, null); + } + + public ColorPickerDialog(Locale locale) { + this((Frame) null, Color.BLUE, false, locale); + } + + public ColorPickerDialog(Frame owner, Color color, boolean includeOpacity, Locale locale) { super(owner); - initialize(owner, color, includeOpacity); + initialize(owner, color, includeOpacity, locale); + } + + public ColorPickerDialog(Dialog owner, Color color, boolean includeOpacity, Locale locale) { + super(owner); + initialize(owner, color, includeOpacity, locale); } /** @@ -74,21 +87,26 @@ public ColorPickerDialog(Dialog owner, Color color, boolean includeOpacity) { * @param title the title for the dialog. * @param originalColor the color the {@code ColorPicker} initially points to. * @param includeOpacity whether to add a control for the opacity of the color. + * @param locale the current active local of the app * @return the {@code Color} the user chooses, or {@code null} if the user cancels the dialog. */ - public static Color showDialog(Window owner, String title, Color originalColor, boolean includeOpacity) { + public static Color showDialog(Window owner, String title, Color originalColor, boolean includeOpacity, Locale locale) { ColorPickerDialog dialog; + ResourceBundle strings; + + if(locale == null) strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH); + else strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH, locale); if (owner instanceof Frame || owner == null) { - dialog = new ColorPickerDialog((Frame) owner, originalColor, includeOpacity); + dialog = new ColorPickerDialog((Frame) owner, originalColor, includeOpacity, locale); } else if (owner instanceof Dialog) { - dialog = new ColorPickerDialog((Dialog) owner, originalColor, includeOpacity); + dialog = new ColorPickerDialog((Dialog) owner, originalColor, includeOpacity, locale); } else { throw new IllegalArgumentException("the owner (" + owner.getClass().getName() + ") must be a java.awt.Frame or a java.awt.Dialog"); } if (title == null) { - dialog.setTitle(STRINGS.getObject("ColorPickerDialogTitle").toString()); + dialog.setTitle(strings.getObject("ColorPickerDialogTitle").toString()); } else { dialog.setTitle(title); } @@ -110,7 +128,23 @@ public static Color showDialog(Window owner, String title, Color originalColor, * @return the {@code Color} the user chooses, or {@code null} if the user cancels the dialog. */ public static Color showDialog(Window owner, Color originalColor, boolean includeOpacity) { - return showDialog(owner, null, originalColor, includeOpacity); + return showDialog(owner, null, originalColor, includeOpacity, null); + } + + /** + * This creates a modal dialog prompting the user to select a color. + *

This uses a generic dialog title: "Choose a Color". + * + * @param owner the dialog this new dialog belongs to. This must be a Frame or a Dialog. + * Java 1.6 supports Windows here, but this package is designed/compiled to work in Java 1.4, + * so an {@code IllegalArgumentException} will be thrown if this target is a {@code Window}. + * @param originalColor the color the {@code ColorPicker} initially points to. + * @param includeOpacity whether to add a control for the opacity of the color. + * @param local the current active local of the app + * @return the {@code Color} the user chooses, or {@code null} if the user cancels the dialog. + */ + public static Color showDialog(Window owner, Color originalColor, boolean includeOpacity, Locale locale) { + return showDialog(owner, null, originalColor, includeOpacity, locale); } /** @@ -124,11 +158,27 @@ public static Color showDialog(Window owner, Color originalColor, boolean includ * @return the {@code Color} the user chooses, or {@code null} if the user cancels the dialog. */ public static Color showDialog(Window owner, Color originalColor) { - return showDialog(owner, null, originalColor, false); + return showDialog(owner, null, originalColor, false, null); } - private void initialize(Component owner, Color color, boolean includeOpacity) { - colorPicker = new ColorPicker(true, includeOpacity); + /** + * This creates a modal dialog prompting the user to select a color. + *

This uses a generic dialog title: "Choose a Color", and does not include opacity. + * + * @param owner the dialog this new dialog belongs to. This must be a Frame or a Dialog. + * Java 1.6 supports Windows here, but this package is designed/compiled to work in Java 1.4, + * so an {@code IllegalArgumentException} will be thrown if this target is a {@code Window}. + * @param originalColor the color the {@code ColorPicker} initially points to. + * @param locale the current active local of the app + * @return the {@code Color} the user chooses, or {@code null} if the user cancels the dialog. + */ + public static Color showDialog(Window owner, Color originalColor, Locale locale) { + return showDialog(owner, null, originalColor, false, locale); + } + + private void initialize(Component owner, Color color, boolean includeOpacity, Locale locale) { + + colorPicker = new ColorPicker(true, includeOpacity, locale); setModal(true); setResizable(false); getContentPane().setLayout(new GridBagLayout()); @@ -143,7 +193,7 @@ private void initialize(Component owner, Color color, boolean includeOpacity) { getContentPane().add(colorPicker, constraints); constraints.gridy++; DialogFooter footer = DialogFooter.createDialogFooter(LEFT_COMPONENTS, - DialogFooter.OK_CANCEL_OPTION, DialogFooter.OK_OPTION, EscapeKeyBehavior.TRIGGERS_CANCEL); + DialogFooter.OK_CANCEL_OPTION, DialogFooter.OK_OPTION, EscapeKeyBehavior.TRIGGERS_CANCEL, locale); constraints.gridy++; constraints.weighty = 0; getContentPane().add(footer, constraints); diff --git a/src/main/java/com/bric/colorpicker/options/AlphaOption.java b/src/main/java/com/bric/colorpicker/options/AlphaOption.java index 27107c0..b6c7893 100644 --- a/src/main/java/com/bric/colorpicker/options/AlphaOption.java +++ b/src/main/java/com/bric/colorpicker/options/AlphaOption.java @@ -6,11 +6,16 @@ import javax.swing.ButtonGroup; import java.awt.Container; import java.awt.GridBagConstraints; +import java.util.Locale; public class AlphaOption extends Option { public AlphaOption() { - super(STRINGS.getObject("alphaLabel").toString(), ColorPickerMode.ALPHA); + this(null); + } + + public AlphaOption(Locale locale) { + super("alphaLabel", ColorPickerMode.ALPHA, locale); } @Override diff --git a/src/main/java/com/bric/colorpicker/options/BlueOption.java b/src/main/java/com/bric/colorpicker/options/BlueOption.java index 188e0ac..f62d2ac 100644 --- a/src/main/java/com/bric/colorpicker/options/BlueOption.java +++ b/src/main/java/com/bric/colorpicker/options/BlueOption.java @@ -1,12 +1,18 @@ package com.bric.colorpicker.options; +import java.util.Locale; + import com.bric.colorpicker.ColorPickerMode; import com.bric.colorpicker.models.ColorModel; public class BlueOption extends Option { public BlueOption() { - super(STRINGS.getObject("blueLabel").toString(), ColorPickerMode.BLUE); + this(null); + } + + public BlueOption(Locale locale) { + super("blueLabel", ColorPickerMode.BLUE, locale); } @Override diff --git a/src/main/java/com/bric/colorpicker/options/BrightnessOption.java b/src/main/java/com/bric/colorpicker/options/BrightnessOption.java index 9724698..7e99c14 100644 --- a/src/main/java/com/bric/colorpicker/options/BrightnessOption.java +++ b/src/main/java/com/bric/colorpicker/options/BrightnessOption.java @@ -1,12 +1,18 @@ package com.bric.colorpicker.options; +import java.util.Locale; + import com.bric.colorpicker.ColorPickerMode; import com.bric.colorpicker.models.ColorModel; public class BrightnessOption extends Option { public BrightnessOption() { - super(STRINGS.getObject("brightnessLabel").toString(), ColorPickerMode.BRIGHTNESS); + this(null); + } + + public BrightnessOption(Locale locale) { + super("brightnessLabel", ColorPickerMode.BRIGHTNESS, locale); } @Override diff --git a/src/main/java/com/bric/colorpicker/options/GreenOption.java b/src/main/java/com/bric/colorpicker/options/GreenOption.java index db510f8..38f33b7 100644 --- a/src/main/java/com/bric/colorpicker/options/GreenOption.java +++ b/src/main/java/com/bric/colorpicker/options/GreenOption.java @@ -1,12 +1,18 @@ package com.bric.colorpicker.options; +import java.util.Locale; + import com.bric.colorpicker.ColorPickerMode; import com.bric.colorpicker.models.ColorModel; public class GreenOption extends Option { public GreenOption() { - super(STRINGS.getObject("greenLabel").toString(), ColorPickerMode.GREEN); + this(null); + } + + public GreenOption(Locale locale) { + super("greenLabel", ColorPickerMode.GREEN, locale); } @Override diff --git a/src/main/java/com/bric/colorpicker/options/HueOption.java b/src/main/java/com/bric/colorpicker/options/HueOption.java index b2a603b..8956e93 100644 --- a/src/main/java/com/bric/colorpicker/options/HueOption.java +++ b/src/main/java/com/bric/colorpicker/options/HueOption.java @@ -1,12 +1,18 @@ package com.bric.colorpicker.options; +import java.util.Locale; + import com.bric.colorpicker.ColorPickerMode; import com.bric.colorpicker.models.ColorModel; public class HueOption extends Option { public HueOption() { - super(STRINGS.getObject("hueLabel").toString(), ColorPickerMode.HUE); + this(null); + } + + public HueOption(Locale locale) { + super("hueLabel", ColorPickerMode.HUE, locale); } @Override diff --git a/src/main/java/com/bric/colorpicker/options/Option.java b/src/main/java/com/bric/colorpicker/options/Option.java index 350ab2b..b5f83a0 100644 --- a/src/main/java/com/bric/colorpicker/options/Option.java +++ b/src/main/java/com/bric/colorpicker/options/Option.java @@ -13,6 +13,7 @@ import java.awt.GridBagConstraints; import java.awt.event.ActionListener; import java.awt.event.FocusListener; +import java.util.Locale; import java.util.ResourceBundle; import javax.swing.ButtonGroup; import javax.swing.JFormattedTextField; @@ -24,7 +25,7 @@ public abstract class Option implements ColorListener, ModeListener { - protected static final ResourceBundle STRINGS = ResourceBundle.getBundle("com.bric.colorpicker.resources.ColorPicker"); + protected static final String LOCALIZATION_BUNDLE_PATH = "com.bric.colorpicker.resources.ColorPicker"; private final ColorListenerWrapper colorListenerWrapper; private final ModeListenerWrapper modeListenerWrapper; private final JRadioButton radioButton = new JRadioButton(); @@ -32,6 +33,21 @@ public abstract class Option implements ColorListener, ModeListener { private final JLabel label; private final ColorPickerMode mode; + private ResourceBundle strings; + + protected Option(String localizationKey, ColorPickerMode mode, Locale locale) { + + if(locale == null) this.strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH); + else this.strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH, locale); + + this.mode = mode; + spinner = new JSpinner(new SpinnerNumberModel(0, 0, mode.getMax(), 5)); + label = new JLabel(this.strings.getObject(localizationKey).toString()); + colorListenerWrapper = ColorListenerWrapper.withListener(this::doColorChanged); + modeListenerWrapper = ModeListenerWrapper.withListener(modeModel -> setSelected(modeModel.getMode() == mode)); + } + + protected Option(String text, ColorPickerMode mode) { this.mode = mode; spinner = new JSpinner(new SpinnerNumberModel(0, 0, mode.getMax(), 5)); diff --git a/src/main/java/com/bric/colorpicker/options/RedOption.java b/src/main/java/com/bric/colorpicker/options/RedOption.java index a3c3cab..560a3a3 100644 --- a/src/main/java/com/bric/colorpicker/options/RedOption.java +++ b/src/main/java/com/bric/colorpicker/options/RedOption.java @@ -1,12 +1,18 @@ package com.bric.colorpicker.options; +import java.util.Locale; + import com.bric.colorpicker.ColorPickerMode; import com.bric.colorpicker.models.ColorModel; public class RedOption extends Option { public RedOption() { - super(STRINGS.getObject("redLabel").toString(), ColorPickerMode.RED); + this(null); + } + + public RedOption(Locale locale) { + super("redLabel", ColorPickerMode.RED, locale); } @Override diff --git a/src/main/java/com/bric/colorpicker/options/SaturationOption.java b/src/main/java/com/bric/colorpicker/options/SaturationOption.java index 321d819..1820ad1 100644 --- a/src/main/java/com/bric/colorpicker/options/SaturationOption.java +++ b/src/main/java/com/bric/colorpicker/options/SaturationOption.java @@ -1,12 +1,18 @@ package com.bric.colorpicker.options; +import java.util.Locale; + import com.bric.colorpicker.ColorPickerMode; import com.bric.colorpicker.models.ColorModel; public class SaturationOption extends Option { public SaturationOption() { - super(STRINGS.getObject("saturationLabel").toString(), ColorPickerMode.SATURATION); + this(null); + } + + public SaturationOption(Locale locale) { + super("saturationLabel", ColorPickerMode.SATURATION, locale); } @Override diff --git a/src/main/java/com/bric/colorpicker/parts/ColorSwatch.java b/src/main/java/com/bric/colorpicker/parts/ColorSwatch.java index 28af005..b393bcb 100644 --- a/src/main/java/com/bric/colorpicker/parts/ColorSwatch.java +++ b/src/main/java/com/bric/colorpicker/parts/ColorSwatch.java @@ -33,6 +33,7 @@ import java.awt.datatransfer.Transferable; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; +import java.util.Locale; import java.util.ResourceBundle; import javax.swing.JPanel; @@ -52,11 +53,29 @@ public class ColorSwatch extends JPanel implements ColorListener { * The default value for this key is assumed to be false if undefined. */ private static final String PROPERTY_COPY_CONTEXTUAL_MENU_ITEM = ColorSwatch.class + ".copyContextualMenuItem"; - private static final ResourceBundle strings = ResourceBundle.getBundle("com.bric.colorpicker.resources.ColorPicker"); + private static final String LOCALIZATION_BUNDLE_PATH = "com.bric.colorpicker.resources.ColorPicker"; private static TexturePaint checkerPaint; + private final ResourceBundle strings; private final int w; public ColorSwatch(int width) { + this(width, null); + } + + private ColorSwatch(Color color, int width) { + this(width); + setForeground(color); + } + + private ColorSwatch(Color color, int width, Locale locale) { + this(width, locale); + setForeground(color); + } + + public ColorSwatch(int width, Locale locale) { + if(locale == null) strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH); + else strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH, locale); + w = width; setPreferredSize(new Dimension(width, width)); setMinimumSize(new Dimension(width, width)); @@ -66,11 +85,6 @@ public ColorSwatch(int width) { updateContextualMenu(); } - private ColorSwatch(Color color, int width) { - this(width); - setForeground(color); - } - private static TexturePaint getCheckerPaint() { if (checkerPaint == null) { int t = 8; diff --git a/src/main/java/com/bric/colorpicker/parts/DialogFooter.java b/src/main/java/com/bric/colorpicker/parts/DialogFooter.java index 7060896..820be7a 100644 --- a/src/main/java/com/bric/colorpicker/parts/DialogFooter.java +++ b/src/main/java/com/bric/colorpicker/parts/DialogFooter.java @@ -36,6 +36,7 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.lang.reflect.Method; +import java.util.Locale; import java.util.Objects; import java.util.ResourceBundle; import javax.swing.AbstractAction; @@ -120,10 +121,12 @@ public class DialogFooter extends JPanel { private static final String PROPERTY_UNSAFE = "Dialog.Unsafe.Action"; private static final KeyStroke escapeKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); private static final KeyStroke commandPeriodKey = KeyStroke.getKeyStroke(KeyEvent.VK_PERIOD, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); + /** - * The localized STRINGS used in dialogs. + * Path to the localization bundle */ - private static final ResourceBundle strings = ResourceBundle.getBundle("com.bric.colorpicker.resources.DialogFooter"); + private static final String LOCALIZATION_BUNDLE_PATH = "com.bric.colorpicker.resources.DialogFooter"; + /** * This is the client property of buttons created in static methods by this class. */ @@ -200,6 +203,12 @@ public class DialogFooter extends JPanel { * should be the only option presented to the user. */ private static final int DONT_SAVE_OPTION = uniqueCtr++; + + /** + * The localized STRINGS used in dialogs. + */ + private static ResourceBundle strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH); + /** * Used to indicate the user selected an option not otherwise * specified in this set of constants. It may be possible @@ -352,7 +361,7 @@ public Component getDefaultComponent(Container focusCycleRoot) { private int buttonGap; private int unsafeButtonGap; - /** + /** * Create a new {@code DialogFooter}. * * @param leftControls the controls on the left side of this dialog, such as a help target, or a "Reset" button. @@ -365,7 +374,28 @@ public Component getDefaultComponent(Container focusCycleRoot) { * (May be null.) */ private DialogFooter(JComponent[] leftControls, JComponent[] dismissControls, boolean autoClose, JButton defaultButton) { + this(leftControls, dismissControls, autoClose, defaultButton, null); + } + + /** + * Create a new {@code DialogFooter}. + * + * @param leftControls the controls on the left side of this dialog, such as a help target, or a "Reset" button. + * @param dismissControls the controls on the right side of this dialog that should dismiss this dialog. Also + * called "action" buttons. + * @param autoClose whether the dismiss buttons should automatically close the containing window. + * If this is {@code false}, then it is assumed someone else is taking care of closing/disposing the + * containing dialog + * @param defaultButton the optional button in {@code dismissControls} to make the default button in this dialog. + * (May be null.) + * @param local the current active local of the app + */ + private DialogFooter(JComponent[] leftControls, JComponent[] dismissControls, boolean autoClose, JButton defaultButton, Locale locale) { super(new GridBagLayout()); + + if(locale == null) strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH); + else strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH, locale); + this.autoClose = autoClose; //this may be common: if (leftControls == null) { @@ -541,7 +571,7 @@ private static JButton createDontSaveButton(boolean escapeKeyIsTrigger) { return button; } - /** + /** * Creates a {@code DialogFooter}. * * @param leftComponents the components to put on the left side of the footer. @@ -554,6 +584,23 @@ private static JButton createDontSaveButton(boolean escapeKeyIsTrigger) { * @return a {@code DialogFooter} */ public static DialogFooter createDialogFooter(JComponent[] leftComponents, int options, int defaultButton, EscapeKeyBehavior escapeKeyBehavior) { + return createDialogFooter(leftComponents, options, defaultButton, escapeKeyBehavior, null); + } + + /** + * Creates a {@code DialogFooter}. + * + * @param leftComponents the components to put on the left side of the footer. + *

The Apple guidelines state that this area is reserved for + * "button[s] that affect the contents of the dialog itself, such as Reset [or Help]". + * @param options one of the OPTIONS fields in this class, such as YES_NO_OPTION or CANCEL_OPTION. + * @param defaultButton the OPTION field corresponding to the button that + * should be the default button, or -1 if there should be no default button. + * @param escapeKeyBehavior one of the EscapeKeyBehavior options in this class. + * @param local the current active local of the app + * @return a {@code DialogFooter} + */ + public static DialogFooter createDialogFooter(JComponent[] leftComponents, int options, int defaultButton, EscapeKeyBehavior escapeKeyBehavior, Locale locale) { if (escapeKeyBehavior == EscapeKeyBehavior.TRIGGERS_NONDEFAULT) { int buttonCount = 1; @@ -570,6 +617,9 @@ public static DialogFooter createDialogFooter(JComponent[] leftComponents, int o } } + if(locale == null) strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH); + else strings = ResourceBundle.getBundle(LOCALIZATION_BUNDLE_PATH, locale); + JButton cancelButton = null; if (options == CANCEL_OPTION || options == OK_CANCEL_OPTION || @@ -649,7 +699,7 @@ public static DialogFooter createDialogFooter(JComponent[] leftComponents, int o } } - return new DialogFooter(leftComponents, dismissControls, true, theDefaultButton); + return new DialogFooter(leftComponents, dismissControls, true, theDefaultButton, locale); } /** diff --git a/src/test/java/com/bric/colorpicker/ColorPickerLocalizedExample.java b/src/test/java/com/bric/colorpicker/ColorPickerLocalizedExample.java new file mode 100644 index 0000000..bc18936 --- /dev/null +++ b/src/test/java/com/bric/colorpicker/ColorPickerLocalizedExample.java @@ -0,0 +1,27 @@ +package com.bric.colorpicker; + +import javax.swing.JFrame; +import javax.swing.WindowConstants; +import java.awt.Color; +import java.awt.EventQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.Locale; + +public class ColorPickerLocalizedExample { + + public static void main(String[] args) throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> { + JFrame frame = new JFrame("ColorPicker Example"); + frame.setSize(600, 400); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + + ColorPicker colorPicker = new ColorPicker(true, true, Locale.FRENCH); + colorPicker.setColor(Color.BLUE); + colorPicker.addColorListener(colorModel -> System.out.println(colorModel.getColor())); + frame.add(colorPicker); + + frame.setVisible(true); + }); + } + +} diff --git a/src/test/java/com/bric/colorpicker/demo/ColorPickerDialogDemo.java b/src/test/java/com/bric/colorpicker/demo/ColorPickerDialogDemo.java index 5576d66..6a993b8 100644 --- a/src/test/java/com/bric/colorpicker/demo/ColorPickerDialogDemo.java +++ b/src/test/java/com/bric/colorpicker/demo/ColorPickerDialogDemo.java @@ -9,7 +9,9 @@ public class ColorPickerDialogDemo { public static void main(String[] args) throws InvocationTargetException, InterruptedException { - EventQueue.invokeAndWait(() -> ColorPickerDialog.showDialog(null, Color.GREEN)); + EventQueue.invokeAndWait(() -> { + ColorPickerDialog.showDialog(null, Color.GREEN); + }); } } diff --git a/src/test/java/com/bric/colorpicker/demo/ColorPickerDialogLocalizedDemo.java b/src/test/java/com/bric/colorpicker/demo/ColorPickerDialogLocalizedDemo.java new file mode 100644 index 0000000..5614ae6 --- /dev/null +++ b/src/test/java/com/bric/colorpicker/demo/ColorPickerDialogLocalizedDemo.java @@ -0,0 +1,18 @@ +package com.bric.colorpicker.demo; + +import com.bric.colorpicker.ColorPickerDialog; + +import java.awt.Color; +import java.awt.EventQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.Locale; + +public class ColorPickerDialogLocalizedDemo { + + public static void main(String[] args) throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> { + ColorPickerDialog.showDialog(null, Color.GREEN, Locale.FRENCH); + }); + } + +} \ No newline at end of file