ca.sqlpower.architect.swingui.enterprise.ProjectSecurityPanel.java Source code

Java tutorial

Introduction

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

Source

/*
 * Copyright (c) 2010, 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.enterprise;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.CellEditorListener;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;

import ca.sqlpower.architect.swingui.ArchitectSwingProject;
import ca.sqlpower.architect.swingui.action.enterprise.RefreshProjectAction;
import ca.sqlpower.enterprise.client.Grant;
import ca.sqlpower.enterprise.client.Group;
import ca.sqlpower.enterprise.client.GroupMember;
import ca.sqlpower.enterprise.client.User;
import ca.sqlpower.object.SPObject;
import ca.sqlpower.swingui.DataEntryPanel;
import ca.sqlpower.swingui.DataEntryPanelBuilder;
import ca.sqlpower.swingui.SPSUtils;

import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

/**
 * The panel that allows editing permissions on a specific project. This may
 * look like a {@link DataEntryPanel}, may implement {@link DataEntryPanel} but
 * don't be fooled, it does not use apply changes, discard changes, or can be
 * put into
 * {@link DataEntryPanelBuilder#createDataEntryPanelDialog(DataEntryPanel, Component, String, String)}
 * . Instead this panel does a nasty hack of recreating the work of {@link DataEntryPanelBuilder}
 * and makes its own buttons to call apply changes on inner classes that are
 * {@link DataEntryPanel}s.
 */
public class ProjectSecurityPanel implements DataEntryPanel {

    private static final ImageIcon ADD_ICON = new ImageIcon(
            RefreshProjectAction.class.getResource("/icons/famfamfam/add.png"));
    private static final ImageIcon REMOVE_ICON = new ImageIcon(
            RefreshProjectAction.class.getResource("/icons/famfamfam/delete.png"));

    private final JPanel panel;
    private final JLabel panelLabel;

    private final Action closeAction;
    private final ArchitectSwingProject securityWorkspace;
    private final SPObject subject;
    private final Class<?> type;

    private final String username;

    private GroupOrUserTableModel userModel;
    private GroupOrUserTableModel groupModel;

    private boolean hasUnsavedChanges = false;

    private final Dialog d;

    public ProjectSecurityPanel(ArchitectSwingProject securityWorkspace, SPObject subject, Class<?> type,
            String username, Dialog d, Action closeAction) {
        this.securityWorkspace = securityWorkspace;
        this.subject = subject;
        this.type = type;
        this.username = username;
        this.closeAction = closeAction;
        this.d = d;

        panelLabel = new JLabel(
                "Permissions for '" + (subject != null ? subject.getName() : type.getSimpleName()) + "'");
        panelLabel.setFont(
                new Font(panelLabel.getFont().getFontName(), Font.BOLD, panelLabel.getFont().getSize() + 1));

        panel = new JPanel();
        refreshPanel();
    }

    /**
     * This rebuilds the panel based on the {@link #userModel} and {@link #groupModel}.
     * To do this it also removes all of the panels from the main {@link #panel} and
     * adds new ones to it.
     */
    private void refreshPanel() {

        userModel = new GroupOrUserTableModel(User.class);
        groupModel = new GroupOrUserTableModel(Group.class);

        CellConstraints cc = new CellConstraints();
        DefaultFormBuilder builder = new DefaultFormBuilder(new FormLayout("pref",
                "pref:grow, 5dlu, pref:grow, pref:grow, 5dlu, pref:grow, pref:grow, 5dlu, pref:grow"));
        builder.add(panelLabel, cc.xy(1, 1));

        // User list and headers
        JLabel userPermissions = new JLabel("User Permissions");
        userPermissions.setFont(
                new Font(userPermissions.getFont().getFontName(), Font.BOLD, userPermissions.getFont().getSize()));
        builder.add(userPermissions, cc.xy(1, 3));
        builder.add(userModel.getPanel(), cc.xy(1, 4));

        // Group list and headers
        JLabel groupPermissions = new JLabel("Group Permissions");
        groupPermissions.setFont(userPermissions.getFont());
        builder.add(groupPermissions, cc.xy(1, 6));
        builder.add(groupModel.getPanel(), cc.xy(1, 7));

        JButton okButton = new JButton(new AbstractAction("OK") {
            public void actionPerformed(ActionEvent e) {
                userModel.applyChanges();
                groupModel.applyChanges();
                closeAction.actionPerformed(e);
            }
        });

        JButton cancelButton = new JButton(new AbstractAction("Cancel") {
            public void actionPerformed(ActionEvent e) {
                userModel.discardChanges();
                groupModel.discardChanges();
                closeAction.actionPerformed(e);
            }
        });

        ButtonBarBuilder buttonBuilder = ButtonBarBuilder.createLeftToRightBuilder();
        buttonBuilder.addGlue();
        buttonBuilder.addGridded(okButton);
        buttonBuilder.addRelatedGap();
        buttonBuilder.addGridded(cancelButton);
        buttonBuilder.setDefaultButtonBarGapBorder();

        builder.add(buttonBuilder.getPanel(), cc.xy(1, 9));
        builder.setDefaultDialogBorder();

        panel.removeAll();
        panel.add(builder.getPanel());
        panel.revalidate();
        disableIfNecessary();
    }

    public boolean applyChanges() {
        return true;
    }

    public void discardChanges() {
    }

    public JComponent getPanel() {
        return panel;
    }

    public boolean hasUnsavedChanges() {
        return hasUnsavedChanges;
    }

    public void disableIfNecessary() {
        User user = null;
        List<Grant> grantsForUser = new ArrayList<Grant>();
        for (User aUser : securityWorkspace.getChildren(User.class)) {
            if (aUser.getUsername().equals(username)) {
                user = aUser;
            }
        }

        if (user == null)
            throw new IllegalStateException("User cannot possibly be null");

        for (Grant g : user.getChildren(Grant.class)) {
            grantsForUser.add(g);
        }

        for (Group g : securityWorkspace.getChildren(Group.class)) {
            for (GroupMember gm : g.getChildren(GroupMember.class)) {
                if (gm.getUser().getUUID().equals(user.getUUID())) {
                    for (Grant gr : g.getChildren(Grant.class)) {
                        grantsForUser.add(gr);
                    }
                }
            }
        }

        boolean disable = true;
        for (Grant g : grantsForUser) {
            if ((!g.isSystemLevel() && subject != null && g.getSubject().equals(subject.getUUID()))
                    || (g.isSystemLevel() && g.getType().equals(type.getName()))) {
                if (g.isGrantPrivilege()) {
                    disable = false;
                }
            }
        }

        if (disable) {
            for (Component[] componentArray : userModel.getComponents()) {
                for (Component component : componentArray) {
                    component.setEnabled(false);
                }
            }
            for (Component[] componentArray : groupModel.getComponents()) {
                for (Component component : componentArray) {
                    component.setEnabled(false);
                }
            }
        }
    }

    private class RowCellRenderer implements TableCellRenderer {
        private GroupOrUserTableModel model;

        public RowCellRenderer(GroupOrUserTableModel model) {
            this.model = model;
        }

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {

            if (column == 0) {
                table.setToolTipText(((JLabel) model.getValueAt(row, column)).getText());
            }

            return (Component) model.getValueAt(row, column);
        }
    }

    private class RowCellEditor implements TableCellEditor {

        private GroupOrUserTableModel model;

        public RowCellEditor(GroupOrUserTableModel model) {
            this.model = model;
        }

        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row,
                int column) {
            return (Component) model.getValueAt(row, column);
        }

        public void addCellEditorListener(CellEditorListener l) {
        }

        public void cancelCellEditing() {
        }

        public Object getCellEditorValue() {
            return null;
        }

        public boolean isCellEditable(EventObject anEvent) {
            return true;
        }

        public void removeCellEditorListener(CellEditorListener l) {
        }

        public boolean shouldSelectCell(EventObject anEvent) {
            return true;
        }

        public boolean stopCellEditing() {
            return true;
        }

    }

    private class GroupOrUserTableModel implements TableModel, DataEntryPanel {

        private final Component[] headerRow;
        private final List<Component[]> rows;
        private final int numColumns = 7;
        private final List<DataEntryPanel> panels;

        private final List<SPObject> objectsWithSpecificGrants;
        private final List<SPObject> objectsWithoutSpecificGrants;
        private final List<SPObject> objectsWithGlobalGrants;
        private final List<SPObject> objectsWithoutGlobalGrants;

        public GroupOrUserTableModel(final Class<? extends SPObject> groupOrUserClass) {
            panels = new ArrayList<DataEntryPanel>();
            rows = new ArrayList<Component[]>();
            objectsWithoutSpecificGrants = new ArrayList<SPObject>();
            objectsWithSpecificGrants = new ArrayList<SPObject>();
            objectsWithGlobalGrants = new ArrayList<SPObject>();
            objectsWithoutGlobalGrants = new ArrayList<SPObject>();

            Map<SPObject, Grant> specificGrants = new HashMap<SPObject, Grant>();
            Map<SPObject, Grant> globalGrants = new HashMap<SPObject, Grant>();

            for (SPObject object : securityWorkspace.getChildren(groupOrUserClass)) {
                for (Grant grant : object.getChildren(Grant.class)) {
                    if (grant.isSystemLevel() && grant.getType().equals(type.getName())) {
                        globalGrants.put(object, grant);
                    }
                    if (subject != null) {
                        if (!grant.isSystemLevel() && grant.getSubject().equals(subject.getUUID())) {
                            specificGrants.put(object, grant);
                        }
                    }
                }
            }

            for (SPObject obj : securityWorkspace.getChildren(groupOrUserClass)) {
                objectsWithoutSpecificGrants.add(obj);
                objectsWithoutGlobalGrants.add(obj);
            }
            for (SPObject obj : specificGrants.keySet()) {
                objectsWithSpecificGrants.add(obj);
            }
            for (SPObject obj : globalGrants.keySet()) {
                objectsWithGlobalGrants.add(obj);
            }
            objectsWithoutSpecificGrants.removeAll(objectsWithSpecificGrants);
            objectsWithoutGlobalGrants.removeAll(objectsWithGlobalGrants);

            Comparator<SPObject> comparator = new Comparator<SPObject>() {
                public int compare(SPObject o1, SPObject o2) {
                    return o1.getName().toUpperCase().compareTo(o2.getName().toUpperCase());
                }
            };

            Collections.sort(objectsWithSpecificGrants, comparator);
            Collections.sort(objectsWithoutSpecificGrants, comparator);
            Collections.sort(objectsWithGlobalGrants, comparator);
            Collections.sort(objectsWithoutGlobalGrants, comparator);

            headerRow = new Component[numColumns];
            headerRow[0] = new JLabel("Name");
            headerRow[1] = new JLabel("View");
            headerRow[2] = new JLabel("Create");
            headerRow[3] = new JLabel("Modify");
            headerRow[4] = new JLabel("Delete");
            headerRow[5] = new JLabel("Grant");
            JButton addButton = new JButton(new AbstractAction() {
                public void actionPerformed(ActionEvent e) {

                    JList list = new JList(new DefaultListModel());
                    DefaultListModel model = (DefaultListModel) list.getModel();
                    for (SPObject obj : (subject != null ? objectsWithoutSpecificGrants
                            : objectsWithoutGlobalGrants)) {
                        model.addElement(obj);
                    }

                    Object[] message = new Object[] { "Select " + groupOrUserClass.getSimpleName() + "s to add",
                            new JScrollPane(list) };
                    Object[] selections = new Object[] { "OK", "Cancel" };

                    Object selection = JOptionPane.showOptionDialog(d, message, "", JOptionPane.DEFAULT_OPTION,
                            JOptionPane.INFORMATION_MESSAGE, null, selections, selections[0]);

                    if (((Integer) selection).intValue() == 0) {

                        int[] selectedIndices = list.getSelectedIndices();
                        for (int i = 0; i < selectedIndices.length; i++) {
                            SPObject obj = (SPObject) model.get(selectedIndices[i]);
                            if (subject != null) {
                                obj.addChild(new Grant(subject, false, false, false, false, false),
                                        obj.getChildren(Grant.class).size());
                            } else {
                                obj.addChild(new Grant(type.getName(), false, false, false, false, false),
                                        obj.getChildren(Grant.class).size());
                            }
                        }

                        refreshPanel();
                    }
                }
            });
            addButton.setIcon(ADD_ICON);
            addButton.setBorderPainted(false);
            addButton.setContentAreaFilled(false);

            headerRow[6] = addButton;
            rows.add(headerRow);

            if (subject != null) {
                for (final SPObject object : objectsWithSpecificGrants) {
                    // can pass in null, it will just be empty
                    final PrivilegesEditorPanel specific = new PrivilegesEditorPanel(specificGrants.get(object),
                            object, subject.getUUID(), type.getName(), username, securityWorkspace);
                    final PrivilegesEditorPanel global = new PrivilegesEditorPanel(globalGrants.get(object), object,
                            subject.getUUID(), type.getName(), username, securityWorkspace);

                    panels.add(specific);
                    panels.add(global);

                    global.getCreatePrivilege().setEnabled(false);
                    global.getModifyPrivilege().setEnabled(false);
                    global.getDeletePrivilege().setEnabled(false);
                    global.getViewPrivilege().setEnabled(false);
                    global.getGrantPrivilege().setEnabled(false);

                    global.getCreatePrivilege().setText(null);
                    global.getModifyPrivilege().setText(null);
                    global.getDeletePrivilege().setText(null);
                    global.getViewPrivilege().setText(null);
                    global.getGrantPrivilege().setText(null);

                    specific.getCreatePrivilege().setText(null);
                    specific.getModifyPrivilege().setText(null);
                    specific.getDeletePrivilege().setText(null);
                    specific.getViewPrivilege().setText(null);
                    specific.getGrantPrivilege().setText(null);

                    JButton removeButton = new JButton(new AbstractAction() {
                        public void actionPerformed(ActionEvent e) {
                            try {
                                object.removeChild(specific.getGrant());
                            } catch (Exception ex) {
                                throw new RuntimeException("Unable to remove grant from object", ex);
                            }

                            refreshPanel();
                        }
                    });
                    removeButton.setIcon(REMOVE_ICON);
                    removeButton.setBorderPainted(false);
                    removeButton.setContentAreaFilled(false);

                    Component[] rowComponents = new Component[numColumns];
                    rowComponents[0] = new JLabel(object.getName());
                    rowComponents[1] = global.getViewPrivilege().isSelected() ? global.getViewPrivilege()
                            : specific.getViewPrivilege();
                    rowComponents[2] = global.getCreatePrivilege().isSelected() ? global.getCreatePrivilege()
                            : specific.getCreatePrivilege();
                    rowComponents[3] = global.getModifyPrivilege().isSelected() ? global.getModifyPrivilege()
                            : specific.getModifyPrivilege();
                    rowComponents[4] = global.getDeletePrivilege().isSelected() ? global.getDeletePrivilege()
                            : specific.getDeletePrivilege();
                    rowComponents[5] = global.getGrantPrivilege().isSelected() ? global.getGrantPrivilege()
                            : specific.getGrantPrivilege();
                    rowComponents[6] = removeButton;

                    for (Component component : rowComponents)
                        component.setBackground(Color.white);

                    rows.add(rowComponents);
                }
            } else {
                for (final SPObject object : objectsWithGlobalGrants) {
                    // can pass in null, it will just be empty
                    final PrivilegesEditorPanel global = new PrivilegesEditorPanel(globalGrants.get(object), object,
                            null, type.getName(), username, securityWorkspace);

                    panels.add(global);

                    global.getCreatePrivilege().setText(null);
                    global.getModifyPrivilege().setText(null);
                    global.getDeletePrivilege().setText(null);
                    global.getViewPrivilege().setText(null);
                    global.getGrantPrivilege().setText(null);

                    JButton removeButton = new JButton(new AbstractAction() {
                        public void actionPerformed(ActionEvent e) {
                            try {
                                object.removeChild(global.getGrant());
                            } catch (Exception ex) {
                                throw new RuntimeException("Unable to remove grant from object", ex);
                            }

                            refreshPanel();
                        }
                    });
                    removeButton.setIcon(REMOVE_ICON);
                    removeButton.setBorderPainted(false);
                    removeButton.setContentAreaFilled(false);

                    Component[] rowComponents = new Component[numColumns];
                    rowComponents[0] = new JLabel(object.getName());
                    rowComponents[1] = global.getViewPrivilege();
                    rowComponents[2] = global.getCreatePrivilege();
                    rowComponents[3] = global.getModifyPrivilege();
                    rowComponents[4] = global.getDeletePrivilege();
                    rowComponents[5] = global.getGrantPrivilege();
                    rowComponents[6] = removeButton;

                    for (Component component : rowComponents)
                        component.setBackground(Color.white);

                    rows.add(rowComponents);
                }
            }
        }

        public Class<?> getColumnClass(int columnIndex) {
            return headerRow[columnIndex].getClass();
        }

        public int getColumnCount() {
            return numColumns;
        }

        public int getRowCount() {
            return rows.size();
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            return rows.get(rowIndex)[columnIndex];
        }

        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }

        public List<Component[]> getComponents() {
            return rows;
        }

        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        }

        public void addTableModelListener(TableModelListener l) {
        }

        public void removeTableModelListener(TableModelListener l) {
        }

        public String getColumnName(int columnIndex) {
            return null;
        }

        public void discardChanges() {
            for (DataEntryPanel dep : panels) {
                dep.discardChanges();
            }
        }

        public JComponent getPanel() {
            JTable table = new JTable(this);
            table.setTableHeader(null);

            for (int i = 0; i < table.getColumnCount(); i++) {
                TableColumn col = table.getColumnModel().getColumn(i);
                col.setCellRenderer(new RowCellRenderer(this));
                col.setCellEditor(new RowCellEditor(this));
            }

            table.getColumnModel().getColumn(6).setPreferredWidth(table.getRowHeight());
            table.setShowHorizontalLines(false);
            table.setShowVerticalLines(false);

            JScrollPane scrollpane = new JScrollPane(table);
            scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            scrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

            int preferredHeight = table.getRowHeight() * 7;
            int preferredWidth = scrollpane.getVerticalScrollBar().getWidth();
            for (int i = 0; i < table.getColumnCount(); i++) {
                preferredWidth += table.getColumnModel().getColumn(i).getWidth();
            }

            scrollpane.setPreferredSize(new Dimension(preferredWidth, preferredHeight));
            scrollpane.getViewport().setBackground(Color.WHITE);

            return scrollpane;
        }

        public boolean applyChanges() {
            boolean success = true;

            for (DataEntryPanel dep : panels) {
                if (!dep.applyChanges()) {
                    success = false;
                }
            }

            return success;
        }

        public boolean hasUnsavedChanges() {
            // TODO Auto-generated method stub
            return false;
        }
    }

    public static Action createShowAction(final ArchitectSwingProject securityWorkspace, final SPObject subject,
            final Class<?> type, final String username, final JComponent panel) {
        return new AbstractAction("Manage Security Settings...") {
            public void actionPerformed(ActionEvent e) {
                final JDialog d = SPSUtils.makeOwnedDialog(panel, "Security Manager");

                Action closeAction = new AbstractAction("Close") {
                    public void actionPerformed(ActionEvent e) {
                        d.dispose();
                    }
                };

                ProjectSecurityPanel spm = new ProjectSecurityPanel(securityWorkspace, subject, type, username, d,
                        closeAction);
                d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                d.setContentPane(spm.getPanel());

                SPSUtils.makeJDialogCancellable(d, null);
                d.pack();
                d.setLocationRelativeTo(panel);
                d.setVisible(true);
            }
        };
    }
}