/*
* Copyright (C) 2010 Laszlo Zsolt Kustra <kl223 AT ludens.elte.hu>
*
* This program 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.
*
* This program 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 jmandelbrotviewer;
// <editor-fold defaultstate="collapsed" desc="import list">
import jmandelbrotviewer.util.SpinnerBigDecimalModel;
import jmandelbrotviewer.util.SpinnerBigDecimalEditor;
import java.awt.Color;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeListenerProxy;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.List;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JComboBox;
import jmandelbrotviewer.worker.MandelbrotWorker;
// </editor-fold>
/**
*
* @author Laszlo Zsolt Kustra <kl223 AT ludens.elte.hu>
*/
public class MainFrame extends javax.swing.JFrame {
public static final BigDecimal iterationLimitStep = new BigDecimal("0.02");
public static final String bigNumDecimalFormat;
public static final String selectedColorsListElementSuffix = " \u00AB";
static {
StringBuilder sb = new StringBuilder("### ##0.0");
for (int idx=1; idx < MandelbrotCtx.mathCtx.getPrecision(); ++idx) {
sb.append('#');
}
sb.append(";-#");
bigNumDecimalFormat = sb.toString();
}
/** Creates new form MainFrame */
public MainFrame() {
ctxDirtyChangeListener = new PropertyChangeListenerProxy("dirty",
new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
ctxDirtyPropertyChanged((Boolean)evt.getNewValue());
}
});
initComponents();
}
// <editor-fold defaultstate="collapsed" desc="private static class ColorsListRenderer">
private static class ColorsListRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof Color) {
Color color = (Color)value;
setBackground(color);
setForeground(new Color(255-color.getRed(), 255-color.getGreen(), 255-color.getBlue()));
if (isSelected) setText("("+color.getRed()+", "+color.getGreen()+", "+color.getBlue()+")"+selectedColorsListElementSuffix);
else setText("("+color.getRed()+", "+color.getGreen()+", "+color.getBlue()+")");
}
return this;
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="initComponents">
/** 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() {
java.awt.GridBagConstraints gridBagConstraints;
bindingGroup = new org.jdesktop.beansbinding.BindingGroup();
fractalChooser = new javax.swing.JFileChooser();
drawPanel = new jmandelbrotviewer.MandelbrotPanel();
javax.swing.JPanel controlPanel = new javax.swing.JPanel();
javax.swing.JLabel jLabel11 = new javax.swing.JLabel();
workersComboBox = new JComboBox(MandelbrotWorker.getWorkerKeys());
javax.swing.JLabel jLabel2 = new javax.swing.JLabel();
iterationLimitSpinner = new javax.swing.JSpinner();
javax.swing.JLabel jLabel3 = new javax.swing.JLabel();
iterationAreaMinXSpinner = new javax.swing.JSpinner();
javax.swing.JLabel jLabel4 = new javax.swing.JLabel();
iterationAreaMinYSpinner = new javax.swing.JSpinner();
javax.swing.JLabel jLabel5 = new javax.swing.JLabel();
iterationAreaMaxXSpinner = new javax.swing.JSpinner();
javax.swing.JLabel jLabel6 = new javax.swing.JLabel();
iterationAreaMaxYSpinner = new javax.swing.JSpinner();
javax.swing.JLabel jLabel1 = new javax.swing.JLabel();
viewportZoomStep = new javax.swing.JSpinner();
javax.swing.JLabel jLabel8 = new javax.swing.JLabel();
viewportCenterX = new javax.swing.JSpinner();
javax.swing.JLabel jLabel9 = new javax.swing.JLabel();
viewportCenterY = new javax.swing.JSpinner();
javax.swing.JLabel jLabel10 = new javax.swing.JLabel();
viewportWidth = new javax.swing.JSpinner();
javax.swing.JPanel jPanel1 = new javax.swing.JPanel();
javax.swing.JLabel jLabel7 = new javax.swing.JLabel();
javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
colorsList = new javax.swing.JList();
topColorButton = new javax.swing.JButton();
upColorButton = new javax.swing.JButton();
javax.swing.JPanel jPanel2 = new javax.swing.JPanel();
downColorButton = new javax.swing.JButton();
bottomColorButton = new javax.swing.JButton();
jPanel3 = new javax.swing.JPanel();
setColorButton = new javax.swing.JButton();
addColorButton = new javax.swing.JButton();
removeColorButton = new javax.swing.JButton();
javax.swing.JPanel jPanel4 = new javax.swing.JPanel();
clearButton = new javax.swing.JButton();
loadButton = new javax.swing.JButton();
saveButton = new javax.swing.JButton();
drawProgressBar = new javax.swing.JProgressBar();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("JMandelbrotViewer v0.2");
setMinimumSize(new java.awt.Dimension(800, 600));
getContentPane().setLayout(new java.awt.GridBagLayout());
drawPanel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
drawPanelMouseClicked(evt);
}
public void mousePressed(java.awt.event.MouseEvent evt) {
drawPanelMousePressed(evt);
}
public void mouseReleased(java.awt.event.MouseEvent evt) {
drawPanelMouseReleased(evt);
}
});
drawPanel.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseDragged(java.awt.event.MouseEvent evt) {
drawPanelMouseDragged(evt);
}
});
drawPanel.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
public void propertyChange(java.beans.PropertyChangeEvent evt) {
drawPanelPropertyChange(evt);
}
});
drawPanel.getCtx().addPropertyChangeListener(ctxDirtyChangeListener);
drawPanel.setLayout(null);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
getContentPane().add(drawPanel, gridBagConstraints);
controlPanel.setPreferredSize(new java.awt.Dimension(200, 0));
controlPanel.setLayout(new java.awt.GridBagLayout());
jLabel11.setText("Worker type:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
controlPanel.add(jLabel11, gridBagConstraints);
workersComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
workersComboBoxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
controlPanel.add(workersComboBox, gridBagConstraints);
jLabel2.setText("Iteration limit:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
controlPanel.add(jLabel2, gridBagConstraints);
iterationLimitSpinner.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(1), Integer.valueOf(0), null, Integer.valueOf(1)));
org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.iterationLimit}"), iterationLimitSpinner, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
controlPanel.add(iterationLimitSpinner, gridBagConstraints);
jLabel3.setText("Iteration min x:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
controlPanel.add(jLabel3, gridBagConstraints);
iterationAreaMinXSpinner.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.0), null, null, iterationLimitStep));
iterationAreaMinXSpinner.setEditor(new SpinnerBigDecimalEditor(iterationAreaMinXSpinner, bigNumDecimalFormat));
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.iterationAreaMinX}"), iterationAreaMinXSpinner, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
controlPanel.add(iterationAreaMinXSpinner, gridBagConstraints);
jLabel4.setText("Iteration min y:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
controlPanel.add(jLabel4, gridBagConstraints);
iterationAreaMinYSpinner.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.0), null, null, iterationLimitStep));
iterationAreaMinYSpinner.setEditor(new SpinnerBigDecimalEditor(iterationAreaMinYSpinner, bigNumDecimalFormat));
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.iterationAreaMinY}"), iterationAreaMinYSpinner, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
controlPanel.add(iterationAreaMinYSpinner, gridBagConstraints);
jLabel5.setText("Iteration max x:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
controlPanel.add(jLabel5, gridBagConstraints);
iterationAreaMaxXSpinner.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.0), null, null, iterationLimitStep));
iterationAreaMaxXSpinner.setEditor(new SpinnerBigDecimalEditor(iterationAreaMaxXSpinner, bigNumDecimalFormat));
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.iterationAreaMaxX}"), iterationAreaMaxXSpinner, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
controlPanel.add(iterationAreaMaxXSpinner, gridBagConstraints);
jLabel6.setText("Iteration max y:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
controlPanel.add(jLabel6, gridBagConstraints);
iterationAreaMaxYSpinner.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.0), null, null, iterationLimitStep));
iterationAreaMaxYSpinner.setEditor(new SpinnerBigDecimalEditor(iterationAreaMaxYSpinner, bigNumDecimalFormat));
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.iterationAreaMaxY}"), iterationAreaMaxYSpinner, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
controlPanel.add(iterationAreaMaxYSpinner, gridBagConstraints);
jLabel1.setText("Zoom step:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
controlPanel.add(jLabel1, gridBagConstraints);
viewportZoomStep.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.25), null, null, iterationLimitStep));
viewportZoomStep.setEditor(new SpinnerBigDecimalEditor(viewportZoomStep, bigNumDecimalFormat));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
controlPanel.add(viewportZoomStep, gridBagConstraints);
jLabel8.setText("Viewport center x:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
controlPanel.add(jLabel8, gridBagConstraints);
viewportCenterX.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.0), null, null, iterationLimitStep));
viewportCenterX.setEditor(new SpinnerBigDecimalEditor(viewportCenterX, bigNumDecimalFormat));
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.viewportCenterX}"), viewportCenterX, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
controlPanel.add(viewportCenterX, gridBagConstraints);
jLabel9.setText("Viewport center y:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
controlPanel.add(jLabel9, gridBagConstraints);
viewportCenterY.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.0), null, null, iterationLimitStep));
viewportCenterY.setEditor(new SpinnerBigDecimalEditor(viewportCenterY, bigNumDecimalFormat));
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.viewportCenterY}"), viewportCenterY, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
controlPanel.add(viewportCenterY, gridBagConstraints);
jLabel10.setText("Viewport width:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
controlPanel.add(jLabel10, gridBagConstraints);
viewportWidth.setModel(new SpinnerBigDecimalModel(MandelbrotCtx.mathCtx, new BigDecimal(0.0), null, null, iterationLimitStep));
viewportWidth.setEditor(new SpinnerBigDecimalEditor(viewportWidth, bigNumDecimalFormat));
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, org.jdesktop.beansbinding.ELProperty.create("${ctx.viewportWidth}"), viewportWidth, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
controlPanel.add(viewportWidth, gridBagConstraints);
jPanel1.setLayout(new java.awt.GridBagLayout());
jLabel7.setText("Color palette:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
jPanel1.add(jLabel7, gridBagConstraints);
colorsList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
colorsList.setCellRenderer(new ColorsListRenderer());
org.jdesktop.beansbinding.ELProperty eLProperty = org.jdesktop.beansbinding.ELProperty.create("${ctx.colors}");
org.jdesktop.swingbinding.JListBinding jListBinding = org.jdesktop.swingbinding.SwingBindings.createJListBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, drawPanel, eLProperty, colorsList);
bindingGroup.addBinding(jListBinding);
colorsList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
colorsListValueChanged(evt);
}
});
jScrollPane1.setViewportView(colorsList);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridheight = 5;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel1.add(jScrollPane1, gridBagConstraints);
topColorButton.setText("Top");
topColorButton.setEnabled(false);
topColorButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
topColorButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
topColorButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
jPanel1.add(topColorButton, gridBagConstraints);
upColorButton.setText("Up");
upColorButton.setEnabled(false);
upColorButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
upColorButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
upColorButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
jPanel1.add(upColorButton, gridBagConstraints);
jPanel2.setLayout(null);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weighty = 1.0;
jPanel1.add(jPanel2, gridBagConstraints);
downColorButton.setText("Down");
downColorButton.setEnabled(false);
downColorButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
downColorButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
downColorButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
jPanel1.add(downColorButton, gridBagConstraints);
bottomColorButton.setText("Bottom");
bottomColorButton.setEnabled(false);
bottomColorButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
bottomColorButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bottomColorButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
jPanel1.add(bottomColorButton, gridBagConstraints);
jPanel3.setLayout(new java.awt.GridBagLayout());
setColorButton.setText("Set");
setColorButton.setEnabled(false);
setColorButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
setColorButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
setColorButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
jPanel3.add(setColorButton, gridBagConstraints);
addColorButton.setText("Add");
addColorButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
addColorButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addColorButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
jPanel3.add(addColorButton, gridBagConstraints);
removeColorButton.setText("Del");
removeColorButton.setEnabled(false);
removeColorButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
removeColorButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeColorButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
jPanel3.add(removeColorButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
jPanel1.add(jPanel3, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
controlPanel.add(jPanel1, gridBagConstraints);
jPanel4.setLayout(new java.awt.GridBagLayout());
clearButton.setText("Clear");
clearButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
clearButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
clearButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
jPanel4.add(clearButton, gridBagConstraints);
loadButton.setText("Load");
loadButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
loadButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
loadButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
jPanel4.add(loadButton, gridBagConstraints);
saveButton.setText("Save");
saveButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
saveButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
jPanel4.add(saveButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0);
controlPanel.add(jPanel4, gridBagConstraints);
drawProgressBar.setEnabled(false);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(1, 0, 0, 0);
controlPanel.add(drawProgressBar, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
getContentPane().add(controlPanel, gridBagConstraints);
bindingGroup.bind();
pack();
}// </editor-fold>//GEN-END:initComponents
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="event handlers">
// <editor-fold defaultstate="collapsed" desc="fractal zoom event handler">
private void drawPanelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_drawPanelMouseClicked
if (!isProcessing()) {
int zoomDir = evt.getButton() == java.awt.event.MouseEvent.BUTTON1 ? 1 : -1;
final MathContext mathCtx = MandelbrotCtx.mathCtx;
BigDecimal zoomStep = (BigDecimal)viewportZoomStep.getValue();
MandelbrotCtx ctx = drawPanel.getCtx();
// calculate current center in the Mandelbrot coordinate system
BigDecimal width = ctx.getViewportWidth();
BigDecimal centerX = ctx.getViewportCenterX();
BigDecimal centerY = ctx.getViewportCenterY();
BigDecimal ratio =
new BigDecimal(drawPanel.getHeight()).divide(
new BigDecimal(drawPanel.getWidth()), mathCtx
);
BigDecimal height = ratio.multiply(width);
BigDecimal minY = centerY.subtract(height.divide(MandelbrotCtx.TWO));
// calculate mouse position in the Mandelbrot coordinate system
BigDecimal px = ctx.getViewportMinX().add(
new BigDecimal(evt.getX()).divide(
new BigDecimal(drawPanel.getWidth()), mathCtx).multiply(
width
), mathCtx);
BigDecimal py = minY.add(
new BigDecimal(evt.getY()).divide(
new BigDecimal(drawPanel.getHeight()), mathCtx).multiply(
height
), mathCtx);
// calculate new center
if (zoomDir < 0) zoomStep = zoomStep.negate();
centerX = centerX.add(px.subtract(centerX).multiply(zoomStep), mathCtx);
centerY = centerY.add(py.subtract(centerY).multiply(zoomStep), mathCtx);
BigDecimal widthStep = width.divide(MandelbrotCtx.TWO).multiply(
BigDecimal.ONE.subtract(zoomStep, mathCtx), mathCtx
);
ctx.setViewportMinX(centerX.subtract(widthStep), true);
ctx.setViewportMaxX(centerX.add(widthStep), true);
ctx.setViewportCenterY(centerY, true);
ctx.setDirty(true);
}
}//GEN-LAST:event_drawPanelMouseClicked
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="fractal move event handlers">
private void drawPanelMouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_drawPanelMouseDragged
if (mouseDragBeginX != -1 && mouseDragBeginY != -1) {
mouseDragValid = true;
drawPanel.setImageDx(evt.getX()-mouseDragBeginX);
drawPanel.setImageDy(evt.getY()-mouseDragBeginY);
drawPanel.repaint();
}
}//GEN-LAST:event_drawPanelMouseDragged
private void drawPanelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_drawPanelMousePressed
if (!isProcessing()) {
mouseDragBeginX = evt.getX();
mouseDragBeginY = evt.getY();
} else {
mouseDragBeginX = -1;
mouseDragBeginY = -1;
}
mouseDragValid = false;
}//GEN-LAST:event_drawPanelMousePressed
private void drawPanelMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_drawPanelMouseReleased
if (mouseDragBeginX != -1 && mouseDragBeginY != -1 && mouseDragValid) {
MandelbrotCtx ctx = drawPanel.getCtx();
final MathContext mathCtx = MandelbrotCtx.mathCtx;
BigDecimal width = ctx.getViewportWidth();
BigDecimal ratio =
new BigDecimal(drawPanel.getHeight()).divide(
new BigDecimal(drawPanel.getWidth()), mathCtx
);
BigDecimal height = ratio.multiply(width);
BigDecimal moveX = new BigDecimal(mouseDragBeginX-evt.getX()).divide(
new BigDecimal(drawPanel.getWidth()), mathCtx).multiply(width);
BigDecimal moveY = new BigDecimal(mouseDragBeginY-evt.getY()).divide(
new BigDecimal(drawPanel.getHeight()), mathCtx).multiply(height);
ctx.setViewportMinX(ctx.getViewportMinX().add(moveX), true);
ctx.setViewportMaxX(ctx.getViewportMaxX().add(moveX), true);
ctx.setViewportCenterY(ctx.getViewportCenterY().add(moveY), true);
ctx.setDirty(true);
}
}//GEN-LAST:event_drawPanelMouseReleased
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="colorsList button event handlers">
private void colorsListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_colorsListValueChanged
if (!evt.getValueIsAdjusting()) {
boolean buttonsEnabled = colorsList.getSelectedIndex() != -1;
setColorButton.setEnabled(buttonsEnabled);
buttonsEnabled = buttonsEnabled && colorsList.getModel().getSize() > 1;
removeColorButton.setEnabled(buttonsEnabled);
int curPos = colorsList.getSelectedIndex();
int colorsSize = colorsList.getModel().getSize();
topColorButton.setEnabled(buttonsEnabled && curPos != 0);
upColorButton.setEnabled(buttonsEnabled && curPos != 0);
downColorButton.setEnabled(buttonsEnabled && curPos != colorsSize-1);
bottomColorButton.setEnabled(buttonsEnabled && curPos != colorsSize-1);
}
}//GEN-LAST:event_colorsListValueChanged
private void setColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_setColorButtonActionPerformed
int selectedIndex = colorsList.getSelectedIndex();
Color color = (Color)colorsList.getSelectedValue();
if (color != null) {
Color newColor = JColorChooser.showDialog(this, "Choose a color", color);
if (newColor != null) {
List<Color> colors = drawPanel.getCtx().getColors();
colors.set(selectedIndex, newColor);
drawPanel.getCtx().setColors(colors);
colorsList.repaint();
}
}
}//GEN-LAST:event_setColorButtonActionPerformed
private void removeColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeColorButtonActionPerformed
int selectedIndex = colorsList.getSelectedIndex();
List<Color> colors = drawPanel.getCtx().getColors();
if (selectedIndex != -1 && colors.size() > 1) {
colors.remove(selectedIndex);
drawPanel.getCtx().setColors(colors);
colorsList.setSelectedIndex(Math.max(0, selectedIndex-1));
colorsList.repaint();
}
}//GEN-LAST:event_removeColorButtonActionPerformed
private void addColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addColorButtonActionPerformed
int newIndex = colorsList.getSelectedIndex();
Color color = (Color)colorsList.getSelectedValue();
List<Color> colors = drawPanel.getCtx().getColors();
if (newIndex == -1) newIndex = colors.size();
Color newColor = JColorChooser.showDialog(this, "Choose a color", color);
if (newColor != null) {
colors.add(newIndex, newColor);
drawPanel.getCtx().setColors(colors);
colorsList.repaint();
}
}//GEN-LAST:event_addColorButtonActionPerformed
private void moveColor(int oldPos, int newPos) {
MandelbrotCtx ctx = drawPanel.getCtx();
List<Color> colors = ctx.getColors();
int colorsSize = colors.size();
if (
0 <= oldPos && oldPos < colorsSize &&
0 <= newPos && newPos < colorsSize &&
oldPos != newPos
)
{
Color temp = colors.get(newPos);
colors.set(newPos, colors.get(oldPos));
colors.set(oldPos, temp);
ctx.setColors(colors);
}
}
private void bottomColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bottomColorButtonActionPerformed
int newPos = colorsList.getModel().getSize()-1;
moveColor(colorsList.getSelectedIndex(), newPos);
colorsList.setSelectedIndex(newPos);
}//GEN-LAST:event_bottomColorButtonActionPerformed
private void topColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_topColorButtonActionPerformed
int newPos = 0;
moveColor(colorsList.getSelectedIndex(), newPos);
colorsList.setSelectedIndex(newPos);
}//GEN-LAST:event_topColorButtonActionPerformed
private void upColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upColorButtonActionPerformed
int newPos = colorsList.getSelectedIndex()-1;
moveColor(colorsList.getSelectedIndex(), newPos);
colorsList.setSelectedIndex(newPos);
}//GEN-LAST:event_upColorButtonActionPerformed
private void downColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downColorButtonActionPerformed
int newPos = colorsList.getSelectedIndex()+1;
moveColor(colorsList.getSelectedIndex(), newPos);
colorsList.setSelectedIndex(newPos);
}//GEN-LAST:event_downColorButtonActionPerformed
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Clear, Load, Save button event handlers">
private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed
drawPanel.setCtx(new MandelbrotCtx());
}//GEN-LAST:event_clearButtonActionPerformed
private void loadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadButtonActionPerformed
int retVal = fractalChooser.showOpenDialog(this);
if (retVal == JFileChooser.APPROVE_OPTION) {
ObjectInputStream in = null;
try {
in = new ObjectInputStream(
new FileInputStream(fractalChooser.getSelectedFile())
);
drawPanel.setCtx((MandelbrotCtx)in.readObject());
} catch (IOException io) {
JOptionPane.showMessageDialog(this, io.getLocalizedMessage(),
"I/O error", JOptionPane.ERROR_MESSAGE);
io.printStackTrace(System.err);
} catch (ClassNotFoundException cnf) {
JOptionPane.showMessageDialog(this, "Invalid file! ("+cnf.getLocalizedMessage()+")",
"File error", JOptionPane.ERROR_MESSAGE);
cnf.printStackTrace(System.err);
} catch (ClassCastException cc) {
JOptionPane.showMessageDialog(this, "Invalid file! ("+cc.getLocalizedMessage()+")",
"File error", JOptionPane.ERROR_MESSAGE);
cc.printStackTrace(System.err);
} finally {
if (in != null) try { in.close(); } catch (IOException io) {}
}
}
}//GEN-LAST:event_loadButtonActionPerformed
private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
int retVal = fractalChooser.showSaveDialog(this);
if (retVal == JFileChooser.APPROVE_OPTION) {
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(
new FileOutputStream(fractalChooser.getSelectedFile())
);
out.writeObject(drawPanel.getCtx());
} catch (IOException io) {
JOptionPane.showMessageDialog(this, io.getMessage(), "I/O error",
JOptionPane.ERROR_MESSAGE);
io.printStackTrace(System.err);
} finally {
if (out != null) try { out.close(); } catch (IOException io) {}
}
}
}//GEN-LAST:event_saveButtonActionPerformed
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="ctx change event handlers (+rebind)">
private void drawPanelPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_drawPanelPropertyChange
if ("ctx".equals(evt.getPropertyName())) {
MandelbrotCtx oldCtx = (MandelbrotCtx)evt.getOldValue();
if (oldCtx != null) oldCtx.removePropertyChangeListener(ctxDirtyChangeListener);
MandelbrotCtx newCtx = (MandelbrotCtx)evt.getNewValue();
if (newCtx != null) newCtx.addPropertyChangeListener(ctxDirtyChangeListener);
newCtx.setDirty(true);
}
}//GEN-LAST:event_drawPanelPropertyChange
/**
* Returns true if the program is currently computing a new Mandelbrot image.
* Returns false otherwise.
*/
public boolean isProcessing() {
synchronized(this) {
return worker != null;
}
}
/**
* Event handler that gets called when the "dirty" property of the
* MandelbrotCtx object changes. Cancels any running computations and
* starts a new worker to compute the changed Mandelbrot image.
* @param dirty the new value of the "dirty" property.
*/
private void ctxDirtyPropertyChanged(boolean dirty) {
synchronized(this) {
if (dirty) {
try {
if (worker != null) worker.cancel(true);
worker = MandelbrotWorker.generateWorker(
(String)workersComboBox.getSelectedItem(),
drawPanel,
new Runnable() {
@Override
public void run() {
drawPanel.setImageDx(0);
drawPanel.setImageDy(0);
drawProgressBar.setValue(100);
drawProgressBar.setEnabled(false);
}
}
);
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
drawProgressBar.setValue((Integer)evt.getNewValue());
}
}
});
drawProgressBar.setValue(0);
drawProgressBar.setEnabled(true);
worker.execute();
} catch (IllegalArgumentException ia) {
JOptionPane.showMessageDialog(this, ia.getLocalizedMessage(),
"Internal error", JOptionPane.ERROR_MESSAGE);
ia.printStackTrace(System.err);
}
} else {
worker = null;
}
}
}
// </editor-fold>
private void workersComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_workersComboBoxActionPerformed
drawPanel.getCtx().setDirty(true);
}//GEN-LAST:event_workersComboBoxActionPerformed
// </editor-fold>
// <editor-fold defaultstate="expanded" desc="data member declarations">
// utility variables for dragging the fractal
private int mouseDragBeginX = -1, mouseDragBeginY = -1;
private boolean mouseDragValid = false;
// ctx property change listener
private PropertyChangeListenerProxy ctxDirtyChangeListener;
// current worker class
private volatile MandelbrotWorker worker;
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addColorButton;
private javax.swing.JButton bottomColorButton;
private javax.swing.JButton clearButton;
private javax.swing.JList colorsList;
private javax.swing.JButton downColorButton;
private jmandelbrotviewer.MandelbrotPanel drawPanel;
private javax.swing.JProgressBar drawProgressBar;
private javax.swing.JFileChooser fractalChooser;
private javax.swing.JSpinner iterationAreaMaxXSpinner;
private javax.swing.JSpinner iterationAreaMaxYSpinner;
private javax.swing.JSpinner iterationAreaMinXSpinner;
private javax.swing.JSpinner iterationAreaMinYSpinner;
private javax.swing.JSpinner iterationLimitSpinner;
private javax.swing.JPanel jPanel3;
private javax.swing.JButton loadButton;
private javax.swing.JButton removeColorButton;
private javax.swing.JButton saveButton;
private javax.swing.JButton setColorButton;
private javax.swing.JButton topColorButton;
private javax.swing.JButton upColorButton;
private javax.swing.JSpinner viewportCenterX;
private javax.swing.JSpinner viewportCenterY;
private javax.swing.JSpinner viewportWidth;
private javax.swing.JSpinner viewportZoomStep;
private javax.swing.JComboBox workersComboBox;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration//GEN-END:variables
// </editor-fold>
}