/*
* This file is part of muCommander, http://www.mucommander.com
* Copyright (C) 2002-2016 Maxence Bernard
*
* muCommander is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* muCommander is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mucommander.ui.chooser;
import com.mucommander.text.Translator;
import com.mucommander.ui.dialog.FocusDialog;
import com.mucommander.ui.layout.XBoxPanel;
import com.mucommander.ui.layout.YBoxPanel;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Component used to let users pick a color.
* <p>
* The main reason for this component's existence is Swing's <code>JColorChooser</code> does not offer
* alpha transparency edition, and that its localisation is incomplete. This is a wrapper that fixes both
* of these shortcomings.
* </p>
* <p>
* This component can be used either as a regular widget and be added to a <code>container</code> or as
* a dialog box through the {@link #createDialog(Frame,ColorChooser) createDialog} method.
* </p>
* @author Nicolas Rinaudo, Maxence Bernard
*/
public class ColorChooser extends YBoxPanel implements ChangeListener {
// - UI components ----------------------------------------------------------
// --------------------------------------------------------------------------
/** Component that displays a preview of the current color */
private JComponent previewComponent;
/** Color chooser. */
private JColorChooser chooser;
/** Alpha transparency chooser. */
private IntegerChooser alpha;
// - Color editing ----------------------------------------------------------
// --------------------------------------------------------------------------
/** Currently selected color. */
private Color currentColor;
/** Color on which the dialog was initialised. */
private Color initialColor;
/** Property to change in the preview component when the current color changes */
private String previewColorPropertyName;
// - Localisation -----------------------------------------------------------
// --------------------------------------------------------------------------
/**
* Overrides the default, incomplete Swing translations.
*/
static {
String buffer;
// Tab labels.
UIManager.put("ColorChooser.rgbNameText", Translator.get("color_chooser.rgb"));
UIManager.put("ColorChooser.hsbNameText", Translator.get("color_chooser.hsb"));
UIManager.put("ColorChooser.swatchesNameText", Translator.get("color_chooser.swatches"));
// Red color name.
UIManager.put("ColorChooser.rgbRedText", buffer = Translator.get("color_chooser.red"));
UIManager.put("ColorChooser.hsbRedText", buffer);
// Green color name.
UIManager.put("ColorChooser.rgbGreenText", buffer = Translator.get("color_chooser.green"));
UIManager.put("ColorChooser.hsbGreenText", buffer);
// Blue color name.
UIManager.put("ColorChooser.rgbBlueText", buffer = Translator.get("color_chooser.blue"));
UIManager.put("ColorChooser.hsbBlueText", buffer);
// HSB tab specific strings.
UIManager.put("ColorChooser.hsbHueText", Translator.get("color_chooser.hue"));
UIManager.put("ColorChooser.hsbSaturationText", Translator.get("color_chooser.saturation"));
UIManager.put("ColorChooser.hsbBrightnessText", Translator.get("color_chooser.brightness"));
// Swatches tab specific strings.
UIManager.put("ColorChooser.swatchesRecentText", Translator.get("color_chooser.recent"));
}
// - Initialisation ---------------------------------------------------------
// --------------------------------------------------------------------------
public ColorChooser() {
this(Color.WHITE, null, null);
}
public ColorChooser(Color initialColor) {
this(initialColor, null, null);
}
public ColorChooser(Color initialColor, JComponent previewComponent, String previewColorPropertyName) {
this.currentColor = initialColor;
this.initialColor = initialColor;
// Initialises the UI.
add(createChooserPanel());
add(createTransparencyPanel());
alpha.setValue(initialColor.getAlpha());
chooser.setColor(initialColor);
if(previewComponent!=null && previewColorPropertyName!=null) {
this.previewComponent = previewComponent;
this.previewColorPropertyName = previewColorPropertyName;
add(createPreviewPanel(previewComponent));
updatePreview();
}
}
// - Dialog creation --------------------------------------------------------
// --------------------------------------------------------------------------
/**
* Creates a dialog containing the specified color chooser.
* @param parent component on which to center the dialog.
* @param chooser chooser to use within the dialog.
* @return a dialog containing the specified chooser.
*/
public static FocusDialog createDialog(Dialog parent, ColorChooser chooser) {
return new ChooserDialog(parent, chooser);
}
/**
* Creates a dialog containing the specified color chooser.
* @param parent component on which to center the dialog.
* @param chooser chooser to use within the dialog.
* @return a dialog containing the specified chooser.
*/
public static FocusDialog createDialog(Frame parent, ColorChooser chooser) {
return new ChooserDialog(parent, chooser);
}
// - UI Initialisation ------------------------------------------------------
// --------------------------------------------------------------------------
/**
* Creates the preview panel.
*/
private JPanel createPreviewPanel(JComponent previewComponent) {
JPanel panel;
Dimension size;
// Sets the label's preferred size (same width as the chooser, twice the normal label height).
size = previewComponent.getPreferredSize();
size.width = chooser.getPreferredSize().width;
size.height *= 2;
previewComponent.setPreferredSize(size);
// Sets the preview label appearance.
previewComponent.setOpaque(true);
// Creates the preview panel.
panel = new JPanel();
panel.add(previewComponent);
panel.setBorder(BorderFactory.createTitledBorder(Translator.get("preview")));
return panel;
}
/**
* Creates the color chooser panel.
*/
private JColorChooser createChooserPanel() {
// Creates the color chooser.
chooser = new JColorChooser();
chooser.setPreviewPanel(new JPanel());
chooser.getSelectionModel().addChangeListener(this);
return chooser;
}
/**
* Creates the transparency selection panel.
*/
private JPanel createTransparencyPanel() {
// Creates and initialises the transparency selector.
alpha = new IntegerChooser(0, 255, 255);
alpha.setMajorTickSpacing(85);
alpha.setMinorTickSpacing(17);
alpha.setPaintTicks(true);
alpha.setPaintLabels(true);
alpha.setBorder(BorderFactory.createTitledBorder(Translator.get("color_chooser.alpha")));
alpha.addChangeListener(this);
return alpha;
}
// - Color / font management ------------------------------------------------
// --------------------------------------------------------------------------
/**
* Returns the color selected by the user.
* @return the color selected by the user.
*/
public Color getColor() {
return currentColor;
}
/**
* Resets the dialog to the initial color.
*/
public void reset() {
reset(true);
}
/**
* Resets the dialog to the initial color.
* @param updateUI if set to <code>false</code>, the component's UI won't be updated.
*/
private void reset(boolean updateUI) {
currentColor = initialColor;
/// Propagates the color to the choosers.
if(updateUI) {
alpha.setValue(currentColor.getAlpha());
chooser.setColor(currentColor);
currentColor = initialColor; // Need to set it again as the value is changed by stateChanged()
updatePreview();
}
}
/**
* Update the preview panel to the current color.
*/
private void updatePreview() {
if(previewComponent!=null) {
previewComponent.putClientProperty(previewColorPropertyName, currentColor);
}
}
/**
* This method is public as an implementation side effect and should not be called directly.
*/
public void stateChanged(ChangeEvent e) {
Color buffer;
// Creates the new current color.
buffer = chooser.getColor();
currentColor = new Color(buffer.getRed(), buffer.getGreen(), buffer.getBlue(), alpha.getValue());
updatePreview();
}
// - Chooser dialog ---------------------------------------------------------
// --------------------------------------------------------------------------
/**
* Component used to present a <code>ColorChooser</code> from within a modal dialog.
* @author Nicolas Rinaudo
*/
private static class ChooserDialog extends FocusDialog implements ActionListener {
/** Resets the color to the original one. */
private JButton resetButton;
/** Closes the dialog without applying the color selection. */
private JButton cancelButton;
/** Color chooser contained by this dialog. */
private ColorChooser chooser;
/**
* Creates a new dialog containing the specified color chooser.
*/
public ChooserDialog(Frame parent, ColorChooser chooser) {
super(parent, Translator.get("color_chooser.title"), parent);
initUI(chooser);
}
/**
* Creates a new dialog containing the specified color chooser.
*/
public ChooserDialog(Dialog parent, ColorChooser chooser) {
super(parent, Translator.get("color_chooser.title"), parent);
initUI(chooser);
}
/**
* Initialises the dialog's UI.
*/
private void initUI(ColorChooser chooser) {
Container contentPane;
this.chooser = chooser;
// Initialises the dialog and its content pane.
contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
// Creates the content of the dialog.
contentPane.add(chooser, BorderLayout.CENTER);
contentPane.add(createButtonsPanel(), BorderLayout.SOUTH);
}
/**
* Creates the panel that contains the dialog's buttons.
*/
private JPanel createButtonsPanel() {
XBoxPanel buttonsPanel;
JPanel panel;
JButton okButton;
// Creates the panel and buttons.
buttonsPanel = new XBoxPanel();
buttonsPanel.add(resetButton = new JButton(Translator.get("reset")));
buttonsPanel.addSpace(20);
buttonsPanel.add(okButton = new JButton(Translator.get("ok")));
buttonsPanel.add(cancelButton = new JButton(Translator.get("cancel")));
// Tracks events.
resetButton.addActionListener(this);
okButton.addActionListener(this);
cancelButton.addActionListener(this);
// OK will be selected when the user presses enter.
getRootPane().setDefaultButton(okButton);
// Aligns the buttons to the right of the panel.
panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
panel.add(buttonsPanel);
return panel;
}
/**
* In case the dialog was cancelled, resets the color before closing it.
*/
@Override
public void cancel() {
chooser.reset(false);
super.cancel();
}
/**
* This method is public as an implementation side effect and should not be called directly.
*/
public void actionPerformed(ActionEvent e) {
// Resets the current color.
if(e.getSource() == resetButton)
chooser.reset(true);
// Closes the dialog, applying modifications if necessary.
else {
if(e.getSource() == cancelButton)
chooser.reset(false);
dispose();
}
}
}
}