/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.constellation.gui;
// User interface
import org.geotoolkit.display.shape.Arrow2D;
import javax.swing.*;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.image.RenderedImage;
// Events
// Geometry and images
// Geotools dependencies
/**
* Boîte de dialogue demandant à l'utilisateur de choisir une couleur. La
* section "aperçu" contiendra une image satellitaire (facultative) avec
* une forme géométrique par dessus.
*
* @version $Id$
* @author Martin Desruisseaux
*/
@SuppressWarnings("serial")
final class MarkColorChooser extends JColorChooser {
/**
* Image à placer en arrière-plan dans l'aperçu,
* ou {@code null} s'il n'y en a pas.
*/
private RenderedImage image;
/**
* Transformation affine à appliquer sur l'image pour son affichage.
* Cette transformation affine comprendra principalement une translation.
*/
private AffineTransform transform;
/**
* Forme géométrique utilisée pour représenter une composante
* sur une image. Cette forme sera utilisée pour permettre à
* l'utilisateur de constater de visu l'effet d'un changement
* de couleur. Cette forme doit être centrée sur (0,0) et ses
* dimensions doivent être en pixels.
*/
private Shape shape = new Arrow2D(-32f, -24f, 64f, 48f);
/**
* Coordonnées (en pixels) de l'espace occupée par la ou les formes
* géométriques dont la couleur variera. Ces coordonnées ne sont pas
* centrées à (0,0), contrairement à {@code shape}.
*/
private Rectangle shapeBounds, paintBounds;
/**
* Construit un paneau qui permettra de choisir une couleur
* pour des composantes à placer par dessus des images.
*
* @param simplified {@code true} s'il faut utiliser la forme simplifiée
* de la boîte de dialogue. La forme simplifiée ne comprend que la palette
* de couleurs, sans les autres paneaux qui servent à contrôler les
* composantes RGBs.
*/
public MarkColorChooser(final boolean simplified) {
final Preview preview = new Preview();
preview.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(/*top*/6,/*left*/6,/*bottom*/6,/*right*/6),
BorderFactory.createLoweredBevelBorder()));
setPreviewPanel(preview);
getSelectionModel().addChangeListener(preview);
if (simplified) {
final AbstractColorChooserPanel[] panels = getChooserPanels();
removeChooserPanel(panels[2]);
removeChooserPanel(panels[1]);
}
setShape(shape);
}
/**
* Spécifie l'image à faire apparaître en arrière plan, ou {@code null}
* s'il n'y en a pas. Cette image sera centrée dans la zone "aperçu" de la
* boîte de dialogue.
*/
public void setBackground(final RenderedImage image) {
this.image=image;
transform = (image!=null) ? AffineTransform.getTranslateInstance(-0.5*image.getWidth(),
-0.5*image.getHeight()) : null;
}
/**
* Spécifie la forme géométrique à tracer. Cette forme devrait être centrée
* à (0,0) et ses coordonnées devraient être exprimées en pixels. Cette forme
* sera centrée dans la zone "aperçu" de la boîte de dialogue. Les dimensions
* de cette forme détermineront les dimensions en pixels de la zone d'aperçu.
*/
public void setShape(final Shape shape) {
shapeBounds = shape.getBounds();
this.shape = shape;
}
/**
* Duplique la forme géométrique. Cette méthode peut être appelée après
* {@link #setShape} pour disperser un peu les exemplaires de la forme
* dans la zone d'aperçu.
*/
public void duplicateShape(final int count) {
final AffineTransform transform = AffineTransform.getTranslateInstance(
-1.25*shape.getBounds2D().getWidth(), 0);
transform.rotate(Math.toRadians(-30));
transform.scale(0.75, 0.75);
final GeneralPath path = new GeneralPath(shape);
path.transform(transform);
path.append(shape, false);
shape = path;
}
/**
* Dessine l'apperçu. Cette méthode n'a pas à se soucier de rétablir
* le graphique dans son état original lorsqu'elle aura terminé.
*
* @return Un rectangle englobant les coordonnées
* de la forme dont la couleur variera.
*/
private Rectangle paintPreview(final Graphics2D graphics) {
if (image != null) {
graphics.drawRenderedImage(image, transform);
}
graphics.setColor(getColor());
graphics.fill(shape);
return shape.getBounds();
}
/**
* Classe de la composante qui affichera un apperçu des
* composantes cartographiques avec leur nouvelle couleur.
*/
@SuppressWarnings("serial")
private final class Preview extends JComponent implements ChangeListener {
/**
* Utilisé temporairement pour éviter des création trop fréquentes.
*/
private final Insets insets=new Insets(0,0,0,0);
/**
* Construit un visualisateur d'aperçus.
*/
public Preview() {
setUI(new ComponentUI() {
public Dimension getPreferredSize(final JComponent c) {
final Dimension size=shapeBounds.getSize();
size.width += 24; // Note: se souvenir que de la place
size.height += 24; // est utilisée pour les bordures
return size;
}
public void paint(final Graphics g, final JComponent c) {
final Insets insets=getInsets(Preview.this.insets);
final Graphics2D graphics = (Graphics2D) g;
final int centerX = getWidth()/2;
final int centerY = getHeight()/2;
graphics.clipRect(insets.left, insets.top, getWidth()-(insets.left+insets.right), getHeight()-(insets.top+insets.bottom));
graphics.translate(centerX, centerY);
paintBounds=paintPreview(graphics);
paintBounds.translate(centerX, centerY);
}
});
}
/**
* Méthode appelée automatiquement chaque fois que
* l'utilisateur sélectionne une nouvelle couleur.
*/
public void stateChanged(final ChangeEvent event) {
if (paintBounds != null) {
repaint(paintBounds);
}
}
}
}