/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.ui.ranking.plugin;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.gephi.ranking.api.ColorTransformer;
import org.gephi.ranking.api.Ranking;
import org.gephi.ranking.api.Transformer;
import org.gephi.ui.components.JRangeSlider;
import org.gephi.ui.components.PaletteIcon;
import org.gephi.ui.components.gradientslider.GradientSlider;
import org.gephi.utils.PaletteUtils;
import org.gephi.utils.PaletteUtils.Palette;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
/**
* @author Mathieu Bastian
*/
public class ColorTransformerPanel extends javax.swing.JPanel {
private static final int SLIDER_MAXIMUM = 100;
private ColorTransformer colorTransformer;
private GradientSlider gradientSlider;
private Ranking ranking;
public ColorTransformerPanel(Transformer transformer, Ranking ranking) {
initComponents();
final String POSITIONS = "ColorTransformerPanel_" + transformer.getClass().getSimpleName() + "_positions";
final String COLORS = "ColorTransformerPanel_" + transformer.getClass().getSimpleName() + "_colors";
colorTransformer = (ColorTransformer) transformer;
this.ranking = ranking;
float[] positionsStart = colorTransformer.getColorPositions();
Color[] colorsStart = colorTransformer.getColors();
try {
positionsStart = deserializePositions(NbPreferences.forModule(ColorTransformerPanel.class).getByteArray(POSITIONS, serializePositions(positionsStart)));
colorsStart = deserializeColors(NbPreferences.forModule(ColorTransformerPanel.class).getByteArray(COLORS, serializeColors(colorsStart)));
colorTransformer.setColorPositions(positionsStart);
colorTransformer.setColors(colorsStart);
} catch (Exception e) {
e.printStackTrace();
}
//Gradient
gradientSlider = new GradientSlider(GradientSlider.HORIZONTAL, positionsStart, colorsStart);
gradientSlider.putClientProperty("GradientSlider.includeOpacity", "false");
gradientSlider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
Color[] colors = gradientSlider.getColors();
float[] positions = gradientSlider.getThumbPositions();
colorTransformer.setColors(Arrays.copyOf(colors, colors.length));
colorTransformer.setColorPositions(Arrays.copyOf(positions, positions.length));
try {
NbPreferences.forModule(ColorTransformerPanel.class).putByteArray(POSITIONS, serializePositions(positions));
NbPreferences.forModule(ColorTransformerPanel.class).putByteArray(COLORS, serializeColors(colors));
} catch (Exception ex) {
ex.printStackTrace();
}
prepareGradientTooltip();
}
});
gradientPanel.add(gradientSlider, BorderLayout.CENTER);
//Range
JRangeSlider slider = (JRangeSlider) rangeSlider;
slider.setMinimum(0);
slider.setMaximum(SLIDER_MAXIMUM);
slider.setValue(0);
slider.setUpperValue(SLIDER_MAXIMUM);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JRangeSlider source = (JRangeSlider) e.getSource();
if (!source.getValueIsAdjusting()) {
setRangeValues();
}
prepareGradientTooltip();
}
});
refreshRangeValues();
prepareGradientTooltip();
//Context
setComponentPopupMenu(getPalettePopupMenu());
}
private void prepareGradientTooltip(){
StringBuilder sb=new StringBuilder();
final double min=((Number)ranking.unNormalize(colorTransformer.getLowerBound())).doubleValue();
final double max=((Number)ranking.unNormalize(colorTransformer.getUpperBound())).doubleValue();
final double range=max-min;
float[] positions = gradientSlider.getThumbPositions();
for (int i = 0; i < positions.length-1; i++) {
sb.append(min+range*positions[i]);
sb.append(", ");
}
sb.append(min+range*positions[positions.length-1]);
gradientSlider.setToolTipText(sb.toString());
}
private void setRangeValues() {
JRangeSlider slider = (JRangeSlider) rangeSlider;
float low = slider.getValue() / 100f;
float high = slider.getUpperValue() / 100f;
colorTransformer.setLowerBound(low);
colorTransformer.setUpperBound(high);
lowerBoundLabel.setText(ranking.unNormalize(colorTransformer.getLowerBound()).toString());
upperBoundLabel.setText(ranking.unNormalize(colorTransformer.getUpperBound()).toString());
}
private void refreshRangeValues() {
JRangeSlider slider = (JRangeSlider) rangeSlider;
slider.setValue((int) (colorTransformer.getLowerBound() * 100f));
slider.setUpperValue((int) (colorTransformer.getUpperBound() * 100f));
lowerBoundLabel.setText(ranking.unNormalize(colorTransformer.getLowerBound()).toString());
upperBoundLabel.setText(ranking.unNormalize(colorTransformer.getUpperBound()).toString());
}
private JPopupMenu getPalettePopupMenu() {
JPopupMenu popupMenu = new JPopupMenu();
JMenu defaultMenu = new JMenu(NbBundle.getMessage(ColorTransformerPanel.class, "PalettePopup.default"));
for (Palette p : PaletteUtils.getSequencialPalettes()) {
final Palette p3 = PaletteUtils.get3ClassPalette(p);
JMenuItem item = new JMenuItem(new PaletteIcon(p3.getColors()));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
gradientSlider.setValues(p3.getPositions(), p3.getColors());
}
});
defaultMenu.add(item);
}
for (Palette p : PaletteUtils.getDivergingPalettes()) {
final Palette p3 = PaletteUtils.get3ClassPalette(p);
JMenuItem item = new JMenuItem(new PaletteIcon(p3.getColors()));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
gradientSlider.setValues(p3.getPositions(), p3.getColors());
}
});
defaultMenu.add(item);
}
popupMenu.add(defaultMenu);
//Invert
JMenuItem invertItem = new JMenuItem(NbBundle.getMessage(ColorTransformerPanel.class, "PalettePopup.invert"));
invertItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
gradientSlider.setValues(invert(gradientSlider.getThumbPositions()), invert(gradientSlider.getColors()));
}
});
popupMenu.add(invertItem);
return popupMenu;
}
private Color[] invert(Color[] source) {
int len = source.length;
Color[] res = new Color[len];
for (int i = 0; i < len; i++) {
res[i] = source[len - 1 - i];
}
return res;
}
private float[] invert(float[] source) {
int len = source.length;
float[] res = new float[len];
for (int i = 0; i < len; i++) {
res[i] = 1 - source[len - 1 - i];
}
return res;
}
private byte[] serializePositions(float[] positions) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(positions);
out.close();
return bos.toByteArray();
}
private float[] deserializePositions(byte[] positions) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(positions);
ObjectInputStream in = new ObjectInputStream(bis);
float[] array = (float[]) in.readObject();
in.close();
return array;
}
private byte[] serializeColors(Color[] colors) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(colors);
out.close();
return bos.toByteArray();
}
private Color[] deserializeColors(byte[] colors) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(colors);
ObjectInputStream in = new ObjectInputStream(bis);
Color[] array = (Color[]) in.readObject();
in.close();
return array;
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
labelColor = new javax.swing.JLabel();
gradientPanel = new javax.swing.JPanel();
rangeSlider = new JRangeSlider();
labelRange = new javax.swing.JLabel();
upperBoundLabel = new javax.swing.JLabel();
lowerBoundLabel = new javax.swing.JLabel();
setPreferredSize(new java.awt.Dimension(225, 114));
labelColor.setText(org.openide.util.NbBundle.getMessage(ColorTransformerPanel.class, "ColorTransformerPanel.labelColor.text")); // NOI18N
gradientPanel.setOpaque(false);
gradientPanel.setLayout(new java.awt.BorderLayout());
rangeSlider.setFocusable(false);
rangeSlider.setOpaque(false);
labelRange.setText(org.openide.util.NbBundle.getMessage(ColorTransformerPanel.class, "ColorTransformerPanel.labelRange.text")); // NOI18N
upperBoundLabel.setFont(new java.awt.Font("Tahoma", 0, 10));
upperBoundLabel.setForeground(new java.awt.Color(102, 102, 102));
upperBoundLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
upperBoundLabel.setText(org.openide.util.NbBundle.getMessage(ColorTransformerPanel.class, "ColorTransformerPanel.upperBoundLabel.text")); // NOI18N
lowerBoundLabel.setFont(new java.awt.Font("Tahoma", 0, 10));
lowerBoundLabel.setForeground(new java.awt.Color(102, 102, 102));
lowerBoundLabel.setText(org.openide.util.NbBundle.getMessage(ColorTransformerPanel.class, "ColorTransformerPanel.lowerBoundLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(labelColor)
.addGap(18, 18, 18)
.addComponent(gradientPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(labelRange)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(lowerBoundLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(upperBoundLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(rangeSlider, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(labelColor, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(gradientPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(rangeSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(labelRange, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lowerBoundLabel)
.addComponent(upperBoundLabel))
.addContainerGap(23, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel gradientPanel;
private javax.swing.JLabel labelColor;
private javax.swing.JLabel labelRange;
private javax.swing.JLabel lowerBoundLabel;
private javax.swing.JSlider rangeSlider;
private javax.swing.JLabel upperBoundLabel;
// End of variables declaration//GEN-END:variables
}