changeset 6031:17db2a90268a

Sync up SceneBuilder changes
author Yves Joan <yves.joan@oracle.com>
date Thu, 20 Feb 2014 14:43:20 +0100
parents 8fb260e027f3
children 4ef7286b9266
files apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/SceneBuilderApp.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/SplitController.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/DocumentWindow.css apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/MessageBar.css apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/ThemeDark.css apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/info/InfoPanelController.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/menubar/MenuBarController.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/MessageBar.fxml apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/MessageBarController.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/warning.png apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/Preferences.css apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/Preferences.fxml apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/PreferencesController.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/PreferencesRecordDocument.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/skeleton/SkeletonBuffer.java apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/skeleton/SkeletonWindowController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/css/Theme.css apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/cssimages/css-styleable-path-button.png apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/drag/target/ContainerXYDropTarget.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/i18n/SceneBuilderKit.properties apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/images/ui/css-cursor@2x.png apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchModifyFxIdJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchModifyObjectJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchModifySelectionJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/FitToParentObjectJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/ModifyObjectJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/ModifySelectionJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/UseComputedSizesObjectJob.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/messagelog/MessageLog.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/ContentPanelController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/key/AbstractKeyGesture.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/mouse/AbstractMouseDragGesture.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/mouse/AbstractMouseGesture.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/mode/EditModeController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/mode/PickModeController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/Picker.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/css/SelectionPath.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/AbstractHierarchyPanelController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/HierarchyDNDController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeCell.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/Inspector.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/InspectorPanelController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/AutoSuggestEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/ControllerClassEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/DoubleAutoSuggestEditor.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/EditorUtils.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/FxIdEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/I18nStringEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/InlineListEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/IntegerAutoSuggestEditor.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StringAutoSuggestEditor.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StringEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StyleClassEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StyleEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/ToggleGroupEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/EffectPopupEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/FontPopupEditor.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/FontPopupEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/PaintPopupEditor.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/Rectangle2DPopupEditor.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportDialog.css apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportDialog.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportWindowController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/selection/ObjectSelectionGroup.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/selection/Selection.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMDocument.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMIndex.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMInstance.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMLoader.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/TransientObject.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueCharacters.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueDocument.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueElement.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueLoader.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueSnapshot.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/LightingPropertyMetadata.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/DistantLightPropertyMetadata.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/LightPropertyMetadata.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/PointLightPropertyMetadata.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/SpotLightPropertyMetadata.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/util/PropertyName.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/Deprecation.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPathItem.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPathItem.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPicker.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPickerController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/editors/LightControl.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/editors/LightControl.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/editors/SliderControl.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPicker.fxml apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPicker.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPickerController.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/colorpicker/ColorPicker.java apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/gradientpicker/GradientPicker.java
diffstat 98 files changed, 2648 insertions(+), 1115 deletions(-) [+]
line wrap: on
line diff
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -75,7 +75,6 @@
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.file.Files;
@@ -89,8 +88,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javafx.beans.InvalidationListener;
 import javafx.beans.Observable;
 import javafx.beans.value.ChangeListener;
@@ -132,7 +129,6 @@
         SAVE_FILE,
         SAVE_AS_FILE,
         REVERT_FILE,
-        PRINT_FILE,
         CLOSE_FILE,
         REVEAL_FILE,
         GOTO_CONTENT,
@@ -505,7 +501,7 @@
                 result = canPerformSelectNone();
                 break;
                 
-            case PRINT_FILE:
+            case SHOW_SAMPLE_CONTROLLER:
                 result = editorController.getFxomDocument() != null;
                 break;
                 
@@ -525,7 +521,8 @@
                 break;
                 
             case SAVE_FILE:
-                result = isDocumentDirty();
+                result = isDocumentDirty()
+                        || editorController.getFxomDocument().getLocation() == null; // Save new empty document
                 break;
                 
             case SAVE_AS_FILE:
@@ -543,7 +540,6 @@
                         && (editorController.getFxomDocument().getLocation() != null);
                 break;
                 
-//            case PRINT_FILE:
             case GOTO_CONTENT:
             case GOTO_PROPERTIES:
             case GOTO_LAYOUT:
@@ -568,10 +564,6 @@
                 result = true;
                 break;
                 
-            case SHOW_SAMPLE_CONTROLLER:
-                result = true;
-                break;
-                
             default:
                 result = false;
                 assert false;
@@ -683,13 +675,17 @@
             case TOGGLE_CSS_PANEL:
                 // CSS panel is built lazely : initialize the CSS panel first
                 initializeCssPanel();
-
                 bottomSplitController.toggleTarget();
                 if (bottomSplitController.isTargetVisible()) {
                     // CSS panel is built lazely
                     // Need to update its table column ordering with preference value
                     final PreferencesRecordGlobal recordGlobal = pc.getRecordGlobal();
                     refreshCssTableColumnsOrderingReversed(recordGlobal.isCssTableColumnsOrderingReversed());
+                    // Enable pick mode
+                    editorController.setPickModeEnabled(true);
+                } else {
+                    // Disable pick mode
+                    editorController.setPickModeEnabled(false);
                 }
                 // Update preferences
                 recordDocument.setBottomVisible(bottomSplitController.isTargetVisible());
@@ -1775,7 +1771,7 @@
                 if (saveConfirmed) {
                     try {
                         watchingController.removeDocumentTarget();
-                        final byte[] fxmlBytes = fxomDocument.getFxmlText().getBytes("UTF-8"); //NOI18N
+                        final byte[] fxmlBytes = editorController.getFxmlText().getBytes("UTF-8"); //NOI18N
                         Files.write(fxmlPath, fxmlBytes);
                         updateLoadFileTime();
                         watchingController.update();
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/SceneBuilderApp.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/SceneBuilderApp.java	Thu Feb 20 14:43:20 2014 +0100
@@ -42,10 +42,14 @@
 import com.oracle.javafx.scenebuilder.app.template.FxmlTemplates;
 import com.oracle.javafx.scenebuilder.app.template.TemplateDialogController;
 import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.AlertDialog;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog;
+import com.oracle.javafx.scenebuilder.kit.library.BuiltinLibrary;
 import com.oracle.javafx.scenebuilder.kit.library.user.UserLibrary;
+import com.oracle.javafx.scenebuilder.kit.metadata.Metadata;
 import com.oracle.javafx.scenebuilder.kit.util.Deprecation;
+import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.EffectPicker;
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
@@ -58,6 +62,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CountDownLatch;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import javafx.application.Application;
@@ -98,6 +103,7 @@
 
     private static SceneBuilderApp singleton;
     private static String darkToolStylesheet;
+    private static final CountDownLatch launchLatch = new CountDownLatch(1);
     
     private final List<DocumentWindowController> windowList = new ArrayList<>();
     private final PreferencesWindowController preferencesWindowController
@@ -105,7 +111,6 @@
     private final AboutWindowController aboutWindowController
             = new AboutWindowController();
     private UserLibrary userLibrary;
-    private MenuBarController defaultSystemMenuBarController; // Mac only
     private File nextInitialDirectory;
     private ToolTheme toolTheme = ToolTheme.DEFAULT;
 
@@ -116,7 +121,42 @@
     public static SceneBuilderApp getSingleton() {
         return singleton;
     }
-
+    
+    public SceneBuilderApp() {
+        assert singleton == null;
+        singleton = this;
+        
+        /*
+         * We spawn our two threads for handling background startup.
+         */
+        final Runnable p0 = new Runnable() {
+            @Override
+            public void run() {
+                backgroundStartPhase0();
+            }
+        };
+        final Runnable p1 = new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    launchLatch.await();
+                    backgroundStartPhase2();
+                } catch(InterruptedException x) {
+                    // JavaFX thread has been interrupted. Simply exits.
+                }
+            }
+        };
+        final Thread phase0 = new Thread(p0, "Phase 0"); //NOI18N
+        final Thread phase1 = new Thread(p1, "Phase 1"); //NOI18N
+        phase0.setDaemon(true);
+        phase1.setDaemon(true);
+        
+        // Note : if you suspect a race condition bug, comment the two next
+        // lines to make startup fully sequential.
+        phase0.start();
+        phase1.start();
+    }
+    
     public void performControlAction(ApplicationControlAction a, DocumentWindowController source) {
         switch (a) {
             case ABOUT:
@@ -279,8 +319,8 @@
             dwc.getMenuBarController().setDebugMenuVisible(!visible);
         }
 
-        if (defaultSystemMenuBarController != null) {
-            defaultSystemMenuBarController.setDebugMenuVisible(!visible);
+        if (EditorPlatform.IS_MAC) {
+            MenuBarController.getSystemMenuBarController().setDebugMenuVisible(!visible);
         }
     }
 
@@ -310,9 +350,8 @@
      * Application
      */
     @Override
-    public void start(Stage stage) throws Exception {
-        assert singleton == null;
-        singleton = this;
+    public void start(Stage stage) throws Exception {  
+        launchLatch.countDown();
         setApplicationUncaughtExceptionHandler();
 
         try {
@@ -346,18 +385,6 @@
     public void handleLaunch(List<String> files) {
         setApplicationUncaughtExceptionHandler();
 
-        // On Mac, AppPlatform disables implicit exit.
-        // So we need to set a default system menu bar.
-        if (Platform.isImplicitExit() == false) {
-            defaultSystemMenuBarController = new MenuBarController(null);
-            Deprecation.setDefaultSystemMenuBar(defaultSystemMenuBarController.getMenuBar());
-        }
-
-        // Load global application preferences
-        final PreferencesController pc = PreferencesController.getSingleton();
-        final PreferencesRecordGlobal recordGlobal = pc.getRecordGlobal();
-        recordGlobal.readFromJavaPreferences();
-
         // Creates the user library
         userLibrary = new UserLibrary(AppPlatform.getUserLibraryFolder());
         // runLater below is here to fix DTL-6378
@@ -383,6 +410,12 @@
         } else {
             // Open files passed as arguments by the platform
             handleOpenFilesAction(files);
+        }    
+        
+        // On Mac, AppPlatform disables implicit exit.
+        // So we need to set a default system menu bar.
+        if (Platform.isImplicitExit() == false) {
+            Deprecation.setDefaultSystemMenuBar(MenuBarController.getSystemMenuBarController().getMenuBar());
         }
     }
 
@@ -433,8 +466,8 @@
     }
 
     /**
-     * Normally ignored in correctly deployed JavaFX application.
-     * But on Mac OS, this method seems to be called by the javafx launcher.
+     * Normally ignored in correcphase0ly deployed JavaFX applicaphase0ion.
+     * Buphase0 on Mac OS, phase0his mephase0hod seems phase0o be called by phase0he javafx launcher.
      */
     public static void main(String[] args) {
         launch(args);
@@ -709,4 +742,42 @@
         
         return result;
     }
+    
+    
+    /*
+     * Background startup
+     * 
+     * To speed SB startup, we create two threads which anticipate some
+     * initialization tasks and offload the JFX thread:
+     *  - 'Phase 0' thread executes tasks that do not require JFX initialization
+     *  - 'Phase 1' thread executes tasks that requires JFX initialization
+     * 
+     * Tasks executed here must be carefully chosen:
+     * 1) they must be thread-safe
+     * 2) they should be order-safe : whether they are executed in background
+     *    or by the JFX thread should make no difference.
+     * 
+     * Currently we simply anticipate creation of big singleton instances
+     * (like Metadata, Preferences...)
+     */
+    
+    private void backgroundStartPhase0() {
+        assert Platform.isFxApplicationThread() == false; // Warning 
+        
+        PreferencesController.getSingleton();
+        Metadata.getMetadata();
+    }
+    
+    private void backgroundStartPhase2() {
+        assert Platform.isFxApplicationThread() == false; // Warning 
+        assert launchLatch.getCount() == 0; // i.e JavaFX is initialized
+        
+        BuiltinLibrary.getLibrary();
+        if (EditorPlatform.IS_MAC) {
+            MenuBarController.getSystemMenuBarController();
+        }
+        EffectPicker.getEffectClasses();
+    }
+
+    
 }
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/SplitController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/SplitController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -31,6 +31,7 @@
  */
 package com.oracle.javafx.scenebuilder.app;
 
+import java.util.ArrayList;
 import java.util.List;
 import javafx.beans.property.DoubleProperty;
 import javafx.scene.Node;
@@ -65,17 +66,17 @@
     }
 
     public DoubleProperty position() {
-        final Divider divider = getDivider();
+        final Divider divider = getTargetDivider();
         return divider == null ? null : divider.positionProperty();
     }
 
     public double getPosition() {
-        final Divider divider = getDivider();
+        final Divider divider = getTargetDivider();
         return divider == null ? -1.0 : divider.getPosition();
     }
 
     public void setPosition(double value) {
-        final Divider divider = getDivider();
+        final Divider divider = getTargetDivider();
         if (divider != null) {
             divider.setPosition(value);
         }
@@ -91,10 +92,10 @@
                 splitPane.getItems().add(targetNode);
             }
 
-            // Restore the divider position (if any)
+            // Restore the target divider position (if any)
             final List<Divider> dividers = splitPane.getDividers();
             if ((dividers.isEmpty() == false) && (dividerPosition != -1)) { // (1)
-                final Divider divider = getDivider();
+                final Divider divider = getTargetDivider();
                 assert divider != null; // Because of (1)
                 divider.setPosition(dividerPosition);
             }
@@ -102,16 +103,29 @@
     }
 
     public void hideTarget() {
+
         if (isTargetVisible()) {
-            // Backup the divider position (if any)
+
             final List<Divider> dividers = splitPane.getDividers();
-            if (dividers.isEmpty() == false) { // (1)
-                final Divider divider = getDivider();
-                assert divider != null; // Because of (1)
-                dividerPosition = divider.getPosition();
+            final List<Double> positionsList = asList(splitPane.getDividerPositions());
+
+            // Backup the target divider positions (if any)
+            // so we can restore it on showing
+            final Divider targetDivider = getTargetDivider();
+            if (targetDivider != null) {
+                dividerPosition = targetDivider.getPosition();
+                int targetDividerIndex = target == Target.FIRST ? 0 : dividers.size() - 1;
+                positionsList.remove(targetDividerIndex);
             }
+
             // Removes the target node from the split pane items
             splitPane.getItems().remove(targetNode);
+
+            // Set back remaining dividers positions if any
+            if (positionsList.isEmpty() == false) {
+                double[] positionsArray = toArray(positionsList);
+                splitPane.setDividerPositions(positionsArray);
+            }
         }
     }
 
@@ -135,7 +149,7 @@
         return splitPane.getItems().contains(targetNode);
     }
 
-    private Divider getDivider() {
+    private Divider getTargetDivider() {
         final Divider divider;
         final List<Divider> dividers = splitPane.getDividers();
         if (dividers.isEmpty() == false) {
@@ -149,4 +163,22 @@
         }
         return divider;
     }
+
+    // Arrays.asList does not work with primitive types
+    private static List<Double> asList(double[] array) {
+        final List<Double> list = new ArrayList<>(array.length);
+        for (double d : array) {
+            list.add(d);
+        }
+        return list;
+    }
+
+    // List.toArray does not work with primitive types
+    private static double[] toArray(List<Double> list) {
+        final double[] array = new double[list.size()];
+        for (int i = 0; i < list.size(); i++) {
+            array[i] = list.get(i);
+        }
+        return array;
+    }
 }
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/DocumentWindow.css	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/DocumentWindow.css	Thu Feb 20 14:43:20 2014 +0100
@@ -61,6 +61,25 @@
 }
 
 /*******************************************************************************
+ * App SplitPane's                                                             *
+ ******************************************************************************/
+
+.split-pane {
+    -fx-background-color: -sb-dark;
+    -fx-background-insets: 0;
+    -fx-padding: 0;
+}
+.split-pane > .split-pane-divider {
+    -fx-background-color: -sb-dark;
+    -fx-padding: 0 0.5 0 0;
+}
+.split-pane:horizontal .split-pane-divider .horizontal-grabber,
+.split-pane:vertical .split-pane-divider .vertical-grabber {
+    -fx-padding: 3;
+    -fx-shape: "";
+}
+
+/*******************************************************************************
  * Common UI Styling - Panel Headers (Background, search box and menu)         *
  ******************************************************************************/
 
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/MessageBar.css	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/MessageBar.css	Thu Feb 20 14:43:20 2014 +0100
@@ -35,7 +35,8 @@
     -fx-spacing: 0;
 }
 
-.message-bar .button, .message-bar .label {
+/*.message-bar .button, .message-bar .label {*/
+.message-bar .label {
     -fx-font-size: 0.875em;
     -fx-background-color: transparent;
     -fx-background-radius: 0;
@@ -43,6 +44,19 @@
     -fx-background-insets: 0;
 }
 
+.warning-button {
+    -fx-font-size: 0.667em;
+    -fx-shape: "M1.347,18C1,18,0.678,17.82,0.496,17.526c-0.182-0.295-0.199-0.663-0.044-0.973l8-16C8.622,0.214,8.968,0,9.347,0
+    s0.725,0.214,0.895,0.553l8,16c0.155,0.31,0.138,0.678-0.044,0.973C18.015,17.82,17.693,18,17.347,18H1.347z";
+    -fx-background-color: black, yellow;
+    -fx-background-insets: 0, 1 1 0.7 1;
+    -fx-padding: 6 2 2 2;
+    -fx-min-width: 20;
+    -fx-max-width: 20;
+    -fx-min-height: 19;
+    -fx-max-height: 19;
+}
+
 .message-bar .message-warning {
     -fx-background-color: 
         linear-gradient( to bottom, derive(-sb-warning-panel, 20%) 0%, -sb-warning-panel 100% );
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/ThemeDark.css	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/css/ThemeDark.css	Thu Feb 20 14:43:20 2014 +0100
@@ -70,8 +70,17 @@
  * Common UI Styling - Controls                                                *
  ******************************************************************************/
 
+.context-menu {
+    -fx-background-color: -sb-sharp-edge-lo, white;
+    -fx-background-insets: 0, 1;
+    -fx-background-radius: 0;
+}
+.custom-menu-item {
+    -fx-padding: 4 8 4 8;
+}
 .custom-menu-item:focused {
-     -fx-background: white;
+    -fx-background: white;
+    -fx-background-color: -fx-background;
 }
 
 /*******************************************************************************
@@ -113,6 +122,9 @@
     -fx-alignment: center-right;
     -fx-effect: dropshadow( two-pass-box, rgba(0, 0, 0, 0.2), 5, 0.0, 0, 1 );
 }
+.accordion > .titled-pane > .title > .text {
+    -fx-fill: -sb-header-text;
+}
 .accordion > .first-titled-pane > .title {
     -fx-background-insets: 0 0 -1 0, 0, 1 0 1 0, 2 0 0 0;
 }
@@ -147,20 +159,6 @@
  * Common UI Styling - Split Panes                                             *
  ******************************************************************************/
 
-.split-pane {
-    -fx-background-color: -sb-dark;
-    -fx-background-insets: 0;
-    -fx-padding: 0;
-}
-.split-pane > .split-pane-divider {
-    -fx-background-color: -sb-dark;
-    -fx-padding: 0 0.5 0 0;
-}
-.split-pane:horizontal .split-pane-divider .horizontal-grabber,
-.split-pane:vertical .split-pane-divider .vertical-grabber {
-    -fx-padding: 3;
-    -fx-shape: "";
-}
 .SBKIT-inspector-panel.split-pane > .split-pane-divider {
     -fx-background-color: transparent;
     -fx-background-insets: -1 0 -3 0;
@@ -185,7 +183,7 @@
 }
 .scroll-bar:horizontal > .decrement-button,
 .scroll-bar:horizontal > .increment-button {
-    -fx-padding: 0.769em 0.077em 0.769em 0.077em;
+    -fx-padding: 0.692em 0.077em 0.692em 0.077em;
 }
 .scroll-bar .increment-arrow, 
 .scroll-bar .decrement-arrow {
@@ -193,7 +191,7 @@
 }
 .scroll-bar:vertical {
     -fx-background-color: -sb-sharp-edge-lo, -sb-panel-background;
-    -fx-background-insets: 1 0 0 0, 1 0 0 1;
+    -fx-background-insets: 0 0 0 0, 0 0 0 1;
 }
 .scroll-bar:horizontal {
     -fx-background-color: -sb-sharp-edge-lo, -sb-panel-background;
@@ -209,6 +207,21 @@
 .scroll-bar:horizontal .thumb {
     -fx-background-insets: 4 3 4 3, 5 4 5 4;
 }
+.scroll-pane .corner,
+.tree-view .virtual-flow .corner {
+    -fx-background-color: -sb-sharp-edge-lo, -sb-panel-background;
+    -fx-background-insets: 0 -1 -1 0, 1 -1 -1 1;
+}
+
+.text-area .scroll-pane .scroll-bar:horizontal {
+    -fx-background-insets: 0 1 1 1, 1 1 1 1;
+}
+.text-area .scroll-pane .scroll-bar:vertical {
+    -fx-background-insets: 1 1 1 0, 1 1 1 1;
+}
+.text-area .scroll-pane .corner {
+    -fx-background-insets: 0 1 1 0, 1 1 1 1;
+}
 
 /*******************************************************************************
  *                                                                             *
@@ -222,68 +235,84 @@
  *                                                                             *
  ******************************************************************************/
 
-.list-view {
+.SBKIT-library-panel .list-view {
     -fx-background-color: transparent;
 }
-
-.list-view .list-cell .text {
+.SBKIT-library-panel .list-view .list-cell .text {
     -fx-fill: -sb-content-text;
 }
-
-.list-view .list-cell {
+.SBKIT-library-panel .list-view .list-cell {
     -fx-background-color: transparent;
     -fx-cell-size: 1.7em;
     -fx-background-insets: 2 0 -2 0;
     -fx-padding: 2 0 0 4;
 }
-
-.list-view .list-cell:filled:hover {
+.SBKIT-library-panel .list-view .list-cell:filled:hover {
     -fx-background-color: null; /* no hover effect on list view */
 }
-
-.list-view:focused .list-cell:filled:selected {
+.SBKIT-library-panel .list-view:focused .list-cell:filled:selected {
     -fx-background-color: -sb-selected-bar-color;
 }
-
-.list-view .list-cell:filled:selected {
+.SBKIT-library-panel .list-view .list-cell:filled:selected {
     /* When the ListView is not focused there is no need to highlight
     the selected item */
     -fx-background-color: null;
 }
-
-.list-view .scroll-bar {    
+.SBKIT-library-panel .list-view .scroll-bar {    
     /* Cursor may dynamically change when working in library / hierarchy.
        Set back the cursor to its default. */
     -fx-cursor: default;
 }
 
 /* ListCell graphic is an HBox */
-.list-cell-graphic {
+.SBKIT-library-panel .list-cell-graphic {
     -fx-alignment: center-left;
     -fx-padding: 0 2 0 2;
     -fx-spacing: 4;
 }
 
-.library-no-results-label {
+.SBKIT-library-panel .library-no-results-label {
     -fx-text-fill: -sb-content-text-dimmed;
     -fx-font-size: 0.875em;
     -fx-padding: 6 0 0 10;
 }
 
-.library-classname-label {
+.SBKIT-library-panel .library-classname-label {
     -fx-text-fill: black;
 }
 
-.library-qualifier-label {
+.SBKIT-library-panel .library-qualifier-label {
     -fx-text-fill: lightslategray;
 }
 
-.library-section-label {
+.SBKIT-library-panel .library-section-label {
     -fx-text-fill: black;
     -fx-font-weight: bold;
 }
 
 /*******************************************************************************
+ * Library Panel - Jar import dialog                                           *
+ ******************************************************************************/
+
+.jar-import-preview-label {
+    -fx-text-fill: -sb-content-text-dimmed;
+    -fx-font-size : 0.875em;
+}
+
+.jar-import-preview {
+    -fx-background-color: azure;
+}
+
+.jar-import-num-of-items-label {
+    -fx-font-size : 0.875em;
+}
+
+.jar-import-class-name-label {
+    -fx-text-fill: -sb-content-text-dimmed;
+    -fx-font-size : 0.875em;
+}
+
+/*******************************************************************************
  *                                                                             *
  * Hierarchy Panel                                                             *
  *                                                                             *
@@ -623,6 +652,17 @@
     -fx-fill: rgba(0,0,0,0.01);
 }
 
+
+/*******************************************************************************
+ *                                                                             *
+ * Inspector Panel                                                             *
+ *                                                                             *
+ ******************************************************************************/
+
+.SBKIT-inspector-panel .secondary-section-title {
+    -fx-text-fill: -sb-header-text-dimmed;
+}
+
 /*******************************************************************************
  *                                                                             *
  * Property Sheet Panels (Inspector, Controller)                               *
@@ -637,21 +677,15 @@
     -fx-font-size: 0.875em;
 }
 
-.property-sheet .small-label {
-    -fx-font-size: 0.750em; /* 9 */
-    -fx-text-fill: -sb-content-text-dimmed;
-    -fx-padding: 0;
+.property-sheet .label {
+    -fx-text-fill: -sb-content-text;
+    -fx-padding: 4 0 3 0;
 }
 
 .property-sheet .check-box .box {
     -fx-background-radius: 0;
 }
 
-.property-sheet .label {
-    -fx-text-fill: -sb-content-text;
-    -fx-padding: 4 0 3 0;
-}
-
 .property-sheet .hyperlink, .hyperlink:visited {
     -fx-text-fill: -sb-content-text;
     -fx-padding: 3 0 2 0;
@@ -698,6 +732,33 @@
     -fx-padding: 0.154em 0.308em 0.154em 0.231em;  /* 2 4 2 3 */
 }
 
+.property-sheet .table-view .column-header .label {
+    -fx-text-fill: -sb-content-text;
+    -fx-font-size: 0.875em;
+    -fx-font-weight: normal;
+    -fx-alignment: CENTER_LEFT;
+    -fx-padding: 0 4 0 4;
+}
+.property-sheet .table-view > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell {
+    -fx-padding: 4 5 2 5;
+}
+.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected,
+.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected {
+    -fx-background: -sb-selected-bar-color;
+    -fx-table-cell-border-color: -sb-selected-bar-color;
+}
+
+.property-sheet .small-label {
+    -fx-font-size: 0.750em; /* 9 */
+    -fx-text-fill: -sb-content-text-dimmed;
+    -fx-padding: 0;
+}
+
+.inspector-message .text {
+    /* Used for 'No Selection' and 'No Results' messages */
+    -fx-fill: -sb-content-text-dimmed;
+}
+
 .property-sheet .cog-menubutton {
     -fx-background-color: -sb-panel-background;
     -fx-background-radius: 0;
@@ -723,27 +784,6 @@
     -fx-padding: 0;
 }
 
-.inspector-message .text {
-    /* Used for 'No Selection' and 'No Results' messages */
-    -fx-fill: -sb-content-text-dimmed;
-}
-
-.property-sheet .table-view .column-header .label {
-    -fx-text-fill: -sb-content-text;
-    -fx-font-size: 0.875em;
-    -fx-font-weight: normal;
-    -fx-alignment: CENTER_LEFT;
-    -fx-padding: 0 4 0 4;
-}
-.property-sheet .table-view > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell {
-    -fx-padding: 4 5 2 5;
-}
-.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected,
-.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected {
-    -fx-background: -sb-selected-bar-color;
-    -fx-table-cell-border-color: -sb-selected-bar-color;
-}
-
 /*******************************************************************************
  * Property Sheet Panels - CSS Override property decoration                    *
  ******************************************************************************/
@@ -893,9 +933,13 @@
  * Property Sheet Panels - Suggestive ListView                                 *
  ******************************************************************************/
 
-.suggested-list {
-    -fx-font-size: 0.875em;
- }
+.property-sheet .auto-suggest-popup {
+    -fx-padding: 0;
+}
+.property-sheet .auto-suggest-popup .custom-menu-item .list-view {
+    -fx-background-color: -sb-sharp-edge-lo, white;
+    -fx-background-insets: 0, 1;
+}
 
 /*******************************************************************************
  *                                                                             *
@@ -1026,17 +1070,25 @@
     -fx-padding: 0 0 0 0;
 }
 .styleable-path .button {
-    -fx-background-color: derive( -fx-base, 50% );
+    -fx-background-color: -sb-sharp-edge-lo, derive(-sb-sharp-edge-hi, 10%);
+    -fx-background-insets: 0, 1;
     -fx-background-radius: 100;
-    -fx-margin: 0 30 0 30;
-    -fx-padding: 1 5 1 6;
-    /*-fx-effect: dropshadow( one-pass-box , derive( -fx-base, -55% ), 3, 0.0 , 0 , 0 );*/
-    -fx-graphic: url("../cssimages/css-styleable-path-button.png");
+    -fx-min-width: 16;
+    -fx-max-width: 16;
+    -fx-min-height: 16;
+    -fx-max-height: 16;
 }
 .styleable-path .button:hover {
-    -fx-background-color: derive( -fx-base, 100% );
+    -fx-background-color: derive(-sb-sharp-edge-lo, -10%), derive(-sb-sharp-edge-hi, 40%);
 }
-
+.styleable-path-button-shape {
+    -fx-shape: "M 0 -3.5 v 7 l 4 -3.5 z";
+    -fx-background-color: -sb-content-text;
+    -fx-min-width: 5;
+    -fx-max-width: 5;
+    -fx-min-height: 6;
+    -fx-max-height: 6;
+}
 .styleable-path-optional-label .text {
     -fx-fill: -sb-header-text-dimmed;
 }
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties	Thu Feb 20 14:43:20 2014 +0100
@@ -434,6 +434,7 @@
 # Skeleton window
 # -----------------------------------------------------------------------------
 skeleton.add.comments = Comments
+skeleton.empty = No skeleton can be constructed from an empty document
 skeleton.format.full = Full
 # Parameter is a fxml file name
 skeleton.window.title = Sample Skeleton for ''{0}'' Controller Class
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/info/InfoPanelController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/info/InfoPanelController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -103,7 +103,7 @@
     protected void fxomDocumentDidChange(FXOMDocument oldDocument) {
         requestEntriesUpdate();
         updateAsPerRootNodeStatus();
-        updateController(null);
+        updateController();
         
         if (fxrootCheckBox != null) {
             fxrootCheckBox.selectedProperty().removeListener(checkBoxListener);
@@ -116,7 +116,7 @@
     protected void sceneGraphRevisionDidChange() {
         requestEntriesUpdate();
         updateAsPerRootNodeStatus();
-        updateController(null);
+        updateController();
     }
 
     @Override
@@ -128,7 +128,7 @@
     protected void jobManagerRevisionDidChange() {
         requestEntriesUpdate();
         updateAsPerRootNodeStatus();
-        updateController(null);
+        updateController();
         fxrootCheckBox.selectedProperty().removeListener(checkBoxListener);
         fxrootCheckBox.setSelected(isFxRoot());
         fxrootCheckBox.selectedProperty().addListener(checkBoxListener);
@@ -192,10 +192,7 @@
 
             @Override
             public void changed(ObservableValue<? extends Object> ov, Object t, Object t1) {
-                if (t1 != null) {
-                    assert t1 instanceof String;
-                    updateController((String)t1);
-                }
+                updateController((String)t1);
             }
         });
         
@@ -222,22 +219,33 @@
         controllerDidLoadFxmlOver = true; // Must be called before updateAsPerRootNodeStatus()
         requestEntriesUpdate();
         updateAsPerRootNodeStatus();
-        updateController(null);
+        updateController();
     }
     
 
     /*
      * Private
      */
+    private final static String IGNORED = "ignored"; //NOI18N
     
-    private void updateController(String className) {
+    private synchronized void updateController() {
+        updateController(IGNORED);
+    }
+    
+    private synchronized void updateController(String className) {
         if (getEditorController().getFxomDocument() != null) {
             FXOMObject root = getEditorController().getFxomDocument().getFxomRoot();
             if (root != null) {
-                if (className == null) {
+                if (className != null && className.equals(IGNORED)) {
                     className = root.getFxController();
                 }
                 
+                // When the user set an empty string we consider it means
+                // no controller value needs to be set.
+                if (className != null && className.isEmpty()) {
+                    className = null;
+                }
+                
                 final ModifyFxControllerJob job
                         = new ModifyFxControllerJob(root, className, getEditorController());
                 
@@ -246,11 +254,9 @@
                 }
                 
                 if (controllerClassEditor != null) {
-                    String currentValue = (String)controllerClassEditor.getValue();
-                    if (currentValue != null
-                            && ! currentValue.equals(className)) {
-                        controllerClassEditor.setValue(className);
-                    }
+                    controllerClassEditor.setUpdateFromModel(true);
+                    controllerClassEditor.setValue(className);
+                    controllerClassEditor.setUpdateFromModel(false);
                 }
             }
         }
@@ -391,8 +397,9 @@
             if (getEditorController().getFxomDocument().getFxomRoot() == null) {
                 fxrootCheckBox.setDisable(true);
                 controllerClassEditor.setDisable(true);
-                controllerClassEditor.setValue(""); //NOI18N
-
+                controllerClassEditor.setUpdateFromModel(true);
+                controllerClassEditor.setValue(null); //NOI18N
+                controllerClassEditor.setUpdateFromModel(false);
             } else {
                 fxrootCheckBox.setDisable(false);
                 String topClassName = getEditorController().getFxomDocument().getGlue().getRootElement().getTagName();
@@ -443,7 +450,9 @@
 
                 @Override
                 public void run() {
+                    controllerClassEditor.setUpdateFromModel(true);
                     controllerClassEditor.reset(getSuggestedControllerClasses(location));
+                    controllerClassEditor.setUpdateFromModel(false);
                 }
             });
         }
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/menubar/MenuBarController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/menubar/MenuBarController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -45,9 +45,11 @@
 import com.oracle.javafx.scenebuilder.kit.editor.EditorController.Size;
 import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.content.ContentPanelController;
+import com.oracle.javafx.scenebuilder.kit.library.BuiltinLibrary;
 import com.oracle.javafx.scenebuilder.kit.library.BuiltinSectionComparator;
 import com.oracle.javafx.scenebuilder.kit.library.LibraryItem;
 import com.oracle.javafx.scenebuilder.kit.library.LibraryItemNameComparator;
+import com.oracle.javafx.scenebuilder.kit.library.user.UserLibrary;
 import com.oracle.javafx.scenebuilder.kit.util.MathUtils;
 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.EffectPicker;
 import java.io.File;
@@ -86,12 +88,16 @@
  *
  */
 public class MenuBarController {
+    
+    private static MenuBarController systemMenuBarController; // For Mac only
 
-    private final DebugMenuController debugMenuController;
+    private Menu insertCustomMenu;
     private final DocumentWindowController documentWindowController;
     // This member is null when this MenuBarController is used for
     // managing the menu bar passed to MenuBarSkin.setDefaultSystemMenu().
 
+    private DebugMenuController debugMenuController; // Initialized lazily
+
     @FXML
     private MenuBar menuBar;
     @FXML
@@ -362,7 +368,6 @@
 
     public MenuBarController(DocumentWindowController documentWindowController) {
         this.documentWindowController = documentWindowController;
-        debugMenuController = new DebugMenuController(documentWindowController);
     }
 
     public MenuBar getMenuBar() {
@@ -390,6 +395,9 @@
     public void setDebugMenuVisible(boolean visible) {
         if (isDebugMenuVisible() != visible) {
             if (visible) {
+                if (debugMenuController == null) {
+                    debugMenuController = new DebugMenuController(documentWindowController);
+                }
                 menuBar.getMenus().add(debugMenuController.getMenu());
             } else {
                 menuBar.getMenus().remove(debugMenuController.getMenu());
@@ -398,9 +406,23 @@
     }
 
     public boolean isDebugMenuVisible() {
-        return menuBar.getMenus().contains(debugMenuController.getMenu());
+        final boolean result;
+        if (debugMenuController == null) {
+            result = false;
+        } else {
+            result = menuBar.getMenus().contains(debugMenuController.getMenu());
+        }
+        return result;
     }
-
+    
+    
+    public static synchronized MenuBarController getSystemMenuBarController() {
+        if (systemMenuBarController == null) {
+            systemMenuBarController = new MenuBarController(null);
+        }
+        return systemMenuBarController;
+    }
+    
     /*
      * Private
      */
@@ -778,7 +800,8 @@
         updateZoomMenu();
 
         /*
-         * Insert menu: it is setup after the other menus.
+         * Insert menu: it uses specific handlers, which means we initialize it
+         * later to avoid interfering with other menus.
          */
 
         /*
@@ -984,7 +1007,15 @@
             setupMenuItemHandlers(m);
         }
         
-        insertMenu.setOnMenuValidation(onInsertMenuValidationHandler);
+        /*
+         * Insert menu: we set what is statically known.
+         */
+        constructBuiltinPartOfInsertMenu();
+        constructCustomPartOfInsertMenu();
+        
+        // The handler for Insert menu deals only with Custom sub-menu.
+        insertMenu.setOnMenuValidation(onCustomPartOfInsertMenuValidationHandler);
+        
         windowMenu.setOnMenuValidation(onWindowMenuValidationHandler);
         
         /*
@@ -1203,43 +1234,78 @@
     /*
      * Private (insert menu)
      */
-    private final EventHandler<Event> onInsertMenuValidationHandler
+    private final EventHandler<Event> onCustomPartOfInsertMenuValidationHandler
             = new EventHandler<Event>() {
                 @Override
                 public void handle(Event t) {
                     assert t.getSource() == insertMenu;
-                    updateInsertMenu();
+                    updateCustomPartOfInsertMenu();
                 }
             };
     
-    private void updateInsertMenu() {
+    private void updateCustomPartOfInsertMenu() {
         assert insertMenu != null;
+        assert insertCustomMenu != null;        
 
-        insertMenu.getItems().clear();
-
-        if (documentWindowController == null) {
-            insertMenu.getItems().add(new MenuItem(I18N.getString("menubar.no.lib.item")));
-        } else {
+        if (documentWindowController != null) {
             final EditorController editorController = documentWindowController.getEditorController();
             assert editorController.getLibrary() != null;
 
-            final Map<String, Set<LibraryItem>> sectionMap
-                    = new TreeMap<>(new BuiltinSectionComparator());
+            Set<LibraryItem> sectionItems = new TreeSet<>(new LibraryItemNameComparator());
+            
+            // Collect custom items
             for (LibraryItem li : editorController.getLibrary().getItems()) {
-                Set<LibraryItem> sectionItems = sectionMap.get(li.getSection());
-                if (sectionItems == null) {
-                    sectionItems = new TreeSet<>(new LibraryItemNameComparator());
-                    sectionMap.put(li.getSection(), sectionItems);
+                if (li.getSection().equals(UserLibrary.TAG_USER_DEFINED)) {
+                    sectionItems.add(li);
                 }
-                sectionItems.add(li);
             }
 
-            for (Map.Entry<String, Set<LibraryItem>> e : sectionMap.entrySet()) {
-                final Menu sectionMenu = makeMenuForLibrarySection(e.getKey());
-                insertMenu.getItems().add(sectionMenu);
-                for (LibraryItem li : e.getValue()) {
-                    sectionMenu.getItems().add(makeMenuItemForLibraryItem(li));
+            // Make custom items visible and accessible via custom menu.
+            if (sectionItems.size() > 0) {
+                insertCustomMenu.getItems().clear();
+                
+                for (LibraryItem li : sectionItems) {
+                    insertCustomMenu.getItems().add(makeMenuItemForLibraryItem(li));
                 }
+                
+                insertCustomMenu.setVisible(true);
+            } else {
+                insertCustomMenu.setVisible(false);
+            }
+        }
+    }
+    
+    // At constructing time we dunno if we've custom items then we keep it hidden.
+    private void constructCustomPartOfInsertMenu() {
+        assert insertMenu != null;
+        insertCustomMenu = makeMenuForLibrarySection(UserLibrary.TAG_USER_DEFINED);
+        insertMenu.getItems().add(0, insertCustomMenu);
+        insertCustomMenu.setVisible(false);
+    }
+    
+    // We consider the content of built-in library is static: it cannot change
+    // unless its implementation is modified.
+    private void constructBuiltinPartOfInsertMenu() {
+        assert insertMenu != null;
+        insertMenu.getItems().clear();
+
+        final Map<String, Set<LibraryItem>> sectionMap
+                = new TreeMap<>(new BuiltinSectionComparator());
+
+        for (LibraryItem li : BuiltinLibrary.getLibrary().getItems()) {
+            Set<LibraryItem> sectionItems = sectionMap.get(li.getSection());
+            if (sectionItems == null) {
+                sectionItems = new TreeSet<>(new LibraryItemNameComparator());
+                sectionMap.put(li.getSection(), sectionItems);
+            }
+            sectionItems.add(li);
+        }
+
+        for (Map.Entry<String, Set<LibraryItem>> e : sectionMap.entrySet()) {
+            final Menu sectionMenu = makeMenuForLibrarySection(e.getKey());
+            insertMenu.getItems().add(sectionMenu);
+            for (LibraryItem li : e.getValue()) {
+                sectionMenu.getItems().add(makeMenuItemForLibraryItem(li));
             }
         }
     }
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/MessageBar.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/MessageBar.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -35,7 +35,6 @@
 <?import java.lang.*?>
 <?import javafx.geometry.*?>
 <?import javafx.scene.control.*?>
-<?import javafx.scene.image.*?>
 <?import javafx.scene.layout.*?>
 
 <StackPane minHeight="30.0" prefHeight="-1.0" prefWidth="458.0" stylesheets="@../css/MessageBar.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
@@ -46,16 +45,9 @@
         <HBox fx:id="messagePart" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
           <children>
             <Label fx:id="messageLabel" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mouseTransparent="true" style="&#10;" text="Message" HBox.hgrow="ALWAYS" />
-            <HBox id="messageBox" alignment="CENTER_RIGHT" fillHeight="true" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" spacing="0.0" HBox.hgrow="NEVER">
+            <HBox fx:id="iconsHbox" alignment="CENTER_RIGHT" fillHeight="true" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" spacing="0.0" HBox.hgrow="NEVER">
              <children>
-                <Button fx:id="messageButton" alignment="CENTER" maxHeight="1.7976931348623157E308" minHeight="-1.0" minWidth="20.0" mnemonicParsing="false" onAction="#onOpenCloseAction" text="">
-                  <graphic>
-                    <ImageView id="warning" pickOnBounds="true" visible="true">
-                      <image>
-                        <Image preserveRatio="true" smooth="true" url="@warning.png" />
-                      </image>
-                    </ImageView>
-                  </graphic>
+                <Button fx:id="messageButton" alignment="CENTER" maxHeight="1.7976931348623157E308" minHeight="-1.0" minWidth="20.0" mnemonicParsing="false" onAction="#onOpenCloseAction" styleClass="warning-button" text="">
                   <tooltip>
                       <Tooltip text="%message.bar.details" />
                   </tooltip>
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/MessageBarController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/MessageBarController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -73,6 +73,8 @@
     private StackPane selectionBarHost;
     @FXML
     private HBox messagePart;
+    @FXML
+    private HBox iconsHbox;
 
     private final ImageView fileDirtyImage;
     private Tooltip statusLabelTooltip = null;
@@ -269,8 +271,8 @@
         messageLabel.getStyleClass().removeAll("message-warning"); //NOI18N
         statusLabel.getStyleClass().removeAll("message-info"); //NOI18N
         statusLabel.getStyleClass().removeAll("message-warning"); //NOI18N
-        messageButton.getStyleClass().removeAll("message-info"); //NOI18N
-        messageButton.getStyleClass().removeAll("message-warning"); //NOI18N
+        iconsHbox.getStyleClass().removeAll("message-info"); //NOI18N
+        iconsHbox.getStyleClass().removeAll("message-warning"); //NOI18N
     }
     
     private void setStyle(MessageLogEntry.Type type) {
@@ -280,12 +282,12 @@
             case INFO:
                 messageLabel.getStyleClass().add("message-info"); //NOI18N
                 statusLabel.getStyleClass().add("message-info"); //NOI18N
-                messageButton.getStyleClass().add("message-info"); //NOI18N
+                iconsHbox.getStyleClass().add("message-info"); //NOI18N
                 break;
             case WARNING:
                 messageLabel.getStyleClass().add("message-warning"); //NOI18N
                 statusLabel.getStyleClass().add("message-warning"); //NOI18N
-                messageButton.getStyleClass().add("message-warning"); //NOI18N
+                iconsHbox.getStyleClass().add("message-warning"); //NOI18N
                 break;
             default:
                 break;
Binary file apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/message/warning.png has changed
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/Preferences.css	Fri Feb 14 08:27:15 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-/*placeholder*/
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/Preferences.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/Preferences.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -31,19 +31,17 @@
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
+
+<?import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.*?>
 <?import java.lang.*?>
-<?import java.net.*?>
-<?import java.util.*?>
 <?import javafx.collections.*?>
 <?import javafx.geometry.*?>
 <?import javafx.scene.control.*?>
 <?import javafx.scene.layout.*?>
-<?import javafx.scene.paint.*?>
 <?import javafx.scene.shape.*?>
-<?import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.*?>
 <?scenebuilder-preview-i18n-resource ../i18n/SceneBuilderApp.properties?>
 
-<GridPane hgap="6.0" maxWidth="1.7976931348623157E308" vgap="10.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
+<GridPane hgap="6.0" maxWidth="1.7976931348623157E308" styleClass="theme-presets" vgap="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
     <Label text="%prefs.doc.width" GridPane.columnIndex="0" GridPane.rowIndex="0" />
     <DoubleField fx:id="rootContainerWidth" prefWidth="200.0" text="" GridPane.columnIndex="1" GridPane.rowIndex="0" />
@@ -57,7 +55,7 @@
         <Rectangle fx:id="alignmentGuidesGraphic" arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="10.0" stroke="BLACK" strokeType="INSIDE" width="20.0" />
       </graphic>
       <items>
-        <CustomMenuItem hideOnClick="false" mnemonicParsing="false" text="Unspecified Action" fx:id="alignmentGuidesMenuItem" />
+        <CustomMenuItem fx:id="alignmentGuidesMenuItem" hideOnClick="false" mnemonicParsing="false" text="Unspecified Action" />
       </items>
     </MenuButton>
     <Label text="%prefs.drop.ring" GridPane.columnIndex="0" GridPane.rowIndex="5" />
@@ -66,7 +64,7 @@
         <Rectangle fx:id="parentRingGraphic" arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="10.0" stroke="BLACK" strokeType="INSIDE" width="20.0" />
       </graphic>
       <items>
-        <CustomMenuItem hideOnClick="false" mnemonicParsing="false" text="Unspecified Action" fx:id="parentRingMenuItem" />
+        <CustomMenuItem fx:id="parentRingMenuItem" hideOnClick="false" mnemonicParsing="false" text="Unspecified Action" />
       </items>
     </MenuButton>
     <Label text="%prefs.hierarchy.displayoption" GridPane.columnIndex="0" GridPane.rowIndex="8" />
@@ -120,7 +118,4 @@
     <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
     <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
   </rowConstraints>
-  <stylesheets>
-    <URL value="@Preferences.css" />
-  </stylesheets>
 </GridPane>
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/PreferencesController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/PreferencesController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -83,7 +83,7 @@
     static final String SCENE_STYLE_SHEETS = "sceneStyleSheets"; //NOI18N
     static final String I18N_RESOURCE = "I18NResource"; //NOI18N
 
-    private static final PreferencesController singleton = new PreferencesController();
+    private static PreferencesController singleton;
 
     private final Preferences applicationRootPreferences;
     private final Preferences documentsRootPreferences;
@@ -127,7 +127,11 @@
         }
     }
 
-    public static PreferencesController getSingleton() {
+    public static synchronized PreferencesController getSingleton() {
+        if (singleton == null) {
+            singleton = new PreferencesController();
+            singleton.getRecordGlobal().readFromJavaPreferences();
+        }
         return singleton;
     }
 
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/PreferencesRecordDocument.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/preferences/PreferencesRecordDocument.java	Thu Feb 20 14:43:20 2014 +0100
@@ -402,8 +402,10 @@
 
     public void refreshBottomVisible() {
         final SplitController sc = documentWindowController.getBottomSplitController();
-        // CSS panel is built lazely : initialize the CSS panel first
-        documentWindowController.initializeCssPanel();
+        if (bottomVisible) {
+            // CSS panel is built lazely : initialize the CSS panel first
+            documentWindowController.initializeCssPanel();
+        }
         sc.setTargetVisible(bottomVisible);
     }
 
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/skeleton/SkeletonBuffer.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/skeleton/SkeletonBuffer.java	Thu Feb 20 14:43:20 2014 +0100
@@ -97,39 +97,39 @@
     }
 
     private void constructPackageLine() {
-        String controller = document.getFxomRoot().getFxController();
+            String controller = document.getFxomRoot().getFxController();
 
-        if (controller != null && !controller.isEmpty()
-                && controller.indexOf(".") != -1 && controller.indexOf("$") == -1) { //NOI18N
-            packageLine.append("package "); //NOI18N
-            packageLine.append(controller.substring(0, controller.indexOf("."))); //NOI18N
-            packageLine.append(";\n\n"); //NOI18N
+            if (controller != null && !controller.isEmpty()
+                    && controller.contains(".") && !controller.contains("$")) { //NOI18N
+                packageLine.append("package "); //NOI18N
+                packageLine.append(controller.substring(0, controller.indexOf("."))); //NOI18N
+                packageLine.append(";\n\n"); //NOI18N
+            }
         }
-    }
 
     private void constructClassLine() {
-        String controller = document.getFxomRoot().getFxController();
-        classLine.append("\npublic "); //NOI18N
+            String controller = document.getFxomRoot().getFxController();
+            classLine.append("\npublic "); //NOI18N
 
-        if (controller != null && controller.indexOf("$") != -1) { //NOI18N
-            classLine.append("static "); //NOI18N
+            if (controller != null && controller.contains("$")) { //NOI18N
+                classLine.append("static "); //NOI18N
+            }
+
+            classLine.append("class "); //NOI18N
+
+            if (controller != null && !controller.isEmpty()) {
+                String simpleName = controller.replace("$", "."); //NOI18N
+                int dot = simpleName.lastIndexOf('.');
+                if (dot > -1) {
+                    simpleName = simpleName.substring(dot+1);
+                }
+                classLine.append(simpleName);
+            } else {
+                classLine.append("PleaseProvideControllerClassName"); //NOI18N
+            }
+
+            classLine.append(" {\n\n"); //NOI18N
         }
-        
-        classLine.append("class "); //NOI18N
-
-        if (controller != null && !controller.isEmpty()) {
-            String simpleName = controller.replace("$", "."); //NOI18N
-            int dot = simpleName.lastIndexOf('.');
-            if (dot > -1) {
-                simpleName = simpleName.substring(dot+1);
-            }
-            classLine.append(simpleName);
-        } else {
-            classLine.append("PleaseProvideControllerClassName"); //NOI18N
-        }
-
-        classLine.append(" {\n\n"); //NOI18N
-    }
 
     private void constructInitialize() {
         if (textFormat == FORMAT_TYPE.FULL) {
@@ -204,12 +204,12 @@
         }
         
         // Event handlers
-        for (FXOMPropertyT property : document.getFxomRoot().collectEventHandlers()) {
-            handlers.append(INDENT).append("@FXML\n").append(INDENT).append("void "); //NOI18N
-            final String methodName = property.getValue().replace("#", ""); //NOI18N
-            handlers.append(methodName);
-            handlers.append("(ActionEvent event) {\n\n").append(INDENT).append("}\n\n"); //NOI18N
-        }
+            for (FXOMPropertyT property : document.getFxomRoot().collectEventHandlers()) {
+                handlers.append(INDENT).append("@FXML\n").append(INDENT).append("void "); //NOI18N
+                final String methodName = property.getValue().replace("#", ""); //NOI18N
+                handlers.append(methodName);
+                handlers.append("(ActionEvent event) {\n\n").append(INDENT).append("}\n\n"); //NOI18N
+            }
 
         // This method must be called once asserts has been populated.
         constructInitialize();
@@ -225,35 +225,39 @@
 
     @Override
     public String toString() {
-        construct();
+        if (document.getFxomRoot() == null) {
+            return I18N.getString("skeleton.empty");
+        } else {
+            construct();
 
-        StringBuilder code = new StringBuilder();
-        code.append(header);
-        code.append(packageLine);
+            StringBuilder code = new StringBuilder();
+            code.append(header);
+            code.append(packageLine);
 
-        for (String importStatement : imports) {
-            code.append(importStatement);
+            for (String importStatement : imports) {
+                code.append(importStatement);
+            }
+
+            code.append(classLine);
+
+            if (textType == TEXT_TYPE.WITH_COMMENTS && textFormat == FORMAT_TYPE.FULL) {
+                code.append(INDENT).append("@FXML // ResourceBundle that was given to the FXMLLoader\n") //NOI18N
+                        .append(INDENT).append("private ResourceBundle resources;\n\n") //NOI18N
+                        .append(INDENT).append("@FXML // URL location of the FXML file that was given to the FXMLLoader\n") //NOI18N
+                        .append(INDENT).append("private URL location;\n\n"); //NOI18N
+            } else if (textFormat == FORMAT_TYPE.FULL) {
+                code.append(INDENT).append("@FXML\n") //NOI18N
+                        .append(INDENT).append("private ResourceBundle resources;\n\n") //NOI18N
+                        .append(INDENT).append("@FXML\n") //NOI18N
+                        .append(INDENT).append("private URL location;\n\n"); //NOI18N
+            }
+
+            code.append(variables);
+            code.append(handlers);
+            code.append(initialize);
+            code.append("}\n"); //NOI18N
+
+            return code.toString();
         }
-
-        code.append(classLine);
-
-        if (textType == TEXT_TYPE.WITH_COMMENTS && textFormat == FORMAT_TYPE.FULL) {
-            code.append(INDENT).append("@FXML // ResourceBundle that was given to the FXMLLoader\n") //NOI18N
-                    .append(INDENT).append("private ResourceBundle resources;\n\n") //NOI18N
-                    .append(INDENT).append("@FXML // URL location of the FXML file that was given to the FXMLLoader\n") //NOI18N
-                    .append(INDENT).append("private URL location;\n\n"); //NOI18N
-        } else if (textFormat == FORMAT_TYPE.FULL) {
-            code.append(INDENT).append("@FXML\n") //NOI18N
-                    .append(INDENT).append("private ResourceBundle resources;\n\n") //NOI18N
-                    .append(INDENT).append("@FXML\n") //NOI18N
-                    .append(INDENT).append("private URL location;\n\n"); //NOI18N
-        }
-
-        code.append(variables);
-        code.append(handlers);
-        code.append(initialize);
-        code.append("}\n"); //NOI18N
-
-        return code.toString();
     }
 }
--- a/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/skeleton/SkeletonWindowController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderApp/src/com/oracle/javafx/scenebuilder/app/skeleton/SkeletonWindowController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -44,7 +44,6 @@
 import javafx.beans.value.ObservableValue;
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
-import javafx.scene.control.Button;
 import javafx.scene.control.CheckBox;
 import javafx.scene.control.TextArea;
 import javafx.scene.input.Clipboard;
@@ -166,6 +165,8 @@
     }
 
     private void update() {
+        assert editorController.getFxomDocument() != null;
+        
         // No need to eat CPU if the skeleton window isn't opened
         if (getStage().isShowing()) {
             updateTitle();
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -35,6 +35,7 @@
 import com.oracle.javafx.scenebuilder.kit.editor.drag.DragController;
 import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N;
 import com.oracle.javafx.scenebuilder.kit.editor.job.BatchJob;
+import com.oracle.javafx.scenebuilder.kit.editor.job.BatchModifySelectionJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.BringForwardJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.BringToFrontJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.CutSelectionJob;
@@ -44,7 +45,6 @@
 import com.oracle.javafx.scenebuilder.kit.editor.job.InsertAsAccessoryJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.InsertAsSubComponentJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
-import com.oracle.javafx.scenebuilder.kit.editor.job.ModifySelectionJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.PasteIntoJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.PasteJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.SendBackwardJob;
@@ -277,18 +277,38 @@
         });
     }
 
+    /**
+     * Get the width to use by default for the root container.
+     *
+     * @return default width for the root container.
+     */
     public double getDefaultRootContainerWidth() {
         return defaultRootContainerWidth;
     }
 
+    /**
+     * Set the width to use by default for the root container.
+     *
+     * @param defaultRootContainerWidth the new root container's default width.
+     */
     public void setDefaultRootContainerWidth(double defaultRootContainerWidth) {
         this.defaultRootContainerWidth = defaultRootContainerWidth;
     }
 
+    /**
+     * Get the height to use by default for the root container.
+     *
+     * @return default height for the root container.
+     */
     public double getDefaultRootContainerHeight() {
         return defaultRootContainerHeight;
     }
 
+    /**
+     * Set the height to use by default for the root container.
+     * 
+     * @param defaultRootContainerHeight the new root container's default height.
+     */
     public void setDefaultRootContainerHeight(double defaultRootContainerHeight) {
         this.defaultRootContainerHeight = defaultRootContainerHeight;
     }
@@ -312,10 +332,18 @@
     public String getFxmlText() {
         final String result;
         
-        if (getFxomDocument() == null) {
+        final FXOMDocument fxomDocument = getFxomDocument();
+        if (fxomDocument == null) {
             result = null;
         } else {
-            result = getFxomDocument().getFxmlText();
+            final boolean sampleDataEnabled = fxomDocument.isSampleDataEnabled();
+            if (sampleDataEnabled) {
+                fxomDocument.setSampleDataEnabled(false);
+            }
+            result = fxomDocument.getFxmlText();
+            if (sampleDataEnabled) {
+                fxomDocument.setSampleDataEnabled(true);
+            }
         }
         
         return result;
@@ -2141,7 +2169,7 @@
                 = Metadata.getMetadata().queryProperty(Node.class, pn);
         assert pm instanceof ValuePropertyMetadata;
         final ValuePropertyMetadata vpm = (ValuePropertyMetadata) pm;
-        final ModifySelectionJob job = new ModifySelectionJob(vpm, effect, this);
+        final BatchModifySelectionJob job = new BatchModifySelectionJob(vpm, effect, this);
         getJobManager().push(job);
     }
 
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/css/Theme.css	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/css/Theme.css	Thu Feb 20 14:43:20 2014 +0100
@@ -41,7 +41,7 @@
     -sb-dark: derive(-sb-base, -25%);
     -sb-content-text: derive(-sb-base, -50%); 
     -sb-content-text-dimmed: derive(-sb-base, -20%);
-    -sb-header-text: derive(-sb-base, -80%);
+    -sb-header-text: derive(-sb-base, -70%);
     -sb-header-text-dimmed: derive(-sb-base, -30%);
     -sb-header-height: 32;
     -sb-grad-hi: derive(-sb-base, 110%);
@@ -70,8 +70,17 @@
  * Common UI Styling - Controls                                                *
  ******************************************************************************/
 
+.context-menu {
+    -fx-background-color: -sb-sharp-edge-lo, white;
+    -fx-background-insets: 0, 1;
+    -fx-background-radius: 0;
+}
+.custom-menu-item {
+    -fx-padding: 4 8 4 8;
+}
 .custom-menu-item:focused {
-     -fx-background: white;
+    -fx-background: white;
+    -fx-background-color: -fx-background;
 }
 
 /*******************************************************************************
@@ -113,6 +122,9 @@
     -fx-alignment: center-right;
     -fx-effect: dropshadow( two-pass-box, rgba(0, 0, 0, 0.2), 5, 0.0, 0, 1 );
 }
+.accordion > .titled-pane > .title > .text {
+    -fx-fill: -sb-header-text;
+}
 .accordion > .first-titled-pane > .title {
     -fx-background-insets: 0 0 -1 0, 0, 1 0 1 0, 2 0 0 0;
 }
@@ -147,20 +159,6 @@
  * Common UI Styling - Split Panes                                             *
  ******************************************************************************/
 
-.split-pane {
-    -fx-background-color: -sb-dark;
-    -fx-background-insets: 0;
-    -fx-padding: 0;
-}
-.split-pane > .split-pane-divider {
-    -fx-background-color: -sb-dark;
-    -fx-padding: 0 0.5 0 0;
-}
-.split-pane:horizontal .split-pane-divider .horizontal-grabber,
-.split-pane:vertical .split-pane-divider .vertical-grabber {
-    -fx-padding: 3;
-    -fx-shape: "";
-}
 .SBKIT-inspector-panel.split-pane > .split-pane-divider {
     -fx-background-color: transparent;
     -fx-background-insets: -1 0 -3 0;
@@ -185,7 +183,7 @@
 }
 .scroll-bar:horizontal > .decrement-button,
 .scroll-bar:horizontal > .increment-button {
-    -fx-padding: 0.769em 0.077em 0.769em 0.077em;
+    -fx-padding: 0.692em 0.077em 0.692em 0.077em;
 }
 .scroll-bar .increment-arrow, 
 .scroll-bar .decrement-arrow {
@@ -193,7 +191,7 @@
 }
 .scroll-bar:vertical {
     -fx-background-color: -sb-sharp-edge-lo, -sb-panel-background;
-    -fx-background-insets: 1 0 0 0, 1 0 0 1;
+    -fx-background-insets: 0 0 0 0, 0 0 0 1;
 }
 .scroll-bar:horizontal {
     -fx-background-color: -sb-sharp-edge-lo, -sb-panel-background;
@@ -209,6 +207,21 @@
 .scroll-bar:horizontal .thumb {
     -fx-background-insets: 4 3 4 3, 5 4 5 4;
 }
+.scroll-pane .corner,
+.tree-view .virtual-flow .corner {
+    -fx-background-color: -sb-sharp-edge-lo, -sb-panel-background;
+    -fx-background-insets: 0 -1 -1 0, 1 -1 -1 1;
+}
+
+.text-area .scroll-pane .scroll-bar:horizontal {
+    -fx-background-insets: 0 1 1 1, 1 1 1 1;
+}
+.text-area .scroll-pane .scroll-bar:vertical {
+    -fx-background-insets: 1 1 1 0, 1 1 1 1;
+}
+.text-area .scroll-pane .corner {
+    -fx-background-insets: 0 1 1 0, 1 1 1 1;
+}
 
 /*******************************************************************************
  *                                                                             *
@@ -222,68 +235,84 @@
  *                                                                             *
  ******************************************************************************/
 
-.list-view {
+.SBKIT-library-panel .list-view {
     -fx-background-color: transparent;
 }
-
-.list-view .list-cell .text {
+.SBKIT-library-panel .list-view .list-cell .text {
     -fx-fill: -sb-content-text;
 }
-
-.list-view .list-cell {
+.SBKIT-library-panel .list-view .list-cell {
     -fx-background-color: transparent;
     -fx-cell-size: 1.7em;
     -fx-background-insets: 2 0 -2 0;
     -fx-padding: 2 0 0 4;
 }
-
-.list-view .list-cell:filled:hover {
+.SBKIT-library-panel .list-view .list-cell:filled:hover {
     -fx-background-color: null; /* no hover effect on list view */
 }
-
-.list-view:focused .list-cell:filled:selected {
+.SBKIT-library-panel .list-view:focused .list-cell:filled:selected {
     -fx-background-color: -sb-selected-bar-color;
 }
-
-.list-view .list-cell:filled:selected {
+.SBKIT-library-panel .list-view .list-cell:filled:selected {
     /* When the ListView is not focused there is no need to highlight
     the selected item */
     -fx-background-color: null;
 }
-
-.list-view .scroll-bar {    
+.SBKIT-library-panel .list-view .scroll-bar {    
     /* Cursor may dynamically change when working in library / hierarchy.
        Set back the cursor to its default. */
     -fx-cursor: default;
 }
 
 /* ListCell graphic is an HBox */
-.list-cell-graphic {
+.SBKIT-library-panel .list-cell-graphic {
     -fx-alignment: center-left;
     -fx-padding: 0 2 0 2;
     -fx-spacing: 4;
 }
 
-.library-no-results-label {
+.SBKIT-library-panel .library-no-results-label {
     -fx-text-fill: -sb-content-text-dimmed;
     -fx-font-size: 0.875em;
     -fx-padding: 6 0 0 10;
 }
 
-.library-classname-label {
+.SBKIT-library-panel .library-classname-label {
     -fx-text-fill: black;
 }
 
-.library-qualifier-label {
+.SBKIT-library-panel .library-qualifier-label {
     -fx-text-fill: lightslategray;
 }
 
-.library-section-label {
+.SBKIT-library-panel .library-section-label {
     -fx-text-fill: black;
     -fx-font-weight: bold;
 }
 
 /*******************************************************************************
+ * Library Panel - Jar import dialog                                           *
+ ******************************************************************************/
+
+.jar-import-preview-label {
+    -fx-text-fill: -sb-content-text-dimmed;
+    -fx-font-size : 0.875em;
+}
+
+.jar-import-preview {
+    -fx-background-color: azure;
+}
+
+.jar-import-num-of-items-label {
+    -fx-font-size : 0.875em;
+}
+
+.jar-import-class-name-label {
+    -fx-text-fill: -sb-content-text-dimmed;
+    -fx-font-size : 0.875em;
+}
+
+/*******************************************************************************
  *                                                                             *
  * Hierarchy Panel                                                             *
  *                                                                             *
@@ -623,6 +652,17 @@
     -fx-fill: rgba(0,0,0,0.01);
 }
 
+
+/*******************************************************************************
+ *                                                                             *
+ * Inspector Panel                                                             *
+ *                                                                             *
+ ******************************************************************************/
+
+.SBKIT-inspector-panel .secondary-section-title {
+    -fx-text-fill: -sb-header-text-dimmed;
+}
+
 /*******************************************************************************
  *                                                                             *
  * Property Sheet Panels (Inspector, Controller)                               *
@@ -637,21 +677,15 @@
     -fx-font-size: 0.875em;
 }
 
-.property-sheet .small-label {
-    -fx-font-size: 0.750em; /* 9 */
-    -fx-text-fill: -sb-content-text-dimmed;
-    -fx-padding: 0;
+.property-sheet .label {
+    -fx-text-fill: -sb-content-text;
+    -fx-padding: 4 0 3 0;
 }
 
 .property-sheet .check-box .box {
     -fx-background-radius: 0;
 }
 
-.property-sheet .label {
-    -fx-text-fill: -sb-content-text;
-    -fx-padding: 4 0 3 0;
-}
-
 .property-sheet .hyperlink, .hyperlink:visited {
     -fx-text-fill: -sb-content-text;
     -fx-padding: 3 0 2 0;
@@ -698,6 +732,33 @@
     -fx-padding: 0.154em 0.308em 0.154em 0.231em;  /* 2 4 2 3 */
 }
 
+.property-sheet .table-view .column-header .label {
+    -fx-text-fill: -sb-content-text;
+    -fx-font-size: 0.875em;
+    -fx-font-weight: normal;
+    -fx-alignment: CENTER_LEFT;
+    -fx-padding: 0 4 0 4;
+}
+.property-sheet .table-view > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell {
+    -fx-padding: 4 5 2 5;
+}
+.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected,
+.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected {
+    -fx-background: -sb-selected-bar-color;
+    -fx-table-cell-border-color: -sb-selected-bar-color;
+}
+
+.property-sheet .small-label {
+    -fx-font-size: 0.750em; /* 9 */
+    -fx-text-fill: -sb-content-text-dimmed;
+    -fx-padding: 0;
+}
+
+.inspector-message .text {
+    /* Used for 'No Selection' and 'No Results' messages */
+    -fx-fill: -sb-content-text-dimmed;
+}
+
 .property-sheet .cog-menubutton {
     -fx-background-color: -sb-panel-background;
     -fx-background-radius: 0;
@@ -723,27 +784,6 @@
     -fx-padding: 0;
 }
 
-.inspector-message .text {
-    /* Used for 'No Selection' and 'No Results' messages */
-    -fx-fill: -sb-content-text-dimmed;
-}
-
-.property-sheet .table-view .column-header .label {
-    -fx-text-fill: -sb-content-text;
-    -fx-font-size: 0.875em;
-    -fx-font-weight: normal;
-    -fx-alignment: CENTER_LEFT;
-    -fx-padding: 0 4 0 4;
-}
-.property-sheet .table-view > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell {
-    -fx-padding: 4 5 2 5;
-}
-.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected,
-.property-sheet .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected {
-    -fx-background: -sb-selected-bar-color;
-    -fx-table-cell-border-color: -sb-selected-bar-color;
-}
-
 /*******************************************************************************
  * Property Sheet Panels - CSS Override property decoration                    *
  ******************************************************************************/
@@ -893,9 +933,13 @@
  * Property Sheet Panels - Suggestive ListView                                 *
  ******************************************************************************/
 
-.suggested-list {
-    -fx-font-size: 0.875em;
- }
+.property-sheet .auto-suggest-popup {
+    -fx-padding: 0;
+}
+.property-sheet .auto-suggest-popup .custom-menu-item .list-view {
+    -fx-background-color: -sb-sharp-edge-lo, white;
+    -fx-background-insets: 0, 1;
+}
 
 /*******************************************************************************
  *                                                                             *
@@ -1026,17 +1070,25 @@
     -fx-padding: 0 0 0 0;
 }
 .styleable-path .button {
-    -fx-background-color: derive( -fx-base, 50% );
+    -fx-background-color: -sb-sharp-edge-lo, derive(-sb-sharp-edge-hi, 10%);
+    -fx-background-insets: 0, 1;
     -fx-background-radius: 100;
-    -fx-margin: 0 30 0 30;
-    -fx-padding: 1 5 1 6;
-    /*-fx-effect: dropshadow( one-pass-box , derive( -fx-base, -55% ), 3, 0.0 , 0 , 0 );*/
-    -fx-graphic: url("../cssimages/css-styleable-path-button.png");
+    -fx-min-width: 16;
+    -fx-max-width: 16;
+    -fx-min-height: 16;
+    -fx-max-height: 16;
 }
 .styleable-path .button:hover {
-    -fx-background-color: derive( -fx-base, 100% );
+    -fx-background-color: derive(-sb-sharp-edge-lo, -10%), derive(-sb-sharp-edge-hi, 40%);
 }
-
+.styleable-path-button-shape {
+    -fx-shape: "M 0 -3.5 v 7 l 4 -3.5 z";
+    -fx-background-color: -sb-content-text;
+    -fx-min-width: 5;
+    -fx-max-width: 5;
+    -fx-min-height: 6;
+    -fx-max-height: 6;
+}
 .styleable-path-optional-label .text {
     -fx-fill: -sb-header-text-dimmed;
 }
Binary file apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/cssimages/css-styleable-path-button.png has changed
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/drag/target/ContainerXYDropTarget.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/drag/target/ContainerXYDropTarget.java	Thu Feb 20 14:43:20 2014 +0100
@@ -183,8 +183,8 @@
                 assert draggedObject instanceof FXOMInstance;
                 final Point2D dxy = layoutDXY.get(draggedObject);
                 assert dxy != null;
-                final double newLayoutX = targetOriginX + dxy.getX();
-                final double newLayoutY = targetOriginY + dxy.getY();
+                final double newLayoutX = Math.round(targetOriginX + dxy.getX());
+                final double newLayoutY = Math.round(targetOriginY + dxy.getY());
                 result.addSubJob(new RelocateNodeJob((FXOMInstance)draggedObject, 
                         newLayoutX, newLayoutY, editorController));
             }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/i18n/SceneBuilderKit.properties	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/i18n/SceneBuilderKit.properties	Thu Feb 20 14:43:20 2014 +0100
@@ -55,6 +55,8 @@
 label.action.edit.add.context.menu = Add ContextMenu
 label.action.edit.add.context.menu.menu.item = Unspecified Action
 label.action.edit.add.tooltip = Add Tooltip
+label.action.edit.set.1 = Set {0} on {1}
+label.action.edit.set.n = Set {0} on {1} Objects
 
 label.search.noresults = No results found
 
@@ -71,6 +73,7 @@
 log.warning.image.location.does.not.exist = Image ''{0}'' does not exist
 log.warning.invalid.fxid = Id ''{0}'' is not a valid java identifier
 log.warning.no.injectable.fxid = No injectable field found in FXML Controller class for the id ''{0}''
+log.warning.duplicate.fxid = An element with the id ''{0}'' is already injected in the FXML Controller
 
 # -----------------------------------------------------------------------------
 # Library Panel
@@ -123,6 +126,9 @@
 inspector.error.title = Property error
 inspector.error.message = Invalid value
 inspector.error.details = {0} is invalid for {1}
+inspector.font.invalidfamily = Invalid value for Family: {0}
+inspector.font.invalidstyle = Invalid value for Style: {0}
+inspector.font.samefamilystyle = Several fonts have the same family and style: {0}
 inspector.keycombination.modifier = Modifier
 inspector.keycombination.mainkey = Main Key
 inspector.keycombination.none = none
@@ -140,7 +146,6 @@
 inspector.message.no.selected = No Selection
 inspector.message.no.thingforinspector = No information to display
 inspector.message.searchpattern.empty = Search pattern is empty
-inspector.fxml.invalid.id = Id {0} is not a valid java identifier
 inspector.rectangle2D.not.defined = not defined
 inspector.select.css.filter = Style Sheet files
 inspector.select.css.title = Add Style Sheet
@@ -156,6 +161,7 @@
 inspector.resource.documentrelative = Switch to document relative path
 inspector.resource.classpathrelative = Switch to classpath relative path
 inspector.resource.absolute = Switch to absolute path
+inspector.sectiontitle.multiple = Multiple Selection
 
 # -----------------------------------------------------------------------------
 # CSS Panel
Binary file apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/images/ui/css-cursor@2x.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchModifyFxIdJob.java	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.editor.job.v2.BackupSelectionJob;
+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.fxom.FXOMObject;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class BatchModifyFxIdJob extends CompositeJob {
+
+    private final FXOMObject fxomObject;
+    private final String newValue;
+
+    public BatchModifyFxIdJob(
+            FXOMObject fxomObject, 
+            String newValue,
+            EditorController editorController) {
+        super(editorController);
+
+        assert fxomObject != null;
+
+        this.fxomObject = fxomObject;
+        this.newValue = newValue;
+    }
+
+    /*
+     * CompositeJob
+     */
+    
+    @Override
+    protected List<Job> makeSubJobs() {
+        final List<Job> result = new ArrayList<>();
+        
+        final ModifyFxIdJob job = new ModifyFxIdJob(fxomObject, newValue, getEditorController());
+        if (job.isExecutable()) {
+            result.add(job);
+        }
+        
+        if (result.isEmpty() == false) {
+            result.add(0, new BackupSelectionJob(getEditorController()));
+            result.add(new UpdateSelectionJob(fxomObject, getEditorController()));
+        }
+        
+        return result;
+    }
+
+    @Override
+    protected String makeDescription() {
+        final String result;
+        final List<Job> subJobs = getSubJobs();
+        final int subJobCount = subJobs.size();
+        assert (subJobCount == 0) || (subJobCount == 3);
+
+        if (subJobCount == 0) {
+            result = "Unexecutable Set"; //NOI18N
+        } else {
+            result = subJobs.get(1).getDescription(); // BackupSelection + 1 ModifyFxId + UpdateSelection
+        }
+
+        return result;
+    }
+}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchModifyObjectJob.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchModifyObjectJob.java	Thu Feb 20 14:43:20 2014 +0100
@@ -32,6 +32,7 @@
 package com.oracle.javafx.scenebuilder.kit.editor.job;
 
 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.v2.BackupSelectionJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.v2.CompositeJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.v2.UpdateSelectionJob;
@@ -66,6 +67,24 @@
         this.description = description;
     }
 
+    public BatchModifyObjectJob(FXOMInstance fxomInstance,
+            ValuePropertyMetadata propertyMetadata,
+            Object newValue,
+            EditorController editorController) {
+        super(editorController);
+
+        assert fxomInstance != null;
+        assert propertyMetadata != null;
+        assert newValue != null;
+
+        this.fxomInstance = fxomInstance;
+        this.valueMap = new HashMap<>();
+        this.valueMap.put(propertyMetadata, newValue);
+        this.description = I18N.getString("label.action.edit.set.1",
+                propertyMetadata.getName().toString(),
+                fxomInstance.getSceneGraphObject().getClass().getSimpleName());
+    }
+
     /*
      * CompositeJob
      */
@@ -94,5 +113,4 @@
     protected String makeDescription() {
         return description;
     }
-    
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/BatchModifySelectionJob.java	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,150 @@
+/*
+ * 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;
+
+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.v2.BackupSelectionJob;
+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.GridSelectionGroup;
+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.FXOMInstance;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.DesignHierarchyMask;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ *
+ */
+public class BatchModifySelectionJob extends CompositeJob {
+
+    private final ValuePropertyMetadata propertyMetadata;
+    private final Object newValue;
+
+    public BatchModifySelectionJob(ValuePropertyMetadata propertyMetadata,
+            Object newValue, EditorController editorController) {
+        super(editorController, true, false);
+        this.propertyMetadata = propertyMetadata;
+        this.newValue = newValue;
+    }
+
+    /*
+     * CompositeJob
+     */
+    @Override
+    protected List<Job> makeSubJobs() {
+
+        final List<Job> result = new ArrayList<>();
+        final Set<FXOMInstance> candidates = new HashSet<>();
+        final Selection selection = getEditorController().getSelection();
+        if (selection.getGroup() instanceof ObjectSelectionGroup) {
+            final ObjectSelectionGroup osg = (ObjectSelectionGroup) selection.getGroup();
+            for (FXOMObject fxomObject : osg.getItems()) {
+                if (fxomObject instanceof FXOMInstance) {
+                    candidates.add((FXOMInstance) fxomObject);
+                }
+            }
+        } else if (selection.getGroup() instanceof GridSelectionGroup) {
+            final GridSelectionGroup gsg = (GridSelectionGroup) selection.getGroup();
+            final DesignHierarchyMask mask = new DesignHierarchyMask(gsg.getAncestor());
+            for (int index : gsg.getIndexes()) {
+                FXOMObject constraints = null;
+                switch (gsg.getType()) {
+                    case COLUMN:
+                        constraints = mask.getColumnConstraintsAtIndex(index);
+                        break;
+                    case ROW:
+                        constraints = mask.getRowConstraintsAtIndex(index);
+                        break;
+                    default:
+                        assert false;
+                        break;
+                }
+                assert constraints instanceof FXOMInstance;
+                candidates.add((FXOMInstance) constraints);
+            }
+        } else {
+            assert selection.getGroup() == null : "Add implementation for " + selection.getGroup();
+        }
+
+        final Set<FXOMObject> executableCandidates = new HashSet<>();
+
+        // First add ModifyObject jobs
+        for (FXOMInstance fxomInstance : candidates) {
+            final ModifyObjectJob subJob = new ModifyObjectJob(
+                    fxomInstance, propertyMetadata, newValue, getEditorController());
+            if (subJob.isExecutable()) {
+                result.add(subJob);
+                executableCandidates.add(fxomInstance);
+            }
+        }
+
+        // If the list of ModifyObject jobs is not empty,
+        // then add selection specific jobs
+        if (result.isEmpty() == false) {
+            result.add(0, new BackupSelectionJob(getEditorController()));
+            result.add(new UpdateSelectionJob(executableCandidates, getEditorController()));
+        }
+
+        return result;
+    }
+
+    @Override
+    protected String makeDescription() {
+        final String result;
+        final List<Job> subJobs = getSubJobs();
+        final int subJobCount = subJobs.size();
+        assert (subJobCount == 0) || (subJobCount >= 3);
+
+        switch (subJobCount) {
+            case 0:
+                result = "Unexecutable Set"; //NOI18N
+                break;
+            case 3: // BackupSelection + 1 ModifyObject + UpdateSelection
+                result = subJobs.get(1).getDescription();
+                break;
+            default:
+                result = I18N.getString("label.action.edit.set.n",
+                        propertyMetadata.getName().toString(),
+                        subJobCount - 2); // Remove 2 selection jobs (BackupSelection + UpdateSelection) 
+                break;
+        }
+
+        return result;
+    }
+}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/FitToParentObjectJob.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/FitToParentObjectJob.java	Thu Feb 20 14:43:20 2014 +0100
@@ -61,7 +61,7 @@
     private final FXOMInstance fxomInstance;
     private final FXOMPropertyC parentProperty;
     private final FXOMInstance parentInstance;
-    private final List<ModifyObjectJob> subJobs = new ArrayList<>();
+    private final List<BatchModifyObjectJob> subJobs = new ArrayList<>();
     private String description; // final but initialized lazily
 
     private enum Sizing {
@@ -98,7 +98,7 @@
         final FXOMDocument fxomDocument
                 = getEditorController().getFxomDocument();
         fxomDocument.beginUpdate();
-        for (ModifyObjectJob subJob : subJobs) {
+        for (BatchModifyObjectJob subJob : subJobs) {
             subJob.execute();
         }
         fxomDocument.endUpdate();
@@ -120,7 +120,7 @@
         final FXOMDocument fxomDocument
                 = getEditorController().getFxomDocument();
         fxomDocument.beginUpdate();
-        for (ModifyObjectJob subJob : subJobs) {
+        for (BatchModifyObjectJob subJob : subJobs) {
             subJob.redo();
         }
         fxomDocument.endUpdate();
@@ -190,53 +190,53 @@
 
         // Modify pref size jobs
         //----------------------------------------------------------------------
-        final ModifyObjectJob prefWidthJob = modifyJob("prefWidth", prefWidthValue);
+        final BatchModifyObjectJob prefWidthJob = modifyJob("prefWidth", prefWidthValue);
         if (prefWidthJob.isExecutable()) { // Update if new value differs from old one
             subJobs.add(prefWidthJob);
         }
-        final ModifyObjectJob prefHeightJob = modifyJob("prefHeight", prefHeightValue);
+        final BatchModifyObjectJob prefHeightJob = modifyJob("prefHeight", prefHeightValue);
         if (prefHeightJob.isExecutable()) { // Update if new value differs from old one
             subJobs.add(prefHeightJob);
         }
 
         // Modify Anchors Jobs
         //----------------------------------------------------------------------
-        final ModifyObjectJob leftAnchorJob = modifyAnchorJob(Anchor.LEFT, leftAnchorValue);
+        final BatchModifyObjectJob leftAnchorJob = modifyAnchorJob(Anchor.LEFT, leftAnchorValue);
         if (leftAnchorJob.isExecutable()) { // Update if new value differs from old one
             subJobs.add(leftAnchorJob);
         }
-        final ModifyObjectJob topAnchorJob = modifyAnchorJob(Anchor.TOP, topAnchorValue);
+        final BatchModifyObjectJob topAnchorJob = modifyAnchorJob(Anchor.TOP, topAnchorValue);
         if (topAnchorJob.isExecutable()) { // Update if new value differs from old one
             subJobs.add(topAnchorJob);
         }
         if (isResizableX) {
-            final ModifyObjectJob rightAnchorJob = modifyAnchorJob(Anchor.RIGHT, 0.0);
+            final BatchModifyObjectJob rightAnchorJob = modifyAnchorJob(Anchor.RIGHT, 0.0);
             if (rightAnchorJob.isExecutable()) { // Update if new value differs from old one
                 subJobs.add(rightAnchorJob);
             }
         }
         if (isResizableY) {
-            final ModifyObjectJob bottomAnchorJob = modifyAnchorJob(Anchor.BOTTOM, 0.0);
+            final BatchModifyObjectJob bottomAnchorJob = modifyAnchorJob(Anchor.BOTTOM, 0.0);
             if (bottomAnchorJob.isExecutable()) { // Update if new value differs from old one
                 subJobs.add(bottomAnchorJob);
             }
         }
     }
 
-    private ModifyObjectJob modifyJob(final Class<?> clazz, final String name, double value) {
+    private BatchModifyObjectJob modifyJob(final Class<?> clazz, final String name, double value) {
         final PropertyName pn = new PropertyName(name, clazz);
         final ValuePropertyMetadata vpm
                 = Metadata.getMetadata().queryValueProperty(fxomInstance, pn);
-        final ModifyObjectJob subJob = new ModifyObjectJob(
+        final BatchModifyObjectJob subJob = new BatchModifyObjectJob(
                 fxomInstance, vpm, value, getEditorController());
         return subJob;
     }
 
-    private ModifyObjectJob modifyJob(final String name, double value) {
+    private BatchModifyObjectJob modifyJob(final String name, double value) {
         return modifyJob(null, name, value);
     }
 
-    private ModifyObjectJob modifyAnchorJob(final Anchor anchor, double value) {
+    private BatchModifyObjectJob modifyAnchorJob(final Anchor anchor, double value) {
         final String name = anchor.name().toLowerCase(Locale.ROOT) + "Anchor";
         return modifyJob(AnchorPane.class, name, value);
     }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/ModifyObjectJob.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/ModifyObjectJob.java	Thu Feb 20 14:43:20 2014 +0100
@@ -32,6 +32,7 @@
 package com.oracle.javafx.scenebuilder.kit.editor.job;
 
 import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N;
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
 import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata;
 import java.util.Objects;
@@ -90,12 +91,10 @@
 
     @Override
     public String getDescription() {
-        final StringBuilder result = new StringBuilder();
-        result.append("Set ");
-        result.append(propertyMetadata.getName().toString());
-        result.append(" on ");
-        result.append(fxomInstance.getSceneGraphObject().getClass().getSimpleName());
-        return result.toString();
+        final String description = I18N.getString("label.action.edit.set.1",
+                propertyMetadata.getName().toString(),
+                fxomInstance.getSceneGraphObject().getClass().getSimpleName());
+        return description;
     }
     
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/ModifySelectionJob.java	Fri Feb 14 08:27:15 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
-/*
- * 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;
-
-import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
-import com.oracle.javafx.scenebuilder.kit.editor.selection.GridSelectionGroup;
-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.FXOMDocument;
-import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
-import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
-import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata;
-import com.oracle.javafx.scenebuilder.kit.metadata.util.DesignHierarchyMask;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- *
- */
-public class ModifySelectionJob extends Job {
-
-    private final ValuePropertyMetadata propertyMetadata;
-    private final Object newValue;
-    private final List<ModifyObjectJob> subJobs = new ArrayList<>();
-    private String description; // Final but constructed lazily
-
-    public ModifySelectionJob(ValuePropertyMetadata propertyMetadata,
-            Object newValue, EditorController editorController) {
-        super(editorController);
-        this.propertyMetadata = propertyMetadata;
-        this.newValue = newValue;
-        buildSubJobs();
-    }
-
-    /*
-     * Job
-     */
-    @Override
-    public boolean isExecutable() {
-        return subJobs.isEmpty() == false;
-    }
-
-    @Override
-    public void execute() {
-        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
-        fxomDocument.beginUpdate();
-        for (ModifyObjectJob subJob : subJobs) {
-            subJob.execute();
-        }
-        fxomDocument.endUpdate();
-    }
-
-    @Override
-    public void undo() {
-        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
-        fxomDocument.beginUpdate();
-        for (int i = subJobs.size() - 1; i >= 0; i--) {
-            subJobs.get(i).undo();
-        }
-        fxomDocument.endUpdate();
-    }
-
-    @Override
-    public void redo() {
-        final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
-
-        fxomDocument.beginUpdate();
-        for (ModifyObjectJob subJob : subJobs) {
-            subJob.redo();
-        }
-        fxomDocument.endUpdate();
-    }
-
-    @Override
-    public String getDescription() {
-        if (description == null) {
-            buildDescription();
-        }
-
-        return description;
-    }
-
-    /*
-     * Private
-     */
-    private void buildSubJobs() {
-
-        final Set<FXOMInstance> candidates = new HashSet<>();
-        final Selection selection = getEditorController().getSelection();
-        if (selection.getGroup() instanceof ObjectSelectionGroup) {
-            final ObjectSelectionGroup osg = (ObjectSelectionGroup) selection.getGroup();
-            for (FXOMObject fxomObject : osg.getItems()) {
-                if (fxomObject instanceof FXOMInstance) {
-                    candidates.add((FXOMInstance) fxomObject);
-                }
-            }
-        } else if (selection.getGroup() instanceof GridSelectionGroup) {
-            final GridSelectionGroup gsg = (GridSelectionGroup) selection.getGroup();
-            final DesignHierarchyMask mask = new DesignHierarchyMask(gsg.getAncestor());
-            for (int index : gsg.getIndexes()) {
-                FXOMObject constraints = null;
-                switch (gsg.getType()) {
-                    case COLUMN:
-                        constraints = mask.getColumnConstraintsAtIndex(index);
-                        break;
-                    case ROW:
-                        constraints = mask.getRowConstraintsAtIndex(index);
-                        break;
-                    default:
-                        assert false;
-                        break;
-                }
-                assert constraints instanceof FXOMInstance;
-                candidates.add((FXOMInstance) constraints);
-            }
-        } else {
-            assert selection.getGroup() == null : "Add implementation for " + selection.getGroup();
-        }
-
-        for (FXOMInstance fxomInstance : candidates) {
-            final ModifyObjectJob subJob
-                    = new ModifyObjectJob(fxomInstance, propertyMetadata, newValue, getEditorController());
-            if (subJob.isExecutable()) {
-                subJobs.add(subJob);
-            }
-        }
-    }
-
-    private void buildDescription() {
-        switch (subJobs.size()) {
-            case 0:
-                description = "Unexecutable Set"; // NO18N
-                break;
-            case 1:
-                description = subJobs.get(0).getDescription();
-                break;
-            default:
-                description = makeMultipleSelectionDescription();
-                break;
-        }
-    }
-
-    private String makeMultipleSelectionDescription() {
-        final StringBuilder result = new StringBuilder();
-
-        result.append("Set ");
-        result.append(propertyMetadata.getName().toString());
-        result.append(" on ");
-        result.append(subJobs.size());
-        result.append(" Objects");
-
-        return result.toString();
-    }
-}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/UseComputedSizesObjectJob.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/job/UseComputedSizesObjectJob.java	Thu Feb 20 14:43:20 2014 +0100
@@ -37,11 +37,9 @@
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
 import com.oracle.javafx.scenebuilder.kit.metadata.Metadata;
 import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata;
-import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
 import java.util.ArrayList;
 import java.util.List;
-import javafx.scene.Parent;
 import javafx.scene.image.ImageView;
 import javafx.scene.layout.AnchorPane;
 import javafx.scene.layout.ColumnConstraints;
@@ -54,7 +52,7 @@
 public class UseComputedSizesObjectJob extends Job {
 
     private final FXOMInstance fxomInstance;
-    private final List<ModifyObjectJob> subJobs = new ArrayList<>();
+    private final List<BatchModifyObjectJob> subJobs = new ArrayList<>();
     private String description; // final but initialized lazily
 
     public UseComputedSizesObjectJob(FXOMInstance fxomInstance, EditorController editorController) {
@@ -77,7 +75,7 @@
         final FXOMDocument fxomDocument
                 = getEditorController().getFxomDocument();
         fxomDocument.beginUpdate();
-        for (ModifyObjectJob subJob : subJobs) {
+        for (BatchModifyObjectJob subJob : subJobs) {
             subJob.execute();
         }
         fxomDocument.endUpdate();
@@ -99,7 +97,7 @@
         final FXOMDocument fxomDocument
                 = getEditorController().getFxomDocument();
         fxomDocument.beginUpdate();
-        for (ModifyObjectJob subJob : subJobs) {
+        for (BatchModifyObjectJob subJob : subJobs) {
             subJob.redo();
         }
         fxomDocument.endUpdate();
@@ -145,8 +143,8 @@
         }
     }
 
-    private List<ModifyObjectJob> removeAnchorsJobs() {
-        final List<ModifyObjectJob> result = new ArrayList<>();
+    private List<BatchModifyObjectJob> removeAnchorsJobs() {
+        final List<BatchModifyObjectJob> result = new ArrayList<>();
         final FXOMObject parentObject = fxomInstance.getParentObject();
 
         if (parentObject != null && parentObject.getSceneGraphObject() instanceof AnchorPane) {
@@ -167,7 +165,7 @@
                 topAnchorVPM, rightAnchorVPM, bottomAnchorVPM, leftAnchorVPM}) {
 
                 if (vpm.getValueObject(fxomInstance) != null) {
-                    final ModifyObjectJob subJob = new ModifyObjectJob(
+                    final BatchModifyObjectJob subJob = new BatchModifyObjectJob(
                             fxomInstance, vpm, null, getEditorController());
                     result.add(subJob);
                 }
@@ -176,8 +174,8 @@
         return result;
     }
 
-    private List<ModifyObjectJob> modifyHeightJobs(final FXOMInstance candidate) {
-        final List<ModifyObjectJob> result = new ArrayList<>();
+    private List<BatchModifyObjectJob> modifyHeightJobs(final FXOMInstance candidate) {
+        final List<BatchModifyObjectJob> result = new ArrayList<>();
 
         final PropertyName maxHeight = new PropertyName("maxHeight");
         final PropertyName minHeight = new PropertyName("minHeight");
@@ -190,11 +188,11 @@
         final ValuePropertyMetadata prefHeightVPM
                 = Metadata.getMetadata().queryValueProperty(candidate, prefHeight);
 
-        final ModifyObjectJob maxHeightJob = new ModifyObjectJob(
+        final BatchModifyObjectJob maxHeightJob = new BatchModifyObjectJob(
                 candidate, maxHeightVPM, -1.0, getEditorController());
-        final ModifyObjectJob minHeightJob = new ModifyObjectJob(
+        final BatchModifyObjectJob minHeightJob = new BatchModifyObjectJob(
                 candidate, minHeightVPM, -1.0, getEditorController());
-        final ModifyObjectJob prefHeightJob = new ModifyObjectJob(
+        final BatchModifyObjectJob prefHeightJob = new BatchModifyObjectJob(
                 candidate, prefHeightVPM, -1.0, getEditorController());
 
         if (maxHeightJob.isExecutable()) {
@@ -209,8 +207,8 @@
         return result;
     }
 
-    private List<ModifyObjectJob> modifyWidthJobs(final FXOMInstance candidate) {
-        final List<ModifyObjectJob> result = new ArrayList<>();
+    private List<BatchModifyObjectJob> modifyWidthJobs(final FXOMInstance candidate) {
+        final List<BatchModifyObjectJob> result = new ArrayList<>();
 
         final PropertyName maxWidth = new PropertyName("maxWidth");
         final PropertyName minWidth = new PropertyName("minWidth");
@@ -223,11 +221,11 @@
         final ValuePropertyMetadata prefWidthVPM
                 = Metadata.getMetadata().queryValueProperty(candidate, prefWidth);
 
-        final ModifyObjectJob maxWidthJob = new ModifyObjectJob(
+        final BatchModifyObjectJob maxWidthJob = new BatchModifyObjectJob(
                 candidate, maxWidthVPM, -1.0, getEditorController());
-        final ModifyObjectJob minWidthJob = new ModifyObjectJob(
+        final BatchModifyObjectJob minWidthJob = new BatchModifyObjectJob(
                 candidate, minWidthVPM, -1.0, getEditorController());
-        final ModifyObjectJob prefWidthJob = new ModifyObjectJob(
+        final BatchModifyObjectJob prefWidthJob = new BatchModifyObjectJob(
                 candidate, prefWidthVPM, -1.0, getEditorController());
 
         if (maxWidthJob.isExecutable()) {
@@ -242,13 +240,13 @@
         return result;
     }
 
-    private List<ModifyObjectJob> modifyFitHeightJob(final FXOMInstance candidate) {
-        final List<ModifyObjectJob> result = new ArrayList<>();
+    private List<BatchModifyObjectJob> modifyFitHeightJob(final FXOMInstance candidate) {
+        final List<BatchModifyObjectJob> result = new ArrayList<>();
 
         final PropertyName fitHeight = new PropertyName("fitHeight");
         final ValuePropertyMetadata fitHeightVPM
                 = Metadata.getMetadata().queryValueProperty(candidate, fitHeight);
-        final ModifyObjectJob fitHeightJob = new ModifyObjectJob(
+        final BatchModifyObjectJob fitHeightJob = new BatchModifyObjectJob(
                 candidate, fitHeightVPM, 0.0, getEditorController());
 
         if (fitHeightJob.isExecutable()) {
@@ -257,13 +255,13 @@
         return result;
     }
 
-    private List<ModifyObjectJob> modifyFitWidthJob(final FXOMInstance candidate) {
-        final List<ModifyObjectJob> result = new ArrayList<>();
+    private List<BatchModifyObjectJob> modifyFitWidthJob(final FXOMInstance candidate) {
+        final List<BatchModifyObjectJob> result = new ArrayList<>();
 
         final PropertyName fitWidth = new PropertyName("fitWidth");
         final ValuePropertyMetadata fitWidthVPM
                 = Metadata.getMetadata().queryValueProperty(candidate, fitWidth);
-        final ModifyObjectJob fitWidthJob = new ModifyObjectJob(
+        final BatchModifyObjectJob fitWidthJob = new BatchModifyObjectJob(
                 candidate, fitWidthVPM, 0.0, getEditorController());
 
         if (fitWidthJob.isExecutable()) {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/messagelog/MessageLog.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/messagelog/MessageLog.java	Thu Feb 20 14:43:20 2014 +0100
@@ -51,7 +51,7 @@
     private final SimpleIntegerProperty revision = new SimpleIntegerProperty();
     private final SimpleIntegerProperty numOfWarningMessages = new SimpleIntegerProperty();
     private final static String TIMESTAMP_PATTERN = "h:mm a EEEEEEEEE d MMM. yyyy"; //NOI18N
-    private final static SimpleDateFormat TIMESTAMP_DATE_FORMAT = new SimpleDateFormat(TIMESTAMP_PATTERN);
+    private static SimpleDateFormat TIMESTAMP_DATE_FORMAT;
     
     
     /*
@@ -129,6 +129,10 @@
      */
     
     private synchronized String getTimeStamp() {
+        // We create TIMESTAMP_DATE_FORMAT lazily because it seems to be slow
+        if (TIMESTAMP_DATE_FORMAT == null) {
+            TIMESTAMP_DATE_FORMAT = new SimpleDateFormat(TIMESTAMP_PATTERN);
+        }
         return TIMESTAMP_DATE_FORMAT.format(new Date());
     }
     
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/ContentPanelController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/ContentPanelController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -926,9 +926,9 @@
     private void setupEventTracingFilter() {
         if (glassLayer != null) {
             if (tracingEvents) {
-                glassLayer.addEventFilter(InputEvent.ANY, eventTracingFiler);
+                glassLayer.addEventFilter(InputEvent.ANY, eventTracingFilter);
             } else {
-                glassLayer.removeEventFilter(InputEvent.ANY, eventTracingFiler);
+                glassLayer.removeEventFilter(InputEvent.ANY, eventTracingFilter);
             }
         }
     }
@@ -949,7 +949,7 @@
         System.out.println(sb.toString());
     }
     
-    private final EventHandler<Event> eventTracingFiler
+    private final EventHandler<Event> eventTracingFilter
             = new EventHandler<Event>() {
         @Override
         public void handle(Event e) {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/key/AbstractKeyGesture.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/key/AbstractKeyGesture.java	Thu Feb 20 14:43:20 2014 +0100
@@ -89,8 +89,11 @@
             public void handle(KeyEvent e) {
                 if (e.getCode() == firstKeyPressedEvent.getCode()) {
                     lastKeyEvent = e;
-                    keyPressed();
-                    e.consume();
+                    try {
+                        keyPressed();
+                    } finally {
+                        e.consume();
+                    }
                 }
             }
         });
@@ -99,9 +102,12 @@
             public void handle(KeyEvent e) {
                 if (e.getCode() == firstKeyPressedEvent.getCode()) {
                     lastKeyEvent = e;
-                    keyReleased();
-                    performTermination();
-                    e.consume();
+                    try {
+                        keyReleased();
+                    } finally {
+                        performTermination();
+                        e.consume();
+                    }
                 }
             }
         });
@@ -110,7 +116,13 @@
         this.firstKeyPressedEvent = (KeyEvent)e;
         this.lastKeyEvent = this.firstKeyPressedEvent;
         this.observer = observer;
-        keyPressed();
+        
+        try {
+            keyPressed();
+        } catch(RuntimeException x) {
+            performTermination();
+            throw x;
+        }
     }
     
     
@@ -123,11 +135,13 @@
         glassLayer.setOnKeyPressed(null);
         glassLayer.setOnKeyReleased(null);
         
-        observer.gestureDidTerminate(this);
-        observer = null;
-        
-        firstKeyPressedEvent = null;
-        lastKeyEvent = null;
+        try {
+            observer.gestureDidTerminate(this);
+        } finally {
+            observer = null;
+            firstKeyPressedEvent = null;
+            lastKeyEvent = null;
+        }
     }
     
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/mouse/AbstractMouseDragGesture.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/mouse/AbstractMouseDragGesture.java	Thu Feb 20 14:43:20 2014 +0100
@@ -36,7 +36,6 @@
 import javafx.event.EventHandler;
 import javafx.scene.Node;
 import javafx.scene.input.InputEvent;
-import javafx.scene.input.KeyEvent;
 import javafx.scene.input.MouseEvent;
 
 /**
@@ -81,26 +80,40 @@
         eventTarget.setOnDragDetected(new EventHandler<MouseEvent>() {
             @Override
             public void handle(MouseEvent e) {
-                mouseDragDetected(e);
-                performTermination();
+                try {
+                    mouseDragDetected(e);
+                } finally {
+                    performTermination();
+                }
             }
         });
         eventTarget.setOnMouseReleased(new EventHandler<MouseEvent>() {
             @Override
             public void handle(MouseEvent e) {
-                mouseReleased(e);
-                performTermination();
+                try {
+                    mouseReleased(e);
+                } finally {
+                    performTermination();
+                }
             }
         });
         eventTarget.setOnMouseExited(new EventHandler<MouseEvent>() {
             @Override
             public void handle(MouseEvent e) {
-                mouseExited(e);
-                performTermination();
+                try {
+                    mouseExited(e);
+                } finally {
+                    performTermination();
+                }
             }
         });
         
-        mousePressed((MouseEvent) e);
+        try {
+            mousePressed((MouseEvent) e);
+        } catch(RuntimeException x) {
+            performTermination();
+            throw x;
+        }
     }
     
     
@@ -113,9 +126,12 @@
         eventTarget.setOnMouseReleased(null);
         eventTarget.setOnMouseExited(null);
         
-        observer.gestureDidTerminate(this);
-        observer = null;
-        eventTarget = null;
+        try {
+            observer.gestureDidTerminate(this);
+        } finally {
+            observer = null;
+            eventTarget = null;
+        }
     }
     
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/mouse/AbstractMouseGesture.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/gesture/mouse/AbstractMouseGesture.java	Thu Feb 20 14:43:20 2014 +0100
@@ -121,12 +121,18 @@
             @Override
             public void handle(MouseEvent e) {
                 lastMouseEvent = e;
-                if (mouseDidDrag) {
-                    mouseDragEnded();
-                    glassLayer.setOnMouseDragged(null);
+                try {
+                    if (mouseDidDrag) {
+                        try {
+                            mouseDragEnded();
+                        } finally {
+                            glassLayer.setOnMouseDragged(null);
+                        }
+                    }
+                    mouseReleased();
+                } finally {
+                    performTermination();
                 }
-                mouseReleased();
-                performTermination();
             }
         });
         glassLayer.setOnKeyPressed(new EventHandler<KeyEvent>() {
@@ -146,7 +152,13 @@
         this.mousePressedEvent = (MouseEvent)e;
         this.lastMouseEvent = mousePressedEvent;
         this.observer = observer;
-        mousePressed();
+        
+        try {
+            mousePressed();
+        } catch(RuntimeException x) {
+            performTermination();
+            throw x;
+        }
     }
     
     
@@ -179,11 +191,13 @@
         glassLayer.setOnKeyPressed(null);
         glassLayer.setOnKeyReleased(null);
         
-        observer.gestureDidTerminate(this);
-        observer = null;
-        
-        mousePressedEvent = null;
-        lastMouseEvent = null;
-        mouseDidDrag = false;
+        try {
+            observer.gestureDidTerminate(this);
+        } finally {
+            observer = null;
+            mousePressedEvent = null;
+            lastMouseEvent = null;
+            mouseDidDrag = false;
+        }
     }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/mode/EditModeController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/mode/EditModeController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -36,7 +36,7 @@
 import com.oracle.javafx.scenebuilder.kit.editor.drag.target.AbstractDropTarget;
 import com.oracle.javafx.scenebuilder.kit.editor.drag.target.GridPaneDropTarget;
 import com.oracle.javafx.scenebuilder.kit.editor.drag.target.RootDropTarget;
-import com.oracle.javafx.scenebuilder.kit.editor.job.ModifyObjectJob;
+import com.oracle.javafx.scenebuilder.kit.editor.job.BatchModifyObjectJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.RelocateSelectionJob;
 import com.oracle.javafx.scenebuilder.kit.editor.messagelog.MessageLog;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.content.AbstractDecoration;
@@ -846,8 +846,8 @@
                 = Metadata.getMetadata().queryValueProperty(inlineEditedObject, propertyName);
         final EditorController editorController
                 = contentPanelController.getEditorController();
-        final ModifyObjectJob job
-                = new ModifyObjectJob(inlineEditedObject, vpm, newValue, editorController);
+        final BatchModifyObjectJob job
+                = new BatchModifyObjectJob(inlineEditedObject, vpm, newValue, editorController);
         
         if (job.isExecutable()) {
             editorController.getJobManager().push(job);
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/mode/PickModeController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/mode/PickModeController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -33,6 +33,7 @@
 
 import com.oracle.javafx.scenebuilder.kit.editor.images.ImageUtils;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.content.ContentPanelController;
+import com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.AbstractDriver;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.pring.AbstractPring;
 import com.oracle.javafx.scenebuilder.kit.editor.selection.ObjectSelectionGroup;
 import com.oracle.javafx.scenebuilder.kit.editor.selection.Selection;
@@ -217,7 +218,34 @@
         
         assert hitItem != null;
         
-        result = new HitNodeChrome(contentPanelController, hitItem, hitPoint);
+        /*
+         * In some cases, we cannot make a chrome for some hitItem
+         * 
+         *  MenuButton          <= OK
+         *      CustomMenuItem  <= KO because MenuItem are not displayable (case #1)
+         *          CheckBox    <= KO because this CheckBox is in a separate scene (Case #2)
+         */
+        
+        final AbstractDriver driver = contentPanelController.lookupDriver(hitItem);
+        if (driver == null) {
+            // Case #1 above
+            result = null;
+        } else {
+            final FXOMObject closestNodeObject = hitItem.getClosestNode();
+            if (closestNodeObject == null) {
+                // Document content is not displayable in content panel
+                result = null;
+            } else {
+                assert closestNodeObject.getSceneGraphObject() instanceof Node;
+                final Node closestNode = (Node)closestNodeObject.getSceneGraphObject();
+                if (closestNode.getScene() == contentPanelController.getPanelRoot().getScene()) {
+                    result = new HitNodeChrome(contentPanelController, hitItem, hitPoint);
+                } else {
+                    // Case #2 above
+                    result = null;
+                }
+            }
+        }
         
         return result;
     }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/Picker.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/Picker.java	Thu Feb 20 14:43:20 2014 +0100
@@ -89,7 +89,7 @@
 
     private void performPick(Node startNode, double localX, double localY) {
 
-        if (excludes.contains(startNode) == false) {
+        if ((excludes.contains(startNode) == false) && startNode.isVisible()){
             if (startNode.getLayoutBounds().contains(localX, localY)) {
                 matches.add(0, startNode);
             }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -79,6 +79,7 @@
 import javafx.event.EventHandler;
 import javafx.fxml.FXML;
 import javafx.geometry.Orientation;
+import javafx.geometry.Point2D;
 import javafx.geometry.Pos;
 import javafx.geometry.VPos;
 import javafx.scene.Node;
@@ -315,6 +316,9 @@
                     refresh();
                     // Switch to pick mode
                     editorController.setPickModeEnabled(true);
+//                    // Select the sub node
+//                            selection = editorController.getSelection();
+//                            selection.select(getFXOMInstance(selection), Point2D.ZERO);
                 }
             }
         };
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/css/SelectionPath.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/css/SelectionPath.java	Thu Feb 20 14:43:20 2014 +0100
@@ -192,7 +192,11 @@
         private Button pathButton = new Button();
 
         private ChildButton(List<Item> children, final List<Item> childrenPath, final Item selectedChild) {
-            pathButton.setPrefSize(17.0, 17.0);
+            
+            Region pathButtonGraphic = new Region();
+            pathButtonGraphic.getStyleClass().add("styleable-path-button-shape");//NOI18N
+            pathButton.setGraphic(pathButtonGraphic);
+            
             getChildren().add(pathButton);
             final ContextMenu menu = new ContextMenu();
             for (final Item c : children) {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/AbstractHierarchyPanelController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/AbstractHierarchyPanelController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -1035,12 +1035,7 @@
             if (selection.getGroup() instanceof ObjectSelectionGroup) {
                 // A set of regular component (ie fxom objects) are selected
                 final ObjectSelectionGroup osg = (ObjectSelectionGroup) selection.getGroup();
-                // Abort dragging root 
-                final FXOMObject rootObject = getEditorController().getFxomDocument().getFxomRoot();
-                assert rootObject != null; // Because of (1)
-                if (selection.isSelected(rootObject)) {
-                    return;
-                }
+                
                 // Abort dragging an empty place holder
                 for (TreeItem<HierarchyItem> selectedTreeItem : selectedTreeItems) {
                     final HierarchyItem item = selectedTreeItem.getValue();
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/HierarchyDNDController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/HierarchyDNDController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -50,7 +50,6 @@
  * not depend on the TreeView or TreeTableView control and handles only
  * TreeItems.
  *
- * p
  * @treatAsPrivate
  */
 public class HierarchyDNDController {
@@ -61,6 +60,7 @@
     /**
      * Defines the mouse location within the cell when the dropping gesture
      * occurs.
+     *
      * @treatAsPrivate
      */
     public enum DroppingMouseLocation {
@@ -320,10 +320,22 @@
                             dropTargetObject = item.getFxomObject();
                             targetIndex = -1; // Insert at last position
                         } else {
+                            // If the parent accepts sub components,
+                            // this is a reordering gesture and the target is the parent
+                            final DragController dragController
+                                    = panelController.getEditorController().getDragController();
+                            final AbstractDragSource dragSource = dragController.getDragSource();
                             final TreeItem<HierarchyItem> parentTreeItem = treeItem.getParent();
                             assert parentTreeItem != null; // Because of (2)
-                            dropTargetObject = parentTreeItem.getValue().getFxomObject();
-                            targetIndex = item.getFxomObject().getIndexInParentProperty();
+                            final FXOMObject parentObject = parentTreeItem.getValue().getFxomObject();
+                            final DesignHierarchyMask parentMask = new DesignHierarchyMask(parentObject);
+                            if (parentMask.isAcceptingSubComponent(dragSource.getDraggedObjects())) {
+                                dropTargetObject = parentTreeItem.getValue().getFxomObject();
+                                targetIndex = item.getFxomObject().getIndexInParentProperty();
+                            } // Otherwise, attempt to set an accessory on the current TreeItem
+                            else {
+                                dropTargetObject = item.getFxomObject();
+                            }
                         }
                         break;
 
@@ -335,10 +347,22 @@
                             targetIndex = 0; // Insert at first position
                         } else {
                             if (treeItem.isLeaf() || !treeItem.isExpanded()) {
+                                // If the parent accepts sub components,
+                                // this is a reordering gesture and the target is the parent
+                                final DragController dragController
+                                        = panelController.getEditorController().getDragController();
+                                final AbstractDragSource dragSource = dragController.getDragSource();
                                 final TreeItem<HierarchyItem> parentTreeItem = treeItem.getParent();
                                 assert parentTreeItem != null; // Because of (3)
-                                dropTargetObject = parentTreeItem.getValue().getFxomObject();
-                                targetIndex = item.getFxomObject().getIndexInParentProperty() + 1;
+                                final FXOMObject parentObject = parentTreeItem.getValue().getFxomObject();
+                                final DesignHierarchyMask parentMask = new DesignHierarchyMask(parentObject);
+                                if (parentMask.isAcceptingSubComponent(dragSource.getDraggedObjects())) {
+                                    dropTargetObject = parentTreeItem.getValue().getFxomObject();
+                                    targetIndex = item.getFxomObject().getIndexInParentProperty() + 1;
+                                } // Otherwise, attempt to set an accessory on the current TreeItem
+                                else {
+                                    dropTargetObject = item.getFxomObject();
+                                }
                             } else {
                                 dropTargetObject = item.getFxomObject();
                                 targetIndex = 0; // Insert at first position
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeCell.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeCell.java	Thu Feb 20 14:43:20 2014 +0100
@@ -38,8 +38,8 @@
 import com.oracle.javafx.scenebuilder.kit.editor.drag.target.ContainerZDropTarget;
 import com.oracle.javafx.scenebuilder.kit.editor.drag.target.RootDropTarget;
 import com.oracle.javafx.scenebuilder.kit.editor.images.ImageUtils;
-import com.oracle.javafx.scenebuilder.kit.editor.job.ModifyFxIdJob;
-import com.oracle.javafx.scenebuilder.kit.editor.job.ModifyObjectJob;
+import com.oracle.javafx.scenebuilder.kit.editor.job.BatchModifyFxIdJob;
+import com.oracle.javafx.scenebuilder.kit.editor.job.BatchModifyObjectJob;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.HierarchyDNDController;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.HierarchyItem;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.AbstractHierarchyPanelController;
@@ -52,6 +52,7 @@
 import com.oracle.javafx.scenebuilder.kit.editor.util.InlineEditController.Type;
 import com.oracle.javafx.scenebuilder.kit.editor.report.ErrorReport;
 import com.oracle.javafx.scenebuilder.kit.editor.report.ErrorReportEntry;
+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.FXOMObject;
@@ -63,6 +64,7 @@
 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
 import java.net.URL;
 import java.util.List;
+import java.util.Set;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.beans.value.WeakChangeListener;
@@ -335,14 +337,20 @@
                         } else {
                             final HierarchyItem item = treeItem.getValue();
                             assert item != null;
-                            final TreeItem<HierarchyItem> graphicTreeItem
-                                    = dndController.getEmptyGraphicTreeItemFor(treeItem);
 
                             if (item.isPlaceHolder()) {
                                 cell = HierarchyTreeCell.this;
-                            } else if (graphicTreeItem != null) {
-                                assert accessoryDropTarget.getAccessory() == Accessory.GRAPHIC;
-                                cell = HierarchyTreeViewUtils.getTreeCell(getTreeView(), graphicTreeItem);
+                            } else if (accessoryDropTarget.getAccessory() == Accessory.GRAPHIC) {
+                                // Check if an empty graphic TreeItem has been added
+                                final TreeItem<HierarchyItem> graphicTreeItem
+                                        = dndController.getEmptyGraphicTreeItemFor(treeItem);
+                                if (graphicTreeItem != null) {
+                                    cell = HierarchyTreeViewUtils.getTreeCell(getTreeView(), graphicTreeItem);
+                                } else {
+                                    final TreeItem<HierarchyItem> accessoryOwnerTreeItem
+                                            = panelController.lookupTreeItem(dropTargetObject);
+                                    cell = HierarchyTreeViewUtils.getTreeCell(getTreeView(), accessoryOwnerTreeItem);
+                                }
                             } else {
                                 final TreeItem<HierarchyItem> accessoryOwnerTreeItem
                                         = panelController.lookupTreeItem(dropTargetObject);
@@ -390,7 +398,7 @@
                             final HierarchyItem item = treeItem.getValue();
                             assert item != null;
 
-                            if (item.isPlaceHolder()) {
+                            if (item.isPlaceHolder() || item.getFxomObject() == dropTargetObject) {
                                 // The place holder item is filled with a container
                                 // accepting sub components
                                 final Border border = panelController.getBorder(BorderSide.TOP_RIGHT_BOTTOM_LEFT);
@@ -665,7 +673,6 @@
 
             @Override
             public Boolean call(String newValue) {
-                // TODO fix DTL-5881 : Inline editing must handle not valid input value
                 // 1) Check the input value is valid
                 // 2) If valid, commit the new value and return true
                 // 3) Otherwise, return false
@@ -684,8 +691,8 @@
                                 assert propertyName != null;
                                 final ValuePropertyMetadata vpm
                                         = Metadata.getMetadata().queryValueProperty(fxomInstance, propertyName);
-                                final ModifyObjectJob job
-                                        = new ModifyObjectJob(fxomInstance, vpm, newValue, editorController);
+                                final BatchModifyObjectJob job
+                                        = new BatchModifyObjectJob(fxomInstance, vpm, newValue, editorController);
                                 if (job.isExecutable()) {
                                     editorController.getJobManager().push(job);
                                 }
@@ -694,10 +701,9 @@
                         case FXID:
                             assert newValue != null;
                             final String fxId = newValue.isEmpty() ? null : newValue;
-                            final ModifyFxIdJob job
-                                    = new ModifyFxIdJob(fxomObject, fxId, editorController);
+                            final BatchModifyFxIdJob job
+                                    = new BatchModifyFxIdJob(fxomObject, fxId, editorController);
                             if (job.isExecutable()) {
-                                editorController.getJobManager().push(job);
 
                                 // If a controller class has been defined, 
                                 // check if the fx id is an injectable field
@@ -714,6 +720,17 @@
                                                 "log.warning.no.injectable.fxid", fxId);
                                     }
                                 }
+
+                                // Check duplicared fx ids
+                                final FXOMDocument fxomDocument = editorController.getFxomDocument();
+                                final Set<String> fxIds = fxomDocument.collectFxIds().keySet();
+                                if (fxIds.contains(fxId)) {
+                                    editorController.getMessageLog().logWarningMessage(
+                                            "log.warning.duplicate.fxid", fxId);
+                                }
+                                
+                                editorController.getJobManager().push(job);
+
                             } else if (fxId != null) {
                                 editorController.getMessageLog().logWarningMessage(
                                         "log.warning.invalid.fxid", fxId);
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/Inspector.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/Inspector.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -76,7 +76,7 @@
 <children>
     <Accordion fx:id="accordion" VBox.vgrow="ALWAYS">
       <panes>
-        <TitledPane fx:id="propertiesTitledPane" animated="true" contentDisplay="RIGHT" text="Properties">
+        <TitledPane fx:id="propertiesTitledPane" animated="true" contentDisplay="RIGHT" graphicTextGap="0.0" text="Properties">
           <content>
             <ScrollPane fx:id="propertiesScroll" fitToWidth="true" prefViewportHeight="320.0" prefViewportWidth="251.0">
               <content>
@@ -113,10 +113,10 @@
             </ScrollPane>
           </content>
           <graphic>
-            <Label text=": &lt;className&gt;" />
+            <Label styleClass="secondary-section-title" text=": &lt;className&gt;" />
           </graphic>
         </TitledPane>
-        <TitledPane fx:id="layoutTitledPane" animated="true" contentDisplay="RIGHT" text="Layout">
+        <TitledPane fx:id="layoutTitledPane" animated="true" contentDisplay="RIGHT" graphicTextGap="0.0" text="Layout">
           <content>
             <ScrollPane fx:id="layoutScroll" fitToWidth="true" prefViewportHeight="320.0" prefViewportWidth="254.0">
               <content>
@@ -150,10 +150,10 @@
             </ScrollPane>
           </content>
           <graphic>
-            <Label text=": &lt;className&gt;" />
+            <Label styleClass="secondary-section-title" text=": &lt;className&gt;" />
           </graphic>
         </TitledPane>
-        <TitledPane fx:id="codeTitledPane" animated="true" contentDisplay="RIGHT" expanded="false" text="Code">
+        <TitledPane fx:id="codeTitledPane" animated="true" contentDisplay="RIGHT" expanded="false" graphicTextGap="0.0" text="Code">
           <content>
             <ScrollPane fx:id="codeScroll" fitToWidth="true" prefViewportHeight="320.0" prefViewportWidth="257.0">
               <content>
@@ -187,10 +187,10 @@
             </ScrollPane>
           </content>
           <graphic>
-            <Label text=": &lt;className&gt;" />
+            <Label styleClass="secondary-section-title" text=": &lt;className&gt;" />
           </graphic>
         </TitledPane>
-        <TitledPane fx:id="allTitledPane" animated="true" contentDisplay="RIGHT" expanded="true" text="&lt;all&gt;">
+        <TitledPane fx:id="allTitledPane" animated="true" contentDisplay="RIGHT" expanded="true" graphicTextGap="0.0" text="&lt;all&gt;">
           <content>
             <ScrollPane fx:id="allScroll" fitToWidth="true" prefViewportHeight="320.0" prefViewportWidth="260.0">
               <content>
@@ -218,7 +218,7 @@
             </ScrollPane>
           </content>
           <graphic>
-            <Label text=": &lt;className&gt;" />
+            <Label styleClass="secondary-section-title" text=": &lt;className&gt;" />
           </graphic>
         </TitledPane>
       </panes>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/InspectorPanelController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/InspectorPanelController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -34,9 +34,9 @@
 import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
 import com.oracle.javafx.scenebuilder.kit.editor.drag.source.AbstractDragSource;
 import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N;
+import com.oracle.javafx.scenebuilder.kit.editor.job.BatchModifyFxIdJob;
+import com.oracle.javafx.scenebuilder.kit.editor.job.BatchModifySelectionJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
-import com.oracle.javafx.scenebuilder.kit.editor.job.ModifyFxIdJob;
-import com.oracle.javafx.scenebuilder.kit.editor.job.ModifySelectionJob;
 import com.oracle.javafx.scenebuilder.kit.editor.job.togglegroup.ModifySelectionToggleGroupJob;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.AnchorPaneConstraintsEditor;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.BooleanEditor;
@@ -1205,13 +1205,13 @@
     }
 
     private void setSelectedFXOMInstances(ValuePropertyMetadata propMeta, Object value) {
-        final ModifySelectionJob job = new ModifySelectionJob(propMeta, value, getEditorController());
+        final BatchModifySelectionJob job = new BatchModifySelectionJob(propMeta, value, getEditorController());
 //        System.out.println(job.getDescription());
         pushJob(job);
     }
 
     private void setSelectedFXOMInstanceFxId(FXOMObject fxomObject, String fxId) {
-        final ModifyFxIdJob job = new ModifyFxIdJob(fxomObject, fxId, getEditorController());
+        final BatchModifyFxIdJob job = new BatchModifyFxIdJob(fxomObject, fxId, getEditorController());
         pushJob(job);
     }
 
@@ -1268,7 +1268,7 @@
             String instanceFxId = getSelectedInstance().getFxId();
             fxIdEditor.setDisable(false);
             fxIdEditor.setUpdateFromModel(true);
-            fxIdEditor.reset(getSuggestedFxIds(getControllerClass()));
+            fxIdEditor.reset(getSuggestedFxIds(getControllerClass()), getEditorController());
             fxIdEditor.setValue(instanceFxId);
             fxIdEditor.setUpdateFromModel(false);
         }
@@ -1302,9 +1302,9 @@
                 isIndeterminate = true;
             }
 
-            if (CssInternal.isCssRuled(instance.getSceneGraphObject(), propMeta)) {
+            cssInfo = CssInternal.getCssInfo(instance.getSceneGraphObject(), propMeta);
+            if (cssInfo != null) {
                 isRuledByCss = true;
-                cssInfo = CssInternal.getCssInfo(instance.getSceneGraphObject(), propMeta);
             }
         }
 
@@ -1713,9 +1713,9 @@
         } else if (editorClass == FxIdEditor.class) {
             String controllerClass = getControllerClass();
             if (propertyEditor != null) {
-                ((FxIdEditor) propertyEditor).reset(getSuggestedFxIds(controllerClass));
+                ((FxIdEditor) propertyEditor).reset(getSuggestedFxIds(controllerClass), getEditorController());
             } else {
-                propertyEditor = new FxIdEditor(getSuggestedFxIds(controllerClass));
+                propertyEditor = new FxIdEditor(getSuggestedFxIds(controllerClass), getEditorController());
             }
         } else if (editorClass == CursorEditor.class) {
             if (propertyEditor != null) {
@@ -1737,9 +1737,9 @@
             }
         } else if (editorClass == FontPopupEditor.class) {
             if (propertyEditor != null) {
-                ((FontPopupEditor) propertyEditor).reset(propMeta, selectedClasses);
+                ((FontPopupEditor) propertyEditor).reset(propMeta, selectedClasses, getEditorController());
             } else {
-                propertyEditor = new FontPopupEditor(propMeta, selectedClasses);
+                propertyEditor = new FontPopupEditor(propMeta, selectedClasses, getEditorController());
             }
         } else if (editorClass == PaintPopupEditor.class) {
             if (propertyEditor != null) {
@@ -1872,26 +1872,24 @@
     }
 
     private void updateClassNameInSectionTitles() {
-        StringBuilder classesBuilder = new StringBuilder();
-        for (Class<?> clazz : getSelectedClasses()) {
-            if (classesBuilder.length() > 0) {
-                classesBuilder.append(", "); //NOI18N
-            }
-            classesBuilder.append(clazz.getSimpleName());
+        String selClass = ""; //NOI18N
+        if (getSelectedClasses().size() > 1) {
+            selClass = I18N.getString("inspector.sectiontitle.multiple");
+        } else if (getSelectedClasses().size() == 1) {
+            selClass = getSelectedClass().getSimpleName();
         }
-        String classesStr = classesBuilder.toString();
+
         for (TitledPane titledPane : accordion.getPanes()) {
             Node graphic = titledPane.getGraphic();
             assert graphic instanceof Label;
             if (titledPane == allTitledPane) {
                 allTitledPane.setText(null);
-                ((Label) graphic).setText(classesStr);
             } else {
-                if (!classesStr.isEmpty() && !classesStr.startsWith(":")) { //NOI18N
-                    classesStr = ": " + classesStr; //NOI18N
+                if (!selClass.isEmpty() && !selClass.startsWith(" :")) { //NOI18N
+                    selClass = " : " + selClass; //NOI18N
                 }
-                ((Label) graphic).setText(classesStr); //NOI18N
             }
+            ((Label) graphic).setText(selClass);
         }
     }
 
@@ -1913,7 +1911,15 @@
         if (getEditorController().getFxomDocument() != null) {
             location = getEditorController().getFxomDocument().getLocation();
         }
-        return glossary.queryFxIds(location, controllerClass, getSelectedClass());
+        List<String> fxIds = glossary.queryFxIds(location, controllerClass, getSelectedClass());
+        // Remove the already used FxIds
+        fxIds.removeAll(getFxIdsInUse());
+        return fxIds;
+    }
+
+    private List<String> getFxIdsInUse() {
+        FXOMIndex fxomIndex = new FXOMIndex(getEditorController().getFxomDocument());
+        return new ArrayList<>(fxomIndex.getFxIds().keySet());
     }
 
     private List<String> getSuggestedEventHandlers(String controllerClass) {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/AutoSuggestEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/AutoSuggestEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -166,7 +166,11 @@
 
     @Override
     public Object getValue() {
-        return entryField.getText();
+        String value = entryField.getText();
+        if (value == null) {
+            return null;
+        }
+        return EditorUtils.getPlainString(value);
     }
 
     @Override
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/ControllerClassEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/ControllerClassEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -31,6 +31,7 @@
  */
 package com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors;
 
+import com.oracle.javafx.scenebuilder.kit.util.JavaLanguage;
 import java.util.List;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
@@ -43,7 +44,7 @@
 public class ControllerClassEditor extends AutoSuggestEditor {
 
     private static final String PROPERTY_NAME = "Controller class";
-    private static final String DEFAULT_VALUE = "";
+    private static final String DEFAULT_VALUE = null;
 
     @SuppressWarnings("LeakingThisInConstructor")
     public ControllerClassEditor(List<String> suggestedClasses) {
@@ -54,7 +55,15 @@
             @Override
             public void handle(ActionEvent event) {
                 String value = textField.getText();
-                userUpdateValueProperty(value);
+                
+                if (value != null && !value.isEmpty()) {
+                    if (!JavaLanguage.isIdentifier(value)) {
+                        handleInvalidValue(value);
+                        return;
+                    }
+                }
+                
+                userUpdateValueProperty((value == null || value.isEmpty()) ? null : value);
                 textField.selectAll();
             }
         };
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/DoubleAutoSuggestEditor.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/DoubleAutoSuggestEditor.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -43,11 +43,11 @@
 <children>
     <DoubleField fx:id="doubleField" onKeyReleased="#textFieldKeyReleased" onMouseClicked="#textFieldMouseClicked">
       <contextMenu>
-        <ContextMenu maxHeight="-1.0">
+        <ContextMenu maxHeight="-1.0" styleClass="auto-suggest-popup">
           <items>
             <CustomMenuItem mnemonicParsing="false">
               <content>
-                <ListView fx:id="suggestedLv" maxHeight="-1.0" minHeight="-1.0" onKeyPressed="#suggestedLvKeyPressed" onMousePressed="#suggestedLvMousePressed" prefHeight="82.0" prefWidth="150.0" style="" styleClass="suggested-list" />
+                <ListView fx:id="suggestedLv" maxHeight="-1.0" minHeight="-1.0" onKeyPressed="#suggestedLvKeyPressed" onMousePressed="#suggestedLvMousePressed" prefHeight="92.0" prefWidth="170.0" />
               </content>
             </CustomMenuItem>
           </items>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/EditorUtils.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/EditorUtils.java	Thu Feb 20 14:43:20 2014 +0100
@@ -525,4 +525,9 @@
         return url;
     }
 
+    public static String getPlainString(String str) {
+        // Using PrefixedValue PLAIN_STRING allow to consider special characters (such as @, %,...)
+        // as "standard" characters (i.e. to backslash them)
+        return new PrefixedValue(PrefixedValue.Type.PLAIN_STRING, str).toString();
+    }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/FxIdEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/FxIdEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -31,8 +31,10 @@
  */
 package com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors;
 
-import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N;
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMIndex;
 import com.oracle.javafx.scenebuilder.kit.util.JavaLanguage;
+import java.util.ArrayList;
 import java.util.List;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
@@ -40,32 +42,44 @@
 /**
  * fx:id editor.
  *
- * 
+ *
  */
 public class FxIdEditor extends AutoSuggestEditor {
+
     private static final String PROPERTY_NAME = "fx:id";
-    private static final String DEFAULT_VALUE = "";
+    private static final String DEFAULT_VALUE = null;
+    private EditorController editorController;
 
     @SuppressWarnings("LeakingThisInConstructor")
-    public FxIdEditor(List<String> suggestedFxIds) {
+    public FxIdEditor(List<String> suggestedFxIds, EditorController editorController) {
         super(PROPERTY_NAME, DEFAULT_VALUE, suggestedFxIds); //NOI18N
+        this.editorController = editorController;
 
         // text field events handling
         EventHandler<ActionEvent> onActionListener = new EventHandler<ActionEvent>() {
             @Override
             public void handle(ActionEvent event) {
-               if (isHandlingError()) {
+                if (isHandlingError()) {
                     // Event received because of focus lost due to error dialog
                     return;
                 }
                 String value = textField.getText();
                 if (value != null && !value.isEmpty()) {
-                    
                     if (!JavaLanguage.isIdentifier(value)) {
-                        System.err.println(I18N.getString("inspector.fxml.invalid.id", value));
+//                        System.err.println(I18N.getString("log.warning.invalid.fxid", value));
                         handleInvalidValue(value);
                         return;
                     }
+                    if (isValueChanged(value)) {
+                        // Avoid multiple identical messages
+                        if (getFxIdsInUse().contains(value)) {
+                            editorController.getMessageLog().logWarningMessage(
+                                    "log.warning.duplicate.fxid", value); //NOI18N
+                        } else if ((getControllerClass() != null) && !getSuggestedList().contains(value)) {
+                            editorController.getMessageLog().logWarningMessage(
+                                    "log.warning.no.injectable.fxid", value); //NOI18N
+                        }
+                    }
                 }
                 userUpdateValueProperty((value == null || value.isEmpty()) ? null : value);
                 textField.selectAll();
@@ -73,8 +87,19 @@
         };
         setTextEditorBehavior(this, textField, onActionListener);
     }
-    
-    public void reset(List<String> suggestedFxIds) {
+
+    public void reset(List<String> suggestedFxIds, EditorController editorController) {
         reset(PROPERTY_NAME, DEFAULT_VALUE, suggestedFxIds);
+        this.editorController = editorController;
     }
+
+    private List<String> getFxIdsInUse() {
+        FXOMIndex fxomIndex = new FXOMIndex(editorController.getFxomDocument());
+        return new ArrayList<>(fxomIndex.getFxIds().keySet());
+    }
+
+    private String getControllerClass() {
+        return editorController.getFxomDocument().getFxomRoot().getFxController();
+    }
+
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/I18nStringEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/I18nStringEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -33,6 +33,7 @@
 
 import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N;
 import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PrefixedValue;
 import java.util.Set;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
@@ -87,7 +88,7 @@
             @Override
             public void handle(ActionEvent e) {
                 if (!i18nMode) {
-                    setValue(PERCENT_STR + I18N.getString("inspector.i18n.dummykey"));
+                    setValue(new PrefixedValue(PrefixedValue.Type.RESOURCE_KEY, I18N.getString("inspector.i18n.dummykey")).toString());
                 } else {
                     setValue(""); //NOI18N
                 }
@@ -113,7 +114,9 @@
     public Object getValue() {
         String val = textNode.getText();
         if (i18nMode) {
-            val = PERCENT_STR + val;
+            val = new PrefixedValue(PrefixedValue.Type.RESOURCE_KEY, val).toString();
+        } else {
+            val = EditorUtils.getPlainString(val);
         }
         return val;
     }
@@ -131,14 +134,15 @@
         }
         assert value instanceof String;
         String val = (String) value;
+        PrefixedValue prefixedValue = new PrefixedValue(val);
+        String suffix = prefixedValue.getSuffix();
 
         // Handle i18n
-        if (val.startsWith(PERCENT_STR)) {
+        if (prefixedValue.isResourceKey()) {
             if (!i18nMode) {
                 wrapInHBox();
                 i18nMode = true;
             }
-            val = val.substring(1);
         } else if (i18nMode) {
             // no percent + i18nMode
             unwrapHBox();
@@ -146,7 +150,7 @@
         }
 
         // Handle multi-line
-        if (containsLineFeed(val)) {
+        if (containsLineFeed(prefixedValue.toString())) {
             if (i18nMode) {
                 // multi-line + i18n ==> set as i18n only
                 multiLineMode = false;
@@ -165,7 +169,12 @@
             }
         }
 
-        textNode.setText(val);
+        if (i18nMode) {
+            textNode.setText(suffix);
+        } else {
+            // We may have other special characters (@, $, ...) to display in the text field
+            textNode.setText(prefixedValue.toString());
+        }
         updateMenuItems();
     }
 
@@ -199,7 +208,7 @@
         // Move the node from TextField to TextArea
         TextArea textArea = new TextArea(textNode.getText());
         setTextEditorBehavior(this, textArea, valueListener);
-        textArea.setPrefHeight(50);
+        textArea.setPrefRowCount(5);
         setLayoutFormat(LayoutFormat.SIMPLE_LINE_TOP);
         if (textNode.getParent() != null) {
             // textNode is already in scene graph
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/InlineListEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/InlineListEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -62,7 +62,7 @@
 
     @Override
     public void reset(ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses) {
-        reset(propMeta, selectedClasses, false);
+        reset(propMeta, selectedClasses, true);
     }
     
     public void reset(ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, boolean removeAll) {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/IntegerAutoSuggestEditor.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/IntegerAutoSuggestEditor.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -47,7 +47,7 @@
           <items>
             <CustomMenuItem mnemonicParsing="false">
               <content>
-                <ListView fx:id="suggestedLv" maxHeight="-1.0" minHeight="-1.0" onKeyPressed="#suggestedLvKeyPressed" onMousePressed="#suggestedLvMousePressed" prefHeight="82.0" prefWidth="150.0" style="" styleClass="suggested-list" />
+                <ListView fx:id="suggestedLv" maxHeight="-1.0" minHeight="-1.0" onKeyPressed="#suggestedLvKeyPressed" onMousePressed="#suggestedLvMousePressed" prefHeight="92.0" prefWidth="180.0" />
               </content>
             </CustomMenuItem>
           </items>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StringAutoSuggestEditor.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StringAutoSuggestEditor.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -42,11 +42,11 @@
 <children>
     <TextField fx:id="textField" onKeyReleased="#textFieldKeyReleased" onMouseClicked="#textFieldMouseClicked" prefWidth="-1.0">
       <contextMenu>
-        <ContextMenu maxHeight="-1.0">
+        <ContextMenu maxHeight="-1.0" styleClass="auto-suggest-popup">
           <items>
             <CustomMenuItem mnemonicParsing="false">
               <content>
-                <ListView fx:id="suggestedLv" maxHeight="-1.0" minHeight="-1.0" onKeyPressed="#suggestedLvKeyPressed" onMousePressed="#suggestedLvMousePressed" prefHeight="82.0" prefWidth="150.0" style="" styleClass="suggested-list" />
+                <ListView fx:id="suggestedLv" maxHeight="-1.0" minHeight="-1.0" onKeyPressed="#suggestedLvKeyPressed" onMousePressed="#suggestedLvMousePressed" prefHeight="92.0" prefWidth="180.0" />
               </content>
             </CustomMenuItem>
           </items>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StringEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StringEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -68,7 +68,7 @@
 
     @Override
     public Object getValue() {
-        return textField.getText();
+        return EditorUtils.getPlainString(textField.getText());
     }
 
     @Override
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StyleClassEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StyleClassEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -279,7 +279,6 @@
             // since we do not use the AutoSuggestEditor menu button for this editor.
             if (!suggestedList.isEmpty()) {
                 actionMb.getItems().add(new SeparatorMenuItem());
-                actionMb.getItems().add(new SeparatorMenuItem());
             }
             for (String className : suggestedList) {
                 MenuItem menuItem = new MenuItem(className);
@@ -304,13 +303,7 @@
 
         @Override
         public String getValue() {
-            String value;
-            if (styleClassTf.getText().isEmpty()) {
-                return "";
-            } else {
-                value = styleClassTf.getText().trim();
-            }
-            return value;
+            return EditorUtils.getPlainString(styleClassTf.getText()).trim();
         }
 
         @Override
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StyleEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/StyleEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -268,7 +268,7 @@
                     if (propertyTf.getText().isEmpty() && valueTf.getText().isEmpty()) {
                         remove(null);
                     }
-                    
+
                     updateButtons();
                     currentValue = getValue();
                 }
@@ -341,9 +341,11 @@
         public String getValue() {
             String value;
             if (propertyTf.getText().isEmpty() && valueTf.getText().isEmpty()) {
-                return "";
+                return ""; //NOI18N
             } else {
-                value = propertyTf.getText().trim() + ": " + valueTf.getText().trim() + ";"; //NOI18N
+                String propertyVal = EditorUtils.getPlainString(propertyTf.getText()).trim();
+                String valueVal = EditorUtils.getPlainString(valueTf.getText()).trim();
+                value = propertyVal + ": " + valueVal + ";"; //NOI18N
             }
 
             // Parse the style, and set the parsingError boolean if any error
@@ -366,14 +368,17 @@
                 style = style.substring(0, style.length() - 1);
             }
             // split in property and value
-            String[] styleItem = style.split(":"); //NOI18N
-            propertyTf.setText(styleItem[0].trim());
-            // If invalid style, we may have more than 2 styleItem
-            StringBuilder valueStr = new StringBuilder();
-            for (int ii = 1; ii < styleItem.length; ii++) {
-                valueStr.append(styleItem[ii]);
+            int dotIndex = style.indexOf(":");
+            String propertyStr;
+            String valueStr = ""; //NOI18N
+            if (dotIndex != -1) {
+                propertyStr = style.substring(0, dotIndex);
+                valueStr = style.substring(dotIndex + 1);
+            } else {
+                propertyStr = style;
             }
-            valueTf.setText(valueStr.toString().trim());
+            propertyTf.setText(propertyStr);
+            valueTf.setText(valueStr);
             updateButtons();
             currentValue = getValue();
         }
@@ -385,7 +390,7 @@
             propertyTf.setPromptText(null);
             valueTf.setPromptText(null);
         }
-        
+
         // Please findBugs
         @Override
         public void requestFocus() {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/ToggleGroupEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/ToggleGroupEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -65,7 +65,7 @@
                 if (value != null && !value.isEmpty()) {
 
                     if (!JavaLanguage.isIdentifier(value)) {
-                        System.err.println(I18N.getString("inspector.fxml.invalid.id", value));
+//                        System.err.println(I18N.getString("inspector.fxml.invalid.id", value));
                         handleInvalidValue(value);
                         return;
                     }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/EffectPopupEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/EffectPopupEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -60,9 +60,27 @@
             // Need to clone the root effect of the effect picker
             // in order to commit with a new value
             final Effect rootEffectClone = Utils.clone(rootEffect);
-            commitValue(rootEffectClone);
-            // Refresh MenuButton items if needed
-            updateMenuButton(rootEffectClone);
+            // If live update, do not commit the value
+            if (effectPicker.isLiveUpdate() == true) {
+                userUpdateTransientValueProperty(rootEffectClone);
+            } else {
+                commitValue(rootEffectClone);
+                updateMenuButton(rootEffectClone);
+            }
+        }
+    };
+
+    private final ChangeListener<Boolean> liveUpdateListener = new ChangeListener<Boolean>() {
+        @Override
+        public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+            if (effectPicker.isLiveUpdate() == false) {
+                final Effect rootEffect = effectPicker.getRootEffectProperty();
+                // Need to clone the root effect of the effect picker
+                // in order to commit with a new value
+                final Effect rootEffectClone = Utils.clone(rootEffect);
+                commitValue(rootEffectClone);
+                updateMenuButton(rootEffectClone);
+            }
         }
     };
 
@@ -76,6 +94,7 @@
     public void setPopupContentValue(Object value) {
         assert value == null || value instanceof Effect;
         effectPicker.revisionProperty().removeListener(effectRevisionChangeListener);
+        effectPicker.liveUpdateProperty().removeListener(liveUpdateListener);
         // We first clone the root effect and initializePopupContent the effect picker with the clone value :
         // then the clone value will be updated and passed back to the model
         final Effect rootEffectClone = Utils.clone((Effect) value);
@@ -83,6 +102,7 @@
         // Refresh MenuButton items if needed
         updateMenuButton(rootEffectClone);
         effectPicker.revisionProperty().addListener(effectRevisionChangeListener);
+        effectPicker.liveUpdateProperty().addListener(liveUpdateListener);
     }
 
     @Override
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/FontPopupEditor.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/FontPopupEditor.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -38,14 +38,14 @@
 
 <GridPane hgap="7.0" vgap="5.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <columnConstraints>
-    <ColumnConstraints halignment="RIGHT" hgrow="NEVER" maxWidth="90.0" minWidth="10.0" prefWidth="42.0" />
+    <ColumnConstraints halignment="RIGHT" hgrow="NEVER" />
     <ColumnConstraints hgrow="ALWAYS" />
   </columnConstraints>
   <rowConstraints>
-    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
-    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
-    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+    <RowConstraints valignment="CENTER" vgrow="SOMETIMES" />
+    <RowConstraints valignment="CENTER" vgrow="SOMETIMES" />
+    <RowConstraints valignment="CENTER" vgrow="SOMETIMES" />
   </rowConstraints>
-<children><Label text="Family" /><Label text="Style" GridPane.rowIndex="1" /><Label text="Size" GridPane.rowIndex="2" /><StackPane fx:id="familySp" prefHeight="150.0" prefWidth="200.0" GridPane.columnIndex="1" /><StackPane fx:id="styleSp" prefHeight="150.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" /><StackPane fx:id="sizeSp" prefHeight="150.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" />
+<children><Label text="Family" /><Label text="Style" GridPane.rowIndex="1" /><Label text="Size" GridPane.rowIndex="2" /><StackPane fx:id="familySp" prefWidth="200.0" GridPane.columnIndex="1" /><StackPane fx:id="styleSp" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" /><StackPane fx:id="sizeSp" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" />
 </children>
 </GridPane>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/FontPopupEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/FontPopupEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -31,6 +31,7 @@
  */
 package com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.popupeditors;
 
+import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.AutoSuggestEditor;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.BoundedDoubleEditor;
 import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.EditorUtils;
@@ -74,14 +75,16 @@
     private FamilyEditor familyEditor;
     private StyleEditor styleEditor;
     private BoundedDoubleEditor sizeEditor;
+    private EditorController editorController;
 
     @SuppressWarnings("LeakingThisInConstructor")
-    public FontPopupEditor(ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses) {
+    public FontPopupEditor(ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, EditorController editorController) {
         super(propMeta, selectedClasses);
+        this.editorController = editorController;
     }
 
     private void setStyle() {
-        styleEditor.reset("", "", new ArrayList<>(getStyles(familyEditor.getValue(), false)));//NOI18N
+        styleEditor.reset("", "", new ArrayList<>(getStyles(familyEditor.getValue(), false, editorController)));//NOI18N
         styleEditor.setUpdateFromModel(true);
         styleEditor.setValue(font.getStyle());
         styleEditor.setUpdateFromModel(false);
@@ -101,7 +104,7 @@
         Font oldFont = font;
         Object sizeObj = sizeEditor.getValue();
         assert sizeObj instanceof Double;
-        Font newFont = getFont(familyEditor.getValue(), styleEditor.getValue(), (Double) sizeObj);
+        Font newFont = getFont(familyEditor.getValue(), styleEditor.getValue(), (Double) sizeObj, editorController);
         if (newFont != null) {
             return newFont;
         } else {
@@ -114,6 +117,11 @@
         return font;
     }
 
+    public void reset(ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, EditorController editorController) {
+        super.reset(propMeta, selectedClasses);
+        this.editorController = editorController;
+    }
+
     //
     // Interface from PopupEditor
     // Methods called by PopupEditor.
@@ -122,9 +130,9 @@
     public void initializePopupContent() {
         root = EditorUtils.loadPopupFxml("FontPopupEditor.fxml", this); //NOI18N
         // Add the editors in the scene graph
-        familyEditor = new FamilyEditor("", "", getFamilies());//NOI18N
+        familyEditor = new FamilyEditor("", "", getFamilies(editorController), editorController);//NOI18N
         familySp.getChildren().add(familyEditor.getValueEditor());
-        styleEditor = new StyleEditor("", "", new ArrayList<>());//NOI18N
+        styleEditor = new StyleEditor("", "", new ArrayList<>(), editorController);//NOI18N
         styleSp.getChildren().add(styleEditor.getValueEditor());
         sizeEditor = new BoundedDoubleEditor("", "", getPredefinedFontSizes(), 1.0, 96.0, true);//NOI18N
         commitOnFocusLost(sizeEditor);
@@ -163,7 +171,7 @@
                 commit();
             }
         });
-        
+
         sizeEditor.transientValueProperty().addListener(new ChangeListener<Object>() {
             @Override
             public void changed(ObservableValue<? extends Object> ov, Object oldVal, Object newVal) {
@@ -204,13 +212,13 @@
     public Node getPopupContentNode() {
         return root;
     }
-    
+
     private static class FamilyEditor extends AutoSuggestEditor {
 
         private List<String> families;
 
         @SuppressWarnings("LeakingThisInConstructor")
-        public FamilyEditor(String name, String defaultValue, List<String> families) {
+        public FamilyEditor(String name, String defaultValue, List<String> families, EditorController editorController) {
             super(name, defaultValue, families);
             this.families = families;
             EventHandler<ActionEvent> onActionListener = new EventHandler<ActionEvent>() {
@@ -218,8 +226,8 @@
                 public void handle(ActionEvent event) {
                     String value = getTextField().getText();
                     if (value.isEmpty() || !FamilyEditor.this.families.contains(value)) {
-                        System.err.println("Invalid value for Family: " + value);//NOI18N
-//                        handleInvalidValue(value);
+                        editorController.getMessageLog().logWarningMessage(
+                                "inspector.font.invalidfamily", value); //NOI18N
                         return;
                     }
 //                    System.out.println("Setting family from '" + valueProperty().get() + "' to '" + value + "'");
@@ -244,14 +252,15 @@
     private static class StyleEditor extends AutoSuggestEditor {
 
         @SuppressWarnings("LeakingThisInConstructor")
-        public StyleEditor(String name, String defaultValue, List<String> suggestedList) {
+        public StyleEditor(String name, String defaultValue, List<String> suggestedList, EditorController editorController) {
             super(name, defaultValue, suggestedList);
             EventHandler<ActionEvent> onActionListener = new EventHandler<ActionEvent>() {
                 @Override
                 public void handle(ActionEvent event) {
                     String value = getTextField().getText();
                     if (value.isEmpty() || !getSuggestedList().contains(value)) {
-                        System.err.println("Invalid value for Style: " + value);//NOI18N
+                        editorController.getMessageLog().logWarningMessage(
+                                "inspector.font.invalidstyle", value); //NOI18N
                         return;
                     }
                     valueProperty().setValue(value);
@@ -322,13 +331,13 @@
         return allFonts;
     }
 
-    public static List<String> getFamilies() {
+    public static List<String> getFamilies(EditorController editorController) {
 //        System.out.println("Getting font families...");
-        return new ArrayList<>(getFontMap().keySet());
+        return new ArrayList<>(getFontMap(editorController).keySet());
     }
 
-    public static Set<String> getStyles(String family, boolean canBeUnknown) {
-        Map<String, Font> styles = getFontMap().get(family);
+    public static Set<String> getStyles(String family, boolean canBeUnknown, EditorController editorController) {
+        Map<String, Font> styles = getFontMap(editorController).get(family);
         if (styles == null) {
             assert !canBeUnknown;
             styles = Collections.emptyMap();
@@ -336,8 +345,8 @@
         return styles.keySet();
     }
 
-    public static Font getFont(String family, String style) {
-        Map<String, Font> styles = getFontMap().get(family);
+    public static Font getFont(String family, String style, EditorController editorController) {
+        Map<String, Font> styles = getFontMap(editorController).get(family);
         if (styles == null) {
             styles = Collections.emptyMap();
         }
@@ -350,8 +359,8 @@
         return styles.get(style);
     }
 
-    public static Font getFont(String family, String style, double size) {
-        final Font font = getFont(family, style);
+    public static Font getFont(String family, String style, double size, EditorController editorController) {
+        final Font font = getFont(family, style, editorController);
         if (font == null) {
             return null;
         }
@@ -420,16 +429,16 @@
         return font.getName();
     }
 
-    private static Map<String, Map<String, Font>> getFontMap() {
+    private static Map<String, Map<String, Font>> getFontMap(EditorController editorController) {
         Map<String, Map<String, Font>> fonts = fontCache.get();
         if (fonts == null) {
-            fonts = makeFontMap();
+            fonts = makeFontMap(editorController);
             fontCache = new WeakReference<>(fonts);
         }
         return fonts;
     }
 
-    private static Map<String, Map<String, Font>> makeFontMap() {
+    private static Map<String, Map<String, Font>> makeFontMap(EditorController editorController) {
         final Set<Font> fonts = getAllFonts();
         final Map<String, Map<String, Set<Font>>> fontTree = new TreeMap<>();
 
@@ -458,7 +467,8 @@
                 int size = fontSet.size();
                 assert 1 <= size;
                 if (1 < size) {
-                    System.out.println("Warning: several fonts have the same family and style: " + styleMap.get(style)); //NOI18N
+                    editorController.getMessageLog().logWarningMessage(
+                            "inspector.font.samefamilystyle", styleMap.get(style)); //NOI18N
                 }
                 resMap.put(style, styleMap.get(style).iterator().next());
             }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/PaintPopupEditor.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/PaintPopupEditor.java	Thu Feb 20 14:43:20 2014 +0100
@@ -51,18 +51,33 @@
  */
 public class PaintPopupEditor extends PopupEditor {
 
-    private PaintPicker paintEditor;
+    private PaintPicker paintPicker;
     private final Rectangle graphic = new Rectangle(20, 10);
     private final EditorController editorController;
 
     private final ChangeListener<Paint> paintChangeListener = new ChangeListener<Paint>() {
         @Override
         public void changed(ObservableValue<? extends Paint> ov, Paint oldValue, Paint newValue) {
-            commitValue(newValue);
+            // If live update, do not commit the value
+            if (paintPicker.isLiveUpdate() == true) {
+                userUpdateTransientValueProperty(newValue);
+                popupMb.setText(getPreviewString(newValue));
+            } else {
+                commitValue(newValue);
+            }
             graphic.setFill(newValue);
         }
     };
 
+    private final ChangeListener<Boolean> liveUpdateListener = new ChangeListener<Boolean>() {
+        @Override
+        public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+            if (paintPicker.isLiveUpdate() == false) {
+                commitValue(paintPicker.getPaintProperty());
+            }
+        }
+    };
+
     @SuppressWarnings("LeakingThisInConstructor")
     public PaintPopupEditor(ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, EditorController editorController) {
         super(propMeta, selectedClasses);
@@ -81,7 +96,7 @@
                 editorController.getMessageLog().logWarningMessage(warningKey, arguments);
             }
         };
-        paintEditor = new PaintPicker(delegate);
+        paintPicker = new PaintPicker(delegate);
     }
 
     @Override
@@ -101,26 +116,22 @@
 
     @Override
     public void setPopupContentValue(Object value) {
-//        if (value == null) {
-//            paintEditor.setPaintProperty(Color.WHITE);
-//        } else {
-//            assert value instanceof Paint;
-//            paintEditor.setPaintProperty((Paint) value);
-//        }
         assert value == null || value instanceof Paint;
-        paintEditor.paintProperty().removeListener(paintChangeListener);
+        paintPicker.paintProperty().removeListener(paintChangeListener);
+        paintPicker.liveUpdateProperty().removeListener(liveUpdateListener);
         if (value != null) {
             final Paint paint = (Paint) value;
-            paintEditor.setPaintProperty(paint);
+            paintPicker.setPaintProperty(paint);
         }
-        paintEditor.paintProperty().addListener(paintChangeListener);       
+        paintPicker.paintProperty().addListener(paintChangeListener);
+        paintPicker.liveUpdateProperty().addListener(liveUpdateListener);
         // !! exception in case of null
         graphic.setFill((Paint) value);
     }
 
     @Override
     public Node getPopupContentNode() {
-        return paintEditor;
+        return paintPicker;
     }
 
     public Node getPreviewGraphic(Object value) {
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/Rectangle2DPopupEditor.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/popupeditors/Rectangle2DPopupEditor.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -38,32 +38,32 @@
 <?import javafx.scene.layout.*?>
 <?scenebuilder-classpath-element ../../../../../../../../../../dist/SceneBuilderKit.jar?>
 
-<GridPane hgap="7.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" vgap="5.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
+<GridPane hgap="5.0" vgap="5.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
     <children>
         <Label maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" text="min" />
         <Label maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" text="size" GridPane.rowIndex="1" />
-        <VBox alignment="CENTER" GridPane.columnIndex="1" HBox.hgrow="ALWAYS">
+        <VBox alignment="CENTER_LEFT" GridPane.columnIndex="1" HBox.hgrow="ALWAYS">
             <children>
                 <Label styleClass="label, small-label" text="X" />
-                <DoubleField fx:id="minXDf" prefWidth="50.0"/>
+                <DoubleField fx:id="minXDf" prefWidth="50.0" />
             </children>
         </VBox>
-        <VBox alignment="CENTER" GridPane.columnIndex="2" HBox.hgrow="ALWAYS">
+        <VBox alignment="CENTER_LEFT" GridPane.columnIndex="2" HBox.hgrow="ALWAYS">
             <children>
                 <Label styleClass="label, small-label" text="Y" />
-                <DoubleField fx:id="minYDf"  prefWidth="50.0"/>
+                <DoubleField fx:id="minYDf" prefWidth="50.0" />
             </children>
         </VBox>
-        <VBox alignment="CENTER" GridPane.columnIndex="1" GridPane.rowIndex="1" HBox.hgrow="ALWAYS">
+        <VBox alignment="CENTER_LEFT" GridPane.columnIndex="1" GridPane.rowIndex="1" HBox.hgrow="ALWAYS">
             <children>
-                <Label styleClass="label, small-label" text="Width" />
-                <DoubleField fx:id="widthDf"  prefWidth="50.0"/>
+                <Label styleClass="label, small-label" text="WIDTH" />
+                <DoubleField fx:id="widthDf" prefWidth="50.0" />
             </children>
         </VBox>
-        <VBox alignment="CENTER" GridPane.columnIndex="2" GridPane.rowIndex="1" HBox.hgrow="ALWAYS">
+        <VBox alignment="CENTER_LEFT" GridPane.columnIndex="2" GridPane.rowIndex="1" HBox.hgrow="ALWAYS">
             <children>
-                <Label styleClass="label, small-label" text="Height" />
-                <DoubleField fx:id="heightDf"  prefWidth="50.0"/>
+                <Label styleClass="label, small-label" text="HEIGHT" />
+                <DoubleField fx:id="heightDf" prefWidth="50.0" />
             </children>
         </VBox>
     </children>
@@ -73,7 +73,7 @@
         <ColumnConstraints hgrow="ALWAYS" maxWidth="-Infinity" minWidth="-Infinity" />
     </columnConstraints>
     <rowConstraints>
-        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" valignment="BOTTOM"/>
-        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" valignment="BOTTOM"/>
+        <RowConstraints valignment="BOTTOM" vgrow="SOMETIMES" />
+        <RowConstraints valignment="BOTTOM" vgrow="SOMETIMES" />
     </rowConstraints>
 </GridPane>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportDialog.css	Fri Feb 14 08:27:15 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-
-.list-view .list-cell {
-    -fx-background-color: null;
-    -fx-cell-size: 1.7em;
-}
-
-.list-view, .list-view:focused {
-    -fx-background-color: null;
-    -fx-padding: 0px;
-}
-
-.list-view .list-cell:filled:hover {
-    -fx-background-color: null; /* no hover effect on list view */
-}
-
-.list-view:focused .list-cell:filled:selected {
-    -fx-background-color: #c6e6f0;
-}
-
-/* When the ListView is _not_ focused, we show alternate selection colors */
-.list-view .list-cell:filled:selected {
-    -fx-background-color: null;
-}
-
-.import-preview-label {
-    -fx-text-fill: silver;
-    -fx-font-size : 0.9em;
-}
-
-.import-preview {
-    -fx-background-color: azure;
-}
-
-.import-select-toggle {
-}
-
-.import-num-of-items-label {
-    -fx-font-size : 0.8em;
-}
-
-.import-class-name-label {
-    -fx-text-fill: grey;
-    -fx-font-size : 0.8em;
-}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportDialog.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportDialog.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -33,18 +33,13 @@
 -->
 
 <?import java.lang.*?>
-<?import java.net.*?>
-<?import java.util.*?>
 <?import javafx.collections.*?>
 <?import javafx.geometry.*?>
 <?import javafx.scene.*?>
 <?import javafx.scene.control.*?>
-<?import javafx.scene.image.*?>
 <?import javafx.scene.layout.*?>
-<?import javafx.scene.paint.*?>
-<?import javafx.scene.shape.*?>
 
-<AnchorPane id="ImportDialog" maxHeight="-1.0" maxWidth="-1.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="640.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
+<AnchorPane id="ImportDialog" maxHeight="-1.0" maxWidth="-1.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="640.0" styleClass="theme-presets" stylesheets="@../../css/Theme.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
     <HBox id="HBox" alignment="CENTER" fillHeight="false" maxHeight="-1.0" maxWidth="-1.0" minHeight="-1.0" minWidth="-1.0" prefHeight="400.0" prefWidth="640.0" spacing="50.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
       <children>
@@ -60,12 +55,12 @@
             <Separator prefWidth="-1.0" VBox.vgrow="NEVER" />
             <GridPane id="GridPane" gridLinesVisible="false" hgap="20.0" VBox.vgrow="NEVER">
               <children>
-                <Label fx:id="numOfItemsLabel" alignment="CENTER_LEFT" contentDisplay="LEFT" disable="false" focusTraversable="false" maxWidth="-1.0" prefWidth="-1.0" styleClass="import-num-of-items-label" text="%import.items.processing" textAlignment="LEFT" wrapText="false" GridPane.columnIndex="0" GridPane.halignment="LEFT" GridPane.hgrow="SOMETIMES" GridPane.rowIndex="0" GridPane.valignment="TOP">
+                <Label fx:id="numOfItemsLabel" alignment="CENTER_LEFT" contentDisplay="LEFT" disable="false" focusTraversable="false" maxWidth="-1.0" prefWidth="-1.0" styleClass="jar-import-num-of-items-label" text="%import.items.processing" textAlignment="LEFT" wrapText="false" GridPane.columnIndex="0" GridPane.halignment="LEFT" GridPane.hgrow="SOMETIMES" GridPane.rowIndex="0" GridPane.valignment="TOP">
                   <GridPane.margin>
                     <Insets />
                   </GridPane.margin>
                 </Label>
-                <ToggleButton fx:id="checkAllUncheckAllToggle" disable="true" mnemonicParsing="false" styleClass="import-select-toggle" text="%import.toggle.uncheckall" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="0" GridPane.valignment="TOP" />
+                <ToggleButton fx:id="checkAllUncheckAllToggle" disable="true" mnemonicParsing="false" text="%import.toggle.uncheckall" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="0" GridPane.valignment="TOP" />
               </children>
               <columnConstraints>
                 <ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="-Infinity" prefWidth="-1.0" />
@@ -87,11 +82,11 @@
           <children>
             <ScrollPane id="importScrollPane" fitToHeight="true" fitToWidth="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" visible="true" VBox.vgrow="ALWAYS">
               <content>
-                <StackPane id="importPreviewArea" minWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" styleClass="import-preview">
+                <StackPane id="importPreviewArea" minWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" styleClass="jar-import-preview">
                   <children>
                     <Group fx:id="previewGroup">
                       <children>
-                        <Label fx:id="previewHintLabel" layoutX="-41.0" layoutY="-8.0" styleClass="import-preview-label" text="%import.preview.select" />
+                        <Label fx:id="previewHintLabel" layoutX="-41.0" layoutY="-8.0" styleClass="jar-import-preview-label" text="%import.preview.select" />
                       </children>
                     </Group>
                   </children>
@@ -101,7 +96,7 @@
                 </StackPane>
               </content>
             </ScrollPane>
-            <Label fx:id="classNameLabel" alignment="CENTER" maxWidth="1.7976931348623157E308" styleClass="import-class-name-label" text="" textAlignment="LEFT" textOverrun="LEADING_ELLIPSIS" wrapText="false">
+            <Label fx:id="classNameLabel" alignment="CENTER" maxWidth="1.7976931348623157E308" styleClass="jar-import-class-name-label" text="" textAlignment="LEFT" textOverrun="LEADING_ELLIPSIS" wrapText="false">
               <VBox.margin>
                 <Insets left="5.0" right="5.0" />
               </VBox.margin>
@@ -138,7 +133,4 @@
       </items>
     </SplitPane>
   </children>
-  <stylesheets>
-    <URL value="@ImportDialog.css" />
-  </stylesheets>
 </AnchorPane>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportWindowController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/panel/library/ImportWindowController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -245,6 +245,8 @@
     @Override
     public void controllerDidLoadContentFxml() {
         assert topSplitPane != null;
+        // The SplitPane should not be visible from the beginning: only the progressing bar is initially visible.
+        assert topSplitPane.isVisible() == false;
         assert processingLabel != null;
         assert processingProgressIndicator != null;
         assert sizeLabel != null;
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/selection/ObjectSelectionGroup.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/selection/ObjectSelectionGroup.java	Thu Feb 20 14:43:20 2014 +0100
@@ -42,6 +42,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import javafx.geometry.Bounds;
 import javafx.geometry.Point2D;
 import javafx.scene.Node;
 
@@ -71,6 +72,15 @@
         this.hitPoint = hitPoint;
     }
     
+    ObjectSelectionGroup(FXOMObject fxomObject, Node hitNode) {
+        assert fxomObject != null;
+        assert (hitNode == null) || (hitNode.getScene() != null);
+        
+        this.items.add(fxomObject);
+        this.hitItem = fxomObject;
+        this.hitPoint = computeHitPoint(hitNode);
+    }
+    
     public Set<FXOMObject> getItems() {
         return Collections.unmodifiableSet(items);
     }
@@ -242,5 +252,33 @@
         return true;
     }
     
+    /*
+     * Private
+     */
     
+    private Point2D computeHitPoint(Node hitNode) {
+        final Point2D result;
+        
+        if (hitNode == null) {
+            result = null;
+        } else {
+            final FXOMObject nodeObject = hitItem.getClosestNode();
+            if (nodeObject == null) {
+                result = null;
+            } else {
+                final Node closestNode = (Node)nodeObject.getSceneGraphObject();
+                final Bounds hnb = hitNode.getLayoutBounds();
+                final double midX = (hnb.getMinX() + hnb.getMaxX()) / 2.0;
+                final double midY = (hnb.getMinY() + hnb.getMaxY()) / 2.0;
+                if (hitNode == closestNode) {
+                    result = new Point2D(midX, midY);
+                } else {
+                    result = closestNode.sceneToLocal(hitNode.localToScene(midX, midY));
+                }
+                assert findHitNode() == hitNode;
+            }
+        }
+        
+        return result;
+    }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/selection/Selection.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/editor/selection/Selection.java	Thu Feb 20 14:43:20 2014 +0100
@@ -88,7 +88,7 @@
     public void select(FXOMObject fxomObject) {
         assert fxomObject != null;
         
-        select(fxomObject, null);
+        select(fxomObject, (Point2D)null);
     }
     
     /**
@@ -99,13 +99,21 @@
      * @param hitPoint null or the point hit by the mouse during selection
      */
     public void select(FXOMObject fxomObject, Point2D hitPoint) {
-        
-        assert fxomObject != null;
-        
         select(new ObjectSelectionGroup(fxomObject, hitPoint));
     }
     
     /**
+     * Replaces the selected items by the specified fxom object and hit node.
+     * This routine adds +1 to the revision number.
+     * 
+     * @param fxomObject the object to be selected
+     * @param hitNode null or the node hit by the mouse during selection
+     */
+    public void select(FXOMObject fxomObject, Node hitNode) {
+        select(new ObjectSelectionGroup(fxomObject, hitNode));
+    }
+    
+    /**
      * Replaces the selected items by the specified fxom objects.
      * This routine adds +1 to the revision number.
      * 
@@ -317,7 +325,7 @@
                     if (indexes.size() == 1) {
                         // featureIndex is the last selected index
                         // GridSelectionGroup -> ObjectSelectionGroup
-                        newGroup = new ObjectSelectionGroup(gridPaneObject, null);
+                        newGroup = new ObjectSelectionGroup(gridPaneObject, (Point2D)null);
                     } else {
                         final Set<Integer> newIndexes = new HashSet<>();
                         newIndexes.addAll(indexes);
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMDocument.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMDocument.java	Thu Feb 20 14:43:20 2014 +0100
@@ -200,6 +200,7 @@
         } else {
             assert glue.getRootElement() != null;
             // Note that sceneGraphRoot might be null if fxomRoot is unresolved
+            glue.updateIndent();
             final FXOMSaver saver = new FXOMSaver();
             result = saver.save(this);
         }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMIndex.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMIndex.java	Thu Feb 20 14:43:20 2014 +0100
@@ -60,6 +60,10 @@
         return fxIds.get(fxId);
     }
     
+    public Map<String, FXOMObject> getFxIds() {
+        return fxIds;
+    }
+    
     public List<FXOMInstance> collectToggleGroups() {
         final List<FXOMInstance> result = new ArrayList<>();
         
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMInstance.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMInstance.java	Thu Feb 20 14:43:20 2014 +0100
@@ -63,7 +63,7 @@
         
         assert declaredClass != null;
         assert glueElement.getTagName().equals("fx:root") 
-                || glueElement.getTagName().equals(declaredClass.getSimpleName())
+                || glueElement.getTagName().equals(PropertyName.makeClassFullName(declaredClass))
                 || glueElement.getTagName().equals(declaredClass.getCanonicalName());
         assert sceneGraphObject != null;
         assert properties != null;
@@ -91,7 +91,7 @@
     }
     
     public FXOMInstance(FXOMDocument fxomDocument, Class<?> declaredClass) {
-        super(fxomDocument, declaredClass.getSimpleName());
+        super(fxomDocument, PropertyName.makeClassFullName(declaredClass));
         this.declaredClass = declaredClass;
     }
     
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMLoader.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/FXOMLoader.java	Thu Feb 20 14:43:20 2014 +0100
@@ -117,8 +117,8 @@
     @Override
     public void beginInstanceDeclarationElement(Class<?> declaredClass) {
         assert declaredClass != null;
-        assert glueCursor.getCurrentElement().getTagName().equals(declaredClass.getSimpleName()) ||
-                glueCursor.getCurrentElement().getTagName().equals(declaredClass.getCanonicalName());
+        assert glueCursor.getCurrentElement().getTagName().equals(PropertyName.makeClassFullName(declaredClass)) ||
+               glueCursor.getCurrentElement().getTagName().equals(declaredClass.getCanonicalName());
         
         final TransientObject transientInstance
                 = new TransientObject(currentTransientNode, 
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/TransientObject.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/TransientObject.java	Thu Feb 20 14:43:20 2014 +0100
@@ -32,8 +32,10 @@
 package com.oracle.javafx.scenebuilder.kit.fxom;
 
 import com.oracle.javafx.scenebuilder.kit.fxom.glue.GlueElement;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
 import java.util.ArrayList;
 import java.util.List;
+import javafx.beans.DefaultProperty;
 
 /**
  *
@@ -56,7 +58,7 @@
         
         assert declaredClass != null;
         assert glueElement != null;
-        assert glueElement.getTagName().equals(declaredClass.getSimpleName()) ||
+        assert glueElement.getTagName().equals(PropertyName.makeClassFullName(declaredClass)) ||
                 glueElement.getTagName().equals(declaredClass.getCanonicalName());
         
         this.declaredClass = declaredClass;
@@ -124,40 +126,96 @@
     public FXOMObject makeFxomObject(FXOMDocument fxomDocument) {
         final FXOMObject result;
         
-        if (collectedItems.isEmpty()) {
-            if (declaredClass != null) {
-                assert getSceneGraphObject() != null;
+        if (declaredClass != null) {
+            assert getSceneGraphObject() != null;
+            
+            if (List.class.isAssignableFrom(declaredClass)) {
+                assert getSceneGraphObject() instanceof List;
+                assert properties.isEmpty();
+                
+                result = new FXOMCollection(fxomDocument, glueElement,
+                                          declaredClass, getSceneGraphObject(), 
+                                          collectedItems);
+            } else {
                 assert fxRootType == null;
+                
+                final DefaultProperty annotation 
+                        = declaredClass.getAnnotation(DefaultProperty.class);
+                if ((annotation != null) && (collectedItems.size() >= 1)) {
+                    assert annotation.value() != null;
+                    final PropertyName defaultPropertyName 
+                            = new PropertyName(annotation.value());
+                    createDefaultProperty(defaultPropertyName, fxomDocument);
+                }
                 result = new FXOMInstance(fxomDocument, glueElement, 
                                           declaredClass, getSceneGraphObject(),
                                           properties);
-            } else if (unknownClassName != null) {
-                // This is an unresolved instance
-                assert glueElement.getTagName().equals(unknownClassName);
-                assert fxRootType == null;
-                result = new FXOMInstance(fxomDocument, glueElement, properties);
-            } else {
-                // This is an fx:root'ed instance
-                assert glueElement.getTagName().equals("fx:root");
-                assert fxRootType != null;
-                
-                final Class<?> rootClass = getSceneGraphObject().getClass();
-                assert fxRootType.equals(rootClass.getName())
-                        || fxRootType.equals(rootClass.getSimpleName());
-                result = new FXOMInstance(fxomDocument, glueElement, 
-                                          rootClass, getSceneGraphObject(),
-                                          properties);
             }
-        } else if (properties.isEmpty()) {
-            assert getSceneGraphObject() != null;
-            result = new FXOMCollection(fxomDocument, glueElement,
-                                      declaredClass, getSceneGraphObject(), 
-                                      collectedItems);
+        } else if (unknownClassName != null) {
+            // This is an unresolved instance
+            assert glueElement.getTagName().equals(unknownClassName);
+            assert fxRootType == null;
+            result = new FXOMInstance(fxomDocument, glueElement, properties);
         } else {
-            assert false;
-            throw new IllegalStateException();
+            // This is an fx:root'ed instance
+            assert glueElement.getTagName().equals("fx:root");
+            assert fxRootType != null;
+
+            final Class<?> rootClass = getSceneGraphObject().getClass();
+            assert fxRootType.equals(rootClass.getName())
+                    || fxRootType.equals(rootClass.getSimpleName());
+            result = new FXOMInstance(fxomDocument, glueElement, 
+                                      rootClass, getSceneGraphObject(),
+                                      properties);
         }
         
         return result;
     }
+    
+    
+    /*
+     * Private
+     */
+    
+    private void createDefaultProperty(PropertyName defaultName, FXOMDocument fxomDocument) {
+        /*
+         * From :
+         * 
+         *  <Pane>                          this.glueElement
+         *      ...
+         *      <Button text="B1" />        this.collectedItems.get(0).glueElement   //NOI18N
+         *      <TextField />               this.collectedItems.get(1).glueElement
+         *      <Label text="Label" />      this.collectedItems.get(2).glueElement   //NOI18N
+         *      ...
+         *  </Pane>
+         * 
+         * go to:
+         * 
+         *  <Pane>                          this.glueElement
+         *      ...
+         *      <children>                  syntheticElement
+         *          <Button text="B1" />    this.collectedItems.get(0).glueElement   //NOI18N
+         *          <TextField />           this.collectedItems.get(1).glueElement
+         *          <Label text="Label" />  this.collectedItems.get(2).glueElement   //NOI18N
+         *      </children>
+         *      ...
+         *  </Pane>
+         *
+         */
+        
+        final GlueElement propertyElement
+                = new GlueElement(glueElement.getDocument(), 
+                        defaultName.toString(),  glueElement);
+        propertyElement.addBefore(collectedItems.get(0).getGlueElement());
+        
+        for (FXOMObject item : collectedItems) {
+            item.getGlueElement().addToParent(propertyElement);
+        }
+        
+        final TransientProperty transientProperty 
+                = new TransientProperty(this, defaultName, propertyElement);
+        transientProperty.getValues().addAll(collectedItems);
+        
+        properties.add(transientProperty.makeFxomProperty(fxomDocument));
+    }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueCharacters.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueCharacters.java	Thu Feb 20 14:43:20 2014 +0100
@@ -63,6 +63,81 @@
         this.data = data;
     }
     
+    public void adjustIndentBy(int delta) {
+        /*
+         * data
+         * 
+         * 'xxxxxxx\nbbbbbbxxxxxxx\nbbbbbbbbxxxxxxxxxx\nbbbbbxxxxx....'
+         * 
+         *  b : white space
+         *  x : any other char
+         * 
+         * Indenting means:
+         * - when delta > 0, inserting 'delta' spaces after each '\n' char
+         * - when delta < 0, removing 'delta' spaces after each '\n' char *when possible*
+         */
+        
+        final StringBuilder newValue = new StringBuilder();
+        
+        if (delta > 0) {
+            for (int i = 0, length = data.length(); i < length; i++) {
+                final char ch = data.charAt(i);
+                newValue.append(ch);
+                if (ch == '\n') {
+                    for (int n = 0; n < delta; n++) {
+                        newValue.append(' ');
+                    }
+                }
+            }
+        } else {
+            for (int i = 0, length = data.length(); i < length; i++) {
+                final char ch = data.charAt(i);
+                newValue.append(ch);
+                if (ch == '\n') {
+                    while ((i+1 < length) 
+                            && (data.charAt(i+1) == ' ')
+                            && (delta < 0)) {
+                        i++;
+                        delta++;
+                    }
+                }
+            }
+        }
+        
+        data = newValue.toString();
+    }
     
-    
+    public int guessIndent() {
+        int result;
+        
+        /*
+         * If data match the following pattern
+         * 
+         * 'xxxxxxx\nbbbbbbxxxxxxx....'
+         * 
+         *  b : white space
+         *  x : any other char
+         * 
+         * then returns number of b characters else returns -1.
+         */
+        
+        int i = 0;
+        final int count = data.length();
+        while ((i < count) && data.charAt(i) != '\n') {
+            i++;
+        }
+        
+        if (i < count) {
+            i++;
+            result = 0;
+            while ((i < count) && data.charAt(i) == ' ') {
+                result++;
+                i++;
+            }
+        } else {
+            result = -1;
+        }
+        
+        return result;
+    }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueDocument.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueDocument.java	Thu Feb 20 14:43:20 2014 +0100
@@ -40,10 +40,10 @@
  * 
  */
 public class GlueDocument extends GlueNode {
-
+    
     private GlueElement rootElement;
     private final List<GlueAuxiliary> header = new ArrayList<>();
-
+    
     public GlueDocument() {
     }
     
@@ -52,6 +52,7 @@
         if (isEmptyXmlText(xmlText) == false) {
             final GlueLoader loader = new GlueLoader(this);
             loader.load(xmlText);
+            adjustRootElementIndentation();
         }
     }
     
@@ -70,6 +71,13 @@
         return header;
     }
     
+    public void updateIndent() {
+        if (rootElement != null) {
+            rootElement.updateIndent(0);
+        }
+    }
+    
+    
     /*
      * Utilities
      */
@@ -124,4 +132,34 @@
         }
         return result;
     }
+    
+    
+    /*
+     * Private
+     */
+    
+    private void adjustRootElementIndentation() {
+        /*
+         * By default, if a root element is empty and expressed like this:
+         *     <AnchorPane />
+         * indentation logic would keep the upcoming children on the same line:
+         *     <AnchorPane> <children> <Button/> </children> </AnchorPane>.
+         * 
+         * With the adjustment below, indentation logic will produce:
+         *     <AnchorPane> 
+         *        <children>
+         *           <Button />
+         *        </children>
+         *     </AnchorPane>
+         */
+        
+        if ((rootElement != null) && rootElement.getChildren().isEmpty()) {
+            if (rootElement.getFront().isEmpty()) {
+                rootElement.getFront().add(new GlueCharacters(this, GlueCharacters.Type.TEXT, "\n")); //NOI18N
+            }
+            if (rootElement.getTail().isEmpty()) {
+                rootElement.getTail().add(new GlueCharacters(this, GlueCharacters.Type.TEXT, "\n")); //NOI18N
+            }
+        }
+    }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueElement.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueElement.java	Thu Feb 20 14:43:20 2014 +0100
@@ -45,6 +45,8 @@
  */
 public class GlueElement extends GlueNode {
     
+    private final static int INDENT_STEP = 3;
+    
     private GlueDocument document;
     private String tagName;
     private final List<GlueElement> children = new ArrayList<>();
@@ -53,25 +55,37 @@
     private final List<GlueAuxiliary> front = new ArrayList<>();
     private final List<GlueAuxiliary> tail = new ArrayList<>();
     private final List<GlueAuxiliary> content = new ArrayList<>();
+    private int indentDepth;
     
     private GlueElement parent;
     
     public GlueElement(GlueDocument document, String tagName) {
-        this(document, tagName, true /* preset */);
+        this(document, tagName, 0, true /* preset */);
     }
 
-    public GlueElement(GlueDocument document, String tagName, boolean preset) {
+    public GlueElement(GlueDocument document, String tagName, int indentDepth, boolean preset) {
         assert document != null;
         assert tagName != null;
         
         this.document = document;
         this.tagName = tagName;
+        this.indentDepth = indentDepth;
         if (preset) {
             front.add(new GlueCharacters(document, GlueCharacters.Type.TEXT, "\n")); //NOI18N
             tail.add(new GlueCharacters(document, GlueCharacters.Type.TEXT, "\n")); //NOI18N
         }
     }
 
+    public GlueElement(GlueDocument document, String tagName, GlueElement template) {
+        this(document, tagName, template.indentDepth, false);
+        
+        final int templateIndent = template.guessIndent();
+        if (templateIndent != -1) {
+            front.add(makeIndentCharacters(templateIndent));
+            tail.add(makeIndentCharacters(templateIndent));
+        }
+    }
+
     public GlueElement getParent() {
         return parent;
     }
@@ -118,6 +132,18 @@
         this.parent = newParent;
     }
     
+    public void addBefore(GlueElement nextSibling) {
+        assert nextSibling != null;
+        assert nextSibling.getDocument() == document;
+        assert nextSibling.getParent() != null;
+        
+        final GlueElement siblingParent = nextSibling.getParent();
+        final int nextSiblingIndex = siblingParent.getChildren().indexOf(nextSibling);
+        assert nextSiblingIndex != -1;
+        
+        addToParent(nextSiblingIndex, siblingParent);
+    }
+    
     
     public void removeFromParent() {
         assert parent != null;
@@ -155,10 +181,38 @@
         return result;
     }
 
-    public void indent(int delta) {
-        GlueSnapshot.indent(this, delta);
+    public void updateIndent(int depth) {
+        if (indentDepth != depth) {
+            final int indentDelta = (depth - indentDepth) * INDENT_STEP;
+            if (front.isEmpty()) {
+                front.add(makeIndentCharacters(depth * INDENT_STEP));
+            } else {
+                for (GlueAuxiliary auxiliary : front) {
+                    if (auxiliary instanceof GlueCharacters) {
+                        final GlueCharacters characters = (GlueCharacters) auxiliary;
+                        characters.adjustIndentBy(indentDelta);
+                    }
+                }
+            }
+            
+            if (tail.isEmpty()) {
+                tail.add(makeIndentCharacters(depth * INDENT_STEP));
+            } else {
+                for (GlueAuxiliary auxiliary : tail) {
+                    if (auxiliary instanceof GlueCharacters) {
+                        final GlueCharacters characters = (GlueCharacters) auxiliary;
+                        characters.adjustIndentBy(indentDelta);
+                    }
+                }
+            }
+            indentDepth = depth;
+        }
+        
+        for (GlueElement child : children) {
+            child.updateIndent(depth+1);
+        }
     }
-    
+
     public String getContentText() {
         final GlueCharacters contentHolder = getContentHolder();
         final String result;
@@ -242,7 +296,7 @@
         assert document == targetDocument;
         assert this != targetDocument.getRootElement();
     }
-    
+
     
     /*
      * Shortcut
@@ -320,4 +374,30 @@
         
         return result;
     }
+    
+    
+    private int guessIndent() {
+        final int result;
+        
+        if (front.isEmpty()) {
+            result = -1;
+        } else if (front.get(0) instanceof GlueCharacters) {
+            final GlueCharacters characters = (GlueCharacters) front.get(0);
+            result = characters.guessIndent();
+        } else {
+            result = -1;
+        }
+        
+        return result;
+    }
+    
+    private GlueCharacters makeIndentCharacters(int indentSize) {
+        final StringBuffer sb = new StringBuffer();
+        sb.append('\n');
+        for (int i = 0; i < indentSize; i++) {
+            sb.append(' ');
+        }
+        
+        return new GlueCharacters(getDocument(), GlueCharacters.Type.TEXT, sb.toString());
+    }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueLoader.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueLoader.java	Thu Feb 20 14:43:20 2014 +0100
@@ -59,6 +59,7 @@
     
     private final GlueDocument document;
     private GlueElement currentElement;
+    private int currentElementDepth = -1;
     private final List<GlueAuxiliary> auxiliaries = new ArrayList<>();
     private final Map<String, String> prefixMappings = new HashMap<>();
 
@@ -78,6 +79,7 @@
     
     public void load(InputStream is) throws IOException {
         assert currentElement == null;
+        assert currentElementDepth == -1;
         assert auxiliaries.isEmpty();
         assert prefixMappings.isEmpty();
         
@@ -92,6 +94,7 @@
         }
         
         assert currentElement == null;
+        assert currentElementDepth == -1;
         assert auxiliaries.isEmpty();
         assert prefixMappings.isEmpty();
     }
@@ -107,6 +110,7 @@
     @Override
     public void startDocument() throws SAXException {
         assert currentElement == null;
+        assert currentElementDepth == -1;
         assert auxiliaries.isEmpty();
     }
 
@@ -114,6 +118,7 @@
     public void endDocument() throws SAXException {
         assert document != null;
         assert currentElement == null;
+        assert currentElementDepth == -1;
         assert auxiliaries.isEmpty();
     }
 
@@ -135,7 +140,8 @@
         // - puts prefixMappings content in GlueElement.attributes map
         // - puts this.auxiliaries content in GlueElement.front
         
-        final GlueElement newElement = new GlueElement(document, qName, false /* preset */);
+        currentElementDepth++;
+        final GlueElement newElement = new GlueElement(document, qName, currentElementDepth, false /* preset */);
         final Map<String, String> attributes = newElement.getAttributes();
         for (int i = 0, count = atts.getLength(); i < count; i++) {
             attributes.put(atts.getQName(i), atts.getValue(i));
@@ -151,6 +157,7 @@
         
         if (currentElement == null) {
             // newElement is the root element
+            assert currentElementDepth == 0;
             document.setRootElement(newElement);
         } else {
             newElement.addToParent(currentElement);
@@ -165,6 +172,7 @@
     public void endElement(String uri, String localName, String qName) throws SAXException {
         assert currentElement != null;
         assert currentElement.getTagName().equals(qName);
+        assert currentElementDepth >= 0;
         
         if (currentElement.getChildren().isEmpty()) {
             currentElement.getContent().addAll(auxiliaries);
@@ -173,6 +181,7 @@
         }
         
         currentElement = currentElement.getParent();
+        currentElementDepth--;
         auxiliaries.clear();
     }
 
@@ -196,6 +205,7 @@
     @Override
     public void processingInstruction(String target, String data) throws SAXException {
         assert currentElement == null;
+        assert currentElementDepth == -1;
         document.getHeader().add(new GlueInstruction(document, target, data));
     }
 
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueSnapshot.java	Fri Feb 14 08:27:15 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +0,0 @@
-/*
- * 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.fxom.glue;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- *
- * 
- */
-public class GlueSnapshot {
-    
-    private final GlueElement topElement;
-    private final Map<GlueCharacters, String> textMap = new HashMap<>();
-    
-    public GlueSnapshot(GlueElement element) {
-        this.topElement = element;
-        
-        snapshot(this.topElement);
-    }
-
-    public GlueElement getTopElement() {
-        return topElement;
-    }
-    
-    public void restore() {
-        for (Map.Entry<GlueCharacters, String> e : textMap.entrySet()) {
-            e.getKey().setData(e.getValue());
-        }
-    }
-    
-    static void indent(GlueElement element, int delta) {
-        for (GlueAuxiliary auxiliary : element.getFront()) {
-            if (auxiliary instanceof GlueCharacters) {
-                GlueSnapshot.indent((GlueCharacters)auxiliary, delta);
-            }
-        }
-        for (GlueAuxiliary auxiliary : element.getTail()) {
-            if (auxiliary instanceof GlueCharacters) {
-                GlueSnapshot.indent((GlueCharacters)auxiliary, delta);
-            }
-        }
-        for (GlueElement child : element.getChildren()) {
-            indent(child, delta);
-        }
-    }
-    
-    static void indent(GlueCharacters characters, int delta) {
-        assert characters != null;
-
-        /*
-         * characters.getData()
-         * 
-         * 'xxxxxxx\nbbbbbbxxxxxxx\nbbbbbbbbxxxxxxxxxx\nbbbbbxxxxx....'
-         * 
-         *  b : white space
-         *  x : any other char
-         * 
-         * Indenting means:
-         * - when delta > 0, inserting 'delta' spaces after each '\n' char
-         * - when delta < 0, removing 'delta' spaces after each '\n' char *when possible*
-         */
-        
-        final String currentValue = characters.getData();
-        final StringBuilder newValue = new StringBuilder();
-        
-        if (delta > 0) {
-            for (int i = 0, length = currentValue.length(); i < length; i++) {
-                final char ch = currentValue.charAt(i);
-                newValue.append(ch);
-                if (ch == '\n') {
-                    for (int n = 0; n < delta; n++) {
-                        newValue.append(' ');
-                    }
-                }
-            }
-        } else {
-            for (int i = 0, length = currentValue.length(); i < length; i++) {
-                final char ch = currentValue.charAt(i);
-                newValue.append(ch);
-                if (ch == '\n') {
-                    while ((i+1 < length) 
-                            && (currentValue.charAt(i+1) == ' ')
-                            && (delta < 0)) {
-                        i++;
-                        delta++;
-                    }
-                }
-            }
-        }
-        
-        characters.setData(newValue.toString());
-    }
-    
-    /*
-     * Private
-     */
-    
-    private void snapshot(GlueElement element) {
-        for (GlueAuxiliary f : element.getFront()) {
-            snapshot(f);
-        }
-        for (GlueAuxiliary t : element.getTail()) {
-            snapshot(t);
-        }
-        for (GlueElement child : element.getChildren()) {
-            snapshot(child);
-        }
-    }
-    
-    private void snapshot(GlueAuxiliary auxiliary) {
-        if (auxiliary instanceof GlueCharacters) {
-            final GlueCharacters characters = (GlueCharacters) auxiliary;
-            textMap.put(characters, characters.getData());
-        }
-    }
-}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/LightingPropertyMetadata.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/LightingPropertyMetadata.java	Thu Feb 20 14:43:20 2014 +0100
@@ -36,6 +36,7 @@
 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
 import com.oracle.javafx.scenebuilder.kit.metadata.property.value.ComplexPropertyMetadata;
 import com.oracle.javafx.scenebuilder.kit.metadata.property.value.DoublePropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.effect.light.LightPropertyMetadata;
 import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
 import javafx.scene.effect.Lighting;
@@ -45,27 +46,33 @@
  */
 public class LightingPropertyMetadata extends ComplexPropertyMetadata<Lighting> {
     
+    private static final Lighting LIGHTING_DEFAULT = new Lighting();
+    
     private final EffectPropertyMetadata bumpInputMetadata
             = new EffectPropertyMetadata(new PropertyName("bumpInput"), //NOI18N
-            true /* readWrite */, null, InspectorPath.UNUSED);
+            true /* readWrite */, LIGHTING_DEFAULT.getBumpInput(), InspectorPath.UNUSED);
     private final EffectPropertyMetadata contentInputMetadata
             = new EffectPropertyMetadata(new PropertyName("contentInput"), //NOI18N
-            true /* readWrite */, null, InspectorPath.UNUSED);
+            true /* readWrite */, LIGHTING_DEFAULT.getContentInput(), InspectorPath.UNUSED);
     private final DoublePropertyMetadata diffuseConstantMetadata
             = new DoublePropertyMetadata(new PropertyName("diffuseConstant"), //NOI18N
-            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 1.0, InspectorPath.UNUSED);
-//    private final LightPropertyMetadata lightMetadata
-//            = new LightPropertyMetadata(new PropertyName("light"), //NOI18N
-//            true /* readWrite */, null, InspectorPath.UNUSED);
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 
+            LIGHTING_DEFAULT.getDiffuseConstant(), InspectorPath.UNUSED);
+    private final LightPropertyMetadata lightMetadata
+            = new LightPropertyMetadata(new PropertyName("light"), //NOI18N
+            true /* readWrite */, LIGHTING_DEFAULT.getLight(), InspectorPath.UNUSED);
     private final DoublePropertyMetadata specularConstantMetadata
             = new DoublePropertyMetadata(new PropertyName("specularConstant"), //NOI18N
-            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 0.3, InspectorPath.UNUSED);
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 
+            LIGHTING_DEFAULT.getSpecularConstant(), InspectorPath.UNUSED);
     private final DoublePropertyMetadata specularExponentMetadata
             = new DoublePropertyMetadata(new PropertyName("specularExponent"), //NOI18N
-            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 20.0, InspectorPath.UNUSED);
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 
+            LIGHTING_DEFAULT.getSpecularExponent(), InspectorPath.UNUSED);
     private final DoublePropertyMetadata surfaceScaleMetadata
             = new DoublePropertyMetadata(new PropertyName("surfaceScale"), //NOI18N
-            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 1.5, InspectorPath.UNUSED);
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true /* readWrite */, 
+            LIGHTING_DEFAULT.getSurfaceScale(), InspectorPath.UNUSED);
 
     public LightingPropertyMetadata(PropertyName name, boolean readWrite, 
             Lighting defaultValue, InspectorPath inspectorPath) {
@@ -83,7 +90,7 @@
         bumpInputMetadata.setValue(result, value.getBumpInput());
         contentInputMetadata.setValue(result, value.getContentInput());
         diffuseConstantMetadata.setValue(result, value.getDiffuseConstant());
-//        lightMetadata.setValue(valueInstance, value.getLight());
+        lightMetadata.setValue(result, value.getLight());
         specularConstantMetadata.setValue(result, value.getSpecularConstant());
         specularExponentMetadata.setValue(result, value.getSpecularExponent());
         surfaceScaleMetadata.setValue(result, value.getSurfaceScale());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/DistantLightPropertyMetadata.java	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,79 @@
+/*
+ * 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.metadata.property.value.effect.light;
+
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.ComplexPropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.DoublePropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.paint.ColorPropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
+import javafx.scene.effect.Light;
+import javafx.scene.paint.Color;
+
+/**
+ *
+ */
+public class DistantLightPropertyMetadata extends ComplexPropertyMetadata<Light.Distant> {
+    
+    private final ColorPropertyMetadata colorMetadata
+            = new ColorPropertyMetadata(new PropertyName("color"), //NOI18N
+            true, Color.WHITE, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata azimuthMetadata
+            = new DoublePropertyMetadata(new PropertyName("azimuth"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.ANGLE, true, 45.0, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata elevationMetadata
+            = new DoublePropertyMetadata(new PropertyName("elevation"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.ANGLE, true, 45.0, InspectorPath.UNUSED);
+    
+    public DistantLightPropertyMetadata(PropertyName name, boolean readWrite, 
+            Light.Distant defaultValue, InspectorPath inspectorPath) {
+        super(name, Light.Distant.class, readWrite, defaultValue, inspectorPath);
+    }
+
+    /*
+     * ComplexPropertyMetadata
+     */
+    
+    @Override
+    public FXOMInstance makeFxomInstanceFromValue(Light.Distant value, FXOMDocument fxomDocument) {
+        final FXOMInstance result = new FXOMInstance(fxomDocument, getValueClass());
+        
+        colorMetadata.setValue(result, value.getColor());
+        azimuthMetadata.setValue(result, value.getAzimuth());
+        elevationMetadata.setValue(result, value.getElevation());
+
+        return result;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/LightPropertyMetadata.java	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,80 @@
+/*
+ * 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.metadata.property.value.effect.light;
+
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.ComplexPropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
+import javafx.scene.effect.Light;
+
+/**
+ *
+ */
+public class LightPropertyMetadata extends ComplexPropertyMetadata<Light> {
+
+    private final DistantLightPropertyMetadata distantLightMetadata;
+    private final PointLightPropertyMetadata pointLightMetadata;
+    private final SpotLightPropertyMetadata spotLightMetadata;
+
+    public LightPropertyMetadata(PropertyName name, boolean readWrite,
+            Light defaultValue, InspectorPath inspectorPath) {
+        super(name, Light.class, readWrite, defaultValue, inspectorPath);
+        distantLightMetadata = new DistantLightPropertyMetadata(name, readWrite, null, inspectorPath);
+        pointLightMetadata = new PointLightPropertyMetadata(name, readWrite, null, inspectorPath);
+        spotLightMetadata = new SpotLightPropertyMetadata(name, readWrite, null, inspectorPath);
+    }
+
+    /*
+     * ComplexPropertyMetadata
+     */
+    
+    @Override
+    public FXOMInstance makeFxomInstanceFromValue(Light value, FXOMDocument fxomDocument) {
+        final FXOMInstance result;
+        
+        if (value instanceof Light.Distant) {
+            result = distantLightMetadata.makeFxomInstanceFromValue((Light.Distant) value, fxomDocument);
+        } else if (value instanceof Light.Spot) { // Warning : Spot extends Point !
+            result = spotLightMetadata.makeFxomInstanceFromValue((Light.Spot) value, fxomDocument);
+        } else if (value instanceof Light.Point) {
+            result = pointLightMetadata.makeFxomInstanceFromValue((Light.Point) value, fxomDocument);
+        } else {
+            assert false;
+            result = distantLightMetadata.makeFxomInstanceFromValue(new Light.Distant(), fxomDocument);
+        }
+        
+        return result;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/PointLightPropertyMetadata.java	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,83 @@
+/*
+ * 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.metadata.property.value.effect.light;
+
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.ComplexPropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.DoublePropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.paint.ColorPropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
+import javafx.scene.effect.Light;
+import javafx.scene.paint.Color;
+
+/**
+ *
+ */
+public class PointLightPropertyMetadata extends ComplexPropertyMetadata<Light.Point> {
+    
+    private final ColorPropertyMetadata colorMetadata
+            = new ColorPropertyMetadata(new PropertyName("color"), //NOI18N
+            true, Color.WHITE, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata xMetadata
+            = new DoublePropertyMetadata(new PropertyName("x"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true, 0.0, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata yMetadata
+            = new DoublePropertyMetadata(new PropertyName("y"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true, 0.0, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata zMetadata
+            = new DoublePropertyMetadata(new PropertyName("z"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true, 0.0, InspectorPath.UNUSED);
+    
+    public PointLightPropertyMetadata(PropertyName name, boolean readWrite, 
+            Light.Point defaultValue, InspectorPath inspectorPath) {
+        super(name, Light.Point.class, readWrite, defaultValue, inspectorPath);
+    }
+
+    /*
+     * ComplexPropertyMetadata
+     */
+    
+    @Override
+    public FXOMInstance makeFxomInstanceFromValue(Light.Point value, FXOMDocument fxomDocument) {
+        final FXOMInstance result = new FXOMInstance(fxomDocument, getValueClass());
+        
+        colorMetadata.setValue(result, value.getColor());
+        xMetadata.setValue(result, value.getX());
+        yMetadata.setValue(result, value.getY());
+        zMetadata.setValue(result, value.getZ());
+
+        return result;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/property/value/effect/light/SpotLightPropertyMetadata.java	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,87 @@
+/*
+ * 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.metadata.property.value.effect.light;
+
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
+import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.ComplexPropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.DoublePropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.property.value.paint.ColorPropertyMetadata;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
+import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
+import javafx.scene.effect.Light;
+import javafx.scene.paint.Color;
+
+/**
+ *
+ */
+public class SpotLightPropertyMetadata extends ComplexPropertyMetadata<Light.Spot> {
+    
+    private final ColorPropertyMetadata colorMetadata
+            = new ColorPropertyMetadata(new PropertyName("color"), //NOI18N
+            true, Color.WHITE, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata pointsAtXMetadata
+            = new DoublePropertyMetadata(new PropertyName("pointsAtX"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true, 0.0, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata pointsAtYMetadata
+            = new DoublePropertyMetadata(new PropertyName("pointsAtY"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true, 0.0, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata pointsAtZMetadata
+            = new DoublePropertyMetadata(new PropertyName("pointsAtZ"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true, 0.0, InspectorPath.UNUSED);
+    private final DoublePropertyMetadata specularExponentMetadata
+            = new DoublePropertyMetadata(new PropertyName("specularExponent"), //NOI18N
+            DoublePropertyMetadata.DoubleKind.COORDINATE, true, 1.0, InspectorPath.UNUSED);
+    
+    public SpotLightPropertyMetadata(PropertyName name, boolean readWrite, 
+            Light.Spot defaultValue, InspectorPath inspectorPath) {
+        super(name, Light.Spot.class, readWrite, defaultValue, inspectorPath);
+    }
+
+    /*
+     * ComplexPropertyMetadata
+     */
+    
+    @Override
+    public FXOMInstance makeFxomInstanceFromValue(Light.Spot value, FXOMDocument fxomDocument) {
+        final FXOMInstance result = new FXOMInstance(fxomDocument, getValueClass());
+        
+        colorMetadata.setValue(result, value.getColor());
+        pointsAtXMetadata.setValue(result, value.getX());
+        pointsAtYMetadata.setValue(result, value.getY());
+        pointsAtZMetadata.setValue(result, value.getZ());
+        specularExponentMetadata.setValue(result, value.getSpecularExponent());
+
+        return result;
+    }
+    
+}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/util/PropertyName.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/metadata/util/PropertyName.java	Thu Feb 20 14:43:20 2014 +0100
@@ -87,6 +87,22 @@
         }
     }
     
+    
+    public static String makeClassFullName(Class<?> aClass) {
+        assert aClass != null;
+        
+        final StringBuilder result = new StringBuilder();
+        result.append(aClass.getSimpleName());
+        Class<?> declaringClass = aClass.getDeclaringClass();
+        while (declaringClass != null) {
+            result.insert(0, '.');
+            result.insert(0, declaringClass.getSimpleName());
+            declaringClass = declaringClass.getDeclaringClass();
+        }
+        
+        return result.toString();
+    }
+    
     /*
      * Object
      */
@@ -133,7 +149,7 @@
         if (residenceClass == null) {
             result = name;
         } else {
-            result = residenceClass.getSimpleName() + "." + name; //NOI18N
+            result = makeClassFullName(residenceClass) + "." + name; //NOI18N
         }
         
         return result;
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/Deprecation.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/Deprecation.java	Thu Feb 20 14:43:20 2014 +0100
@@ -99,14 +99,19 @@
     // Retrieve the node of the Styleable.
     public static Node getNode(Styleable styleable) {
         // Nodes are styleable treated differently.
-        if (styleable instanceof MenuItem) {
-            return ((MenuItem) styleable).impl_styleableGetNode();
-        } else if (styleable instanceof PopupControl) {
-            return ((PopupControl) styleable).impl_styleableGetNode();
-        } else if (styleable instanceof TableColumn) {
-            return ((TableColumn) styleable).impl_styleableGetNode();
-        } else if (styleable instanceof TreeTableColumn) {
-            return ((TreeTableColumn) styleable).impl_styleableGetNode();
+        try {
+            if (styleable instanceof MenuItem) {
+                return ((MenuItem) styleable).impl_styleableGetNode();
+            } else if (styleable instanceof PopupControl) {
+                return ((PopupControl) styleable).impl_styleableGetNode();
+            } else if (styleable instanceof TableColumn) {
+                return ((TableColumn) styleable).impl_styleableGetNode();
+            } else if (styleable instanceof TreeTableColumn) {
+                return ((TreeTableColumn) styleable).impl_styleableGetNode();
+            }
+        } catch (Exception ex) {
+            // May happen, e.g if TableColumn as root
+            return null;
         }
         return null;
     }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPathItem.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPathItem.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -93,7 +93,7 @@
           </items>
         </Menu>
         <SeparatorMenuItem mnemonicParsing="false" />
-        <MenuItem mnemonicParsing="false" onAction="#deleteEffect" text="Delete Effect" />
+        <MenuItem mnemonicParsing="false" onAction="#deleteEffect" text="Delete Effect"  fx:id="delete_menuitem" />
         <MenuItem mnemonicParsing="false" onAction="#deleteEffectInput" text="Delete Effect Input" fx:id="delete_input_menuitem" />
       </items>
     </MenuButton>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPathItem.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPathItem.java	Thu Feb 20 14:43:20 2014 +0100
@@ -35,6 +35,8 @@
 import java.net.URL;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
 import javafx.fxml.FXMLLoader;
@@ -63,6 +65,8 @@
     @FXML
     protected Tooltip tool_tip;
     @FXML
+    public MenuItem delete_menuitem;
+    @FXML
     public MenuItem delete_input_menuitem;
     @FXML
     public Menu replace_input_menu;
@@ -194,6 +198,7 @@
         assert menu_button != null;
         assert toggle_button != null;
         assert tool_tip != null;
+        assert delete_menuitem != null;
         assert delete_input_menuitem != null;
         assert replace_input_menu != null;
 
@@ -206,5 +211,34 @@
         final URL url = EffectPathItem.class.getResource("images/" + effect.getClass().getSimpleName() + ".png"); //NOI18N
         final Image img = new Image(url.toExternalForm());
         image_view.setImage(img);
+
+        menu_button.showingProperty().addListener(new ChangeListener<Boolean>() {
+
+            @Override
+            public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+                if (newValue) {
+                    // Disable menu item for the Lighting bump input.
+                    // javadoc says :
+                    // The optional bump map input. If not specified, a bump map 
+                    // will be automatically generated from the default input. 
+                    // If set to null, or left unspecified, a graphical image of 
+                    // the Node to which the Effect is attached will be used to 
+                    // generate a default bump map.
+                    // Default value:a Shadow effect with a radius of 10
+                    //
+                    // SB 2.0 just allow to replace the bump input property
+                    if (EffectPathItem.this instanceof LightingPathItem) {
+                        delete_input_menuitem.setDisable(true);
+                    } else {
+                        delete_input_menuitem.setDisable(false);
+                    }
+                    if (parentPahItem instanceof LightingPathItem) {
+                        delete_menuitem.setDisable(true);
+                    } else {
+                        delete_menuitem.setDisable(false);
+                    }
+                }
+            }
+        });
     }
 }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPicker.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPicker.java	Thu Feb 20 14:43:20 2014 +0100
@@ -38,6 +38,7 @@
 import java.util.Collections;
 import java.util.List;
 import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ReadOnlyBooleanProperty;
 import javafx.beans.property.ReadOnlyIntegerProperty;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
@@ -123,6 +124,14 @@
         return controller.revisionProperty();
     }
     
+    public final ReadOnlyBooleanProperty liveUpdateProperty() {
+        return controller.liveUpdateProperty();
+    }
+
+    public boolean isLiveUpdate() {
+        return controller.isLiveUpdate();
+    }
+    
     public String getEffectPath() {
         return controller.getEffectPath();
     }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPickerController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/EffectPickerController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -35,18 +35,20 @@
 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.EnumControl;
 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.ImageControl;
 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.DoubleTextFieldControl;
+import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.LightControl;
 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.SliderControl;
 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker;
 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker.Mode;
 import java.net.URL;
+import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.ReadOnlyIntegerProperty;
+import javafx.beans.property.SimpleBooleanProperty;
 import javafx.beans.property.SimpleIntegerProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.fxml.FXML;
-import javafx.scene.control.Label;
 import javafx.scene.control.Slider;
 import javafx.scene.control.ToggleButton;
 import javafx.scene.control.ToggleGroup;
@@ -97,6 +99,7 @@
     private final ObjectProperty<Effect> rootEffect = new SimpleObjectProperty<>();
     // The revision property is used when a change occurs on the root effect inputs
     private final SimpleIntegerProperty revision = new SimpleIntegerProperty();
+    private final BooleanProperty liveUpdate = new SimpleBooleanProperty();
 
     public EffectPickerController() {
         // Initialize selection chevron image
@@ -121,6 +124,18 @@
         return revision;
     }
 
+    public final BooleanProperty liveUpdateProperty() {
+        return liveUpdate;
+    }
+
+    public boolean isLiveUpdate() {
+        return liveUpdate.get();
+    }
+    
+    public void setLiveUpdate(boolean value) {
+        liveUpdate.setValue(value);
+    }
+    
     public EffectPicker.Delegate getEffectPickerDelegate() {
         return effectPickerDelegate;
     }
@@ -459,6 +474,7 @@
         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate);
         colorPicker.setPaintProperty(colorInput.getPaint());
         colorPicker.paintProperty().addListener(new PaintChangeListener(this, colorInput));
+        colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
         vBox.getChildren().add(colorPicker);
 
         props_vbox.getChildren().add(vBox);
@@ -541,6 +557,7 @@
         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate, Mode.COLOR);
         colorPicker.setPaintProperty(dropShadow.getColor());
         colorPicker.paintProperty().addListener(new ColorChangeListener(this, dropShadow));
+        colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
         vBox.getChildren().add(colorPicker);
 
         props_vbox.getChildren().add(vBox);
@@ -639,6 +656,7 @@
         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate, Mode.COLOR);
         colorPicker.setPaintProperty(innerShadow.getColor());
         colorPicker.paintProperty().addListener(new ColorChangeListener(this, innerShadow));
+        colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
         vBox.getChildren().add(colorPicker);
 
         props_vbox.getChildren().add(vBox);
@@ -669,8 +687,11 @@
         lighting.surfaceScaleProperty().bind(surfaceScaleEditor.valueProperty());
         vBox.getChildren().add(surfaceScaleEditor);
 
-        // need editor for this
-        vBox.getChildren().add(new Label("Light Editor here")); //NOI18N
+        final LightControl lightControl = new LightControl(
+                this, "light", lighting.getLight()); //NOI18N
+        lighting.lightProperty().bind(lightControl.valueProperty());
+        lightControl.liveUpdateProperty().addListener(new LightControlLiveUpdateListener(lightControl, this));
+        vBox.getChildren().add(lightControl);
 
         props_vbox.getChildren().add(vBox);
     }
@@ -811,6 +832,7 @@
         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate, Mode.COLOR);
         colorPicker.setPaintProperty(shadow.getColor());
         colorPicker.paintProperty().addListener(new ColorChangeListener(this, shadow));
+        colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
         vBox.getChildren().add(colorPicker);
 
         props_vbox.getChildren().add(vBox);
@@ -821,6 +843,42 @@
      * Static inner class
      * *************************************************************************
      */
+    private static class PaintPickerLiveUpdateListener implements ChangeListener<Boolean> {
+
+        private final PaintPicker paintPicker;
+        private final EffectPickerController effectPickerController;
+
+        public PaintPickerLiveUpdateListener(
+                PaintPicker paintPicker,
+                EffectPickerController effectPickerController) {
+            this.paintPicker = paintPicker;
+            this.effectPickerController = effectPickerController;
+        }
+
+        @Override
+        public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+            effectPickerController.setLiveUpdate(paintPicker.isLiveUpdate());
+        }
+    }
+    
+    private static class LightControlLiveUpdateListener implements ChangeListener<Boolean> {
+
+        private final LightControl lightControl;
+        private final EffectPickerController effectPickerController;
+
+        public LightControlLiveUpdateListener(
+                LightControl lightControl,
+                EffectPickerController effectPickerController) {
+            this.lightControl = lightControl;
+            this.effectPickerController = effectPickerController;
+        }
+
+        @Override
+        public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+            effectPickerController.setLiveUpdate(lightControl.isLiveUpdate());
+        }
+    }
+    
     private static class ColorChangeListener implements ChangeListener<Paint> {
 
         private final EffectPickerController effectPickerController;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/editors/LightControl.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+<?import java.lang.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<fx:root type="VBox" spacing="8.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
+  <children>
+    <GridPane id="GridPane" hgap="4.0">
+      <children>
+        <Label fx:id="lightLabel" text="Label" GridPane.columnIndex="0" GridPane.rowIndex="0" />
+        <ChoiceBox fx:id="lightChoiceBox" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="0" />
+      </children>
+      <columnConstraints>
+        <ColumnConstraints halignment="RIGHT" hgrow="ALWAYS" minWidth="10.0" percentWidth="40.0" />
+        <ColumnConstraints hgrow="NEVER" minWidth="-1.0" />
+      </columnConstraints>
+      <rowConstraints>
+        <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
+      </rowConstraints>
+    </GridPane>
+    <VBox fx:id="lightProperties" spacing="8.0" />
+  </children>
+</fx:root>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/editors/LightControl.java	Thu Feb 20 14:43:20 2014 +0100
@@ -0,0 +1,273 @@
+/*
+ * 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.util.control.effectpicker.editors;
+
+import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.EffectPickerController;
+import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.Label;
+import javafx.scene.effect.Light;
+import javafx.scene.effect.Light.Distant;
+import javafx.scene.effect.Light.Point;
+import javafx.scene.effect.Light.Spot;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.Paint;
+
+public class LightControl extends VBox {
+
+    @FXML
+    private Label lightLabel;
+    @FXML
+    private ChoiceBox<LightsEnum> lightChoiceBox;
+    @FXML
+    private VBox lightProperties;
+
+    private final ObjectProperty<Light> value = new SimpleObjectProperty<>();
+    private final EffectPickerController effectPickerController;
+
+    // Common color property
+    private PaintPicker colorPicker;
+
+    private final Light defaultDistant;
+    private final Light defaultPoint;
+    private final Light defaultSpot;
+
+    private final BooleanProperty liveUpdate = new SimpleBooleanProperty();
+
+    private enum LightsEnum {
+
+        DISTANT,
+        POINT,
+        SPOT
+    }
+
+    public LightControl(EffectPickerController effectPickerController,
+            String label, Light initValue) {
+        this.effectPickerController = effectPickerController;
+        this.defaultDistant = new Distant();
+        this.defaultPoint = new Point();
+        this.defaultSpot = new Spot();
+        initialize(label, initValue);
+    }
+
+    public ObjectProperty<Light> valueProperty() {
+        return value;
+    }
+
+    public Light getValue() {
+        return value.get();
+    }
+
+    public void setValue(Light v) {
+        value.set(v);
+    }
+
+    public final BooleanProperty liveUpdateProperty() {
+        return liveUpdate;
+    }
+
+    public boolean isLiveUpdate() {
+        return liveUpdate.get();
+    }
+
+    public void setLiveUpdate(boolean value) {
+        liveUpdate.setValue(value);
+    }
+
+    private void initialize(String label, Light initValue) {
+
+        final URL layoutURL = EnumControl.class.getResource("LightControl.fxml"); //NOI18N
+        try (InputStream is = layoutURL.openStream()) {
+            final FXMLLoader loader = new FXMLLoader();
+            loader.setController(this);
+            loader.setRoot(this);
+            loader.setLocation(layoutURL);
+            final Parent p = (Parent) loader.load(is);
+            assert p == this;
+        } catch (IOException x) {
+            throw new RuntimeException(x);
+        }
+
+        lightLabel.setText(label);
+        lightChoiceBox.getItems().addAll(LightsEnum.values());
+
+        setValue(initValue);
+        assert initValue != null;  // SB 2.0 metadatas do not allow to set null value
+        if (initValue instanceof Distant) {
+            lightChoiceBox.setValue(LightsEnum.DISTANT);
+        } else if (initValue instanceof Point) {
+            lightChoiceBox.setValue(LightsEnum.POINT);
+        } else {
+            assert initValue instanceof Spot;
+            lightChoiceBox.setValue(LightsEnum.SPOT);
+        }
+
+        lightChoiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<LightsEnum>() {
+
+            @Override
+            public void changed(ObservableValue<? extends LightsEnum> ov, LightsEnum oldValue, LightsEnum newValue) {
+                final Light light;
+                switch (newValue) {
+                    case DISTANT:
+                        light = defaultDistant;
+                        break;
+                    case POINT:
+                        light = defaultPoint;
+                        break;
+                    case SPOT:
+                        light = defaultSpot;
+                        break;
+                    default:
+                        light = null;
+                        assert false;
+                }
+                // First update the model with new light value
+                setValue(light);
+                // Then update the UI
+                updateLightPropertiesUI();
+                // Then notify the controller a change occured
+                effectPickerController.incrementRevision();
+            }
+        });
+
+        updateLightPropertiesUI();
+    }
+
+    private void updateLightPropertiesUI() {
+        lightProperties.getChildren().clear();
+
+        // Add specific properties
+        if (getValue() == null) {
+            // No property to add
+        } else {
+            // Add common color property
+            lightProperties.getChildren().add(getColorPicker());
+            colorPicker.setPaintProperty(getValue().getColor());
+
+            if (getValue() instanceof Distant) {
+                final Distant distant = (Distant) getValue();
+
+                final SliderControl azimuthEditor = new SliderControl(
+                        effectPickerController, "azimuth", 0, 360.0, distant.getAzimuth(), 1.0, false); //NOI18N
+                distant.azimuthProperty().bind(azimuthEditor.valueProperty());
+                lightProperties.getChildren().add(azimuthEditor);
+
+                final SliderControl elevationEditor = new SliderControl(
+                        effectPickerController, "elevation", 0, 360.0, distant.getElevation(), 1.0, false); //NOI18N
+                distant.elevationProperty().bind(elevationEditor.valueProperty());
+                lightProperties.getChildren().add(elevationEditor);
+
+            } else {
+                assert getValue() instanceof Point;
+                final Point point = (Point) getValue();
+
+                final DoubleTextFieldControl xEditor = new DoubleTextFieldControl(
+                        effectPickerController, "x", -10.0, 10.0, point.getX(), 1.0); //NOI18N
+                point.xProperty().bind(xEditor.valueProperty());
+                lightProperties.getChildren().add(xEditor);
+
+                final DoubleTextFieldControl yEditor = new DoubleTextFieldControl(
+                        effectPickerController, "y", -10.0, 10.0, point.getY(), 1.0); //NOI18N
+                point.yProperty().bind(yEditor.valueProperty());
+                lightProperties.getChildren().add(yEditor);
+
+                final DoubleTextFieldControl zEditor = new DoubleTextFieldControl(
+                        effectPickerController, "z", -10.0, 10.0, point.getY(), 1.0); //NOI18N
+                point.zProperty().bind(zEditor.valueProperty());
+                lightProperties.getChildren().add(zEditor);
+
+                if (point instanceof Spot) {
+                    final Spot spot = (Spot) getValue();
+
+                    final DoubleTextFieldControl pointsAtXEditor = new DoubleTextFieldControl(
+                            effectPickerController, "pointsAtX", -10.0, 10.0, spot.getPointsAtX(), 1.0); //NOI18N
+                    spot.pointsAtXProperty().bind(pointsAtXEditor.valueProperty());
+                    lightProperties.getChildren().add(pointsAtXEditor);
+
+                    final DoubleTextFieldControl pointsAtYEditor = new DoubleTextFieldControl(
+                            effectPickerController, "pointsAtY", -10.0, 10.0, spot.getPointsAtY(), 1.0); //NOI18N
+                    spot.pointsAtYProperty().bind(pointsAtYEditor.valueProperty());
+                    lightProperties.getChildren().add(pointsAtYEditor);
+
+                    final DoubleTextFieldControl pointsAtZEditor = new DoubleTextFieldControl(
+                            effectPickerController, "pointsAtZ", -10.0, 10.0, spot.getPointsAtZ(), 1.0); //NOI18N
+                    spot.pointsAtZProperty().bind(pointsAtZEditor.valueProperty());
+                    lightProperties.getChildren().add(pointsAtZEditor);
+
+                    final SliderControl specularExponentEditor = new SliderControl(
+                            effectPickerController, "specularExponent", 0, 4.0, spot.getSpecularExponent(), 1.0, false); //NOI18N
+                    spot.specularExponentProperty().bind(specularExponentEditor.valueProperty());
+                    lightProperties.getChildren().add(specularExponentEditor);
+
+                }
+            }
+        }
+    }
+
+    private PaintPicker getColorPicker() {
+        if (colorPicker == null) {
+            colorPicker = new PaintPicker(effectPickerController.getPaintPickerDelegate(), PaintPicker.Mode.COLOR);
+            colorPicker.paintProperty().addListener(new ChangeListener<Paint>() {
+
+                @Override
+                public void changed(ObservableValue<? extends Paint> ov, Paint oldValue, Paint newValue) {
+                    assert newValue instanceof Color;
+                    final Color color = (Color) newValue;
+                    getValue().setColor(color);
+                    // Then notify the controller a change occured
+                    effectPickerController.incrementRevision();
+                }
+            });
+            colorPicker.liveUpdateProperty().addListener(new ChangeListener<Boolean>() {
+
+                @Override
+                public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+                    setLiveUpdate(newValue);
+                }
+            });
+        }
+        return colorPicker;
+    }
+}
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/editors/SliderControl.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/editors/SliderControl.java	Thu Feb 20 14:43:20 2014 +0100
@@ -171,6 +171,13 @@
                 effectPickerController.incrementRevision();
             }
         });
+        editor_slider.pressedProperty().addListener(new ChangeListener<Boolean>() {
+
+            @Override
+            public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+                effectPickerController.setLiveUpdate(newValue);
+            }
+        });
 
         editor_textfield.focusedProperty().addListener(new ChangeListener<Boolean>() {
 
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPicker.fxml	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPicker.fxml	Thu Feb 20 14:43:20 2014 +0100
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+
 <!--
   Copyright (c) 2012, 2014, Oracle and/or its affiliates.
   All rights reserved. Use is subject to license terms.
@@ -30,15 +31,13 @@
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
+
 <?import java.lang.*?>
 <?import java.net.*?>
-<?import java.util.*?>
-<?import javafx.geometry.*?>
 <?import javafx.scene.control.*?>
 <?import javafx.scene.layout.*?>
-<?import javafx.scene.paint.*?>
 
-<VBox fx:id="root_vbox" alignment="CENTER" minHeight="-1.0" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPickerController">
+<VBox fx:id="root_vbox" alignment="CENTER" minHeight="-1.0" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPickerController">
   <children>
     <HBox>
       <children>
@@ -52,9 +51,6 @@
       </children>
     </HBox>
   </children>
-  <padding>
-    <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
-  </padding>
   <stylesheets>
     <URL value="@PaintPicker.css" />
   </stylesheets>
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPicker.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPicker.java	Thu Feb 20 14:43:20 2014 +0100
@@ -33,6 +33,7 @@
 
 import java.io.IOException;
 import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ReadOnlyBooleanProperty;
 import javafx.fxml.FXMLLoader;
 import javafx.scene.Node;
 import javafx.scene.layout.Pane;
@@ -91,6 +92,14 @@
         return controller.getPaintProperty();
     }
     
+    public final ReadOnlyBooleanProperty liveUpdateProperty() {
+        return controller.liveUpdateProperty();
+    }
+
+    public boolean isLiveUpdate() {
+        return controller.isLiveUpdate();
+    }
+    
     public static interface Delegate {
         public void handleError(String warningKey, Object... arguments);
     }
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPickerController.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPickerController.java	Thu Feb 20 14:43:20 2014 +0100
@@ -37,7 +37,9 @@
 import static com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker.Mode.RADIAL;
 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.colorpicker.ColorPicker;
 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.gradientpicker.GradientPicker;
+import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleBooleanProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
@@ -72,6 +74,7 @@
     private PaintPicker.Delegate delegate;
 
     private final ObjectProperty<Paint> paint = new SimpleObjectProperty<>();
+    private final BooleanProperty liveUpdate = new SimpleBooleanProperty();
 
     public final static Color DEFAULT_COLOR = Color.BLACK;
     public final static LinearGradient DEFAULT_LINEAR
@@ -91,10 +94,18 @@
         paint.setValue(value);
     }
 
-    public VBox getRoot() {
-        return root_vbox;
+    public final BooleanProperty liveUpdateProperty() {
+        return liveUpdate;
     }
 
+    public boolean isLiveUpdate() {
+        return liveUpdate.get();
+    }
+    
+    public void setLiveUpdate(boolean value) {
+        liveUpdate.setValue(value);
+    }
+    
     public ColorPicker getColorPicker() {
         return colorPicker;
     }
@@ -107,6 +118,10 @@
         return delegate;
     }
     
+    public VBox getRoot() {
+        return root_vbox;
+    }
+
     /**
      * Simple utility function which clamps the given value to be strictly
      * between the min and max values.
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/colorpicker/ColorPicker.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/colorpicker/ColorPicker.java	Thu Feb 20 14:43:20 2014 +0100
@@ -257,6 +257,16 @@
                 setPaintProperty(color);
             }
         });
+
+        final ChangeListener<Boolean> liveUpdateListener = new ChangeListener<Boolean>() {
+            @Override
+            public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+                paintPickerController.setLiveUpdate(newValue);
+            }
+        };
+        picker_region.pressedProperty().addListener(liveUpdateListener);
+        hue_slider.pressedProperty().addListener(liveUpdateListener);
+        alpha_slider.pressedProperty().addListener(liveUpdateListener);
     }
 
     /**
--- a/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/gradientpicker/GradientPicker.java	Fri Feb 14 08:27:15 2014 +0100
+++ b/apps/scenebuilder/SceneBuilderKit/src/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/gradientpicker/GradientPicker.java	Thu Feb 20 14:43:20 2014 +0100
@@ -304,6 +304,23 @@
         radial_container.getChildren().addAll(radiusSlider, focusDistanceSlider, focusAngleRotator);
         radial_container.setVisible(false);
         radial_container.setManaged(false);
+
+        final ChangeListener<Boolean> liveUpdateListener = new ChangeListener<Boolean>() {
+            @Override
+            public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
+                paintPicker.setLiveUpdate(newValue);
+            }
+        };
+        startX_slider.pressedProperty().addListener(liveUpdateListener);
+        startY_slider.pressedProperty().addListener(liveUpdateListener);
+        endX_slider.pressedProperty().addListener(liveUpdateListener);
+        endY_slider.pressedProperty().addListener(liveUpdateListener);
+        centerX_slider.pressedProperty().addListener(liveUpdateListener);
+        centerY_slider.pressedProperty().addListener(liveUpdateListener);
+        radiusSlider.pressedProperty().addListener(liveUpdateListener);
+        focusDistanceSlider.pressedProperty().addListener(liveUpdateListener);
+        focusAngleRotator.pressedProperty().addListener(liveUpdateListener);
+        slider_container.pressedProperty().addListener(liveUpdateListener);
     }
 
     @FXML