Package jmandelbrotviewer

Source Code of jmandelbrotviewer.MainFrame

/*
*  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>
}
TOP

Related Classes of jmandelbrotviewer.MainFrame

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.