diff --git a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/DnDialog.java b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/DnDialog.java
index d3ce8ff8d3..1dd09bb478 100644
--- a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/DnDialog.java
+++ b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/DnDialog.java
@@ -41,6 +41,9 @@
/**
* The DnDialog is used from the Dn value editor to edit and select a Dn.
*
+ * In multi-select mode it allows the user to manage a list of DNs at once,
+ * which is useful e.g. when adding multiple members to a group.
+ *
* @author Apache Directory Project
*/
@@ -59,13 +62,18 @@ public class DnDialog extends Dialog
/** The connection. */
private IBrowserConnection connection;
- /** The dn */
- private Dn dn;
+ /** One dn (single-select mode) or multiple DNs (multi-select mode). */
+ private Dn[] dns;
+
+ /** True when the dialog operates in multi-select mode. */
+ private boolean multiSelect;
/**
- * Creates a new instance of DnDialog.
+ * Creates a new instance of DnDialog in single-select mode.
*
+ * Use {@link #getDn()} to retrieve the result after the dialog is closed.
+ *
* @param parentShell the parent shell
* @param title the title of the dialog
* @param description the description of the dialog
@@ -79,7 +87,31 @@ public DnDialog( Shell parentShell, String title, String description, IBrowserCo
this.title = title;
this.description = description;
this.connection = connection;
- this.dn = dn;
+ this.dns = dn != null ? new Dn[]{ dn } : new Dn[0];
+ this.multiSelect = false;
+ }
+
+
+ /**
+ * Creates a new instance of DnDialog in multi-select mode.
+ *
+ * Use {@link #getDns()} to retrieve the result after the dialog is closed.
+ *
+ * @param parentShell the parent shell
+ * @param title the title of the dialog
+ * @param description the description of the dialog
+ * @param connection the connection used to browse the directory
+ * @param dns the initial list of DNs, may be null or empty
+ */
+ public DnDialog( Shell parentShell, String title, String description, IBrowserConnection connection, Dn[] dns )
+ {
+ super( parentShell );
+ super.setShellStyle( super.getShellStyle() | SWT.RESIZE );
+ this.title = title;
+ this.description = description;
+ this.connection = connection;
+ this.dns = dns != null ? dns : new Dn[0];
+ this.multiSelect = true;
}
@@ -99,8 +131,11 @@ protected void configureShell( Shell shell )
*/
protected void okPressed()
{
- dn = entryWidget.getDn();
- entryWidget.saveDialogSettings();
+ dns = entryWidget.getDns();
+ if ( !multiSelect )
+ {
+ entryWidget.saveDialogSettings();
+ }
super.okPressed();
}
@@ -124,6 +159,10 @@ protected Control createDialogArea( Composite parent )
Composite composite = ( Composite ) super.createDialogArea( parent );
GridData gd = new GridData( GridData.FILL_BOTH );
gd.widthHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH ) * 3 / 2;
+ if ( multiSelect )
+ {
+ gd.heightHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH );
+ }
composite.setLayoutData( gd );
if ( description != null )
@@ -132,7 +171,17 @@ protected Control createDialogArea( Composite parent )
}
Composite innerComposite = BaseWidgetUtils.createColumnContainer( composite, 2, 1 );
- entryWidget = new EntryWidget( connection, dn );
+
+ if ( multiSelect )
+ {
+ entryWidget = new EntryWidget( connection, dns );
+ innerComposite.setLayoutData( new GridData( GridData.FILL_BOTH ) );
+ }
+ else
+ {
+ entryWidget = new EntryWidget( connection, dns.length == 0 ? null : dns[0] );
+ }
+
entryWidget.addWidgetModifyListener( new WidgetModifyListener()
{
public void widgetModified( WidgetModifyEvent event )
@@ -154,20 +203,39 @@ private void updateWidgets()
{
if ( getButton( IDialogConstants.OK_ID ) != null )
{
- getButton( IDialogConstants.OK_ID ).setEnabled(
- entryWidget.getDn() != null && !"".equals( entryWidget.getDn().toString() ) ); //$NON-NLS-1$
+ if ( multiSelect )
+ {
+ // Always allow confirming in multi-select mode (empty list is valid)
+ getButton( IDialogConstants.OK_ID ).setEnabled( true );
+ }
+ else
+ {
+ getButton( IDialogConstants.OK_ID ).setEnabled(
+ entryWidget.getDn() != null && !"".equals( entryWidget.getDn().toString() ) ); //$NON-NLS-1$
+ }
}
}
/**
- * Gets the dn.
- *
+ * Gets the dn (single-select mode).
+ *
* @return the dn
*/
public Dn getDn()
{
- return dn;
+ return dns.length == 0 ? null : dns[0];
+ }
+
+
+ /**
+ * Gets the list of DNs (multi-select mode).
+ *
+ * @return the array of selected DNs, never null
+ */
+ public Dn[] getDns()
+ {
+ return dns;
}
}
diff --git a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/SelectEntryDialog.java b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/SelectEntryDialog.java
index d74798767e..499190aa0f 100644
--- a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/SelectEntryDialog.java
+++ b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/SelectEntryDialog.java
@@ -21,6 +21,9 @@
package org.apache.directory.studio.ldapbrowser.common.dialogs;
+import java.util.ArrayList;
+import java.util.List;
+
import org.apache.directory.studio.ldapbrowser.common.widgets.browser.BrowserActionGroup;
import org.apache.directory.studio.ldapbrowser.common.widgets.browser.BrowserConfiguration;
import org.apache.directory.studio.ldapbrowser.common.widgets.browser.BrowserUniversalListener;
@@ -60,6 +63,9 @@ public class SelectEntryDialog extends Dialog
/** The selected entry. */
private IEntry selectedEntry;
+ /** All selected entries (supports multi-selection). */
+ private List selectedEntries;
+
/** The browser configuration. */
private BrowserConfiguration browserConfiguration;
@@ -89,6 +95,7 @@ public SelectEntryDialog( Shell parentShell, String title, IEntry rootEntry, IEn
this.rootEntry = rootEntry;
this.initialEntry = initialEntry;
this.selectedEntry = null;
+ this.selectedEntries = new ArrayList<>();
}
@@ -128,7 +135,23 @@ public boolean close()
*/
protected void okPressed()
{
- selectedEntry = initialEntry;
+ selectedEntries = new ArrayList<>();
+ if ( browserWidget != null )
+ {
+ IStructuredSelection sel = ( IStructuredSelection ) browserWidget.getViewer().getSelection();
+ for ( Object o : sel.toList() )
+ {
+ if ( o instanceof IEntry )
+ {
+ selectedEntries.add( ( IEntry ) o );
+ }
+ else if ( o instanceof ISearchResult )
+ {
+ selectedEntries.add( ( ( ISearchResult ) o ).getEntry() );
+ }
+ }
+ }
+ selectedEntry = selectedEntries.isEmpty() ? initialEntry : selectedEntries.get( 0 );
super.okPressed();
}
@@ -189,14 +212,22 @@ public void selectionChanged( SelectionChangedEvent event )
{
if ( !event.getSelection().isEmpty() )
{
- Object o = ( ( IStructuredSelection ) event.getSelection() ).getFirstElement();
- if ( o instanceof IEntry )
+ IStructuredSelection sel = ( IStructuredSelection ) event.getSelection();
+ selectedEntries = new ArrayList<>();
+ for ( Object o : sel.toList() )
{
- initialEntry = ( IEntry ) o;
+ if ( o instanceof IEntry )
+ {
+ selectedEntries.add( ( IEntry ) o );
+ }
+ else if ( o instanceof ISearchResult )
+ {
+ selectedEntries.add( ( ( ISearchResult ) o ).getEntry() );
+ }
}
- else if ( o instanceof ISearchResult )
+ if ( !selectedEntries.isEmpty() )
{
- initialEntry = ( ( ISearchResult ) o ).getEntry();
+ initialEntry = selectedEntries.get( 0 );
}
}
}
@@ -222,12 +253,23 @@ else if ( o instanceof ISearchResult )
/**
* Gets the selected entry.
- *
- * @return the selected entry
+ *
+ * @return the selected entry, or null if none
*/
public IEntry getSelectedEntry()
{
return selectedEntry;
}
+
+ /**
+ * Gets all selected entries (supports multi-selection via Ctrl/Shift+click).
+ *
+ * @return the list of selected entries, never null
+ */
+ public List getSelectedEntries()
+ {
+ return selectedEntries;
+ }
+
}
diff --git a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/EntryWidget.java b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/EntryWidget.java
index f92ab2f4c5..921807b2f9 100644
--- a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/EntryWidget.java
+++ b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/EntryWidget.java
@@ -21,6 +21,10 @@
package org.apache.directory.studio.ldapbrowser.common.widgets.search;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.studio.common.ui.HistoryUtils;
@@ -54,10 +58,16 @@
* a browse button to open a {@link SelectEntryDialog}
*
*
+ * In multi-select mode the widget shows a list of DNs together with
+ * Add and Remove buttons so the user can manage several entries at once
+ * (e.g. when adding multiple members to a group).
+ *
* @author Apache Directory Project
*/
public class EntryWidget extends AbstractWidget
{
+ // ---- single-select fields ----
+
/** The Dn combo. */
private Combo dnCombo;
@@ -67,9 +77,6 @@ public class EntryWidget extends AbstractWidget
/** The entry browse button. */
private Button entryBrowseButton;
- /** The connection. */
- private IBrowserConnection browserConnection;
-
/** The selected Dn. */
private Dn dn;
@@ -79,6 +86,28 @@ public class EntryWidget extends AbstractWidget
/** Flag indicating if using local name for the dn */
boolean useLocalName;
+ // ---- multi-select fields ----
+
+ /** True when the widget operates in multi-select mode. */
+ private boolean multiSelect;
+
+ /** SWT list showing the selected DNs (multi-select mode). */
+ private org.eclipse.swt.widgets.List dnListControl;
+
+ /** Ordered list of DNs managed in multi-select mode. */
+ private List dns;
+
+ /** Button to open the entry browser and add entries (multi-select mode). */
+ private Button addButton;
+
+ /** Button to remove the currently highlighted entries (multi-select mode). */
+ private Button removeButton;
+
+ // ---- shared fields ----
+
+ /** The connection. */
+ private IBrowserConnection browserConnection;
+
/**
* Creates a new instance of EntryWidget.
@@ -87,11 +116,12 @@ public EntryWidget()
{
browserConnection = null;
dn = null;
+ multiSelect = false;
}
/**
- * Creates a new instance of EntryWidget.
+ * Creates a new instance of EntryWidget (single-select mode).
*
* @param browserConnection the connection
* @param dn the initial Dn
@@ -103,7 +133,7 @@ public EntryWidget( IBrowserConnection browserConnection, Dn dn )
/**
- * Creates a new instance of EntryWidget.
+ * Creates a new instance of EntryWidget (single-select mode).
*
* @param browserConnection the connection
* @param dn the initial Dn
@@ -116,6 +146,21 @@ public EntryWidget( IBrowserConnection browserConnection, Dn dn, Dn suffix, bool
this.dn = dn;
this.suffix = suffix;
this.useLocalName = useLocalName;
+ this.multiSelect = false;
+ }
+
+
+ /**
+ * Creates a new instance of EntryWidget in multi-select mode.
+ *
+ * @param browserConnection the connection
+ * @param initialDns the initial list of DNs, may be null or empty
+ */
+ public EntryWidget( IBrowserConnection browserConnection, Dn[] initialDns )
+ {
+ this.browserConnection = browserConnection;
+ this.dns = new ArrayList<>( initialDns != null ? Arrays.asList( initialDns ) : new ArrayList() );
+ this.multiSelect = true;
}
@@ -126,7 +171,22 @@ public EntryWidget( IBrowserConnection browserConnection, Dn dn, Dn suffix, bool
*/
public void createWidget( final Composite parent )
{
+ if ( multiSelect )
+ {
+ createMultiSelectWidget( parent );
+ }
+ else
+ {
+ createSingleSelectWidget( parent );
+ }
+ }
+
+ /**
+ * Creates the single-select widget (original behaviour).
+ */
+ private void createSingleSelectWidget( final Composite parent )
+ {
// Dn combo
Composite textAndUpComposite = BaseWidgetUtils.createColumnContainer( parent, 2, 1 );
dnCombo = BaseWidgetUtils.createCombo( textAndUpComposite, new String[0], -1, 1 );
@@ -213,7 +273,7 @@ public void widgetSelected( SelectionEvent e )
}
catch ( LdapInvalidDnException lide )
{
- // Do nothing
+ // Do nothing
}
}
}
@@ -263,7 +323,87 @@ public void widgetSelected( SelectionEvent e )
/**
- * Notifies that the Dn has been changed.
+ * Creates the multi-select widget (list + Add/Remove buttons).
+ */
+ private void createMultiSelectWidget( final Composite parent )
+ {
+ // DN list
+ dnListControl = new org.eclipse.swt.widgets.List( parent,
+ SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL );
+ GridData listGd = new GridData( GridData.FILL_BOTH );
+ listGd.heightHint = 100;
+ listGd.widthHint = 200;
+ dnListControl.setLayoutData( listGd );
+
+ for ( Dn d : dns )
+ {
+ dnListControl.add( d.getName() );
+ }
+
+ dnListControl.addSelectionListener( new SelectionAdapter()
+ {
+ public void widgetSelected( SelectionEvent e )
+ {
+ internalSetEnabled();
+ }
+ } );
+
+ // Buttons composite (stacked vertically in the second column)
+ Composite buttonsComposite = BaseWidgetUtils.createColumnContainer( parent, 1, 1 );
+ GridData bgd = new GridData( SWT.FILL, SWT.TOP, false, false );
+ buttonsComposite.setLayoutData( bgd );
+
+ addButton = BaseWidgetUtils.createButton( buttonsComposite,
+ Messages.getString( "EntryWidget.AddButton" ), 1 ); //$NON-NLS-1$
+ addButton.addSelectionListener( new SelectionAdapter()
+ {
+ public void widgetSelected( SelectionEvent e )
+ {
+ if ( browserConnection != null )
+ {
+ IEntry rootEntry = browserConnection.getRootDSE();
+ SelectEntryDialog dialog = new SelectEntryDialog( parent.getShell(),
+ Messages.getString( "EntryWidget.SelectDN" ), rootEntry, null ); //$NON-NLS-1$
+ dialog.open();
+ for ( IEntry entry : dialog.getSelectedEntries() )
+ {
+ Dn entryDn = entry.getDn();
+ if ( !dns.contains( entryDn ) )
+ {
+ dns.add( entryDn );
+ dnListControl.add( entryDn.getName() );
+ }
+ }
+ internalSetEnabled();
+ notifyListeners();
+ }
+ }
+ } );
+
+ removeButton = BaseWidgetUtils.createButton( buttonsComposite,
+ Messages.getString( "EntryWidget.RemoveButton" ), 1 ); //$NON-NLS-1$
+ removeButton.addSelectionListener( new SelectionAdapter()
+ {
+ public void widgetSelected( SelectionEvent e )
+ {
+ int[] indices = dnListControl.getSelectionIndices();
+ // remove in reverse order so earlier indices stay valid
+ for ( int i = indices.length - 1; i >= 0; i-- )
+ {
+ dns.remove( indices[i] );
+ dnListControl.remove( indices[i] );
+ }
+ internalSetEnabled();
+ notifyListeners();
+ }
+ } );
+
+ internalSetEnabled();
+ }
+
+
+ /**
+ * Notifies that the Dn has been changed (single-select mode).
*/
private void dnChanged()
{
@@ -281,14 +421,25 @@ private void dnChanged()
*/
public void setEnabled( boolean enabled )
{
- dnCombo.setEnabled( enabled );
-
- if ( enabled )
+ if ( multiSelect )
{
- this.dnChanged();
+ if ( dnListControl != null )
+ {
+ dnListControl.setEnabled( enabled );
+ }
+ internalSetEnabled();
}
+ else
+ {
+ dnCombo.setEnabled( enabled );
- internalSetEnabled();
+ if ( enabled )
+ {
+ this.dnChanged();
+ }
+
+ internalSetEnabled();
+ }
}
@@ -297,18 +448,38 @@ public void setEnabled( boolean enabled )
*/
private void internalSetEnabled()
{
- upButton.setEnabled( !Dn.isNullOrEmpty( dn ) && dnCombo.isEnabled() );
- entryBrowseButton.setEnabled( browserConnection != null && dnCombo.isEnabled() );
+ if ( multiSelect )
+ {
+ if ( addButton != null )
+ {
+ addButton.setEnabled( browserConnection != null
+ && ( dnListControl == null || dnListControl.isEnabled() ) );
+ }
+ if ( removeButton != null )
+ {
+ removeButton.setEnabled( dnListControl != null
+ && dnListControl.isEnabled()
+ && dnListControl.getSelectionCount() > 0 );
+ }
+ }
+ else
+ {
+ upButton.setEnabled( !Dn.isNullOrEmpty( dn ) && dnCombo.isEnabled() );
+ entryBrowseButton.setEnabled( browserConnection != null && dnCombo.isEnabled() );
+ }
}
/**
- * Saves dialog settings.
+ * Saves dialog settings (single-select mode only).
*/
public void saveDialogSettings()
{
- HistoryUtils.save( BrowserCommonActivator.getDefault().getDialogSettings(),
- BrowserCommonConstants.DIALOGSETTING_KEY_DN_HISTORY, this.dnCombo.getText() );
+ if ( !multiSelect && dnCombo != null )
+ {
+ HistoryUtils.save( BrowserCommonActivator.getDefault().getDialogSettings(),
+ BrowserCommonConstants.DIALOGSETTING_KEY_DN_HISTORY, this.dnCombo.getText() );
+ }
}
@@ -324,7 +495,7 @@ public Dn getSuffix()
/**
- * Gets the Dn or null if the Dn isn't valid.
+ * Gets the Dn or null if the Dn isn't valid (single-select mode).
*
* @return the Dn or null if the Dn isn't valid
*/
@@ -334,6 +505,25 @@ public Dn getDn()
}
+ /**
+ * Gets all selected DNs (multi-select mode).
+ * In single-select mode returns an array with the single Dn, or an empty array.
+ *
+ * @return the array of selected DNs, never null
+ */
+ public Dn[] getDns()
+ {
+ if ( multiSelect )
+ {
+ return dns.toArray( new Dn[0] );
+ }
+ else
+ {
+ return dn != null ? new Dn[]{ dn } : new Dn[0];
+ }
+ }
+
+
/**
* Gets the browser connection.
*
diff --git a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages.properties b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages.properties
index 23be55c93b..daface90ab 100644
--- a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages.properties
+++ b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages.properties
@@ -22,6 +22,8 @@ BrowserConnectionWidget.SelectConnection=Select Connection
EntryWidget.BrowseButton=Br&owse...
EntryWidget.Parent=Parent
EntryWidget.SelectDN=Select DN
+EntryWidget.AddButton=&Add...
+EntryWidget.RemoveButton=&Remove
FilterWidget.FilterEditor=Filter Editor
FilterWidget.FilterEditorButton=F&ilter Editor...
LimitWidget.CountLimit=&Count Limit:
diff --git a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages_de.properties b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages_de.properties
index 7b47d604f4..c4e83850e3 100644
--- a/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages_de.properties
+++ b/plugins/ldapbrowser.common/src/main/java/org/apache/directory/studio/ldapbrowser/common/widgets/search/messages_de.properties
@@ -22,6 +22,8 @@ BrowserConnectionWidget.SelectConnection=Verbindung ausw\u00E4hlen
EntryWidget.BrowseButton=Br&owsen...
EntryWidget.Parent=Übergeordneter Eintrag
EntryWidget.SelectDN=DN ausw\u00E4hlen
+EntryWidget.AddButton=&Hinzufügen...
+EntryWidget.RemoveButton=&Entfernen
FilterWidget.FilterEditor=Filtereditor
FilterWidget.FilterEditorButton=F&iltereditor...
LimitWidget.CountLimit=&Max. Anzahl:
diff --git a/plugins/valueeditors/src/main/java/org/apache/directory/studio/valueeditors/dn/DnValueEditor.java b/plugins/valueeditors/src/main/java/org/apache/directory/studio/valueeditors/dn/DnValueEditor.java
index e6a238643b..9e7db3d4b1 100644
--- a/plugins/valueeditors/src/main/java/org/apache/directory/studio/valueeditors/dn/DnValueEditor.java
+++ b/plugins/valueeditors/src/main/java/org/apache/directory/studio/valueeditors/dn/DnValueEditor.java
@@ -26,8 +26,11 @@
import org.apache.directory.studio.ldapbrowser.common.dialogs.DnDialog;
import org.apache.directory.studio.ldapbrowser.common.dialogs.TextDialog;
import org.apache.directory.studio.ldapbrowser.core.model.AttributeHierarchy;
+import org.apache.directory.studio.ldapbrowser.core.model.IAttribute;
import org.apache.directory.studio.ldapbrowser.core.model.IBrowserConnection;
+import org.apache.directory.studio.ldapbrowser.core.model.IEntry;
import org.apache.directory.studio.ldapbrowser.core.model.IValue;
+import org.apache.directory.studio.ldapbrowser.core.utils.CompoundModification;
import org.apache.directory.studio.valueeditors.AbstractDialogStringValueEditor;
import org.eclipse.swt.widgets.Shell;
@@ -44,15 +47,68 @@ public class DnValueEditor extends AbstractDialogStringValueEditor
/**
* {@inheritDoc}
*
- * This implementation opens the DnDialog.
+ * When the value being edited is an empty placeholder (a newly added value),
+ * the dialog opens in multi-select mode so the user can pick several DNs at
+ * once (e.g. to add multiple members to a group). If more than one DN is
+ * chosen, the additional values are written directly via
+ * {@link CompoundModification} and the cell-editor path is bypassed.
+ *
+ * For existing (non-empty) values the dialog opens in the original
+ * single-select mode.
*/
protected boolean openDialog( Shell shell )
{
Object value = getValue();
-
+
if ( value instanceof DnValueEditorRawValueWrapper )
{
DnValueEditorRawValueWrapper wrapper = ( DnValueEditorRawValueWrapper ) value;
+
+ // --- Multi-select mode for new (empty) values ---
+ if ( wrapper.ivalue != null && wrapper.ivalue.isEmpty() )
+ {
+ DnDialog dialog = new DnDialog( shell,
+ Messages.getString( "DnValueEditor.DNEditor" ), null, wrapper.connection, new Dn[0] ); //$NON-NLS-1$
+
+ if ( dialog.open() != TextDialog.OK )
+ {
+ return false;
+ }
+
+ Dn[] selectedDns = dialog.getDns();
+ if ( selectedDns.length == 0 )
+ {
+ return false;
+ }
+
+ if ( selectedDns.length == 1 )
+ {
+ // Single selection – use the normal cell-editor path
+ setValue( selectedDns[0].getName() );
+ return true;
+ }
+
+ // Multiple selections: commit everything directly so that each DN
+ // becomes its own attribute value.
+ IValue original = wrapper.ivalue;
+ IAttribute attribute = original.getAttribute();
+ IEntry entry = attribute.getEntry();
+ String attrDesc = attribute.getDescription();
+
+ CompoundModification modification = new CompoundModification();
+ // Replace the empty placeholder with the first selected DN.
+ modification.modifyValue( original, selectedDns[0].getName() );
+ // Append the remaining DNs as additional values.
+ for ( int i = 1; i < selectedDns.length; i++ )
+ {
+ modification.createValue( entry, attrDesc, selectedDns[i].getName() );
+ }
+ // We have already committed the changes; tell the cell editor to cancel
+ // so it does not try to set a value a second time.
+ return false;
+ }
+
+ // --- Single-select mode for existing values (original behaviour) ---
Dn dn;
try
{
@@ -112,7 +168,9 @@ else if ( attributeHierarchy.size() == 1 && attributeHierarchy.getAttribute().ge
* {@inheritDoc}
*
* Returns a DnValueEditorRawValueWrapper with the connection of
- * the value and a Dn build from the given value.
+ * the value and a Dn built from the given value. The IValue itself is
+ * stored in the wrapper so that {@link #openDialog} can detect whether
+ * the value is an empty placeholder and act accordingly.
*/
public Object getRawValue( IValue value )
{
@@ -120,7 +178,7 @@ public Object getRawValue( IValue value )
if ( o instanceof String )
{
IBrowserConnection connection = value.getAttribute().getEntry().getBrowserConnection();
- return new DnValueEditorRawValueWrapper( connection, ( String ) o );
+ return new DnValueEditorRawValueWrapper( connection, ( String ) o, value );
}
return null;
@@ -140,17 +198,38 @@ private class DnValueEditorRawValueWrapper
/** The Dn, used as initial value in DnDialog */
private String dn;
+ /**
+ * The IValue being edited. Set when the wrapper originates from the
+ * cell-editor path ({@link #getRawValue(IValue)}); null when it comes
+ * from the read-only display path ({@link #getRawValue(AttributeHierarchy)}).
+ */
+ private IValue ivalue;
+
/**
- * Creates a new instance of DnValueEditorRawValueWrapper.
+ * Creates a new instance of DnValueEditorRawValueWrapper (display path).
*
* @param connection the connection
* @param dn the Dn
*/
private DnValueEditorRawValueWrapper( IBrowserConnection connection, String dn )
+ {
+ this( connection, dn, null );
+ }
+
+
+ /**
+ * Creates a new instance of DnValueEditorRawValueWrapper (cell-editor path).
+ *
+ * @param connection the connection
+ * @param dn the Dn
+ * @param ivalue the IValue being edited
+ */
+ private DnValueEditorRawValueWrapper( IBrowserConnection connection, String dn, IValue ivalue )
{
this.connection = connection;
this.dn = dn;
+ this.ivalue = ivalue;
}