Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localization support (Issue #54) #55

Merged
merged 1 commit into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
64 changes: 50 additions & 14 deletions src/main/java/com/bric/colorpicker/ColorPicker.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -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}.
*
Expand All @@ -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.
* <P>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();

Expand All @@ -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++) {
Expand All @@ -173,13 +203,15 @@ 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++;
constraints.anchor = GridBagConstraints.LINE_START;
constraints.fill = GridBagConstraints.HORIZONTAL;
optionsPanel.add(hexField, constraints);

alphaOption = new AlphaOption(locale);
alphaOption.addTo(optionsPanel, constraints);

constraints.gridx = 0;
Expand Down Expand Up @@ -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++;
Expand All @@ -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++;
Expand All @@ -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();
Expand Down
76 changes: 63 additions & 13 deletions src/main/java/com/bric/colorpicker/ColorPickerDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}

/**
Expand All @@ -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);
}
Expand All @@ -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.
* <P>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);
}

/**
Expand All @@ -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.
* <P>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());
Expand All @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/com/bric/colorpicker/options/AlphaOption.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/com/bric/colorpicker/options/BlueOption.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/com/bric/colorpicker/options/GreenOption.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading
Loading