changeset 7935:b0a0f059cc4e

[SCENEBUILDER] First step for DTL-6774 implementation. JobManager now automatically incokes UpdateReferencesJob. This job takes care to fix any forward reference created by the last editing action.
author eric.le.ponner@oracle.com
date Mon, 01 Sep 2014 19:32:54 +0200
parents 5ee50928c1d6
children b4976c12c98b 64c45eaad799
files apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/JobManager.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/reference/ReferencesUpdater.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/reference/UpdateReferencesJob.java
diffstat 3 files changed, 324 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/JobManager.java	Mon Sep 01 16:24:02 2014 +0200
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/JobManager.java	Mon Sep 01 19:32:54 2014 +0200
@@ -32,6 +32,7 @@
 package com.oracle.javafx.scenebuilder.kit.editor;
 
 import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
+import com.oracle.javafx.scenebuilder.kit.editor.job.reference.UpdateReferencesJob;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -77,8 +78,9 @@
             throw new IllegalStateException("Pushing jobs from another job or a job manager listener is forbidden"); //NOI18N
         }
         
-        executeJob(job);
-        undoStack.add(0, job);
+        final Job fixJob = new UpdateReferencesJob(job);
+        executeJob(fixJob);
+        undoStack.add(0, fixJob);
         if (undoStack.size() > undoStackMaxSize) {
             undoStack.remove(undoStack.size()-1);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/reference/ReferencesUpdater.java	Mon Sep 01 19:32:54 2014 +0200
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2012, 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.reference;
+
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
+import com.oracle.javafx.scenebuilder.kit.editor.job.atomic.RemoveNodeJob;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMCloner;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMCollection;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMIntrinsic;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMNode;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMNodes;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMProperty;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyC;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyT;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PrefixedValue;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
+import com.oracle.javafx.scenebuilder.kit.util.JavaLanguage;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+public class ReferencesUpdater {
+    
+    private final EditorController editorController;
+    private final FXOMDocument fxomDocument;
+    private final List<Job> executedJobs = new LinkedList<>();
+    private final Set<String> declaredFxIds = new HashSet<>();
+    private final FXOMCloner cloner;
+    
+    public ReferencesUpdater(EditorController editorController) {
+        assert editorController != null;
+        assert editorController.getFxomDocument() != null;
+        this.editorController = editorController;
+        this.fxomDocument = editorController.getFxomDocument();
+        this.cloner = new FXOMCloner(this.fxomDocument);
+    }
+    
+    public void update() {
+        if (fxomDocument.getFxomRoot() != null) {
+            declaredFxIds.clear();
+            update(fxomDocument.getFxomRoot());
+        }
+    }
+    
+    public List<Job> getExecutedJobs() {
+        return new LinkedList<>(executedJobs);
+    }
+    
+    
+    /*
+     * Private
+     */
+    
+    private void update(FXOMNode node) {
+        if (node instanceof FXOMCollection) {
+            updateCollection((FXOMCollection) node);
+        } else if (node instanceof FXOMInstance) {
+            updateInstance((FXOMInstance) node);
+        } else if (node instanceof FXOMIntrinsic) {
+            updateIntrinsic((FXOMIntrinsic) node);
+        } else if (node instanceof FXOMPropertyC) {
+            updatePropertyC((FXOMPropertyC) node);
+        } else if (node instanceof FXOMPropertyT) {
+            updatePropertyT((FXOMPropertyT) node);
+        } else {
+            throw new RuntimeException("Bug"); //NOI18N
+        }
+    }
+    
+    
+    private void updateCollection(FXOMCollection collection) {
+        if (collection.getFxId() != null) {
+            declaredFxIds.add(collection.getFxId());
+        }
+        final List<FXOMObject> items = collection.getItems();
+        for (int i = 0, count = items.size(); i < count; i++) {
+            update(items.get(i));
+        }
+    }
+    
+    
+    private void updateInstance(FXOMInstance instance) {
+        if (instance.getFxId() != null) {
+            declaredFxIds.add(instance.getFxId());
+        }
+        final Map<PropertyName, FXOMProperty> properties = instance.getProperties();
+        final List<PropertyName> names = new LinkedList<>(properties.keySet());
+        for (PropertyName propertyName : names) {
+            update(properties.get(propertyName));
+        }
+    }
+    
+    
+    private void updateIntrinsic(FXOMIntrinsic intrinsic) {
+        switch(intrinsic.getType()) {
+            case FX_REFERENCE:
+            case FX_COPY:
+                updateReference(intrinsic, intrinsic.getSource());
+                break;
+            default:
+                break;
+        }
+    }
+    
+    
+    private void updatePropertyC(FXOMPropertyC property) {
+        final List<FXOMObject> values = property.getValues();
+        for (int i = 0, count = values.size(); i < count; i++) {
+            update(values.get(i));
+        }
+    }
+    
+    
+    private void updatePropertyT(FXOMPropertyT property) {
+        final PrefixedValue pv = new PrefixedValue(property.getValue());
+        if (pv.isExpression()) {
+            final String suffix = pv.getSuffix();
+            if (JavaLanguage.isIdentifier(suffix)) {
+                updateReference(property, suffix);
+            }
+        }
+    }
+    
+    
+    private void updateReference(FXOMNode r, String fxId) {
+        assert (r instanceof FXOMPropertyT) || (r instanceof FXOMIntrinsic);
+        assert fxId != null;
+        
+        if (declaredFxIds.contains(fxId) == false) {
+            // r is a forward reference
+            //
+            // 1) r is a weak reference (like labelFor)
+            //    => we remove the reference
+            // 2) else r is a strong reference
+            //    => we expand the reference
+            
+
+            // 1)
+            final FXOMObject declarer = fxomDocument.searchWithFxId(fxId);
+            if (FXOMNodes.isWeakReference(r) || (declarer == null)) {
+                final Job removeJob = new RemoveNodeJob(r, editorController);
+                removeJob.execute();
+                executedJobs.add(removeJob);
+                
+            // 2)
+            } else {
+                
+                final Job expandJob = new ExpandReferenceJob(r, cloner, editorController);
+                expandJob.execute();
+                executedJobs.add(expandJob);
+            }
+        }
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/reference/UpdateReferencesJob.java	Mon Sep 01 19:32:54 2014 +0200
@@ -0,0 +1,126 @@
+/*
+ * 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.reference;
+
+import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
+import com.oracle.javafx.scenebuilder.kit.editor.selection.Selection;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ *
+ */
+public class UpdateReferencesJob extends Job {
+    
+    private final Job subJob;
+    private final List<Job> fixJobs = new ArrayList<>();
+    
+    public UpdateReferencesJob(Job subJob) {
+        super(subJob.getEditorController());
+        this.subJob = subJob;
+    }
+    
+    public Job getSubJob() {
+        return subJob;
+    }
+    
+    public List<Job> getFixJobs() {
+        return Collections.unmodifiableList(fixJobs);
+    }
+    
+    /*
+     * Job
+     */
+    
+    @Override
+    public boolean isExecutable() {
+        return subJob.isExecutable();
+    }
+
+    @Override
+    public void execute() {
+        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
+        final Selection selection = getEditorController().getSelection();
+        
+        selection.beginUpdate();
+        fxomDocument.beginUpdate();
+        
+        // First executes the subjob => references may become valid
+        subJob.execute();
+        
+        // Now sorts the reference in the document and archives the sorting jobs
+        final ReferencesUpdater updater = new ReferencesUpdater(getEditorController());
+        updater.update();
+        fixJobs.addAll(updater.getExecutedJobs());
+        
+        fxomDocument.endUpdate();
+        selection.endUpdate();
+    }
+
+    @Override
+    public void undo() {
+        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
+        final Selection selection = getEditorController().getSelection();
+        
+        selection.beginUpdate();
+        fxomDocument.beginUpdate();
+        for (int i = fixJobs.size() - 1; i >= 0; i--) {
+            fixJobs.get(i).undo();
+        }
+        subJob.undo();
+        fxomDocument.endUpdate();
+        selection.endUpdate();
+    }
+
+    @Override
+    public void redo() {
+        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
+        final Selection selection = getEditorController().getSelection();
+        
+        selection.beginUpdate();
+        fxomDocument.beginUpdate();
+        subJob.redo();
+        for (Job fixJob : fixJobs) {
+            fixJob.redo();
+        }
+        fxomDocument.endUpdate();
+        selection.endUpdate();
+    }
+
+    @Override
+    public String getDescription() {
+        return subJob.getDescription();
+    }
+}