blob: 43112752de14b3ef53082b4fad99343aaec618e3 [file] [log] [blame]
/*
* 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 java.util.Iterator;
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.name.Ava;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.api.ldap.model.name.Rdn;
import org.apache.directory.studio.common.ui.widgets.AbstractWidget;
import org.apache.directory.studio.common.ui.widgets.BaseWidgetUtils;
import org.apache.directory.studio.connection.core.DnUtils;
import org.apache.directory.studio.connection.ui.widgets.ExtendedContentAssistCommandAdapter;
import org.apache.directory.studio.ldapbrowser.common.widgets.search.EntryWidget;
import org.apache.directory.studio.ldapbrowser.core.model.IBrowserConnection;
import org.eclipse.jface.fieldassist.ComboContentAdapter;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
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.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* The DnBuilderWidget provides input elements to select a parent Dn
* and to build a (multivalued) Rdn.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class DnBuilderWidget extends AbstractWidget implements ModifyListener
{
/** The attribute names that could be selected from drop-down list. */
private String[] attributeNames;
/** True if the Rdn input elements should be shown. */
private boolean showRDN;
/** True if the parent Dn input elements should be shown. */
private boolean showParent;
/** The shell. */
private Shell shell;
/** The selected parent Dn. */
private Dn parentDn;
/** The entry widget label. */
private Label parentEntryLabel;
/** The entry widget to enter/select the parent Dn. */
private EntryWidget parentEntryWidget;
/** The Rdn label */
private Label rdnLabel;
/** The composite that contains the RdnLines. */
private Composite rdnComposite;
/** The resulting Rdn. */
private Rdn rdn;
/** The list of RdnLines. */
private ArrayList<RdnLine> rdnLineList;
/** The preview label. */
private Label previewLabel;
/** The preview text. */
private Text previewText;
// Listeners
private SelectionListener rdnAddButtonSelectionListener = new SelectionAdapter()
{
@Override
public void widgetSelected( SelectionEvent e )
{
int index = rdnLineList.size();
for ( int i = 0; i < rdnLineList.size(); i++ )
{
RdnLine rdnLine = rdnLineList.get( i );
if ( rdnLine.rdnAddButton == e.widget )
{
index = i + 1;
}
}
addRdnLine( rdnComposite, index );
validate();
}
};
private SelectionListener rdnDeleteButtonSelectionListener = new SelectionAdapter()
{
@Override
public void widgetSelected( SelectionEvent e )
{
int index = 0;
for ( int i = 0; i < rdnLineList.size(); i++ )
{
RdnLine rdnLine = rdnLineList.get( i );
if ( rdnLine.rdnDeleteButton == e.widget )
{
index = i;
}
}
deleteRdnLine( rdnComposite, index );
validate();
}
};
/**
* Creates a new instance of DnBuilderWidget.
*
* @param showParent true if the parent Dn input elements should be shown
* @param showRDN true if the Rdn input elements should be shown
*/
public DnBuilderWidget( boolean showRDN, boolean showParent )
{
this.showRDN = showRDN;
this.showParent = showParent;
}
/**
* Disposes this widget.
*/
public void dispose()
{
}
/**
* Sets the input.
*
* @param rdn the initial Rdn
* @param attributeNames the attribute names that could be selected from drop-down list
* @param browserConnection the connection
* @param parentDn the initial parent Dn
*/
public void setInput( IBrowserConnection browserConnection, String[] attributeNames, Rdn rdn, Dn parentDn )
{
this.attributeNames = attributeNames;
Rdn currentRdn = rdn;
Dn currentParentDn = parentDn;
if ( showRDN )
{
for ( int i = 0; i < rdnLineList.size(); i++ )
{
RdnLine rdnLine = rdnLineList.get( i );
String oldName = rdnLine.rdnTypeCombo.getText();
rdnLine.rdnTypeCombo.setItems( attributeNames );
rdnLine.rdnNameCPA.setContentProposalProvider( new ListContentProposalProvider( attributeNames ) );
if ( Arrays.asList( rdnLine.rdnTypeCombo.getItems() ).contains( oldName ) )
{
rdnLine.rdnTypeCombo.setText( oldName );
}
}
}
if ( showRDN )
{
while ( !rdnLineList.isEmpty() )
{
deleteRdnLine( rdnComposite, 0 );
}
if ( currentRdn == null || currentRdn.size() == 0 )
{
addRdnLine( rdnComposite, 0 );
rdnLineList.get( 0 ).rdnTypeCombo.setFocus();
}
else
{
int i = 0;
Iterator<Ava> atavIterator = currentRdn.iterator();
while ( atavIterator.hasNext() )
{
Ava ava = atavIterator.next();
addRdnLine( rdnComposite, i );
removeRdnLineListeners( i );
rdnLineList.get( i ).rdnTypeCombo.setText( ava.getType() );
rdnLineList.get( i ).rdnValueText.setText( (String)ava.getValue().getNormalized() );
addRdnLineListeners( i );
if ( i == 0 )
{
RdnLine rdnLine = rdnLineList.get( i );
if ( rdnLine.rdnTypeCombo != null ) //$NON-NLS-1$
{
rdnLine.rdnTypeCombo.setFocus();
}
else
{
rdnLine.rdnValueText.selectAll();
rdnLine.rdnValueText.setFocus();
}
}
i++;
}
}
}
if ( showParent )
{
parentEntryWidget.setInput( browserConnection, currentParentDn );
}
validate();
}
/**
* Gets the Rdn.
*
* @return the Rdn
*/
public Rdn getRdn()
{
return rdn;
}
/**
* Gets the parent Dn.
*
* @return the parent Dn
*/
public Dn getParentDn()
{
return parentDn;
}
/**
* Creates the contents.
*
* @param parent the parent composite
*
* @return the created composite
*/
public Composite createContents( Composite parent )
{
this.shell = parent.getShell();
Composite composite = BaseWidgetUtils.createColumnContainer( parent, 3, 1 );
// draw parent
if ( showParent )
{
parentEntryLabel = BaseWidgetUtils.createLabel( composite,
Messages.getString( "DnBuilderWidget.Parent" ), 1 ); //$NON-NLS-1$
parentEntryWidget = new EntryWidget();
parentEntryWidget.createWidget( composite );
parentEntryWidget.addWidgetModifyListener( event -> validate() );
BaseWidgetUtils.createSpacer( composite, 3 );
}
// draw Rdn group
if ( showRDN )
{
rdnLabel = BaseWidgetUtils.createLabel( composite, Messages.getString( "DnBuilderWidget.RDN" ), 1 ); //$NON-NLS-1$
rdnComposite = BaseWidgetUtils.createColumnContainer( composite, 5, 2 );
rdnLineList = new ArrayList<>();
BaseWidgetUtils.createSpacer( composite, 3 );
}
// draw dn/rdn preview
if ( showRDN )
{
previewLabel = BaseWidgetUtils.createLabel( composite, showParent ? Messages
.getString( "DnBuilderWidget.DNPreview" ) : Messages.getString( "DnBuilderWidget.RDNPreview" ), 1 ); //$NON-NLS-1$ //$NON-NLS-2$
previewText = BaseWidgetUtils.createReadonlyText( composite, "", 2 ); //$NON-NLS-1$
BaseWidgetUtils.createSpacer( composite, 3 );
}
return composite;
}
/**
* {@inheritDoc}
*/
public void modifyText( ModifyEvent e )
{
validate();
}
/**
* Saves the dialog settings.
*/
public void saveDialogSettings()
{
if ( parentEntryWidget != null )
{
parentEntryWidget.saveDialogSettings();
}
}
/**
* Validates the input elements.
*/
public void validate()
{
Exception rdnE = null;
if ( showRDN )
{
try
{
// calculate Rdn
String[] rdnTypes = new String[rdnLineList.size()];
String[] rdnValues = new String[rdnLineList.size()];
for ( int i = 0; i < rdnLineList.size(); i++ )
{
RdnLine rdnLine = rdnLineList.get( i );
rdnTypes[i] = rdnLine.rdnTypeCombo.getText();
rdnValues[i] = rdnLine.rdnValueText.getText();
if ( rdnLineList.size() > 1 )
{
rdnLine.rdnDeleteButton.setEnabled( true );
}
else
{
rdnLine.rdnDeleteButton.setEnabled( false );
}
}
rdn = DnUtils.composeRdn( rdnTypes, rdnValues );
}
catch ( Exception e )
{
rdnE = e;
rdn = null;
}
}
Exception parentE = null;
if ( showParent )
{
try
{
// calculate Dn
parentDn = parentEntryWidget.getDn();
}
catch ( Exception e )
{
parentE = e;
parentDn = null;
}
}
String s = ""; //$NON-NLS-1$
if ( rdnE != null )
{
s += rdnE.getMessage() != null ? rdnE.getMessage() : Messages.getString( "DnBuilderWidget.ErrorInRDN" ); //$NON-NLS-1$
}
if ( parentE != null )
{
s += ", " + parentE.getMessage() != null ? parentE.getMessage() : Messages.getString( "DnBuilderWidget.ErrorInParentDN" ); //$NON-NLS-1$ //$NON-NLS-2$
}
if ( previewText != null )
{
if ( s.length() > 0 )
{
previewText.setText( s );
}
else
{
Dn dn;
if ( showParent && showRDN )
{
try
{
dn = parentDn.add( rdn );
}
catch ( LdapInvalidDnException lide )
{
// Do nothing
dn = Dn.EMPTY_DN;
}
}
else if ( showParent )
{
dn = parentDn;
}
else if ( showRDN )
{
try
{
dn = new Dn( rdn );
}
catch ( LdapInvalidDnException lide )
{
// Do nothing
dn = Dn.EMPTY_DN;
}
}
else
{
dn = Dn.EMPTY_DN;
}
previewText.setText( dn.getName() );
}
}
notifyListeners();
}
/**
* Adds an Rdn line at the given index.
*
* @param rdnComposite the Rdn composite
* @param index the index
*/
private void addRdnLine( Composite rdnComposite, int index )
{
RdnLine[] rdnLines = rdnLineList.toArray( new RdnLine[rdnLineList.size()] );
if ( rdnLines.length > 0 )
{
for ( int i = 0; i < rdnLines.length; i++ )
{
RdnLine oldRdnLine = rdnLines[i];
// remember values
String oldName = oldRdnLine.rdnTypeCombo.getText();
String oldValue = oldRdnLine.rdnValueText.getText();
// delete old
oldRdnLine.rdnTypeCombo.dispose();
oldRdnLine.rdnEqualsLabel.dispose();
oldRdnLine.rdnValueText.dispose();
oldRdnLine.rdnAddButton.dispose();
oldRdnLine.rdnDeleteButton.dispose();
rdnLineList.remove( oldRdnLine );
// add new
RdnLine newRdnLine = createRdnLine( rdnComposite );
rdnLineList.add( newRdnLine );
// restore value
newRdnLine.rdnTypeCombo.setText( oldName );
newRdnLine.rdnValueText.setText( oldValue );
// check
if ( index == i + 1 )
{
RdnLine rdnLine = createRdnLine( rdnComposite );
rdnLineList.add( rdnLine );
}
}
}
else
{
RdnLine rdnLine = createRdnLine( rdnComposite );
rdnLineList.add( rdnLine );
}
shell.layout( true, true );
}
/**
* Creates and returns an Rdn line.
*
* @param rdnComposite the Rdn composite
*
* @return the created Rdn line
*/
private RdnLine createRdnLine( final Composite rdnComposite )
{
final RdnLine rdnLine = new RdnLine();
rdnLine.rdnTypeCombo = new Combo( rdnComposite, SWT.DROP_DOWN | SWT.BORDER );
GridData gd = new GridData();
gd.widthHint = 180;
rdnLine.rdnTypeCombo.setLayoutData( gd );
rdnLine.rdnNameCPA = new ExtendedContentAssistCommandAdapter( rdnLine.rdnTypeCombo, new ComboContentAdapter(),
new ListContentProposalProvider( attributeNames ), null, null, true );
rdnLine.rdnEqualsLabel = new Label( rdnComposite, SWT.NONE );
rdnLine.rdnEqualsLabel.setText( "=" ); //$NON-NLS-1$
rdnLine.rdnValueText = new Text( rdnComposite, SWT.BORDER );
gd = new GridData( GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL );
rdnLine.rdnValueText.setLayoutData( gd );
rdnLine.rdnAddButton = new Button( rdnComposite, SWT.PUSH );
rdnLine.rdnAddButton.setText( " + " ); //$NON-NLS-1$
rdnLine.rdnDeleteButton = new Button( rdnComposite, SWT.PUSH );
rdnLine.rdnDeleteButton.setText( " \u2212 " ); //$NON-NLS-1$
if ( attributeNames != null )
{
rdnLine.rdnTypeCombo.setItems( attributeNames );
}
addRdnLineListeners( rdnLine );
return rdnLine;
}
/**
* Delete the Rdn line on the given index.
*
* @param rdnComposite the Rdn composite
* @param index the index
*/
private void deleteRdnLine( Composite rdnComposite, int index )
{
RdnLine rdnLine = rdnLineList.remove( index );
if ( rdnLine != null )
{
rdnLine.rdnTypeCombo.dispose();
rdnLine.rdnEqualsLabel.dispose();
rdnLine.rdnValueText.dispose();
rdnLine.rdnAddButton.dispose();
rdnLine.rdnDeleteButton.dispose();
if ( !rdnComposite.isDisposed() )
{
shell.layout( true, true );
}
}
}
/**
* Adds listeners for the Rdn line at the given index.
*
* @param index the index
*/
private void addRdnLineListeners( int index )
{
if ( rdnLineList != null )
{
addRdnLineListeners( rdnLineList.get( index ) );
}
}
/**
* Adds listeners for the Rdn line.
*
* @param rdnLine the Rdn line
*/
private void addRdnLineListeners( RdnLine rdnLine )
{
if ( rdnLine != null )
{
rdnLine.rdnAddButton.addSelectionListener( rdnAddButtonSelectionListener );
rdnLine.rdnDeleteButton.addSelectionListener( rdnDeleteButtonSelectionListener );
rdnLine.rdnTypeCombo.addModifyListener( this );
rdnLine.rdnValueText.addModifyListener( this );
}
}
/**
* Removes listeners for the Rdn line at the given index.
*
* @param index the index
*/
private void removeRdnLineListeners( int index )
{
if ( rdnLineList != null )
{
removeRdnLineListeners( rdnLineList.get( index ) );
}
}
/**
* Removes listeners for the Rdn line.
*
* @param rdnLine the Rdn line
*/
private void removeRdnLineListeners( RdnLine rdnLine )
{
if ( rdnLine != null )
{
rdnLine.rdnAddButton.removeSelectionListener( rdnAddButtonSelectionListener );
rdnLine.rdnDeleteButton.removeSelectionListener( rdnDeleteButtonSelectionListener );
rdnLine.rdnTypeCombo.removeModifyListener( this );
rdnLine.rdnValueText.removeModifyListener( this );
}
}
/**
* The Class RdnLine is a wrapper for all input elements
* of an Rdn line. It contains a combo for the Rdn attribute,
* an input field for the Rdn value and + and - buttons
* to add and remove other Rdn lines. It looks like this:
* <pre>
* --------------------------------------------------
* | attribute type v | = | attribute value | + | - |
* --------------------------------------------------
* </pre>
*/
private class RdnLine
{
/** The rdn name combo. */
private Combo rdnTypeCombo;
/** The content proposal adapter */
private ContentProposalAdapter rdnNameCPA;
/** The rdn value text. */
private Text rdnValueText;
/** The rdn equals label. */
private Label rdnEqualsLabel;
/** The rdn add button. */
private Button rdnAddButton;
/** The rdn delete button. */
private Button rdnDeleteButton;
}
/**
* Enables or disables this widget.
*
* @param b true to enable, false to disable
*/
public void setEnabled( boolean b )
{
if ( parentEntryWidget != null )
{
parentEntryLabel.setEnabled( b );
parentEntryWidget.setEnabled( b );
}
if ( rdnComposite != null && rdnLineList != null )
{
rdnLabel.setEnabled( b );
rdnComposite.setEnabled( b );
for ( RdnLine rdnLine : rdnLineList )
{
rdnLine.rdnTypeCombo.setEnabled( b );
rdnLine.rdnEqualsLabel.setEnabled( b );
rdnLine.rdnValueText.setEnabled( b );
rdnLine.rdnAddButton.setEnabled( b );
rdnLine.rdnDeleteButton.setEnabled( b && rdnLineList.size() > 1 );
}
if ( b )
{
rdnLineList.get( 0 ).rdnValueText.setFocus();
}
}
if ( previewText != null )
{
previewLabel.setEnabled( b );
previewText.setEnabled( b );
}
}
}