ca.sqlpower.matchmaker.swingui.engine.MungeProcessSelectionList.java Source code

Java tutorial

Introduction

Here is the source code for ca.sqlpower.matchmaker.swingui.engine.MungeProcessSelectionList.java

Source

/*
 * Copyright (c) 2008, SQL Power Group Inc.
 *
 * This file is part of DQguru
 *
 * DQguru 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.
 *
 * DQguru 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 ca.sqlpower.matchmaker.swingui.engine;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.log4j.Logger;

import ca.sqlpower.matchmaker.MungeProcessPriorityComparator;
import ca.sqlpower.matchmaker.Project;
import ca.sqlpower.matchmaker.munge.MungeProcess;

import com.jgoodies.forms.debug.FormDebugPanel;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

public abstract class MungeProcessSelectionList extends JButton {

    private static final Logger logger = Logger.getLogger(MungeProcessSelectionList.class);

    /**
     * A flag for knowing when the UI should fire events to change the model if it is updated. Since the model
     * also fires events to update the UI, without this, we can get into a sticky infinite loop and get
     * a stack overflow error. 
     */
    private boolean fireEvents = true;

    /**
     * The actual JList of munge processes.
     */
    private JList processesList;

    /**
     * The scrollpane containing the JList of munge processes.
     */
    private JScrollPane processesPane;

    /**
     * The project of which the Munge Processes will be retrieved from.
     */
    private Project project;

    /**
     * The popup menu that contains the list of Munge Processes.
     */
    private JPopupMenu popupMenu;

    /**
     * The list of Munge Process to be selected.
     */
    private List<MungeProcess> mps;

    /**
     * The action which is run when the selection window is closed.
     * It can be null.
     */
    private Runnable closeAction;

    public MungeProcessSelectionList(Project project) {
        super();
        this.project = project;
        buildPopupMenu();
        addActionListener(new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                refreshList();
                popupMenu.show(MungeProcessSelectionList.this, 0, 0);
            }
        });
    }

    /** 
     * This sets the popup button text according to the number
     * of munge processes selected.
     */
    private void setPopupButtonText() {
        int count = processesList.getSelectedIndices().length;

        if (count == 0) {
            setText("Choose Transformations (None Selected)...");
        } else if (count == mps.size()) {
            setText("Choose Transformations (All Selected)...");
        } else {
            setText("Choose Transformations (" + count + " Selected)...");
        }
    }

    /**
     * Builds and returns the popup menu for choosing the munge processes. 
     */
    private void buildPopupMenu() {
        if (mps == null) {
            mps = new ArrayList<MungeProcess>();
        } else {
            mps.clear();
        }
        for (MungeProcess mp : project.getMungeProcesses()) {
            mps.add(mp);
        }
        popupMenu = new JPopupMenu("Choose Processes");

        popupMenu.setBorder(BorderFactory.createRaisedBevelBorder());

        final JButton selectAll = new JButton("Select All");
        selectAll.addActionListener(new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                processesList.setSelectionInterval(0, mps.size() - 1);
            }
        });

        final JButton unselectAll = new JButton(new AbstractAction("Unselect All") {
            public void actionPerformed(ActionEvent e) {
                processesList.clearSelection();
            }
        });

        final JButton close = new JButton(new AbstractAction("OK") {
            public void actionPerformed(ActionEvent e) {
                popupMenu.setVisible(false);
                if (closeAction != null) {
                    closeAction.run();
                }
            }
        });

        FormLayout layout = new FormLayout("10dlu,pref,10dlu", "4dlu,pref,4dlu,pref,4dlu,pref,4dlu");
        JPanel menu = logger.isDebugEnabled() ? new FormDebugPanel(layout) : new JPanel(layout);

        JPanel top = new JPanel(new FlowLayout());
        top.add(selectAll);
        top.add(unselectAll);

        CellConstraints cc = new CellConstraints();

        int row = 2;
        menu.add(top, cc.xy(2, row));

        row += 2;
        Collections.sort(mps, new MungeProcessPriorityComparator());
        processesList = new JList(mps.toArray());
        fireEvents = false;
        setIndices();
        fireEvents = true;

        processesList.addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {
                if (fireEvents)
                    applyChanges();
            }
        });

        processesPane = new JScrollPane(processesList);
        processesPane.setPreferredSize(new Dimension(160, 100));
        menu.add(processesPane, cc.xy(2, row));

        row += 2;
        JPanel tmp = new JPanel(new FlowLayout());
        tmp.add(close);
        menu.add(tmp, cc.xy(2, row));

        popupMenu.add(menu);

        setPopupButtonText();
    }

    /**
     * Refreshes the list so it will contain newly created Munge Processes.
     */
    public void refreshList() {
        mps.clear();
        for (MungeProcess mp : project.getMungeProcesses()) {
            mps.add(mp);
        }
        Collections.sort(mps, new MungeProcessPriorityComparator());
        processesList.setListData(mps.toArray());
        fireEvents = false;
        setIndices();
        fireEvents = true;
        setPopupButtonText();
    }

    /**
     * Used to keep the UI in synch with the model
     */
    public void checkModel() {
        setIndices();
        setPopupButtonText();
    }

    public void setIndices() {
        processesList.setSelectedIndices(getSelectedIndices());
    }

    /** 
     * Returns an int[] of the active munge processes.
     */
    private int[] getSelectedIndices() {
        int count = 0;
        int index = 0;
        int[] indices;

        // This determines the size required for the array
        for (MungeProcess mp : mps) {
            if (getValue(mp)) {
                count++;
            }
        }
        indices = new int[count];
        count = 0;

        // This fills in the array with the active indices.
        // A List.toArray() was not used instead because it
        // returns a Integer[] instead of a int[].
        for (MungeProcess mp : mps) {
            if (getValue(mp)) {
                indices[count++] = index;
            }
            index++;
        }
        return indices;
    }

    public void applyChanges() {
        int index = 0;
        try {
            project.getMungeSettings().begin("Updating which Transformations are active.");
            for (MungeProcess mp : mps) {
                if (processesList.isSelectedIndex(index) != getValue(mp)) {
                    setValue(mp, processesList.isSelectedIndex(index));
                }
                index++;
            }
            project.getMungeSettings().commit();
        } catch (Exception e) {
            project.getMungeSettings().rollback("Rolling back");
            throw new RuntimeException(e);
        }
        setPopupButtonText();
    }

    /**
     * Call to be invoked whenever the selection window is closed.
     */
    public abstract void setValue(MungeProcess mp, boolean value);

    /**
     * Call to be invoked whenever the list of munge processes is refreshed.
     */
    public abstract boolean getValue(MungeProcess mp);

    /**
     * Sets the action to be called when the window is closed.
     */
    public void setCloseAction(Runnable closeAction) {
        this.closeAction = closeAction;
    }

}