ca.sqlpower.architect.swingui.IndexEditPanel.java Source code

Java tutorial

Introduction

Here is the source code for ca.sqlpower.architect.swingui.IndexEditPanel.java

Source

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

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import ca.sqlpower.object.ObjectDependentException;
import ca.sqlpower.object.SPChildEvent;
import ca.sqlpower.object.SPListener;
import ca.sqlpower.sql.JDBCDataSourceType;
import ca.sqlpower.sqlobject.SQLIndex;
import ca.sqlpower.sqlobject.SQLObjectException;
import ca.sqlpower.sqlobject.SQLObjectRuntimeException;
import ca.sqlpower.sqlobject.SQLTable;
import ca.sqlpower.sqlobject.SQLIndex.Column;
import ca.sqlpower.swingui.ChangeListeningDataEntryPanel;
import ca.sqlpower.swingui.DataEntryPanelChangeUtil;
import ca.sqlpower.swingui.SPSUtils;
import ca.sqlpower.util.SQLPowerUtils;
import ca.sqlpower.util.TransactionEvent;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

public class IndexEditPanel extends ChangeListeningDataEntryPanel implements SPListener {
    protected SQLIndex index;

    protected SQLTable parent;

    protected SQLIndex indexCopy;

    JTextField name;

    JCheckBox unique;

    JCheckBox primaryKey;

    JComboBox indexType;

    JCheckBox clustered;

    IndexColumnTable columnsTable;

    private JPanel panel;

    /**
     * This session that contains this index panel.
     */
    ArchitectSwingSession session;

    /**
     * Identifier for the default index type.
     */
    private static String DEFAULT_INDEX_TYPE = Messages.getString("IndexEditPanel.defaultIndexType"); //$NON-NLS-1$

    public IndexEditPanel(SQLIndex index, ArchitectSwingSession session) throws SQLObjectException {
        this(index, index.getParent(), session);
    }

    public IndexEditPanel(SQLIndex index, SQLTable parent, ArchitectSwingSession session)
            throws SQLObjectException {
        panel = new JPanel(new FormLayout("pref,4dlu,pref,4dlu,pref:grow,4dlu,pref", //$NON-NLS-1$
                "pref,4dlu,pref,4dlu,pref,4dlu,pref,4dlu,pref,4dlu,pref,4dlu,pref:grow,4dlu,pref,4dlu")); //$NON-NLS-1$
        this.session = session;
        SQLPowerUtils.listenToHierarchy(index, this);
        createGUI(index, parent, session);
    }

    private void createGUI(SQLIndex index, SQLTable parent, ArchitectSwingSession session)
            throws SQLObjectException {
        this.parent = parent;
        PanelBuilder pb = new PanelBuilder((FormLayout) panel.getLayout(), panel);
        CellConstraints cc = new CellConstraints();
        pb.add(new JLabel(Messages.getString("IndexEditPanel.indexName")), cc.xy(1, 1)); //$NON-NLS-1$
        pb.add(name = new JTextField("", 30), cc.xyw(3, 1, 4)); //$NON-NLS-1$
        unique = new JCheckBox(Messages.getString("IndexEditPanel.uniqueIndex")); //$NON-NLS-1$
        pb.add(unique, cc.xy(3, 3));
        primaryKey = new JCheckBox(Messages.getString("IndexEditPanel.primaryKeyIndex")); //$NON-NLS-1$
        pb.add(primaryKey, cc.xy(3, 5));
        clustered = new JCheckBox(Messages.getString("IndexEditPanel.clusteredIndex")); //$NON-NLS-1$
        clustered.setSelected(index.isClustered());
        pb.add(clustered, cc.xy(3, 7));
        pb.add(new JLabel(Messages.getString("IndexEditPanel.indexType")), cc.xy(1, 9)); //$NON-NLS-1$

        indexType = new JComboBox();
        //add the platform default type
        indexType.addItem(DEFAULT_INDEX_TYPE);
        for (String type : getIndexTypes()) {
            indexType.addItem(type);
        }
        pb.add(indexType, cc.xyw(3, 9, 4));

        editIndex(index);
        columnsTable = new IndexColumnTable(parent, indexCopy, index);

        pb.add(new JScrollPane(columnsTable.getTable()), cc.xyw(1, 13, 6));

        // we want the buttons at their natural sizes, and the buttonbarbuilder wasn't doing that
        JPanel upDownPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        upDownPanel.add(new JButton(new AbstractAction(null, SPSUtils.createIcon("chevrons_up1", null)) { //$NON-NLS-1$

            public void actionPerformed(ActionEvent e) {
                columnsTable.moveRow(true);
            }

        }));
        upDownPanel.add(new JButton(new AbstractAction(null, SPSUtils.createIcon("chevrons_down1", null)) { //$NON-NLS-1$
            public void actionPerformed(ActionEvent e) {
                columnsTable.moveRow(false);
            }
        }));

        pb.add(upDownPanel, cc.xyw(1, 15, 6));
        loadIndexIntoPanel();
    }

    /**
     * Returns an unique index name;
     */
    private String getIndexName() {
        int i = 0;
        String name = null;
        do {
            name = generateName(i);
            i++;
        } while (indexNameAlreadyExists(name));
        return name;
    }

    /**
     * This will check if an index name already exits on the table.
     * @return True if index already exists, false otherwise
     */
    private boolean indexNameAlreadyExists(String name) {
        try {
            for (SQLIndex index : parent.getIndices()) {
                if (name.equals(index.getName())) {
                    return true;
                }
            }
        } catch (SQLObjectException e) {
            throw new SQLObjectRuntimeException(e);
        }
        return false;
    }

    /**
     * This will generate an index name if the format: $tablename_idx(#)
     */
    private String generateName(int number) {
        if (number == 0) {
            return new String(parent.getName() + "_idx"); //$NON-NLS-1$
        } else {
            return new String(parent.getName() + "_idx" + Integer.toString(number)); //$NON-NLS-1$
        }
    }

    /**
     *This will return a list of Index Types that are found in the pl.ini file
     */
    private List<String> getIndexTypes() {
        List<String> indexTypes = new ArrayList<String>();
        List<JDBCDataSourceType> dsTypes = this.session.getDataSources().getDataSourceTypes();
        for (JDBCDataSourceType dsType : dsTypes) {
            for (int dataTypeCount = 0;; dataTypeCount += 1) {
                String supportedType = dsType.getProperty(SQLIndex.INDEX_TYPE_DESCRIPTOR + "_" + dataTypeCount); //$NON-NLS-1$
                if (supportedType == null)
                    break;
                if (!indexTypes.contains(supportedType)) {
                    indexTypes.add(supportedType);
                }
            }
        }
        return indexTypes;
    }

    public void editIndex(SQLIndex index) throws SQLObjectException {
        this.index = index;
        name.setText(index.getName());
        indexCopy = new SQLIndex(index);
        indexCopy.setParent(null);
    }

    private void loadIndexIntoPanel() {
        if (index.getName() != null) {
            name.setText(index.getName());
        } else {
            name.setText(getIndexName());
        }
        primaryKey.setSelected(index.isPrimaryKeyIndex());
        primaryKey.setEnabled(false);
        unique.setSelected(index.isUnique());
        clustered.setSelected(index.isClustered());
        if (index.getType() == null) {
            indexType.setSelectedItem(DEFAULT_INDEX_TYPE);
        } else {
            indexType.setSelectedItem(index.getType());
        }
        name.selectAll();
    }

    protected SQLIndex getIndexCopy() {
        return indexCopy;
    }

    // --------------------- ArchitectPanel interface ------------------
    /**
     * Applies the changes to the panel if the data is valid
     *
     * the data is valid if it has a name, an index type and all
     * of the columns contain primary keys
     *
     * returns true if saved, false otherwise
     */
    public boolean applyChanges() {
        SQLPowerUtils.unlistenToHierarchy(index, this);
        columnsTable.cleanUp();
        columnsTable.finalizeIndex();
        // if this was done on the index, listeners would only start listening after the index has
        // been added to its parent and compound edit would not work. Compound edits belong to the parent. 
        parent.begin(Messages.getString("IndexEditPanel.compoundEditName")); //$NON-NLS-1$
        try {
            StringBuffer warnings = new StringBuffer();
            //We need to check if the index name and/or primary key name is empty or not
            //if they are, we need to warn the user since it will mess up the SQLScripts we create
            if (name.getText().trim().length() == 0) {
                warnings.append(Messages.getString("IndexEditPanel.blankIndexName")); //$NON-NLS-1$

            }
            if (index.isPrimaryKeyIndex()) {
                for (Column c : indexCopy.getChildren(Column.class)) {
                    if (c.getColumn() == null) {
                        warnings.append(Messages.getString("IndexEditPanel.onlyAddColumnsToPK")); //$NON-NLS-1$
                        break;
                    }
                }
            }

            if (indexType.getSelectedItem() == null) {
                warnings.append(Messages.getString("IndexEditPanel.mustSelectIndexType")); //$NON-NLS-1$
            }

            if (warnings.toString().length() == 0) {
                //The operation is successful
                index.makeColumnsLike(indexCopy);
                SQLTable parentTable = parent;
                index.setName(name.getText().trim());

                // make the physical name identitical as long as there  is
                // no separate input field for it
                index.setPhysicalName(name.getText().trim());
                index.setUnique(unique.isSelected());
                index.setClustered(clustered.isSelected());
                if (indexType.getSelectedItem().toString().equals(DEFAULT_INDEX_TYPE)) {
                    index.setType(null);
                } else {
                    index.setType(indexType.getSelectedItem().toString());
                }
                List<SQLIndex> children = parentTable.getIndices();
                if (!children.contains(index)) {
                    parentTable.addIndex(index);
                }
                index.cleanUpIfChildless();
                return true;
            } else {
                JOptionPane.showMessageDialog(panel, warnings.toString());
                //this is done so we can go back to this dialog after the error message
                return false;
            }
        } catch (SQLObjectException e) {
            throw new SQLObjectRuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (ObjectDependentException e) {
            throw new RuntimeException(e);
        } finally {
            parent.commit();
        }
    }

    public void discardChanges() {
        SQLPowerUtils.unlistenToHierarchy(index, this);
    }

    public JPanel getPanel() {
        return panel;
    }

    public String getNameText() {
        return name.getText();
    }

    public void setNameText(String newName) {
        name.setText(newName);
    }

    public boolean hasUnsavedChanges() {
        // TODO return whether this panel has been changed
        return true;
    }

    public void childAdded(SPChildEvent e) {
        // XXX Make this actually check for a conflict or not.
        if (e.getSource() == index) {
            columnsTable.getTable().setBackground(DataEntryPanelChangeUtil.NONCONFLICTING_COLOR);
            setErrorText(DataEntryPanelChangeUtil.ERROR_MESSAGE);
        }
    }

    public void childRemoved(SPChildEvent e) {
        // XXX Make this actually check for a conflict or not.
        if (e.getSource() == index) {
            columnsTable.getTable().setBackground(DataEntryPanelChangeUtil.NONCONFLICTING_COLOR);
            setErrorText(DataEntryPanelChangeUtil.ERROR_MESSAGE);
        }
    }

    public void propertyChanged(PropertyChangeEvent e) {
        String property = e.getPropertyName();
        boolean error = false;
        if (e.getSource() == index) {
            if (property.equals("name")) {
                error = DataEntryPanelChangeUtil.incomingChange(name, e);
            } else if (property.equals("unique")) {
                error = DataEntryPanelChangeUtil.incomingChange(unique, e);
            } else if (property.equals("clustered")) {
                error = DataEntryPanelChangeUtil.incomingChange(clustered, e);
            } else if (property.equals("type")) {
                Object oldValue = e.getOldValue();
                Object newValue = e.getNewValue();
                if (oldValue == null || oldValue.equals(""))
                    oldValue = "Platform Default";
                if (newValue == null || oldValue.equals(""))
                    newValue = "Platform Default";
                error = DataEntryPanelChangeUtil.incomingChange(indexType,
                        new PropertyChangeEvent(e.getSource(), e.getPropertyName(), oldValue, newValue));
            }
        } else if (e.getSource() instanceof Column) {
            if (property.equals("ascendingOrDescending")) {
                // XXX Make this find the appropriate checkbox and highlight that.
                columnsTable.getTable().setBackground(DataEntryPanelChangeUtil.NONCONFLICTING_COLOR);
                error = true;
            }
        }
        if (error) {
            setErrorText(DataEntryPanelChangeUtil.ERROR_MESSAGE);
        }
    }

    public void transactionEnded(TransactionEvent e) {
        // no-op
    }

    public void transactionRollback(TransactionEvent e) {
        // no-op
    }

    public void transactionStarted(TransactionEvent e) {
        // no-op
    }
}