/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.directory.studio.aciitemeditor.widgets; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.apache.directory.api.ldap.aci.GrantAndDenial; import org.apache.directory.studio.aciitemeditor.Activator; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CheckboxCellEditor; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; /** * This composite contains GUI elements to edit ACI item grants and denials. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public class ACIItemGrantsAndDenialsComposite extends Composite { /** The tree viewer containing all grants and denials */ private TreeViewer treeViewer = null; /** The undo button */ private Button undoButton = null; /** The redo button */ private Button redoButton = null; /** Colum 1 */ private static final String PERMISSION = Messages.getString( "ACIItemGrantsAndDenialsComposite.column1.header" ); //$NON-NLS-1$ /** Colum2 */ private static final String STATE = Messages.getString( "ACIItemGrantsAndDenialsComposite.column2.header" ); //$NON-NLS-1$ /** The colums */ private static final String[] COLUMNS = new String[] { PERMISSION, STATE }; /** The undo/redo stack size */ private static final int MAX_STACK_SIZE = 25; /** Used as input for the tree viewer */ private GrantAndDenialCategory[] grantAndDenialCategories = new GrantAndDenialCategory[] { new GrantAndDenialCategory( Messages.getString( "ACIItemGrantsAndDenialsComposite.category.read" ), true, new GrantAndDenialWrapper[] //$NON-NLS-1$ { new GrantAndDenialWrapper( GrantAndDenial.GRANT_BROWSE, GrantAndDenial.DENY_BROWSE ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_READ, GrantAndDenial.DENY_READ ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_COMPARE, GrantAndDenial.DENY_COMPARE ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_FILTER_MATCH, GrantAndDenial.DENY_FILTER_MATCH ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_RETURN_DN, GrantAndDenial.DENY_RETURN_DN ) } ), new GrantAndDenialCategory( Messages.getString( "ACIItemGrantsAndDenialsComposite.category.modify" ), true, new GrantAndDenialWrapper[] //$NON-NLS-1$ { new GrantAndDenialWrapper( GrantAndDenial.GRANT_ADD, GrantAndDenial.DENY_ADD ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_MODIFY, GrantAndDenial.DENY_MODIFY ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_REMOVE, GrantAndDenial.DENY_REMOVE ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_RENAME, GrantAndDenial.DENY_RENAME ) } ), new GrantAndDenialCategory( Messages.getString( "ACIItemGrantsAndDenialsComposite.category.advanced" ), false, new GrantAndDenialWrapper[] //$NON-NLS-1$ { new GrantAndDenialWrapper( GrantAndDenial.GRANT_EXPORT, GrantAndDenial.DENY_EXPORT ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_IMPORT, GrantAndDenial.DENY_IMPORT ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_INVOKE, GrantAndDenial.DENY_INVOKE ), new GrantAndDenialWrapper( GrantAndDenial.GRANT_DISCLOSE_ON_ERROR, GrantAndDenial.DENY_DISCLOSE_ON_ERROR ) } ) }; /** * A GrantAndDenialCategory is used to categorize grants and denials in a tree. */ private class GrantAndDenialCategory { /** The category name, displayed in tree */ private String name; /** The initial expanded state */ private boolean expanded; /** The grants and denials wrappers display under this category */ private GrantAndDenialWrapper[] grantAndDenialWrappers; /** * Creates a new instance of GrantAndDenialCategory. * * @param name the category name, displayed in tree * @param expanded true if category should be initially expanded * @param grantAndDenialWrappers the grants and denials wrappers display under this category */ private GrantAndDenialCategory( String name, boolean expanded, GrantAndDenialWrapper[] grantAndDenialWrappers ) { this.name = name; this.expanded = expanded; this.grantAndDenialWrappers = grantAndDenialWrappers; } } /** * A GrantAndDenialWrapper is used to display grants and denials in tree and to * track the current state (not specified, grant or deny). Additional it provides * undo/redo functionality. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ private class GrantAndDenialWrapper { /** The grant */ private GrantAndDenial grant; /** The denial */ private GrantAndDenial denial; /** The current state: null=not specified, grant or denial */ private GrantAndDenial activeGrantAndDenial; /** List containing previous states of activeGrandAndDenial */ private List<GrantAndDenial> undoStack; /** List containing "future" states of activeGrandAndDenial */ private List<GrantAndDenial> redoStack; /** * Creates a new instance of GrantAndDenialWrapper. * * @param grant * @param denial */ private GrantAndDenialWrapper( GrantAndDenial grant, GrantAndDenial denial ) { this.grant = grant; this.denial = denial; this.activeGrantAndDenial = null; undoStack = new LinkedList<GrantAndDenial>(); redoStack = new LinkedList<GrantAndDenial>(); } } /** * Creates a new instance of ACIItemGrantsAndDenialsComposite. * * @param parent * @param style */ public ACIItemGrantsAndDenialsComposite( Composite parent, int style ) { super( parent, style ); GridLayout layout = new GridLayout(); layout.makeColumnsEqualWidth = false; layout.numColumns = 2; setLayout( layout ); GridData layoutData = new GridData(); layoutData.grabExcessHorizontalSpace = true; layoutData.grabExcessVerticalSpace = true; layoutData.horizontalAlignment = GridData.FILL; layoutData.verticalAlignment = GridData.FILL; setLayoutData( layoutData ); GridData labelGridData = new GridData(); labelGridData.horizontalSpan = 2; labelGridData.verticalAlignment = GridData.CENTER; labelGridData.grabExcessHorizontalSpace = true; labelGridData.horizontalAlignment = GridData.FILL; Label label = new Label( this, SWT.NONE ); label.setText( Messages.getString( "ACIItemGrantsAndDenialsComposite.description" ) ); //$NON-NLS-1$ label.setLayoutData( labelGridData ); createTree(); createButtonComposite(); } /** * This method initializes tree * */ private void createTree() { GridData tableGridData = new GridData( GridData.FILL_BOTH ); tableGridData.grabExcessHorizontalSpace = true; tableGridData.grabExcessVerticalSpace = true; tableGridData.verticalAlignment = GridData.FILL; tableGridData.horizontalAlignment = GridData.FILL; //tableGridData.heightHint = 100; Tree tree = new Tree( this, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.HIDE_SELECTION ); tree.setHeaderVisible( true ); tree.setLayoutData( tableGridData ); tree.setLinesVisible( true ); TreeColumn treeColumn1 = new TreeColumn( tree, SWT.LEFT, 0 ); treeColumn1.setText( COLUMNS[0] ); treeColumn1.setWidth( 160 ); TreeColumn treeColumn2 = new TreeColumn( tree, SWT.LEFT, 1 ); treeColumn2.setText( COLUMNS[1] ); treeColumn2.setWidth( 80 ); // TreeColumn c3 = new TreeColumn( tree, SWT.LEFT, 2 ); // c3.setText( " " ); //$NON-NLS-1$ // c3.setWidth( 0 ); treeViewer = new TreeViewer( tree ); treeViewer.setUseHashlookup( true ); treeViewer.setColumnProperties( COLUMNS ); ICellModifier cellModifier = new GrantsAndDenialsCellModifier(); treeViewer.setCellModifier( cellModifier ); CellEditor[] cellEditors = new CellEditor[] { null, new CheckboxCellEditor( tree ), null }; treeViewer.setCellEditors( cellEditors ); treeViewer.setContentProvider( new GrantsAndDenialsContentProvider() ); treeViewer.setLabelProvider( new GrantsAndDenialsLabelProvider() ); treeViewer.setInput( grantAndDenialCategories ); // set expanded state List<GrantAndDenialCategory> expandedList = new ArrayList<GrantAndDenialCategory>(); for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { if ( grantAndDenialCategory.expanded ) { expandedList.add( grantAndDenialCategory ); } } treeViewer.setExpandedElements( expandedList.toArray() ); } /** * This method initializes buttonComposite * */ private void createButtonComposite() { GridData deselectAllButtonGridData = new GridData(); deselectAllButtonGridData.horizontalAlignment = GridData.FILL; deselectAllButtonGridData.grabExcessHorizontalSpace = false; deselectAllButtonGridData.verticalAlignment = GridData.BEGINNING; deselectAllButtonGridData.widthHint = Activator.getButtonWidth( this ); GridData denyAllButtonGridData = new GridData(); denyAllButtonGridData.horizontalAlignment = GridData.FILL; denyAllButtonGridData.grabExcessHorizontalSpace = false; denyAllButtonGridData.verticalAlignment = GridData.BEGINNING; denyAllButtonGridData.widthHint = Activator.getButtonWidth( this ); GridData grantAllButtonGridData = new GridData(); grantAllButtonGridData.horizontalAlignment = GridData.FILL; grantAllButtonGridData.grabExcessHorizontalSpace = false; grantAllButtonGridData.verticalAlignment = GridData.BEGINNING; grantAllButtonGridData.widthHint = Activator.getButtonWidth( this ); GridData undoButtonGridData = new GridData(); undoButtonGridData.horizontalAlignment = GridData.FILL; undoButtonGridData.grabExcessHorizontalSpace = false; undoButtonGridData.verticalAlignment = GridData.BEGINNING; undoButtonGridData.widthHint = Activator.getButtonWidth( this ); GridData redoButtonGridData = new GridData(); redoButtonGridData.horizontalAlignment = GridData.FILL; redoButtonGridData.grabExcessHorizontalSpace = false; redoButtonGridData.verticalAlignment = GridData.BEGINNING; redoButtonGridData.widthHint = Activator.getButtonWidth( this ); GridLayout gridLayout = new GridLayout(); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; GridData gridData = new GridData(); gridData.horizontalAlignment = GridData.CENTER; gridData.grabExcessHorizontalSpace = false; gridData.grabExcessVerticalSpace = false; gridData.verticalAlignment = GridData.FILL; Composite buttonComposite = new Composite( this, SWT.NONE ); buttonComposite.setLayoutData( gridData ); buttonComposite.setLayout( gridLayout ); Button grantAllButton = new Button( buttonComposite, SWT.NONE ); grantAllButton.setText( Messages.getString( "ACIItemGrantsAndDenialsComposite.grantAll.button" ) ); //$NON-NLS-1$ grantAllButton.setLayoutData( grantAllButtonGridData ); grantAllButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { backup(); for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.grant; } } treeViewer.refresh(); } } ); Button denyAllButton = new Button( buttonComposite, SWT.NONE ); denyAllButton.setText( Messages.getString( "ACIItemGrantsAndDenialsComposite.denyAll.button" ) ); //$NON-NLS-1$ denyAllButton.setLayoutData( denyAllButtonGridData ); denyAllButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { backup(); for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.denial; } } treeViewer.refresh(); } } ); Button deselectAllButton = new Button( buttonComposite, SWT.NONE ); deselectAllButton.setText( Messages.getString( "ACIItemGrantsAndDenialsComposite.deselectAll.button" ) ); //$NON-NLS-1$ deselectAllButton.setLayoutData( deselectAllButtonGridData ); deselectAllButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { backup(); for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { grantAndDenialWrapper.activeGrantAndDenial = null; } } treeViewer.refresh(); } } ); undoButton = new Button( buttonComposite, SWT.NONE ); undoButton.setText( Messages.getString( "ACIItemGrantsAndDenialsComposite.undo.button" ) ); //$NON-NLS-1$ undoButton.setLayoutData( undoButtonGridData ); undoButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { undo(); treeViewer.refresh(); } } ); undoButton.setEnabled( false ); redoButton = new Button( buttonComposite, SWT.NONE ); redoButton.setText( Messages.getString( "ACIItemGrantsAndDenialsComposite.redo.button" ) ); //$NON-NLS-1$ redoButton.setLayoutData( redoButtonGridData ); redoButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { redo(); treeViewer.refresh(); } } ); redoButton.setEnabled( false ); } /** * The ICellModifier user for this tree viewer. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ private class GrantsAndDenialsCellModifier implements ICellModifier { /** * Only GrantAndDenialWrappers and the STATE colum is modifiable. * * @param element the element * @param property the property * * @return true, if can modify */ public boolean canModify( Object element, String property ) { if ( element instanceof GrantAndDenialWrapper ) { return property.equals( STATE ); } return false; } /** * The used CheckboxCellEditor accepts only Booleans. * * @param element the element * @param property the property * * @return the value */ public Object getValue( Object element, String property ) { if ( ( element instanceof GrantAndDenialWrapper ) && property.equals( STATE ) ) { return Boolean.TRUE; } return null; } /** * Performs the tree-state transtion. * * @param element the element * @param value the value * @param property the property */ public void modify( Object element, String property, Object value ) { Object target = element; if ( element instanceof Item ) { target = ( ( Item ) element ).getData(); } if ( target instanceof GrantAndDenialWrapper ) { GrantAndDenialWrapper grantAndDenialWrapper = ( GrantAndDenialWrapper ) target; if ( property.equals( STATE ) ) { backup(); if ( grantAndDenialWrapper.activeGrantAndDenial == null ) { grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.grant; } else if ( grantAndDenialWrapper.activeGrantAndDenial == grantAndDenialWrapper.grant ) { grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.denial; } else if ( grantAndDenialWrapper.activeGrantAndDenial == grantAndDenialWrapper.denial ) { grantAndDenialWrapper.activeGrantAndDenial = null; } } } treeViewer.refresh(); } } /** * The content provider used for this tree viewer. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ private class GrantsAndDenialsContentProvider extends ArrayContentProvider implements ITreeContentProvider { /** * Only GrantAndDenialCategories have children. * * @param parentElement the parent element * * @return the children */ public Object[] getChildren( Object parentElement ) { if ( parentElement instanceof GrantAndDenialCategory ) { GrantAndDenialCategory cat = ( GrantAndDenialCategory ) parentElement; return cat.grantAndDenialWrappers; } return null; } /** * Not used. * * @param element the element * * @return the parent */ public Object getParent( Object element ) { return null; } /** * Only GrantAndDenialCategories have children. * * @param element the element * * @return true, if has children */ public boolean hasChildren( Object element ) { return ( element instanceof GrantAndDenialCategory ); } } /** * The label provider used for this tree viewer. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ private class GrantsAndDenialsLabelProvider extends LabelProvider implements ITableLabelProvider { /** * The STATE is displayed as image. * * @param element the element * @param columnIndex the column index * * @return the column image */ public Image getColumnImage( Object element, int columnIndex ) { if ( element instanceof GrantAndDenialWrapper ) { GrantAndDenialWrapper grantAndDenialWrapper = ( GrantAndDenialWrapper ) element; switch ( columnIndex ) { case 0: return null; case 1: if ( grantAndDenialWrapper.activeGrantAndDenial == null ) { return Activator.getDefault().getImage( Messages.getString( "ACIItemGrantsAndDenialsComposite.unspecified.icon" ) ); //$NON-NLS-1$ } else if ( grantAndDenialWrapper.activeGrantAndDenial == grantAndDenialWrapper.grant ) { return Activator.getDefault().getImage( Messages.getString( "ACIItemGrantsAndDenialsComposite.grant.icon" ) ); //$NON-NLS-1$ } else if ( grantAndDenialWrapper.activeGrantAndDenial == grantAndDenialWrapper.denial ) { return Activator.getDefault().getImage( Messages.getString( "ACIItemGrantsAndDenialsComposite.deny.icon" ) ); //$NON-NLS-1$ } case 2: return null; } } return null; } /** * Returns GrantAndDenialCategory name or the MicroOperation name. * * @param element the element * @param columnIndex the column index * * @return the column text */ public String getColumnText( Object element, int columnIndex ) { if ( element instanceof GrantAndDenialCategory ) { if ( columnIndex == 0 ) { GrantAndDenialCategory cat = ( GrantAndDenialCategory ) element; return cat.name; } } else if ( ( element instanceof GrantAndDenialWrapper ) && ( columnIndex == 0 ) ) { GrantAndDenialWrapper wrapper = ( GrantAndDenialWrapper ) element; return wrapper.grant.getMicroOperation().getName(); } return ""; //$NON-NLS-1$ } } /** * Sets the grants and denials. * * @param grantsAndDenials */ public void setGrantsAndDenials( Collection<GrantAndDenial> grantsAndDenials ) { for ( GrantAndDenial grantAndDenial : grantsAndDenials ) { for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { if ( grantAndDenialWrapper.grant == grantAndDenial ) { grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.grant; } else if ( grantAndDenialWrapper.denial == grantAndDenial ) { grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.denial; } } } } treeViewer.refresh(); } /** * Returns the grants and denials as selected by the user. * * @return the grants and denials * @throws ParseException */ public Collection<GrantAndDenial> getGrantsAndDenials() throws ParseException { Collection<GrantAndDenial> grantsAndDenials = new ArrayList<GrantAndDenial>(); for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { if ( grantAndDenialWrapper.activeGrantAndDenial != null ) { grantsAndDenials.add( grantAndDenialWrapper.activeGrantAndDenial ); } } } return grantsAndDenials; } /** * Undos the last modification. */ private void undo() { for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { if ( !grantAndDenialWrapper.undoStack.isEmpty() ) { grantAndDenialWrapper.redoStack.add( 0, grantAndDenialWrapper.activeGrantAndDenial ); grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.undoStack.remove( 0 ); } undoButton.setEnabled( !grantAndDenialWrapper.undoStack.isEmpty() ); redoButton.setEnabled( !grantAndDenialWrapper.redoStack.isEmpty() ); } } } /** * Redos the last modification */ private void redo() { for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { if ( !grantAndDenialWrapper.redoStack.isEmpty() ) { grantAndDenialWrapper.undoStack.add( 0, grantAndDenialWrapper.activeGrantAndDenial ); grantAndDenialWrapper.activeGrantAndDenial = grantAndDenialWrapper.redoStack.remove( 0 ); } undoButton.setEnabled( !grantAndDenialWrapper.undoStack.isEmpty() ); redoButton.setEnabled( !grantAndDenialWrapper.redoStack.isEmpty() ); } } } /** * Saves the current state to the undo stack. */ private void backup() { for ( GrantAndDenialCategory grantAndDenialCategory : grantAndDenialCategories ) { for ( GrantAndDenialWrapper grantAndDenialWrapper : grantAndDenialCategory.grantAndDenialWrappers ) { if ( grantAndDenialWrapper.undoStack.size() == MAX_STACK_SIZE ) { grantAndDenialWrapper.undoStack.remove( grantAndDenialWrapper.undoStack.size() - 1 ); } grantAndDenialWrapper.undoStack.add( 0, grantAndDenialWrapper.activeGrantAndDenial ); grantAndDenialWrapper.redoStack.clear(); undoButton.setEnabled( !grantAndDenialWrapper.undoStack.isEmpty() ); redoButton.setEnabled( !grantAndDenialWrapper.redoStack.isEmpty() ); } } } }