You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by se...@apache.org on 2010/03/29 23:18:12 UTC

svn commit: r928904 - in /directory/studio/trunk: ldapbrowser-common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/ ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/

Author: seelmann
Date: Mon Mar 29 21:18:11 2010
New Revision: 928904

URL: http://svn.apache.org/viewvc?rev=928904&view=rev
Log:
Fix for DIRSTUDIO-609 (Studio "hangs" when performing large search that is to be displayed)
o removed cloning of whole search result set
o deactivated sorting of large data set

Modified:
    directory/studio/trunk/ldapbrowser-common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/MultivaluedDialog.java
    directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditor.java
    directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCellModifier.java
    directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorConfiguration.java
    directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorContentProvider.java
    directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCursor.java

Modified: directory/studio/trunk/ldapbrowser-common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/MultivaluedDialog.java
URL: http://svn.apache.org/viewvc/directory/studio/trunk/ldapbrowser-common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/MultivaluedDialog.java?rev=928904&r1=928903&r2=928904&view=diff
==============================================================================
--- directory/studio/trunk/ldapbrowser-common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/MultivaluedDialog.java (original)
+++ directory/studio/trunk/ldapbrowser-common/src/main/java/org/apache/directory/studio/ldapbrowser/common/dialogs/MultivaluedDialog.java Mon Mar 29 21:18:11 2010
@@ -23,7 +23,6 @@ package org.apache.directory.studio.ldap
 
 import java.util.Iterator;
 
-import org.apache.directory.studio.connection.ui.RunnableContextRunner;
 import org.apache.directory.studio.ldapbrowser.common.BrowserCommonActivator;
 import org.apache.directory.studio.ldapbrowser.common.BrowserCommonConstants;
 import org.apache.directory.studio.ldapbrowser.common.widgets.entryeditor.EntryEditorWidget;
@@ -35,20 +34,19 @@ import org.apache.directory.studio.ldapb
 import org.apache.directory.studio.ldapbrowser.core.events.EmptyValueAddedEvent;
 import org.apache.directory.studio.ldapbrowser.core.events.EmptyValueDeletedEvent;
 import org.apache.directory.studio.ldapbrowser.core.events.EntryModificationEvent;
+import org.apache.directory.studio.ldapbrowser.core.events.EventRegistry;
 import org.apache.directory.studio.ldapbrowser.core.events.ValueAddedEvent;
 import org.apache.directory.studio.ldapbrowser.core.events.ValueDeletedEvent;
 import org.apache.directory.studio.ldapbrowser.core.events.ValueModifiedEvent;
-import org.apache.directory.studio.ldapbrowser.core.jobs.UpdateEntryRunnable;
+import org.apache.directory.studio.ldapbrowser.core.events.ValueMultiModificationEvent;
 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.IEntry;
 import org.apache.directory.studio.ldapbrowser.core.model.IValue;
 import org.apache.directory.studio.ldapbrowser.core.utils.CompoundModification;
 import org.apache.directory.studio.ldapbrowser.core.utils.Utils;
-import org.apache.directory.studio.ldifparser.LdifFormatParameters;
 import org.apache.directory.studio.ldifparser.model.LdifFile;
 import org.apache.directory.studio.valueeditors.ValueEditorManager;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
@@ -74,7 +72,10 @@ public class MultivaluedDialog extends D
     private static final String DIALOG_TITLE = Messages.getString( "MultivaluedDialog.MultivaluedEditor" ); //$NON-NLS-1$
 
     /** The attribute hierarchy to edit. */
-    private AttributeHierarchy attributeHierarchy;
+    private AttributeHierarchy workingAttributeHierarchy;
+
+    /** The original attribute hierarchy. */
+    private AttributeHierarchy referenceAttributeHierarchy;
 
     /** The entry editor widget configuration. */
     private MultiValuedEntryEditorConfiguration configuration;
@@ -96,18 +97,19 @@ public class MultivaluedDialog extends D
      * Creates a new instance of MultivaluedDialog.
      * 
      * @param parentShell the parent shell
-     * @param attributeHierarchy the attribute hierarchy
+     * @param workingAttributeHierarchy the attribute hierarchy
      */
     public MultivaluedDialog( Shell parentShell, AttributeHierarchy attributeHierarchy )
     {
         super( parentShell );
         setShellStyle( getShellStyle() | SWT.RESIZE );
+        this.referenceAttributeHierarchy = attributeHierarchy;
 
         // clone the entry and attribute hierarchy
         IEntry entry = attributeHierarchy.getEntry();
         String attributeDescription = attributeHierarchy.getAttributeDescription();
         IEntry clone = new CompoundModification().cloneEntry( entry );
-        this.attributeHierarchy = clone.getAttributeWithSubtypes( attributeDescription );
+        this.workingAttributeHierarchy = clone.getAttributeWithSubtypes( attributeDescription );
     }
 
 
@@ -125,24 +127,27 @@ public class MultivaluedDialog extends D
     @Override
     protected void okPressed()
     {
-        IEntry modifiedEntry = attributeHierarchy.getEntry();
-        IEntry originalEntry = modifiedEntry.getBrowserConnection().getEntryFromCache( modifiedEntry.getDn() );
-        LdifFile diff = Utils.computeDiff( originalEntry, modifiedEntry );
+        LdifFile diff = Utils
+            .computeDiff( referenceAttributeHierarchy.getEntry(), workingAttributeHierarchy.getEntry() );
         if ( diff != null )
         {
-            // save
-            UpdateEntryRunnable runnable = new UpdateEntryRunnable( originalEntry, diff
-                .toFormattedString( LdifFormatParameters.DEFAULT ) );
-            IStatus status = RunnableContextRunner.execute( runnable, null, true );
-            if ( status.isOK() )
+            EventRegistry.suspendEventFiringInCurrentThread();
+            IEntry entry = referenceAttributeHierarchy.getEntry();
+            for ( IAttribute attribute : referenceAttributeHierarchy.getAttributes() )
             {
-                super.okPressed();
+                entry.deleteAttribute( attribute );
             }
+            for ( IAttribute attribute : workingAttributeHierarchy.getAttributes() )
+            {
+                entry.addAttribute( attribute );
+            }
+            EventRegistry.resumeEventFiringInCurrentThread();
+
+            ValueMultiModificationEvent event = new ValueMultiModificationEvent( entry.getBrowserConnection(), entry );
+            EventRegistry.fireEntryUpdated( event, this );
         }
-        else
-        {
-            super.okPressed();
-        }
+
+        super.okPressed();
     }
 
 
@@ -151,9 +156,9 @@ public class MultivaluedDialog extends D
      */
     public int open()
     {
-        if ( attributeHierarchy.getAttribute().getValueSize() == 0 )
+        if ( workingAttributeHierarchy.getAttribute().getValueSize() == 0 )
         {
-            attributeHierarchy.getAttribute().addEmptyValue();
+            workingAttributeHierarchy.getAttribute().addEmptyValue();
         }
 
         return super.open();
@@ -171,7 +176,7 @@ public class MultivaluedDialog extends D
             dispose();
 
             // cleanup attribute hierarchy after editing
-            for ( Iterator<IAttribute> it = attributeHierarchy.iterator(); it.hasNext(); )
+            for ( Iterator<IAttribute> it = workingAttributeHierarchy.iterator(); it.hasNext(); )
             {
                 IAttribute attribute = it.next();
                 if ( attribute != null )
@@ -254,10 +259,10 @@ public class MultivaluedDialog extends D
         // create the listener
         universalListener = new MultiValuedEntryEditorUniversalListener( mainWidget.getViewer(), configuration,
             actionGroup, actionGroup.getOpenDefaultEditorAction() );
-        universalListener.setInput( attributeHierarchy );
+        universalListener.setInput( workingAttributeHierarchy );
 
         // start edit mode if an empty value exists
-        for ( Iterator<IAttribute> it = attributeHierarchy.iterator(); it.hasNext(); )
+        for ( Iterator<IAttribute> it = workingAttributeHierarchy.iterator(); it.hasNext(); )
         {
             IAttribute attribute = it.next();
             IValue[] values = attribute.getValues();

Modified: directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditor.java
URL: http://svn.apache.org/viewvc/directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditor.java?rev=928904&r1=928903&r2=928904&view=diff
==============================================================================
--- directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditor.java (original)
+++ directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditor.java Mon Mar 29 21:18:11 2010
@@ -22,17 +22,21 @@ package org.apache.directory.studio.ldap
 
 
 import org.apache.directory.studio.connection.ui.RunnableContextRunner;
-import org.apache.directory.studio.entryeditors.EntryEditorUtils;
 import org.apache.directory.studio.ldapbrowser.common.BrowserCommonActivator;
 import org.apache.directory.studio.ldapbrowser.core.events.EntryModificationEvent;
 import org.apache.directory.studio.ldapbrowser.core.events.EntryUpdateListener;
 import org.apache.directory.studio.ldapbrowser.core.events.EventRegistry;
+import org.apache.directory.studio.ldapbrowser.core.events.ValueAddedEvent;
+import org.apache.directory.studio.ldapbrowser.core.events.ValueDeletedEvent;
+import org.apache.directory.studio.ldapbrowser.core.events.ValueModifiedEvent;
+import org.apache.directory.studio.ldapbrowser.core.events.ValueMultiModificationEvent;
+import org.apache.directory.studio.ldapbrowser.core.events.ValueRenamedEvent;
 import org.apache.directory.studio.ldapbrowser.core.jobs.UpdateEntryRunnable;
+import org.apache.directory.studio.ldapbrowser.core.model.IAttribute;
 import org.apache.directory.studio.ldapbrowser.core.model.IEntry;
 import org.apache.directory.studio.ldapbrowser.core.model.ISearch;
 import org.apache.directory.studio.ldapbrowser.core.model.ISearchResult;
-import org.apache.directory.studio.ldapbrowser.core.model.impl.SearchResult;
-import org.apache.directory.studio.ldapbrowser.core.utils.CompoundModification;
+import org.apache.directory.studio.ldapbrowser.core.model.IValue;
 import org.apache.directory.studio.ldapbrowser.core.utils.Utils;
 import org.apache.directory.studio.ldapbrowser.ui.BrowserUIConstants;
 import org.apache.directory.studio.ldapbrowser.ui.BrowserUIPlugin;
@@ -40,7 +44,6 @@ import org.apache.directory.studio.ldapb
 import org.apache.directory.studio.ldifparser.LdifFormatParameters;
 import org.apache.directory.studio.ldifparser.model.LdifFile;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
 import org.eclipse.jface.viewers.ISelection;
@@ -86,62 +89,50 @@ public class SearchResultEditor extends 
     /** The universal listener. */
     private SearchResultEditorUniversalListener universalListener;
 
-    private ISearch workingCopy;
-
     protected EntryUpdateListener entryUpdateListener = new EntryUpdateListener()
     {
         public void entryUpdated( EntryModificationEvent event )
         {
-            if ( workingCopy == null || mainWidget.getViewer() == null || mainWidget.getViewer().getInput() == null )
+            if ( mainWidget.getViewer() == null || mainWidget.getViewer().getInput() == null )
             {
                 return;
             }
 
             IEntry modifiedEntry = event.getModifiedEntry();
+            IEntry originalEntry = modifiedEntry.getBrowserConnection().getEntryFromCache( modifiedEntry.getDn() );
+            ISearchResult referenceCopy = configuration.getCursor( mainWidget.getViewer() ).getSelectedReferenceCopy();
+            ISearchResult workingCopy = configuration.getCursor( mainWidget.getViewer() ).getSelectedSearchResult();
 
-            if ( workingCopy != null && workingCopy.getSearchResults() != null )
+            // check on object identity, nothing should be done for equal objects from other editors
+            if ( workingCopy != null && workingCopy.getEntry() == modifiedEntry )
             {
-                for ( ISearchResult sr : workingCopy.getSearchResults() )
+                // only save if we receive a real value modification event
+                if ( !( event instanceof ValueAddedEvent || event instanceof ValueDeletedEvent
+                    || event instanceof ValueModifiedEvent || event instanceof ValueRenamedEvent || event instanceof ValueMultiModificationEvent ) )
+                {
+                    return;
+                }
+                // consistency check: don't save if there is an empty value, silently return in that case
+                for ( IAttribute attribute : modifiedEntry.getAttributes() )
                 {
-                    // check on object identity, nothing should be done for equal objects from other editors
-                    if ( modifiedEntry == sr.getEntry() )
+                    for ( IValue value : attribute.getValues() )
                     {
-                        IEntry originalEntry = modifiedEntry.getBrowserConnection().getEntryFromCache(
-                            modifiedEntry.getDn() );
-                        LdifFile diff = Utils.computeDiff( originalEntry, modifiedEntry );
-                        if ( diff != null )
+                        if ( value.isEmpty() )
                         {
-                            // save
-                            UpdateEntryRunnable runnable = new UpdateEntryRunnable( originalEntry, diff
-                                .toFormattedString( LdifFormatParameters.DEFAULT ) );
-                            IStatus status = RunnableContextRunner.execute( runnable, null, true );
-                            if ( status.isOK() )
-                            {
-                                EntryEditorUtils.ensureAttributesInitialized( originalEntry );
-                                setSearchResultEditorWidgetInput( ( SearchResultEditorInput ) getEditorInput() );
-                            }
+                            return;
                         }
-
-                        return;
                     }
                 }
 
-                IEditorInput input = getEditorInput();
-                if ( input instanceof SearchResultEditorInput )
+                LdifFile diff = Utils.computeDiff( referenceCopy.getEntry(), modifiedEntry );
+                if ( diff != null )
                 {
-                    SearchResultEditorInput srei = ( SearchResultEditorInput ) input;
-                    if ( srei.getSearch() != null && srei.getSearch().getSearchResults() != null )
-                    {
-                        for ( ISearchResult sr : srei.getSearch().getSearchResults() )
-                        {
-                            if ( modifiedEntry == sr.getEntry() )
-                            {
-                                // original entry has been updated, update widget input
-                                setSearchResultEditorWidgetInput( srei );
-                            }
-                        }
-                    }
+                    // save
+                    UpdateEntryRunnable runnable = new UpdateEntryRunnable( originalEntry, diff
+                        .toFormattedString( LdifFormatParameters.DEFAULT ) );
+                    RunnableContextRunner.execute( runnable, null, true );
                 }
+                configuration.getCursor( mainWidget.getViewer() ).resetCopies();
             }
         }
     };
@@ -202,26 +193,8 @@ public class SearchResultEditor extends 
 
     private void setSearchResultEditorWidgetInput( SearchResultEditorInput srei )
     {
-        // clone search, search results, entries
         ISearch search = srei.getSearch();
-        workingCopy = search != null ? ( ISearch ) search.clone() : search;
-        if ( search != null && search.getSearchResults() != null )
-        {
-            ISearchResult[] searchResults = search.getSearchResults();
-            ISearchResult[] clonedSearchResults = new ISearchResult[searchResults.length];
-            for ( int i = 0; i < searchResults.length; i++ )
-            {
-                IEntry entry = searchResults[i].getEntry();
-                IEntry clonedEntry = new CompoundModification().cloneEntry( entry );
-                clonedSearchResults[i] = new SearchResult( clonedEntry, workingCopy );
-            }
-
-            EventRegistry.suspendEventFiringInCurrentThread();
-            workingCopy.setSearchResults( clonedSearchResults );
-            EventRegistry.resumeEventFiringInCurrentThread();
-        }
-
-        universalListener.setInput( workingCopy );
+        universalListener.setInput( search );
     }
 
 
@@ -307,7 +280,6 @@ public class SearchResultEditor extends 
         if ( configuration != null )
         {
             EventRegistry.removeEntryUpdateListener( entryUpdateListener );
-            workingCopy = null;
             actionGroup.dispose();
             actionGroup = null;
             universalListener.dispose();

Modified: directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCellModifier.java
URL: http://svn.apache.org/viewvc/directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCellModifier.java?rev=928904&r1=928903&r2=928904&view=diff
==============================================================================
--- directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCellModifier.java (original)
+++ directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCellModifier.java Mon Mar 29 21:18:11 2010
@@ -49,15 +49,20 @@ public class SearchResultEditorCellModif
     /** The value editor manager. */
     private ValueEditorManager valueEditorManager;
 
+    /** The cursor */
+    private SearchResultEditorCursor cursor;
+
 
     /**
      * Creates a new instance of SearchResultEditorCellModifier.
      * 
      * @param valueEditorManager the value editor manager
+     * @param cursor the cursor
      */
-    public SearchResultEditorCellModifier( ValueEditorManager valueEditorManager )
+    public SearchResultEditorCellModifier( ValueEditorManager valueEditorManager, SearchResultEditorCursor cursor )
     {
         this.valueEditorManager = valueEditorManager;
+        this.cursor = cursor;
     }
 
 
@@ -110,7 +115,8 @@ public class SearchResultEditorCellModif
     {
         if ( element != null && element instanceof ISearchResult && property != null )
         {
-            ISearchResult result = ( ISearchResult ) element;
+            // perform modifications on the clone
+            ISearchResult result = cursor.getSelectedSearchResult();
             AttributeHierarchy ah = result.getAttributeWithSubtypes( property );
 
             if ( !canModify( element, property ) )
@@ -145,7 +151,8 @@ public class SearchResultEditorCellModif
 
         if ( element != null && element instanceof ISearchResult && property != null )
         {
-            ISearchResult result = ( ISearchResult ) element;
+            // perform modifications on the clone
+            ISearchResult result = cursor.getSelectedSearchResult();
             AttributeHierarchy ah = result.getAttributeWithSubtypes( property );
 
             // switch operation:

Modified: directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorConfiguration.java
URL: http://svn.apache.org/viewvc/directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorConfiguration.java?rev=928904&r1=928903&r2=928904&view=diff
==============================================================================
--- directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorConfiguration.java (original)
+++ directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorConfiguration.java Mon Mar 29 21:18:11 2010
@@ -208,7 +208,7 @@ public class SearchResultEditorConfigura
     {
         if ( cellModifier == null )
         {
-            cellModifier = new SearchResultEditorCellModifier( getValueEditorManager( viewer ) );
+            cellModifier = new SearchResultEditorCellModifier( getValueEditorManager( viewer ), getCursor( viewer ) );
         }
         return cellModifier;
     }

Modified: directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorContentProvider.java
URL: http://svn.apache.org/viewvc/directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorContentProvider.java?rev=928904&r1=928903&r2=928904&view=diff
==============================================================================
--- directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorContentProvider.java (original)
+++ directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorContentProvider.java Mon Mar 29 21:18:11 2010
@@ -108,9 +108,10 @@ public class SearchResultEditorContentPr
             if ( elements.length > 1000 && mainWidget.getViewer() != null
                 && !mainWidget.getViewer().getTable().isDisposed() )
             {
-                FilterAndSortRunnable runnable = new FilterAndSortRunnable( configuration, mainWidget, elements );
-                RunnableContextRunner.execute( runnable, null, true );
-                filteredAndSortedElements = runnable.getFilteredAndSortedElements();
+                // deactivate fitering and sorting for large data set
+                // FilterAndSortRunnable runnable = new FilterAndSortRunnable( configuration, mainWidget, elements );
+                // RunnableContextRunner.execute( runnable, null, true );
+                // filteredAndSortedElements = runnable.getFilteredAndSortedElements();
             }
             else if ( elements.length > 0 && mainWidget.getViewer() != null
                 && !mainWidget.getViewer().getTable().isDisposed() )

Modified: directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCursor.java
URL: http://svn.apache.org/viewvc/directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCursor.java?rev=928904&r1=928903&r2=928904&view=diff
==============================================================================
--- directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCursor.java (original)
+++ directory/studio/trunk/ldapbrowser-ui/src/main/java/org/apache/directory/studio/ldapbrowser/ui/editors/searchresult/SearchResultEditorCursor.java Mon Mar 29 21:18:11 2010
@@ -31,8 +31,11 @@ import org.apache.directory.studio.ldapb
 import org.apache.directory.studio.ldapbrowser.core.events.EventRegistry;
 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.IEntry;
 import org.apache.directory.studio.ldapbrowser.core.model.ISearchResult;
 import org.apache.directory.studio.ldapbrowser.core.model.impl.Attribute;
+import org.apache.directory.studio.ldapbrowser.core.model.impl.SearchResult;
+import org.apache.directory.studio.ldapbrowser.core.utils.CompoundModification;
 import org.apache.directory.studio.ldapbrowser.ui.BrowserUIConstants;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
@@ -63,6 +66,12 @@ public class SearchResultEditorCursor ex
     /** The selection changes listener list. */
     private List<ISelectionChangedListener> selectionChangesListenerList;
 
+    /** The cloned reference copy of the search result under the cursor */
+    private ISearchResult referenceCopy;
+
+    /** The cloned working copy of the search result under the cursor */
+    private ISearchResult workingCopy;
+
 
     /**
      * Creates a new instance of SearchResultEditorCursor.
@@ -192,11 +201,10 @@ public class SearchResultEditorCursor ex
         if ( !isDisposed() && getRow() != null && viewer != null && viewer.getColumnProperties() != null
             && viewer.getColumnProperties().length >= getColumn() + 1 )
         {
-            Object o = getRow().getData();
+            ISearchResult sr = getSelectedSearchResult();
             String property = ( String ) viewer.getColumnProperties()[getColumn()];
-            if ( o instanceof ISearchResult && !BrowserUIConstants.DN.equals( property ) )
+            if ( sr != null && !BrowserUIConstants.DN.equals( property ) )
             {
-                ISearchResult sr = ( ISearchResult ) o;
                 AttributeHierarchy ah = sr.getAttributeWithSubtypes( property );
 
                 if ( ah == null )
@@ -224,7 +232,17 @@ public class SearchResultEditorCursor ex
             Object o = getRow().getData();
             if ( o instanceof ISearchResult )
             {
-                return ( ISearchResult ) o;
+                ISearchResult sr = ( ISearchResult ) o;
+                if ( !sr.equals( workingCopy ) )
+                {
+                    IEntry entry = sr.getEntry();
+                    IEntry referenceEntry = new CompoundModification().cloneEntry( entry );
+                    referenceCopy = new SearchResult( referenceEntry, sr.getSearch() );
+                    IEntry workingEntry = new CompoundModification().cloneEntry( entry );
+                    workingCopy = new SearchResult( workingEntry, sr.getSearch() );
+                }
+
+                return workingCopy;
             }
         }
         return null;
@@ -232,6 +250,34 @@ public class SearchResultEditorCursor ex
 
 
     /**
+     * Gets the selected reference copy.
+     * 
+     * @return the selected reference copy, may be null
+     */
+    public ISearchResult getSelectedReferenceCopy()
+    {
+        return referenceCopy;
+    }
+
+
+    /**
+     * Resets reference and working copy copy.
+     */
+    public void resetCopies()
+    {
+        referenceCopy = null;
+        workingCopy = null;
+
+        // update all actions with the fresh selection
+        for ( Iterator<?> it = selectionChangesListenerList.iterator(); it.hasNext(); )
+        {
+            ( ( ISelectionChangedListener ) it.next() ).selectionChanged( new SelectionChangedEvent(
+                SearchResultEditorCursor.this, getSelection() ) );
+        }
+    }
+
+
+    /**
      * {@inheritDoc}
      */
     public void addSelectionChangedListener( ISelectionChangedListener listener )