changeset 7746:38e6776160ac

[SCENEBUILDER] Partial for Fix DTL-6783: Rationalize job implementation between Hierarchy and Content Panels => Define new jobs architecture + adapt Delete and Paste jobs As a consequence : Fix DTL-6819 : [regression] Multiple selection lost after undoing paste job
author slions
date Thu, 21 Aug 2014 09:24:35 +0200
parents a3d4992f65ea
children 6ba670dbf9a4
files apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchDocumentJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchSelectionJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/CompositeJob2.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/DeleteObjectJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/DeleteObjectSelectionJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/InlineDocumentJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/PasteJob.java
diffstat 7 files changed, 445 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchDocumentJob.java	Thu Aug 21 09:24:35 2014 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.oracle.javafx.scenebuilder.kit.editor.job;
+
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This Job updates the FXOM document at execution time. The selection is not
+ * updated.
+ *
+ * The sub jobs are FIRST all created, THEN executed.
+ */
+public abstract class BatchDocumentJob extends CompositeJob2 {
+
+    public BatchDocumentJob(EditorController editorController) {
+        super(editorController);
+    }
+
+    @Override
+    public final List<Job> getSubJobs() {
+        if (subJobs == null) {
+            subJobs = makeSubJobs();
+            assert subJobs != null;
+            subJobs = Collections.unmodifiableList(subJobs);
+        }
+        return subJobs;
+    }
+
+    @Override
+    public final boolean isExecutable() {
+        return getSubJobs().isEmpty() == false;
+    }
+
+    @Override
+    public final void execute() {
+        final FXOMDocument fxomDocument
+                = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        for (Job subJob : getSubJobs()) {
+            subJob.execute();
+        }
+        fxomDocument.endUpdate();
+    }
+
+    @Override
+    public final void undo() {
+        final FXOMDocument fxomDocument
+                = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        for (int i = getSubJobs().size() - 1; i >= 0; i--) {
+            getSubJobs().get(i).undo();
+        }
+        fxomDocument.endUpdate();
+    }
+
+    @Override
+    public final void redo() {
+        final FXOMDocument fxomDocument
+                = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        for (Job subJob : getSubJobs()) {
+            subJob.redo();
+        }
+        fxomDocument.endUpdate();
+    }
+
+    protected abstract List<Job> makeSubJobs();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchSelectionJob.java	Thu Aug 21 09:24:35 2014 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.oracle.javafx.scenebuilder.kit.editor.job;
+
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.editor.selection.AbstractSelectionGroup;
+import com.oracle.javafx.scenebuilder.kit.editor.selection.Selection;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This Job updates the FXOM document AND the selection at execution time.
+ *
+ * The sub jobs are FIRST all created, THEN executed.
+ */
+public abstract class BatchSelectionJob extends CompositeJob2 {
+
+    protected AbstractSelectionGroup oldSelectionGroup;
+    protected AbstractSelectionGroup newSelectionGroup;
+
+    public BatchSelectionJob(EditorController editorController) {
+        super(editorController);
+    }
+
+    @Override
+    public final List<Job> getSubJobs() {
+        if (subJobs == null) {
+            subJobs = makeSubJobs();
+            assert subJobs != null;
+            subJobs = Collections.unmodifiableList(subJobs);
+        }
+        return subJobs;
+    }
+
+    @Override
+    public final boolean isExecutable() {
+        return getSubJobs().isEmpty() == false;
+    }
+
+    @Override
+    public final void execute() {
+        final Selection selection = getEditorController().getSelection();
+        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
+        try {
+            fxomDocument.beginUpdate();
+            selection.beginUpdate();
+            oldSelectionGroup = selection.getGroup() == null ? null
+                    : selection.getGroup().clone();
+            for (Job subJob : getSubJobs()) {
+                subJob.execute();
+            }
+            newSelectionGroup = getNewSelectionGroup();
+            selection.select(newSelectionGroup);
+            selection.endUpdate();
+            fxomDocument.endUpdate();
+
+        } catch (CloneNotSupportedException x) {
+            // Emergency code
+            throw new RuntimeException(x);
+        }
+    }
+
+    @Override
+    public final void undo() {
+        final Selection selection = getEditorController().getSelection();
+        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        selection.beginUpdate();
+        for (int i = getSubJobs().size() - 1; i >= 0; i--) {
+            getSubJobs().get(i).undo();
+        }
+        selection.select(oldSelectionGroup);
+        selection.endUpdate();
+        fxomDocument.endUpdate();
+    }
+
+    @Override
+    public final void redo() {
+        final Selection selection = getEditorController().getSelection();
+        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        selection.beginUpdate();
+        for (Job subJob : getSubJobs()) {
+            subJob.redo();
+        }
+        selection.select(newSelectionGroup);
+        selection.endUpdate();
+        fxomDocument.endUpdate();
+    }
+
+    protected abstract List<Job> makeSubJobs();
+
+    protected abstract AbstractSelectionGroup getNewSelectionGroup();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/CompositeJob2.java	Thu Aug 21 09:24:35 2014 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.oracle.javafx.scenebuilder.kit.editor.job;
+
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import java.util.List;
+
+/**
+ * This Job handles a list of sub jobs and a description.
+ */
+public abstract class CompositeJob2 extends Job {
+
+    protected List<Job> subJobs;
+    protected String description;
+
+    public CompositeJob2(EditorController editorController) {
+        super(editorController);
+    }
+
+    @Override
+    public final String getDescription() {
+        if (description == null) {
+            description = makeDescription();
+            assert description != null;
+        }
+        return description;
+    }
+
+    public abstract List<Job> getSubJobs();
+    protected abstract String makeDescription();
+}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/DeleteObjectJob.java	Thu Aug 21 13:28:03 2014 +1200
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/DeleteObjectJob.java	Thu Aug 21 09:24:35 2014 +0200
@@ -39,35 +39,29 @@
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMIntrinsic;
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyC;
+import java.util.ArrayList;
+import java.util.List;
 import javafx.scene.chart.Axis;
 
 /**
  *
  */
-public class DeleteObjectJob extends Job {
-    
+public class DeleteObjectJob extends InlineDocumentJob {
+
     private final FXOMObject targetFxomObject;
-    private String description; // final but initialized lazily
-
-    private BatchJob subJob;
 
     public DeleteObjectJob(FXOMObject fxomObject, EditorController editorController) {
         super(editorController);
-        
+
         assert fxomObject != null;
-        
+
         this.targetFxomObject = fxomObject;
     }
-    
-    
-    /*
-     * Job
-     */
 
     @Override
     public boolean isExecutable() {
         final boolean result;
-        
+
         if (targetFxomObject == targetFxomObject.getFxomDocument().getFxomRoot()) {
             // targetFxomObject is the root
             result = true;
@@ -77,24 +71,22 @@
         } else {
             result = (targetFxomObject.getParentProperty() != null);
         }
-        
+
         return result;
     }
 
     @Override
-    public void execute() {
-        assert subJob == null;
-        
-        subJob = new BatchJob(getEditorController(), true /* shouldRefreshSceneGraph */, null);
-        
-        if (targetFxomObject.getParentProperty() == null) { 
+    protected List<Job> makeAndExecuteSubJobs() {
+
+        final List<Job> result = new ArrayList<>();
+        if (targetFxomObject.getParentProperty() == null) {
             /*
              * targetFxomObject is the root object
              */
-            subJob.addSubJob(new SetDocumentRootJob(null, getEditorController()));
-            
+            result.add(new SetDocumentRootJob(null, getEditorController()));
+
         } else {
-            
+
             /*
              * Two cases:
              *    1) targetFxomObject is the last value of its parent property
@@ -113,65 +105,50 @@
             if ((parentProperty.getValues().size() == 1) && (parentInstance != null)) {
                 // We make a job for removing the property
                 final Job removePropJob = new RemovePropertyJob(
-                        targetFxomObject.getParentProperty(), 
+                        targetFxomObject.getParentProperty(),
                         getEditorController());
-                subJob.addSubJob(removePropJob);
+                result.add(removePropJob);
             }
 
             // Then we make a job for removing the value
             final Job removeValueJob = new RemovePropertyValueJob(
-                    targetFxomObject, 
+                    targetFxomObject,
                     getEditorController());
-            subJob.addSubJob(removeValueJob);
-            
+            result.add(removeValueJob);
+        }
+
+        for (Job subJob : result) {
+            subJob.execute();
         }
         
-        // Now execute the batch
-        subJob.execute();
+        assert targetFxomObject.getParentProperty() == null;
         
-        assert targetFxomObject.getParentProperty() == null;
+        return result;
     }
 
     @Override
-    public void undo() {
-        assert subJob != null;
-        subJob.undo();
-    }
+    protected String makeDescription() {
+        final StringBuilder sb = new StringBuilder();
 
-    @Override
-    public void redo() {
-        assert subJob != null;
-        getEditorController().getSelection().clear();
-        subJob.redo();
-    }
+        sb.append("Delete ");
 
-    @Override
-    public String getDescription() {
-        if (description == null) {
-            final StringBuilder sb = new StringBuilder();
+        if (targetFxomObject instanceof FXOMInstance) {
+            final Object sceneGraphObject = targetFxomObject.getSceneGraphObject();
+            if (sceneGraphObject != null) {
+                sb.append(sceneGraphObject.getClass().getSimpleName());
+            } else {
+                sb.append("Unresolved Object");
+            }
+        } else if (targetFxomObject instanceof FXOMCollection) {
+            sb.append("Collection");
+        } else if (targetFxomObject instanceof FXOMIntrinsic) {
+            sb.append(targetFxomObject.getGlueElement().getTagName());
+        } else {
+            assert false;
+            sb.append(targetFxomObject.getClass().getSimpleName());
+        }
 
-            sb.append("Delete ");
-
-            if (targetFxomObject instanceof FXOMInstance) {
-                final Object sceneGraphObject = targetFxomObject.getSceneGraphObject();
-                if (sceneGraphObject != null) {
-                    sb.append(sceneGraphObject.getClass().getSimpleName());
-                } else {
-                    sb.append("Unresolved Object");
-                }
-            } else if (targetFxomObject instanceof FXOMCollection) {
-                sb.append("Collection");
-            } else if (targetFxomObject instanceof FXOMIntrinsic) {
-                sb.append(targetFxomObject.getGlueElement().getTagName());
-            } else {
-                assert false;
-                sb.append(targetFxomObject.getClass().getSimpleName());
-            }
-
-            description = sb.toString();
-        }
-        
-        return description;
+        return sb.toString();
     }
     
     FXOMObject getTargetFxomObject() {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/DeleteObjectSelectionJob.java	Thu Aug 21 13:28:03 2014 +1200
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/DeleteObjectSelectionJob.java	Thu Aug 21 09:24:35 2014 +0200
@@ -34,8 +34,7 @@
 import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
 import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N;
 import com.oracle.javafx.scenebuilder.kit.editor.job.togglegroup.AdjustAllToggleGroupJob;
-import com.oracle.javafx.scenebuilder.kit.editor.job.v2.ClearSelectionJob;
-import com.oracle.javafx.scenebuilder.kit.editor.job.v2.CompositeJob;
+import com.oracle.javafx.scenebuilder.kit.editor.selection.AbstractSelectionGroup;
 import com.oracle.javafx.scenebuilder.kit.editor.selection.ObjectSelectionGroup;
 import com.oracle.javafx.scenebuilder.kit.editor.selection.Selection;
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
@@ -45,17 +44,12 @@
 /**
  * Delete job for ObjectSelectionGroup.
  */
-public class DeleteObjectSelectionJob extends CompositeJob {
+public class DeleteObjectSelectionJob extends BatchSelectionJob {
 
     public DeleteObjectSelectionJob(EditorController editorController) {
         super(editorController);
-        
     }
 
-    /*
-     * CompositeJob
-     */
-
     @Override
     protected List<Job> makeSubJobs() {
         final Selection selection = getEditorController().getSelection();
@@ -63,9 +57,6 @@
         final ObjectSelectionGroup osg = (ObjectSelectionGroup) selection.getGroup();
         final List<Job> result = new ArrayList<>();
         
-        // First we clear the selection
-        result.add(new ClearSelectionJob(getEditorController()));
-        
         // Next we make one DeleteObjectJob for each selected objects
         int cannotDeleteCount = 0;
         for (FXOMObject candidate : osg.getFlattenItems()) {
@@ -93,22 +84,27 @@
     @Override
     protected String makeDescription() {
         final String result;
-        final List<Job> subJobs = getSubJobs();
-        final int subJobCount = subJobs.size();
-        assert (subJobCount == 0) || (subJobCount >= 3);
+        final int subJobCount = getSubJobs().size();
+        assert (subJobCount == 0) || (subJobCount >= 2);
         
         switch (subJobCount) {
             case 0:
                 result = "Unexecutable Delete"; // NO18N
                 break;
-            case 3: // Clear + one delete + one AdjustAllToggleGroup
-                result = subJobs.get(1).getDescription();
+            case 2: // one delete + one AdjustAllToggleGroup
+                result = getSubJobs().get(0).getDescription();
                 break;
             default:
-                result = I18N.getString("label.action.edit.delete.n", subJobCount-2);
+                result = I18N.getString("label.action.edit.delete.n", subJobCount-1);
                 break;
         }
         
         return result;
     }
+
+    @Override
+    protected AbstractSelectionGroup getNewSelectionGroup() {
+        // Selection emptied
+        return null;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/InlineDocumentJob.java	Thu Aug 21 09:24:35 2014 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.oracle.javafx.scenebuilder.kit.editor.job;
+
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This Job updates the FXOM document at execution time. The selection is not
+ * updated.
+ *
+ * The sub jobs are created and executed just after.
+ */
+public abstract class InlineDocumentJob extends CompositeJob2 {
+
+    public InlineDocumentJob(EditorController editorController) {
+        super(editorController);
+    }
+
+    @Override
+    public final List<Job> getSubJobs() {
+        return Collections.unmodifiableList(subJobs);
+    }
+
+    @Override
+    public final void execute() {
+        final FXOMDocument fxomDocument
+                = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        subJobs = makeAndExecuteSubJobs();
+        fxomDocument.endUpdate();
+    }
+
+    @Override
+    public final void undo() {
+        final FXOMDocument fxomDocument
+                = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        for (int i = getSubJobs().size() - 1; i >= 0; i--) {
+            getSubJobs().get(i).undo();
+        }
+        fxomDocument.endUpdate();
+    }
+
+    @Override
+    public final void redo() {
+        final FXOMDocument fxomDocument
+                = getEditorController().getFxomDocument();
+        fxomDocument.beginUpdate();
+        for (Job subJob : getSubJobs()) {
+            subJob.redo();
+        }
+        fxomDocument.endUpdate();
+    }
+
+    protected abstract List<Job> makeAndExecuteSubJobs();
+}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/PasteJob.java	Thu Aug 21 13:28:03 2014 +1200
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/PasteJob.java	Thu Aug 21 09:24:35 2014 +0200
@@ -34,9 +34,8 @@
 import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
 import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N;
 import com.oracle.javafx.scenebuilder.kit.editor.job.togglegroup.AdjustAllToggleGroupJob;
-import com.oracle.javafx.scenebuilder.kit.editor.job.v2.ClearSelectionJob;
-import com.oracle.javafx.scenebuilder.kit.editor.job.v2.CompositeJob;
-import com.oracle.javafx.scenebuilder.kit.editor.job.v2.UpdateSelectionJob;
+import com.oracle.javafx.scenebuilder.kit.editor.selection.AbstractSelectionGroup;
+import com.oracle.javafx.scenebuilder.kit.editor.selection.ObjectSelectionGroup;
 import com.oracle.javafx.scenebuilder.kit.editor.selection.Selection;
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMCollection;
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
@@ -52,19 +51,16 @@
 /**
  *
  */
-public class PasteJob extends CompositeJob {
+public class PasteJob extends BatchSelectionJob {
     
     private final List<Job> insertJobs = new ArrayList<>();
     private FXOMObject targetObject;
+    private List<FXOMObject> newObjects;
 
     public PasteJob(EditorController editorController) {
         super(editorController);
     }
 
-    /*
-     * CompositeJob
-     */
-    
     @Override
     protected List<Job> makeSubJobs() {
         final List<Job> result = new ArrayList<>();
@@ -75,8 +71,7 @@
             // Retrieve the FXOMObjects from the clipboard
             final ClipboardDecoder clipboardDecoder
                     = new ClipboardDecoder(Clipboard.getSystemClipboard());
-            final List<FXOMObject> newObjects 
-                    = clipboardDecoder.decode(fxomDocument);
+            newObjects = clipboardDecoder.decode(fxomDocument);
             assert newObjects != null; // But possible empty
 
             if (newObjects.isEmpty() == false) {
@@ -103,14 +98,12 @@
                 if (targetObject == null) {
                     // Document is empty : only one object can be inserted
                     if (newObjects.size() == 1) {
-                        result.add(new ClearSelectionJob(getEditorController()));
                         final FXOMObject newObject0 = newObjects.get(0);
                         final SetDocumentRootJob subJob = new SetDocumentRootJob(
                                 newObject0,
                                 getEditorController());
                         result.add(subJob);
                         result.add(new AdjustAllToggleGroupJob(getEditorController()));
-                        result.add(new UpdateSelectionJob(newObject0, getEditorController()));
                         insertJobs.add(subJob);
                     }
                 } else {
@@ -126,7 +119,6 @@
                         } else {
                             relocateDelta = 0.0;
                         }
-                        result.add(new ClearSelectionJob(getEditorController()));
                         for (FXOMObject newObject : newObjects) {
                             final InsertAsSubComponentJob subJob = new InsertAsSubComponentJob(
                                     newObject,
@@ -147,7 +139,6 @@
                             }
                         }
                         result.add(new AdjustAllToggleGroupJob(getEditorController()));
-                        result.add(new UpdateSelectionJob(newObjects, getEditorController()));
                     }
                 }
             }
@@ -170,6 +161,16 @@
         return result;
     }
 
+    @Override
+    protected AbstractSelectionGroup getNewSelectionGroup() {
+        assert newObjects != null; // But possibly empty
+        if (newObjects.isEmpty()) {
+            return null;
+        } else {
+            return new ObjectSelectionGroup(newObjects, newObjects.iterator().next(), null);
+        }
+    }
+
     /*
      * Private
      */