/* * 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.ldapbrowser.common.widgets; import java.util.ArrayList; import java.util.Arrays; import org.apache.directory.studio.common.ui.widgets.AbstractWidget; import org.apache.directory.studio.common.ui.widgets.BaseWidgetUtils; import org.apache.directory.studio.connection.ui.widgets.ExtendedContentAssistCommandAdapter; import org.apache.directory.studio.ldapbrowser.core.BrowserCoreConstants; import org.apache.directory.studio.ldapbrowser.core.model.schema.Schema; import org.apache.directory.studio.ldapbrowser.core.model.schema.SchemaUtils; import org.eclipse.jface.fieldassist.ComboContentAdapter; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; 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.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Text; /** * The ModWidget provides input elements to define an LDAP modify * operation. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public class ModWidget extends AbstractWidget { /** The scrolled composite */ private ScrolledComposite scrolledComposite; /** The composite that contains the ModSpecs */ private Composite composite; /** The list of ModSpecs */ private ArrayList<ModSpec> modSpecList = new ArrayList<ModSpec>(); /** The list content proposal provider */ private ListContentProposalProvider listContentProposalProvider; /** The resulting LDIF */ private String ldif; // Listeners private ModifyListener modifyListener = new ModifyListener() { public void modifyText( ModifyEvent e ) { validate( true ); } }; /** * Creates a new instance of ModWidget. * * @param schema the schema with the possible attribute types */ public ModWidget( Schema schema ) { String[] attributeDescriptions = SchemaUtils.getNamesAsArray( schema.getAttributeTypeDescriptions() ); Arrays.sort( attributeDescriptions ); listContentProposalProvider = new ListContentProposalProvider( attributeDescriptions ); } /** * Disposes this widget. */ public void dispose() { } /** * Gets the ldif. * * @return the ldif */ public String getLdif() { return ldif; } /** * Creates the contents. * * @param parent the parent composite * * @return the created composite */ public Composite createContents( Composite parent ) { // Creating the scrolled composite containing all UI scrolledComposite = new ScrolledComposite( parent, SWT.H_SCROLL | SWT.V_SCROLL ); scrolledComposite.setLayout( new GridLayout() ); scrolledComposite.setExpandHorizontal( true ); scrolledComposite.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) ); // Creating the composite composite = BaseWidgetUtils.createColumnContainer( scrolledComposite, 3, 1 ); composite.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) ); scrolledComposite.setContent( composite ); addInitialModSpec(); validate( false ); return scrolledComposite; } /** * Validates the input elements. */ public void validate( boolean notifyListeners ) { for ( int i = 0; i < modSpecList.size(); i++ ) { ModSpec modSpec = ( ModSpec ) modSpecList.get( i ); if ( modSpecList.size() > 1 ) { modSpec.modDeleteButton.setEnabled( true ); } else { modSpec.modDeleteButton.setEnabled( false ); } for ( int k = 0; k < modSpec.valueLineList.size(); k++ ) { ValueLine valueLine = ( ValueLine ) modSpec.valueLineList.get( k ); if ( modSpec.valueLineList.size() > 1 ) { valueLine.valueDeleteButton.setEnabled( true ); } else { valueLine.valueDeleteButton.setEnabled( false ); } } } if ( notifyListeners ) { notifyListeners(); } } /** * Adds an initial modification spec. * */ private void addInitialModSpec() { addModSpec( 0 ); } /** * Adds a modification spec at the given index. * * @param index the index */ private void addModSpec( int index ) { // Getting the array of modification specs ModSpec[] modSpecs = ( ModSpec[] ) modSpecList.toArray( new ModSpec[modSpecList.size()] ); // Adding a new modification spec ModSpec newModSpec = createModSpec( true ); modSpecList.add( newModSpec ); if ( modSpecs.length > 0 ) { for ( int i = index; i < modSpecs.length; i++ ) { ModSpec modSpec = modSpecs[i]; // That's a trick to relocate the modification spec // beneath the newly created one modSpec.modGroup.setParent( scrolledComposite ); modSpec.modAddButton.setParent( scrolledComposite ); modSpec.modDeleteButton.setParent( scrolledComposite ); modSpec.modGroup.setParent( composite ); modSpec.modAddButton.setParent( composite ); modSpec.modDeleteButton.setParent( composite ); // Same trick to update the id in the list modSpecList.remove( modSpec ); modSpecList.add( modSpec ); } } composite.setSize( composite.computeSize( SWT.DEFAULT, SWT.DEFAULT ) ); } /** * Creates and returns a modification spec. * * @param addFirstValueLine if a first value line should added * @return the created modification spec */ private ModSpec createModSpec( boolean addFirstValueLine ) { ModSpec modSpec = new ModSpec(); modSpec.modGroup = BaseWidgetUtils.createGroup( composite, "", 1 ); //$NON-NLS-1$ modSpec.modGroup.setLayoutData( new GridData( SWT.FILL, SWT.NONE, true, false ) ); Composite modSpecComposite = BaseWidgetUtils.createColumnContainer( modSpec.modGroup, 2, 1 ); modSpec.modType = BaseWidgetUtils.createReadonlyCombo( modSpecComposite, new String[] { "add", "replace", "delete" }, 0, 1 ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ modSpec.modType.setLayoutData( new GridData() ); modSpec.modType.addModifyListener( modifyListener ); // attribute combo with field decoration and content proposal modSpec.modAttributeCombo = BaseWidgetUtils.createCombo( modSpecComposite, new String[0], -1, 1 ); new ExtendedContentAssistCommandAdapter( modSpec.modAttributeCombo, new ComboContentAdapter(), listContentProposalProvider, null, null, true ); modSpec.modAttributeCombo.addModifyListener( modifyListener ); // add button with listener modSpec.modAddButton = new Button( composite, SWT.PUSH ); modSpec.modAddButton.setText( " + " ); //$NON-NLS-1$ modSpec.modAddButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { int index = modSpecList.size(); for ( int i = 0; i < modSpecList.size(); i++ ) { ModSpec modSpec = modSpecList.get( i ); if ( modSpec.modAddButton == e.widget ) { index = i + 1; } } addModSpec( index ); validate( true ); } } ); // delete button with listener modSpec.modDeleteButton = new Button( composite, SWT.PUSH ); modSpec.modDeleteButton.setText( " \u2212 " ); //$NON-NLS-1$ modSpec.modDeleteButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { int index = 0; for ( int i = 0; i < modSpecList.size(); i++ ) { ModSpec modSpec = modSpecList.get( i ); if ( modSpec.modDeleteButton == e.widget ) { index = i; } } deleteModSpec( index ); validate( true ); } } ); if ( addFirstValueLine ) { addValueLine( modSpec, 0, false ); } return modSpec; } /** * Delets a modification spec. * * @param index the index */ private void deleteModSpec( int index ) { ModSpec modSpec = modSpecList.remove( index ); if ( modSpec != null ) { modSpec.modGroup.dispose(); modSpec.modAddButton.dispose(); modSpec.modDeleteButton.dispose(); composite.setSize( composite.computeSize( SWT.DEFAULT, SWT.DEFAULT ) ); } } /** * Adds a value line to the given modification spec. * * @param modSpec the modification spec * @param index the index * @param boolean the flag to update the size */ private void addValueLine( ModSpec modSpec, int index, boolean updateSize ) { ValueLine[] valueLines = modSpec.valueLineList.toArray( new ValueLine[modSpec.valueLineList.size()] ); ValueLine newValueLine = createValueLine( modSpec ); modSpec.valueLineList.add( newValueLine ); if ( valueLines.length > 0 ) { for ( int i = index; i < valueLines.length; i++ ) { ValueLine valueLine = valueLines[i]; // That's a trick to relocate the value line // beneath the newly created one Composite parentComposite = valueLine.valueComposite.getParent(); valueLine.valueComposite.setParent( scrolledComposite ); valueLine.valueComposite.setParent( parentComposite ); // Same trick to update the id in the list modSpec.valueLineList.remove( valueLine ); modSpec.valueLineList.add( valueLine ); } } if ( updateSize ) { composite.setSize( composite.computeSize( SWT.DEFAULT, SWT.DEFAULT ) ); } } /** * Creates the value line. * * @param modSpec the modification spec * * @return the value line */ private ValueLine createValueLine( final ModSpec modSpec ) { final ValueLine valueLine = new ValueLine(); // text field valueLine.valueComposite = BaseWidgetUtils.createColumnContainer( modSpec.modGroup, 3, 1 ); valueLine.valueText = BaseWidgetUtils.createText( valueLine.valueComposite, "", 1 ); //$NON-NLS-1$ valueLine.valueText.addModifyListener( modifyListener ); // add button with listener valueLine.valueAddButton = new Button( valueLine.valueComposite, SWT.PUSH ); valueLine.valueAddButton.setText( " + " ); //$NON-NLS-1$ valueLine.valueAddButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { int index = modSpec.valueLineList.size(); for ( int i = 0; i < modSpec.valueLineList.size(); i++ ) { ValueLine valueLine = modSpec.valueLineList.get( i ); if ( valueLine.valueAddButton == e.widget ) { index = i + 1; } } addValueLine( modSpec, index, true ); validate( true ); } } ); // delete button with listener valueLine.valueDeleteButton = new Button( valueLine.valueComposite, SWT.PUSH ); valueLine.valueDeleteButton.setText( " \u2212 " ); //$NON-NLS-1$ valueLine.valueDeleteButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { int index = 0; for ( int i = 0; i < modSpec.valueLineList.size(); i++ ) { ValueLine valueLine = modSpec.valueLineList.get( i ); if ( valueLine.valueDeleteButton == e.widget ) { index = i; } } deleteValueLine( modSpec, index ); validate( true ); } } ); return valueLine; } /** * Delete value line. * * @param modSpec the mod spec * @param index the index */ private void deleteValueLine( ModSpec modSpec, int index ) { ValueLine valueLine = ( ValueLine ) modSpec.valueLineList.remove( index ); if ( valueLine != null ) { valueLine.valueComposite.dispose(); composite.setSize( composite.computeSize( SWT.DEFAULT, SWT.DEFAULT ) ); } } /** * Gets the LDIF fragment. * * @return the LDIF fragment */ public String getLdifFragment() { StringBuffer sb = new StringBuffer(); sb.append( "changetype: modify" ).append( BrowserCoreConstants.LINE_SEPARATOR ); //$NON-NLS-1$ ModSpec[] modSpecs = ( ModSpec[] ) modSpecList.toArray( new ModSpec[modSpecList.size()] ); if ( modSpecs.length > 0 ) { for ( int i = 0; i < modSpecs.length; i++ ) { ModSpec modSpec = modSpecs[i]; // get values String type = modSpec.modType.getText(); String attribute = modSpec.modAttributeCombo.getText(); String[] values = new String[modSpec.valueLineList.size()]; for ( int k = 0; k < values.length; k++ ) { values[k] = ( ( ValueLine ) modSpec.valueLineList.get( k ) ).valueText.getText(); } // build ldif sb.append( type ).append( ": " ).append( attribute ).append( BrowserCoreConstants.LINE_SEPARATOR ); //$NON-NLS-1$ for ( int k = 0; k < values.length; k++ ) { if ( values[k].length() > 0 ) { sb.append( attribute ).append( ": " ).append( values[k] ).append( //$NON-NLS-1$ BrowserCoreConstants.LINE_SEPARATOR ); } } sb.append( "-" ).append( BrowserCoreConstants.LINE_SEPARATOR ); //$NON-NLS-1$ // sb.append(BrowserCoreConstants.NEWLINE); } } return sb.toString(); } /** * The Class ModSpec is a wrapper for all input elements * of an modification. It contains a combo for the modify * operation, a combo for the attribute to modify, * value lines and + and - buttons to add and remove * other modifications. It looks like this: * <pre> * ---------------------------------- * | operation v | attribute type v |-------- * ------------------------ --------| + | - | * | value | + | - |-------- * ---------------------------------- * </pre> */ private class ModSpec { /** The mod group. */ private Group modGroup; /** The mod type. */ private Combo modType; /** The modification attribute. */ private Combo modAttributeCombo; /** The mod add button. */ private Button modAddButton; /** The mod delete button. */ private Button modDeleteButton; /** The value line list. */ private ArrayList<ValueLine> valueLineList = new ArrayList<ValueLine>();; } /** * The Class ValueLine is a wrapper for all input elements * of an value line. It contains an input field for the value * and + and - buttons to add and remove other value lines. * It looks like this: * <pre> * ------------------------------------- * | value | + | - | * ------------------------------------- * </pre> */ private class ValueLine { /** The value composite. */ private Composite valueComposite; /** The value text. */ private Text valueText; /** The value add button. */ private Button valueAddButton; /** The value delete button. */ private Button valueDeleteButton; } }