/* * 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.valueeditors; import java.text.ParseException; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; import org.apache.directory.api.ldap.model.name.Dn; import org.apache.directory.api.ldap.model.subtree.BaseSubtreeSpecification; import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification; import org.apache.directory.api.ldap.model.subtree.SubtreeSpecificationParser; import org.apache.directory.studio.aciitemeditor.Activator; import org.apache.directory.studio.common.ui.widgets.BaseWidgetUtils; import org.apache.directory.studio.common.ui.widgets.WidgetModifyEvent; import org.apache.directory.studio.common.ui.widgets.WidgetModifyListener; import org.apache.directory.studio.ldapbrowser.common.dialogs.TextDialog; import org.apache.directory.studio.ldapbrowser.common.widgets.search.EntryWidget; import org.apache.directory.studio.ldapbrowser.common.widgets.search.FilterWidget; import org.apache.directory.studio.ldapbrowser.core.model.IBrowserConnection; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; 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.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Spinner; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Text; /** * This class provides a dialog to enter the Subtree Specification value. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ class SubtreeSpecificationDialog extends Dialog { /** The parser. */ private final SubtreeSpecificationParser parser = new SubtreeSpecificationParser( null ); /** The connection */ private IBrowserConnection connection; /** The subentry's Dn */ private Dn subentryDn; /** Flag indicating if the refinement or filter widget should be visible */ private boolean refinementOrFilterVisible; /** Flag indicating if a local name should be used for the base */ private boolean useLocalName; /** The initial SubtreeSpecification */ private SubtreeSpecification subtreeSpecification; /** The Exclusions List */ private List<String> exclusions; /** The returned SubtreeSpecification */ private String returnValue; // UI Fields private EntryWidget entryWidget; private Spinner minimumSpinner; private Spinner maximumSpinner; private TableViewer exclusionsTableViewer; private Button exclusionsTableEditButton; private Button exclusionsTableDeleteButton; private Button refinementButton; private Text refinementText; private Button filterButton; private FilterWidget filterWidget; /** * Creates a new instance of SubtreeSpecificationDialog. * * @param shell * the shell to use * @param connection * the connection to use * @param subentryDn * the subentry's Dn * @param initialSubtreeSpecification * the initial SubtreeSpecification * @param refinementOrFilterVisible * true if the refinement of filter widget should be visible * @param useLocalName * true to use local name for the base */ SubtreeSpecificationDialog( Shell shell, IBrowserConnection connection, Dn subentryDn, String initialSubtreeSpecification, boolean refinementOrFilterVisible, boolean useLocalName ) { super( shell ); this.connection = connection; this.subentryDn = subentryDn; this.refinementOrFilterVisible = refinementOrFilterVisible; this.useLocalName = useLocalName; // parse try { subtreeSpecification = parser.parse( initialSubtreeSpecification ); if ( subtreeSpecification == null ) { subtreeSpecification = new BaseSubtreeSpecification(); } } catch ( ParseException pe ) { // TODO pe.printStackTrace(); subtreeSpecification = new BaseSubtreeSpecification(); } exclusions = new ArrayList<String>(); Set<Dn> chopBeforeExclusions = subtreeSpecification.getChopBeforeExclusions(); for ( Dn dn : chopBeforeExclusions ) { exclusions.add( "chopBefore: \"" + dn.getNormName() + "\"" ); //$NON-NLS-1$ //$NON-NLS-2$ } Set<Dn> chopAfterExclusions = subtreeSpecification.getChopAfterExclusions(); for ( Dn dn : chopAfterExclusions ) { exclusions.add( "chopAfter: \"" + dn.getNormName() + "\"" ); //$NON-NLS-1$ //$NON-NLS-2$ } returnValue = null; } /** * {@inheritDoc} */ protected void configureShell( Shell newShell ) { super.configureShell( newShell ); newShell.setText( Messages.getString( "SubtreeValueEditor.title" ) ); //$NON-NLS-1$ newShell.setImage( Activator.getDefault().getImage( Messages.getString( "SubtreeValueEditor.icon" ) ) ); //$NON-NLS-1$ } /** * {@inheritDoc} */ protected void okPressed() { // set return value //returnValue = buildSubreeSpecification(); StringBuilder sb = new StringBuilder(); subtreeSpecification.toString( sb ); returnValue = sb.toString(); // save filter and dn history if ( refinementOrFilterVisible ) { filterWidget.saveDialogSettings(); } entryWidget.saveDialogSettings(); super.okPressed(); } /** * {@inheritDoc} */ protected Control createDialogArea( Composite parent ) { Composite outer = ( Composite ) super.createDialogArea( parent ); GridData gd = new GridData( GridData.FILL_BOTH ); gd.widthHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH ); outer.setLayoutData( gd ); Composite composite = BaseWidgetUtils.createColumnContainer( outer, 3, 1 ); BaseWidgetUtils.createLabel( composite, Messages.getString( "SubtreeValueEditor.label.base" ), 1 ); //$NON-NLS-1$ Dn base = subtreeSpecification.getBase(); Dn suffix = null; if ( subentryDn != null ) { suffix = subentryDn.getParent(); } entryWidget = new EntryWidget( connection, base, suffix, useLocalName ); entryWidget.createWidget( composite ); entryWidget.addWidgetModifyListener( new WidgetModifyListener() { public void widgetModified( WidgetModifyEvent event ) { validate(); } } ); GridData spinnersGridData = new GridData(); spinnersGridData.grabExcessHorizontalSpace = true; spinnersGridData.verticalAlignment = GridData.CENTER; spinnersGridData.horizontalSpan = 2; spinnersGridData.horizontalAlignment = GridData.BEGINNING; spinnersGridData.widthHint = 3 * 12; BaseWidgetUtils.createLabel( composite, Messages.getString( "SubtreeValueEditor.label.minimum" ), 1 ); //$NON-NLS-1$ minimumSpinner = new Spinner( composite, SWT.BORDER ); minimumSpinner.setMinimum( 0 ); minimumSpinner.setMaximum( Integer.MAX_VALUE ); minimumSpinner.setDigits( 0 ); minimumSpinner.setIncrement( 1 ); minimumSpinner.setPageIncrement( 100 ); minimumSpinner.setSelection( subtreeSpecification.getMinBaseDistance() ); minimumSpinner.setLayoutData( spinnersGridData ); minimumSpinner.addModifyListener( new ModifyListener() { public void modifyText( ModifyEvent event ) { validate(); } } ); BaseWidgetUtils.createLabel( composite, Messages.getString( "SubtreeValueEditor.label.maximum" ), 1 ); //$NON-NLS-1$ maximumSpinner = new Spinner( composite, SWT.BORDER ); maximumSpinner.setMinimum( 0 ); maximumSpinner.setMaximum( Integer.MAX_VALUE ); maximumSpinner.setDigits( 0 ); maximumSpinner.setIncrement( 1 ); maximumSpinner.setPageIncrement( 100 ); maximumSpinner.setSelection( subtreeSpecification.getMaxBaseDistance() ); maximumSpinner.setLayoutData( spinnersGridData ); maximumSpinner.addModifyListener( new ModifyListener() { public void modifyText( ModifyEvent event ) { validate(); } } ); createExclusionsTable( composite ); if ( refinementOrFilterVisible ) { BaseWidgetUtils.createSpacer( composite, 3 ); createRefinementOrFilterWidgets( composite ); } applyDialogFont( outer ); validate(); return outer; } /** * Creates the Exclusions Table. * * @param composite * the composite */ private void createExclusionsTable( Composite composite ) { GridData tableGridData = new GridData(); tableGridData.grabExcessHorizontalSpace = true; tableGridData.verticalAlignment = GridData.FILL; tableGridData.horizontalAlignment = GridData.FILL; tableGridData.heightHint = 100; BaseWidgetUtils.createLabel( composite, Messages.getString( "SubtreeValueEditor.label.exclusions" ), 1 ); //$NON-NLS-1$ Table exclusionsTable = new Table( composite, SWT.BORDER ); exclusionsTable.setHeaderVisible( false ); exclusionsTable.setLayoutData( tableGridData ); exclusionsTable.setLinesVisible( false ); exclusionsTableViewer = new TableViewer( exclusionsTable ); exclusionsTableViewer.setContentProvider( new ArrayContentProvider() ); exclusionsTableViewer.setLabelProvider( new LabelProvider() ); exclusionsTableViewer.setInput( exclusions ); exclusionsTableViewer.addSelectionChangedListener( new ISelectionChangedListener() { public void selectionChanged( SelectionChangedEvent event ) { valueSelectedExclusionsTable(); } } ); exclusionsTableViewer.addDoubleClickListener( new IDoubleClickListener() { public void doubleClick( DoubleClickEvent event ) { editValueExclusionsTable(); } } ); 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( composite, SWT.NONE ); buttonComposite.setLayoutData( gridData ); buttonComposite.setLayout( gridLayout ); GridData buttonGridData = new GridData(); buttonGridData.horizontalAlignment = GridData.FILL; buttonGridData.grabExcessHorizontalSpace = false; buttonGridData.verticalAlignment = GridData.BEGINNING; buttonGridData.widthHint = Activator.getButtonWidth( buttonComposite ); Button exclusionsTableAddButton = new Button( buttonComposite, SWT.PUSH ); exclusionsTableAddButton.setText( Messages.getString( "SubtreeValueEditor.button.add" ) ); //$NON-NLS-1$ exclusionsTableAddButton.setLayoutData( buttonGridData ); exclusionsTableAddButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { addValueExclusionsTable(); } } ); exclusionsTableEditButton = new Button( buttonComposite, SWT.PUSH ); exclusionsTableEditButton.setText( Messages.getString( "SubtreeValueEditor.button.edit" ) ); //$NON-NLS-1$ exclusionsTableEditButton.setLayoutData( buttonGridData ); exclusionsTableEditButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { editValueExclusionsTable(); } } ); exclusionsTableEditButton.setEnabled( false ); exclusionsTableDeleteButton = new Button( buttonComposite, SWT.PUSH ); exclusionsTableDeleteButton.setText( Messages.getString( "SubtreeValueEditor.button.delete" ) ); //$NON-NLS-1$ exclusionsTableDeleteButton.setLayoutData( buttonGridData ); exclusionsTableDeleteButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { deleteValueExclusionsTable(); } } ); exclusionsTableDeleteButton.setEnabled( false ); } /** * Creates the refinement or filter widgets * * @param composite * the composite */ private void createRefinementOrFilterWidgets( Composite parent ) { // Messages.getString( "SubtreeValueEditor.label.exclusions" ) BaseWidgetUtils.createLabel( parent, Messages .getString( "SubtreeValueEditor.SubtreeValueEditor.label.refinementOrFilter" ), 1 ); //$NON-NLS-1$ Composite composite = BaseWidgetUtils.createColumnContainer( parent, 2, 2 ); // refinement redio button refinementButton = BaseWidgetUtils.createRadiobutton( composite, Messages .getString( "SubtreeValueEditor.SubtreeValueEditor.label.refinement" ), 2 ); //$NON-NLS-1$ // refinement text refinementText = new Text( composite, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL ); GridData gd = new GridData( GridData.FILL_BOTH ); gd.horizontalSpan = 2; gd.widthHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH ); gd.heightHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH / 6 ); refinementText.setLayoutData( gd ); try { StringBuilder refinementBuffer = new StringBuilder(); if ( subtreeSpecification.getRefinement() != null ) { subtreeSpecification.getRefinement().printRefinementToBuffer( refinementBuffer ); } refinementText.setText( refinementBuffer.toString().trim() ); refinementText.setEnabled( true ); refinementButton.setSelection( true ); } catch ( UnsupportedOperationException e ) { // thrown if the ExprNode doesn't represent a valid refinement refinementText.setText( "" ); //$NON-NLS-1$ refinementText.setEnabled( false ); refinementButton.setSelection( false ); } // filter radio button filterButton = BaseWidgetUtils.createRadiobutton( composite, Messages .getString( "SubtreeValueEditor.SubtreeValueEditor.label.filter" ), 2 ); //$NON-NLS-1$ // filter widget String filter = ""; //$NON-NLS-1$ if ( subtreeSpecification.getRefinement() != null ) { filter = subtreeSpecification.getRefinement().toString(); } filterWidget = new FilterWidget( filter ); filterWidget.createWidget( composite ); filterWidget.setBrowserConnection( connection ); filterButton.setSelection( !refinementButton.getSelection() ); filterWidget.setEnabled( !refinementButton.getSelection() ); // add listeners refinementButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent arg0 ) { refinementText.setEnabled( true ); //filterButton.setSelection( false ); filterWidget.setEnabled( false ); validate(); } } ); refinementText.addModifyListener( new ModifyListener() { public void modifyText( ModifyEvent event ) { validate(); } } ); filterButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent arg0 ) { //refinementButton.setSelection( false ); refinementText.setEnabled( false ); filterWidget.setEnabled( true ); validate(); } } ); filterWidget.addWidgetModifyListener( new WidgetModifyListener() { public void widgetModified( WidgetModifyEvent event ) { validate(); } } ); } /** * Validates if the composed subtree specification is valid. */ private void validate() { boolean valid = true; Dn base = entryWidget.getDn(); valid &= base != null; String ss = buildSubreeSpecification(); try { subtreeSpecification = parser.parse( ss ); valid &= true; } catch ( ParseException pe ) { subtreeSpecification = null; valid &= false; } if ( refinementOrFilterVisible && filterButton.getSelection() ) { valid &= filterWidget.getFilter() != null; } if ( getButton( IDialogConstants.OK_ID ) != null ) { getButton( IDialogConstants.OK_ID ).setEnabled( valid ); } } private String buildSubreeSpecification() { // build subtree specification tree StringBuilder sb = new StringBuilder(); sb.append( "{" ); //$NON-NLS-1$ // Adding base Dn base = entryWidget.getDn(); if ( ( base != null ) && !SubtreeValueEditor.EMPTY.equals( base.toString() ) ) { sb.append( " base \"" ); sb.append( base.toString() ); sb.append( "\"," ); //$NON-NLS-1$ //$NON-NLS-2$ } // Adding Minimum int minimum = minimumSpinner.getSelection(); if ( minimum != 0 ) { sb.append( " minimum " ).append( minimum ).append( ',' ); //$NON-NLS-1$ //$NON-NLS-2$ } // Adding Maximum int maximum = maximumSpinner.getSelection(); if ( maximum != 0 ) { sb.append( " maximum " ).append( maximum ).append( ',' ); //$NON-NLS-1$ //$NON-NLS-2$ } // Adding Exclusions if ( !exclusions.isEmpty() ) { sb.append( " specificExclusions {" ); //$NON-NLS-1$ boolean isFirst = true; for ( String exclusion : exclusions ) { if ( isFirst ) { isFirst = false; } else { sb.append( ',' ); } sb.append( ' ' ).append( exclusion ); //$NON-NLS-1$ } sb.append( " }," ); //$NON-NLS-1$ } // Add Refinement or Filter String refinementOrFilter = ""; //$NON-NLS-1$ if ( refinementOrFilterVisible ) { if ( refinementButton.getSelection() ) { refinementOrFilter = refinementText.getText(); } else { refinementOrFilter = filterWidget.getFilter(); } } else { refinementOrFilter = ""; //$NON-NLS-1$ } if ( refinementOrFilter != null && !SubtreeValueEditor.EMPTY.equals( refinementOrFilter ) ) { sb.append( " specificationFilter " + refinementOrFilter + "," ); //$NON-NLS-1$ //$NON-NLS-2$ } // Removing the last ',' if ( sb.charAt( sb.length() - 1 ) == ',' ) { sb.deleteCharAt( sb.length() - 1 ); } sb.append( " }" ); //$NON-NLS-1$ return sb.toString(); } /** * Called when value is selected in Exclusions table viewer. * Updates the enabled/disabled state of the buttons. */ private void valueSelectedExclusionsTable() { String value = getSelectedValueExclusionsTable(); if ( value == null ) { exclusionsTableEditButton.setEnabled( false ); exclusionsTableDeleteButton.setEnabled( false ); } else { exclusionsTableEditButton.setEnabled( true ); exclusionsTableDeleteButton.setEnabled( true ); } } /** * Retuns the current selection in the Exclusions table viewer. * * @return * the value that is selected in the Exclusions table viewer, or null. */ private String getSelectedValueExclusionsTable() { String value = null; IStructuredSelection selection = ( IStructuredSelection ) exclusionsTableViewer.getSelection(); if ( !selection.isEmpty() ) { Object element = selection.getFirstElement(); if ( element instanceof String ) { value = ( String ) element; } } return value; } /** * Opens the editor and adds the new Exclusion value to the list. */ private void addValueExclusionsTable() { Dn chopBase = subtreeSpecification.getBase(); if ( useLocalName && ( subentryDn != null ) ) { Dn suffix = subentryDn.getParent(); if ( !Dn.isNullOrEmpty( suffix ) ) { try { chopBase = chopBase.add( suffix ); } catch ( LdapInvalidDnException lide ) { // Do nothing } } } ExclusionDialog dialog = new ExclusionDialog( getShell(), connection, chopBase, "" ); //$NON-NLS-1$ if ( dialog.open() == TextDialog.OK && !SubtreeValueEditor.EMPTY.equals( dialog.getType() ) && !SubtreeValueEditor.EMPTY.equals( dialog.getDN() ) ) { String newValue = dialog.getType() + ": \"" + dialog.getDN() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ exclusions.add( newValue ); exclusionsTableViewer.refresh(); validate(); } } /** * Opens the editor with the currently selected Exclusion * value and puts the modified value into the list. */ private void editValueExclusionsTable() { String oldValue = getSelectedValueExclusionsTable(); if ( oldValue != null ) { Dn chopBase = subtreeSpecification.getBase(); if ( useLocalName && ( subentryDn != null ) ) { Dn suffix = subentryDn.getParent(); if ( !Dn.isNullOrEmpty( suffix ) ) { try { chopBase = chopBase.add( suffix ); } catch ( LdapInvalidDnException lide ) { // Do nothing } } } ExclusionDialog dialog = new ExclusionDialog( getShell(), connection, chopBase, oldValue ); if ( dialog.open() == TextDialog.OK && !SubtreeValueEditor.EMPTY.equals( dialog.getType() ) && !SubtreeValueEditor.EMPTY.equals( dialog.getDN() ) ) { String newValue = dialog.getType() + ": \"" + dialog.getDN() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ exclusions.remove( oldValue ); exclusions.add( newValue ); exclusionsTableViewer.refresh(); validate(); } } } /** * Deletes the currently selected Exclusion value from list. */ private void deleteValueExclusionsTable() { String value = getSelectedValueExclusionsTable(); if ( value != null ) { exclusions.remove( value ); exclusionsTableViewer.refresh(); validate(); } } /** * Gets the subtree specification value or null if canceled. * * @return the subtree specification value or null if canceled */ public String getSubtreeSpecificationValue() { return returnValue; } }