Commits

Samir Hadzic committed 355e418 Merge

Merged controlsfx/controlsfx into default

Comments (0)

Files changed (35)

controlsfx-samples/build.gradle

     }
 }
 
+compileJava {  
+    options.encoding = "UTF-8"
+}
+
 jar {
     manifest {
         attributes 'Implementation-Title': 'ControlsFX-Samples', 'Implementation-Version': project.version

controlsfx-samples/src/main/java/org/controlsfx/samples/HelloGridView.java

 import org.controlsfx.control.GridCell;
 import org.controlsfx.control.GridView;
 import org.controlsfx.control.SegmentedButton;
-import org.controlsfx.control.action.AbstractAction;
+import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.ActionUtils;
 import org.controlsfx.control.cell.ColorGridCell;
 import org.controlsfx.control.cell.ImageGridCell;
         return root;
     }
     
-    class ActionShowGrid extends AbstractAction {
+    class ActionShowGrid extends Action {
 
         GridView<?> grid;
         

controlsfx-samples/src/main/java/org/controlsfx/samples/HelloNotificationPane.java

 
 import org.controlsfx.ControlsFXSample;
 import org.controlsfx.control.NotificationPane;
-import org.controlsfx.control.action.AbstractAction;
+import org.controlsfx.control.action.Action;
 
 public class HelloNotificationPane extends ControlsFXSample {
     
         ImageView image = new ImageView(imagePath);
         notificationPane.setGraphic(image);
         
-        notificationPane.getActions().addAll(new AbstractAction("Sync") {
+        notificationPane.getActions().addAll(new Action("Sync") {
             @Override public void handle(ActionEvent ae) {
                 // do sync
                 

controlsfx-samples/src/main/java/org/controlsfx/samples/HelloPropertySheet.java

 import org.controlsfx.control.PropertySheet.Item;
 import org.controlsfx.control.PropertySheet.Mode;
 import org.controlsfx.control.SegmentedButton;
-import org.controlsfx.control.action.AbstractAction;
+import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.ActionUtils;
 import org.controlsfx.property.BeanProperty;
 import org.controlsfx.property.BeanPropertyUtils;
 
     }
 
-    class ActionShowInPropertySheet extends AbstractAction {
+    class ActionShowInPropertySheet extends Action {
 
         private Object bean;
 
         return infoPane;
     }
 
-    class ActionModeChange extends AbstractAction {
+    class ActionModeChange extends Action {
 
         private Mode mode;
 

controlsfx-samples/src/main/java/org/controlsfx/samples/actions/HelloActionGroup.java

 import javafx.stage.Stage;
 
 import org.controlsfx.ControlsFXSample;
-import org.controlsfx.control.action.AbstractAction;
+import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.ActionGroup;
 import org.controlsfx.control.action.ActionUtils;
                                            new DummyAction("Action 4.2"))
     );
     
-    static class DummyAction extends AbstractAction {
+    static class DummyAction extends Action {
         public DummyAction(String name, Node image) {
             super(name);
             setGraphic(image);
         hbox.getChildren().add(new Label("Dynamically enable/disable action: "));
         hbox.getChildren().add(cbActions);
         
-        Action toggleAction = new AbstractAction("Enable/Disable") {
+        Action toggleAction = new Action("Enable/Disable") {
 
             @Override public void handle(ActionEvent ae) {
                Action action = cbActions.getSelectionModel().getSelectedItem();

controlsfx-samples/src/main/java/org/controlsfx/samples/actions/HelloActionProxy.java

 import javafx.stage.Stage;
 
 import org.controlsfx.ControlsFXSample;
-import org.controlsfx.control.action.AbstractAction;
+import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.ActionGroup;
 import org.controlsfx.control.action.ActionMap;
         hbox.getChildren().add(new Label("Dynamically enable/disable action: "));
         hbox.getChildren().add(cbActions);
         
-        Action toggleAction = new AbstractAction("Enable/Disable") {
+        Action toggleAction = new Action("Enable/Disable") {
 
             @Override public void handle(ActionEvent ae) {
                Action action = cbActions.getSelectionModel().getSelectedItem();

controlsfx-samples/src/main/java/org/controlsfx/samples/dialogs/HelloDialog.java

 import javafx.scene.control.SelectionModel;
 import javafx.scene.control.TextField;
 import javafx.scene.control.ToggleButton;
+import javafx.scene.image.Image;
 import javafx.scene.image.ImageView;
 import javafx.scene.layout.GridPane;
 import javafx.scene.layout.HBox;
 import org.controlsfx.control.ButtonBar.ButtonType;
 import org.controlsfx.control.SegmentedButton;
 import org.controlsfx.control.action.Action;
-import org.controlsfx.dialog.DefaultDialogAction;
+import org.controlsfx.dialog.DialogAction;
 import org.controlsfx.dialog.Dialog;
 import org.controlsfx.dialog.Dialog.ActionTrait;
-import org.controlsfx.dialog.DialogStyle;
 import org.controlsfx.dialog.Dialogs;
 import org.controlsfx.dialog.Dialogs.CommandLink;
 import org.controlsfx.dialog.Dialogs.UserInfo;
 
 public class HelloDialog extends ControlsFXSample {
 
-    private final ComboBox<DialogStyle> styleCombobox = new ComboBox<>();
-	private final CheckBox cbUseLightweightDialog = new CheckBox("Use Lightweight Dialogs");
-	private final CheckBox cbShowMasthead = new CheckBox("Show Masthead");
-	private final CheckBox cbSetOwner = new CheckBox("Set Owner");
+    private final ComboBox<String> styleCombobox = new ComboBox<>();
+	private final CheckBox cbUseLightweightDialog = new CheckBox();
+	private final CheckBox cbShowMasthead = new CheckBox();
+	private final CheckBox cbSetOwner = new CheckBox();
+	private final CheckBox cbCustomGraphic = new CheckBox();
+	
 
 	@Override
 	public String getSampleName() {
 
 			final TextField txUserName = new TextField();
 			final PasswordField txPassword = new PasswordField();
-			final Action actionLogin = new DefaultDialogAction("Login",
+			final Action actionLogin = new DialogAction("Login",
 					ActionTrait.CLOSING, ActionTrait.DEFAULT) {
 
 				{
 			@Override
 			public void handle(ActionEvent arg0) {
 				Dialog dlg = new Dialog(includeOwner() ? stage : null,
-						"Login Dialog", cbUseLightweightDialog.isSelected(),getDialogStyle());
+						"Login Dialog", cbUseLightweightDialog.isSelected());
+				dlg.getStyleClass().addAll(getDialogStyle());
+				
 				if (cbShowMasthead.isSelected()) {
 					dlg.setMasthead("Login to ControlsFX");
 				}
 			dialog.lightweight();
 		}
 		
-		dialog.style(getDialogStyle());
+		if (cbCustomGraphic.isSelected()) {
+		    dialog.graphic(new ImageView(new Image(getClass().getResource("../controlsfx-logo.png").toExternalForm())));
+		}
+		
+		dialog.styleClass(getDialogStyle());
 
 		return dialog;
 	}
 		
 		// stage style
 		grid.add(createLabel("Style: ", "property"), 0, row);
-        styleCombobox.getItems().addAll(DialogStyle.values());
+        styleCombobox.getItems().addAll("Cross-platform", "Native", "Undecorated");
         styleCombobox.setValue(styleCombobox.getItems().get(0));
         grid.add(styleCombobox, 1, row);
         row++;
 		grid.add(createLabel("Set dialog owner: ", "property"), 0, row);
 		grid.add(cbSetOwner, 1, row);
 		row++;
+		
+		// custom graphic
+        grid.add(createLabel("Use custom graphic: ", "property"), 0, row);
+        grid.add(cbCustomGraphic, 1, row);
+        row++;
 
 		return grid;
 	}
 	
-	private DialogStyle getDialogStyle() {
-	    SelectionModel<DialogStyle> sm = styleCombobox.getSelectionModel();
-	    return sm.getSelectedItem() == null ? DialogStyle.CROSS_PLATFORM_DARK : sm.getSelectedItem();
+	private String getDialogStyle() {
+	    SelectionModel<String> sm = styleCombobox.getSelectionModel();
+	    return sm.getSelectedItem() == null ? "cross-platform" : sm.getSelectedItem().toLowerCase();
 	}
 
 	public static void main(String[] args) {

controlsfx-samples/src/main/java/org/controlsfx/samples/propertysheet/PopupPropertyEditor.java

 import org.controlsfx.control.ButtonBar;
 import org.controlsfx.control.PropertySheet;
 import org.controlsfx.control.action.Action;
-import org.controlsfx.dialog.DefaultDialogAction;
+import org.controlsfx.dialog.DialogAction;
 import org.controlsfx.dialog.Dialog;
-import org.controlsfx.dialog.DialogStyle;
 import org.controlsfx.property.BeanProperty;
 import org.controlsfx.property.BeanPropertyUtils;
 import org.controlsfx.property.editor.PropertyEditor;
     private final PropertySheet.Item item;
     private final ObjectProperty<T> value = new SimpleObjectProperty<>();
 
-    final Action actionSave = new DefaultDialogAction("Save",
+    final Action actionSave = new DialogAction("Save",
             Dialog.ActionTrait.CLOSING, Dialog.ActionTrait.DEFAULT) {
                 {
                     ButtonBar.setType(this, ButtonBar.ButtonType.OK_DONE);
     private void displayPopupEditor() {
         PopupPropertySheet<T> sheet = new PopupPropertySheet<>(item, this);
 
-        Dialog dlg = new Dialog(null, "Popup Property Editor", false,
-                DialogStyle.CROSS_PLATFORM_DARK);
+        Dialog dlg = new Dialog(null, "Popup Property Editor", false);
 
         dlg.setResizable(false);
         dlg.setIconifiable(false);

controlsfx/build.gradle

     specification_title = commons.controlsfx_specification_title
     implementation_version = commons.controlsfx_version
 }
+
 sourceCompatibility = '1.8'
 targetCompatibility = '1.8'
 
 
 processResources.dependsOn(generatei18nResources)
 
+compileJava {  
+    options.encoding = "UTF-8"
+}
+
 javadoc {
     exclude 'impl/*'
     failOnError = true

controlsfx/mavenPublish.gradle

                 distribution 'repo'
             }
         }
+        properties {
+            project.build.sourceEncoding='UTF-8'
+        }
     }
 }
 
             throw new StopExecutionException()
         }
     }
-}
+}
+

controlsfx/src/main/java/impl/org/controlsfx/ImplUtils.java

  */
 package impl.org.controlsfx;
 
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 import javafx.collections.ObservableList;
+import javafx.scene.Group;
 import javafx.scene.Node;
 import javafx.scene.Parent;
 import javafx.scene.Scene;
+import javafx.scene.control.Control;
+import javafx.scene.control.Skin;
+import javafx.scene.control.SkinBase;
+import javafx.scene.layout.Pane;
 
 public class ImplUtils {
 
         // no-op
     }
     
-    public static void injectAsRootPane(Scene scene, Parent injectedParent) {
+    public static void injectAsRootPane(Scene scene, Parent injectedParent, boolean useReflection) {
         Parent originalParent = scene.getRoot();
         scene.setRoot(injectedParent);
         
         if (originalParent != null) {
-            getChildren(injectedParent).add(0, originalParent);
+            getChildren(injectedParent, useReflection).add(0, originalParent);
             
             // copy in layout properties, etc, so that the dialogStack displays
             // properly in (hopefully) whatever layout the owner node is in
         }
     }
     
-    public static void injectPane(Parent parent, Parent injectedParent) {
-        ObservableList<Node> ownerParentChildren = getChildren(parent.getParent());
+    // parent is where we want to inject the injectedParent. We then need to
+    // set the child of the injectedParent to include parent.
+    // The end result is that we've forced in the injectedParent node above parent.
+    public static void injectPane(Parent parent, Parent injectedParent, boolean useReflection) {
+        if (parent == null) {
+            throw new IllegalArgumentException("parent can not be null");
+        }
+        
+        ObservableList<Node> ownerParentChildren = getChildren(parent.getParent(), useReflection);
         
         // we've got the children list, now we need to insert a temporary
         // layout container holding our dialogs and opaque layer / effect
         ownerParentChildren.remove(ownerPos);
         ownerParentChildren.add(ownerPos, injectedParent);
         
-        if (parent != null) {
-            getChildren(injectedParent).add(0, parent);
-            
-            // copy in layout properties, etc, so that the dialogStack displays
-            // properly in (hopefully) whatever layout the owner node is in
-            injectedParent.getProperties().putAll(parent.getProperties());
-        }
+        // now we install the parent as a child of the injectedParent
+        getChildren(injectedParent, useReflection).add(0, parent);
+        
+        // copy in layout properties, etc, so that the dialogStack displays
+        // properly in (hopefully) whatever layout the owner node is in
+        injectedParent.getProperties().putAll(parent.getProperties());
     }
     
-    public static void stripRootPane(Scene scene, Parent originalParent) {
+    public static void stripRootPane(Scene scene, Parent originalParent, boolean useReflection) {
         Parent oldParent = scene.getRoot();
-        getChildren(oldParent).remove(originalParent);
+        getChildren(oldParent, useReflection).remove(originalParent);
         originalParent.getStyleClass().remove("root"); //$NON-NLS-1$
         scene.setRoot(originalParent);        
     }
     
     @SuppressWarnings("unchecked")
-    public static ObservableList<Node> getChildren(Parent p) {
+    public static ObservableList<Node> getChildren(Parent p, boolean useReflection) {
         ObservableList<Node> children = null;
         
-        try {
-            Method getChildrenMethod = Parent.class.getDeclaredMethod("getChildren"); //$NON-NLS-1$
-            
-            if (getChildrenMethod != null) {
-                if (! getChildrenMethod.isAccessible()) {
-                    getChildrenMethod.setAccessible(true);
+        // previously we used reflection immediately, now we try to avoid reflection
+        // by checking the type of the Parent. Still not great...
+        if (p instanceof Pane) {
+            // This should cover the majority of layout containers, including
+            // AnchorPane, FlowPane, GridPane, HBox, Pane, StackPane, TilePane, VBox
+            children = ((Pane)p).getChildren();
+        } else if (p instanceof Group) {
+            children = ((Group)p).getChildren();
+        } else if (p instanceof Control) {
+            Control c = (Control) p;
+            Skin<?> s = c.getSkin();
+            children = s instanceof SkinBase ? ((SkinBase<?>)s).getChildren() : null;
+        } else if (useReflection) {
+            // we really want to avoid using this!!!!
+            try {
+                Method getChildrenMethod = Parent.class.getDeclaredMethod("getChildren"); //$NON-NLS-1$
+                
+                if (getChildrenMethod != null) {
+                    if (! getChildrenMethod.isAccessible()) {
+                        getChildrenMethod.setAccessible(true);
+                    }
+                    children = (ObservableList<Node>) getChildrenMethod.invoke(p);
+                } else {
+                    // uh oh, trouble
                 }
-                children = (ObservableList<Node>) getChildrenMethod.invoke(p);
-            } else {
-                // uh oh, trouble
+            } catch (ReflectiveOperationException | IllegalArgumentException e) {
+            	throw new RuntimeException("Unable to get children for Parent of type " + p.getClass(), e);
             }
-        } catch (SecurityException e) {
-            e.printStackTrace();
-        } catch (IllegalArgumentException e) {
-            e.printStackTrace();
-        } catch (NoSuchMethodException e) {
-            e.printStackTrace();
-        } catch (IllegalAccessException e) {
-            e.printStackTrace();
-        } catch (InvocationTargetException e) {
-            e.printStackTrace();
+        }
+        
+        if (children == null) {
+            throw new RuntimeException("Unable to get children for Parent of type " + p.getClass() + 
+                                       ". useReflection is set to " + useReflection);
         }
         
         return children;

controlsfx/src/main/java/impl/org/controlsfx/skin/PropertySheetSkin.java

 import org.controlsfx.control.PropertySheet.Item;
 import org.controlsfx.control.PropertySheet.Mode;
 import org.controlsfx.control.SegmentedButton;
-import org.controlsfx.control.action.AbstractAction;
+import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.ActionUtils;
 import org.controlsfx.control.textfield.TextFields;
 import org.controlsfx.property.editor.AbstractPropertyEditor;
      * 
      **************************************************************************/
     
-    private class ActionChangeMode extends AbstractAction {
+    private class ActionChangeMode extends Action {
         
     	private final Image CATEGORY_IMAGE = new Image("/impl/org/controlsfx/dialog/resources/oxygen/16/format-indent-more.png");
     	private final Image NAME_IMAGE = new Image("/impl/org/controlsfx/dialog/resources/oxygen/16/format-line-spacing-triple.png");

controlsfx/src/main/java/org/controlsfx/control/NotificationPane.java

 import javafx.scene.control.Skin;
 import javafx.scene.web.WebView;
 
-import org.controlsfx.control.action.AbstractAction;
+import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.Action;
 
 /**
  * }}</pre>
  * 
  * @see Action
- * @see AbstractAction
+ * @see Action
  */
 public class NotificationPane extends ControlsFXControl {
     

controlsfx/src/main/java/org/controlsfx/control/action/AbstractAction.java

-/**
- * Copyright (c) 2013, ControlsFX
- * All rights reserved.
- *
- * 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 ControlsFX, any associated website, 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 CONTROLSFX 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 org.controlsfx.control.action;
-
-import impl.org.controlsfx.i18n.Localization;
-import impl.org.controlsfx.i18n.SimpleLocalizedStringProperty;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.SimpleBooleanProperty;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.beans.property.StringProperty;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableMap;
-import javafx.scene.Node;
-import javafx.scene.control.Button;
-import javafx.scene.input.KeyCombination;
-
-/**
- * A convenience class that implements the {@link Action} interface and provides
- * a simpler API. It is highly recommended to use this class rather than 
- * implement the {@link Action} interface directly.
- * 
- * <p>To better understand how to use actions, and where they fit within the
- * JavaFX ecosystem, refer to the {@link Action} class documentation.
- * 
- * @see Action
- */
-public abstract class AbstractAction implements Action {
-    
-    /**************************************************************************
-     * 
-     * Private fields
-     * 
-     **************************************************************************/
-    
-    private ObservableMap<Object, Object> properties;
-    
-    
-    
-    /**************************************************************************
-     * 
-     * Constructors
-     * 
-     **************************************************************************/
-    
-    /**
-     * Creates a new AbstractAction instance with the given String set as the 
-     * {@link #textProperty() text} value.
-     *  
-     * @param text The string to display in the text property of controls such
-     *      as {@link Button#textProperty() Button}.
-     */
-    public AbstractAction(String text) {
-        setText(text);
-    }
-    
-    
-    
-    
-    /**************************************************************************
-     * 
-     * Properties
-     * 
-     **************************************************************************/
-    
-    // --- text
-    private final StringProperty textProperty = new SimpleLocalizedStringProperty(this, "text"); //$NON-NLS-1$
-    
-    /** {@inheritDoc} */
-    @Override public StringProperty textProperty() {
-        return textProperty;
-    }
-    
-    /**
-     * 
-     * @return the text of the Action.
-     */
-    public final String getText() {
-        return textProperty.get();
-    }
-
-    /**
-     * Sets the text of the Action.
-     * @param value 
-     */
-    public final void setText(String value) {
-        textProperty.set(value);
-    }
-    
-    
-    // --- disabled
-    private final BooleanProperty disabledProperty = new SimpleBooleanProperty(this, "disabled"); //$NON-NLS-1$
-    
-    /** {@inheritDoc} */
-    @Override public BooleanProperty disabledProperty() {
-        return disabledProperty;
-    }
-    
-    /**
-     * 
-     * @return whether the action is available to the end user,
-     * or whether it should appeared 'grayed out'.
-     */
-    public final boolean isDisabled() {
-        return disabledProperty.get();
-    }
-    
-    /**
-     * Sets whether the action should be available to the end user,
-     * or whether it should appeared 'grayed out'.
-     * @param value 
-     */
-    public final void setDisabled(boolean value) {
-        disabledProperty.set(value);
-    }
-
-    
-    // --- longText
-    private final StringProperty longTextProperty = new SimpleLocalizedStringProperty(this, "longText"); //$NON-NLS-1$
-    
-    /** {@inheritDoc} */
-    @Override public StringProperty longTextProperty() {
-        return longTextProperty;
-    }
-    
-    /**
-     * @see #longTextProperty() 
-     * @return The longer form of the text to show to the user
-     */
-    public final String getLongText() {
-        return Localization.localize(longTextProperty.get());
-    }
-    
-    /**
-     * Sets the longer form of the text to show to the user
-     * @param value 
-     * @see #longTextProperty() 
-     */
-    public final void setLongText(String value) {
-        longTextProperty.set(value);
-    }
-    
-    
-    // --- graphic
-    private final ObjectProperty<Node> graphicProperty = new SimpleObjectProperty<Node>(this, "graphic"); //$NON-NLS-1$
-    
-    /** {@inheritDoc} */
-    @Override public ObjectProperty<Node> graphicProperty() {
-        return graphicProperty;
-    }
-    
-    /**
-     * 
-     * @return The graphic that should be shown to the user in relation to this action.
-     */
-    public final Node getGraphic() {
-        return graphicProperty.get();
-    }
-    
-    /**
-     * Sets the graphic that should be shown to the user in relation to this action.
-     * @param value 
-     */
-    public final void setGraphic(Node value) {
-        graphicProperty.set(value);
-    }
-    
-    
-    // --- accelerator
-    private final ObjectProperty<KeyCombination> acceleratorProperty = new SimpleObjectProperty<KeyCombination>(this, "accelerator"); //$NON-NLS-1$
-    
-    /** {@inheritDoc} */
-    @Override public ObjectProperty<KeyCombination> acceleratorProperty() {
-        return acceleratorProperty;
-    }
-    
-    /**
-     * 
-     * @return The accelerator {@link KeyCombination} that should be used for this action,
-     * if it is used in an applicable UI control
-     */
-    public final KeyCombination getAccelerator() {
-        return acceleratorProperty.get();
-    }
-    
-    /**
-     * Sets the accelerator {@link KeyCombination} that should be used for this action,
-     * if it is used in an applicable UI control
-     * @param value 
-     */
-    public final void setAccelerator(KeyCombination value) {
-        acceleratorProperty.set(value);
-    }
-    
-    
-    // --- properties
-    /** {@inheritDoc} */
-    @Override public ObservableMap<Object, Object> getProperties() {
-        if (properties == null) {
-            properties = FXCollections.observableHashMap();
-        }
-        return properties;
-    }
-
-    
-    
-    /**************************************************************************
-     * 
-     * Public API
-     * 
-     **************************************************************************/
-    
-}

controlsfx/src/main/java/org/controlsfx/control/action/Action.java

  * (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 org.controlsfx.control.action;
+package org.controlsfx.control.action;
 
+import impl.org.controlsfx.i18n.Localization;
+import impl.org.controlsfx.i18n.SimpleLocalizedStringProperty;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.property.StringProperty;
+import javafx.collections.FXCollections;
 import javafx.collections.ObservableMap;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
 import javafx.scene.input.KeyCombination;
 
 /**
- * Common interface for dialog actions, where Actions are converted into buttons 
- * in the dialogs button bar. It is highly recommended that rather than 
- * implement this interface that developers instead use {@link AbstractAction}.
+ * A base class for Action API. 
  * 
  * <h3>What is an Action?</h3>
  * An action in JavaFX can be used to separate functionality and state from a 
  * centralized handling of the state of action-event-firing components such as 
  * buttons, menu items, etc. The state that an action can handle includes text, 
  * graphic, long text (i.e. tooltip text), and disabled.
- * 
- * @see AbstractAction
  */
-public interface Action extends EventHandler<ActionEvent> {
-
+public abstract class Action implements EventHandler<ActionEvent> {
+    
+    /**************************************************************************
+     * 
+     * Private fields
+     * 
+     **************************************************************************/
+    
+    private boolean locked = false;
+    
+    /**************************************************************************
+     * 
+     * Constructors
+     * 
+     **************************************************************************/
+    
+    /**
+     * Creates a new AbstractAction instance with the given String set as the 
+     * {@link #textProperty() text} value.
+     *  
+     * @param text The string to display in the text property of controls such
+     *      as {@link Button#textProperty() Button}.
+     */
+    public Action(String text) {
+        setText(text);
+    }
+    
+    public Action() {
+    	this("");
+    }
+    
+    protected void lock() {
+    	locked = true;
+    }
+    
+    
+    /**************************************************************************
+     * 
+     * Properties
+     * 
+     **************************************************************************/
+    
+    // --- text
+    private final StringProperty textProperty = new SimpleLocalizedStringProperty(this, "text"){ //$NON-NLS-1$
+    	public void set(String value) {
+    		if ( locked ) throw new RuntimeException("The action is immutable, property change suppport is disabled.");
+    		super.set(value);
+    	}
+    };
+    
     /**
      * The text to show to the user.
      * 
      * @return An observable {@link StringProperty} that represents the current
      *      text for this property, and which can be observed for changes.
      */
-    public StringProperty textProperty();
+    public final StringProperty textProperty() {
+        return textProperty;
+    }
+    
+    /**
+     * 
+     * @return the text of the Action.
+     */
+    public final String getText() {
+        return textProperty.get();
+    }
+
+    /**
+     * Sets the text of the Action.
+     * @param value 
+     */
+    public final void setText(String value) {
+        textProperty.set(value);
+    }
+    
+    
+    // --- disabled
+    private final BooleanProperty disabledProperty = new SimpleBooleanProperty(this, "disabled"){ //$NON-NLS-1$
+    	public void set(boolean value) {
+    		if ( locked ) throw new RuntimeException("The action is immutable, property change suppport is disabled.");
+    		super.set(value);
+    	}
+    };
     
     /**
      * This represents whether the action should be available to the end user,
      *      disabled state for this property, and which can be observed for 
      *      changes.
      */
-    public BooleanProperty disabledProperty();
+    public final BooleanProperty disabledProperty() {
+        return disabledProperty;
+    }
+    
+    /**
+     * 
+     * @return whether the action is available to the end user,
+     * or whether it should appeared 'grayed out'.
+     */
+    public final boolean isDisabled() {
+        return disabledProperty.get();
+    }
+    
+    /**
+     * Sets whether the action should be available to the end user,
+     * or whether it should appeared 'grayed out'.
+     * @param value 
+     */
+    public final void setDisabled(boolean value) {
+        disabledProperty.set(value);
+    }
 
+    
+    // --- longText
+    private final StringProperty longTextProperty = new SimpleLocalizedStringProperty(this, "longText"){ //$NON-NLS-1$
+    	public void set(String value) {
+    		if ( locked ) throw new RuntimeException("The action is immutable, property change suppport is disabled.");
+    		super.set(value);
+
+    	};
+    };
+    
     /**
      * The longer form of the text to show to the user (e.g. on a 
      * {@link Button}, it is usually a tooltip that should be shown to the user 
      * @return An observable {@link StringProperty} that represents the current
      *      long text for this property, and which can be observed for changes.
      */
-    public StringProperty longTextProperty();
+    public final StringProperty longTextProperty() {
+        return longTextProperty;
+    }
+    
+    /**
+     * @see #longTextProperty() 
+     * @return The longer form of the text to show to the user
+     */
+    public final String getLongText() {
+        return Localization.localize(longTextProperty.get());
+    }
+    
+    /**
+     * Sets the longer form of the text to show to the user
+     * @param value 
+     * @see #longTextProperty() 
+     */
+    public final void setLongText(String value) {
+        longTextProperty.set(value);
+    }
+    
+    
+    // --- graphic
+    private final ObjectProperty<Node> graphicProperty = new SimpleObjectProperty<Node>(this, "graphic"){ //$NON-NLS-1$
+    	public void set(Node value) {
+    		if ( locked ) throw new RuntimeException("The action is immutable, property change suppport is disabled.");
+    		super.set(value);
+
+    	};
+    };
     
     /**
      * The graphic that should be shown to the user in relation to this action.
      * @return An observable {@link ObjectProperty} that represents the current
      *      graphic for this property, and which can be observed for changes.
      */
-    public ObjectProperty<Node> graphicProperty();
+    public final ObjectProperty<Node> graphicProperty() {
+        return graphicProperty;
+    }
+    
+    /**
+     * 
+     * @return The graphic that should be shown to the user in relation to this action.
+     */
+    public final Node getGraphic() {
+        return graphicProperty.get();
+    }
+    
+    /**
+     * Sets the graphic that should be shown to the user in relation to this action.
+     * @param value 
+     */
+    public final void setGraphic(Node value) {
+        graphicProperty.set(value);
+    }
+    
+    
+    // --- accelerator
+    private final ObjectProperty<KeyCombination> acceleratorProperty = new SimpleObjectProperty<KeyCombination>(this, "accelerator"){ //$NON-NLS-1$
+    	public void set(KeyCombination value) {
+    		if ( locked ) throw new RuntimeException("The action is immutable, property change suppport is disabled.");
+    		super.set(value);
+
+    	}
+    };
     
     /**
      * The accelerator {@link KeyCombination} that should be used for this action,
      * @return An observable {@link ObjectProperty} that represents the current
      *      accelerator for this property, and which can be observed for changes.
      */
-    public ObjectProperty<KeyCombination> acceleratorProperty();
+    public final ObjectProperty<KeyCombination> acceleratorProperty() {
+        return acceleratorProperty;
+    }
     
     /**
+     * 
+     * @return The accelerator {@link KeyCombination} that should be used for this action,
+     * if it is used in an applicable UI control
+     */
+    public final KeyCombination getAccelerator() {
+        return acceleratorProperty.get();
+    }
+    
+    /**
+     * Sets the accelerator {@link KeyCombination} that should be used for this action,
+     * if it is used in an applicable UI control
+     * @param value 
+     */
+    public final void setAccelerator(KeyCombination value) {
+        acceleratorProperty.set(value);
+    }
+    
+    /**
+     * Using 'Initialization on Demand Holder' idiom to enable a safe, 
+     * highly concurrent lazy initialization with good performance
+     */
+    private static class LazyProps {
+        private static final ObservableMap<Object, Object> INSTANCE = FXCollections.observableHashMap();
+    }
+    
+    // --- properties
+    /**
      * Returns an observable map of properties on this Action for use primarily
      * by application developers.
      *
      * @return An observable map of properties on this Action for use primarily
      * by application developers
      */
-    public ObservableMap<Object, Object> getProperties();
+    public final ObservableMap<Object, Object> getProperties() {
+    	return LazyProps.INSTANCE;
+    }
+
+    
+    
+    /**************************************************************************
+     * 
+     * Public API
+     * 
+     **************************************************************************/
+    
 }

controlsfx/src/main/java/org/controlsfx/control/action/ActionGroup.java

  * 
  * <h3>Code Examples</h3>
  * <p>Consider the following code example (note that DummyAction is a fake class
- * that extends from (and implements) {@link AbstractAction}):
+ * that extends from (and implements) {@link Action}):
  * 
  * <pre>
  * {@code
  * @see Action
  * @see ActionUtils
  */
-public class ActionGroup extends AbstractAction {
+public class ActionGroup extends Action {
     
     /**
      * Creates an ActionGroup with the given text as the name of the {@link Action}, 

controlsfx/src/main/java/org/controlsfx/control/action/ActionMap.java

 	
 }
 
-class AnnotatedAction extends AbstractAction {
+class AnnotatedAction extends Action {
 
 	private Method method;
 	private Object target;

controlsfx/src/main/java/org/controlsfx/control/action/ActionUtils.java

 import java.util.Collection;
 
 import javafx.beans.binding.ObjectBinding;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.StringProperty;
 import javafx.collections.FXCollections;
 import javafx.collections.MapChangeListener;
 import javafx.collections.ObservableList;
-import javafx.collections.ObservableMap;
 import javafx.event.ActionEvent;
 import javafx.scene.Node;
 import javafx.scene.control.Button;
 import javafx.scene.control.ToolBar;
 import javafx.scene.control.Tooltip;
 import javafx.scene.image.ImageView;
-import javafx.scene.input.KeyCombination;
 
 import org.controlsfx.control.ButtonBar;
 import org.controlsfx.control.SegmentedButton;
      * action tree serves as indication that separator has be created in its place.
      * See {@link ActionGroup} for example of action tree creation
      */
-    public static Action ACTION_SEPARATOR = new Action() {
-
-        @Override public StringProperty textProperty() {
-            return null;
-        }
-
-        @Override public BooleanProperty disabledProperty() {
-            return null;
-        }
-
-        @Override public StringProperty longTextProperty() {
-            return null;
-        }
-
-        @Override public ObjectProperty<Node> graphicProperty() {
-            return null;
-        }
-        
-        @Override public ObjectProperty<KeyCombination> acceleratorProperty() {
-            return null;
-        }
-
-        @Override public ObservableMap<Object, Object> getProperties() {
-            return null;
-        }
+    public static Action ACTION_SEPARATOR = new Action(null) {
 
         @Override public void handle(ActionEvent ae) {
         }

controlsfx/src/main/java/org/controlsfx/control/action/package-info.java

 /**
  * A package containing the {@link org.controlsfx.control.action.Action} API, as well
- * as the {@link org.controlsfx.control.action.AbstractAction} convenience subclass. 
+ * as the {@link org.controlsfx.control.action.Action} convenience subclass. 
  * Refer to these two classes for the necessary details on what actions are in
  * the JavaFX context.
  */

controlsfx/src/main/java/org/controlsfx/control/decoration/Decorator.java

             }
             p = new DecorationPane();
             Node oldRoot = scene.getRoot();
-            ImplUtils.injectAsRootPane(scene, p);
+            ImplUtils.injectAsRootPane(scene, p, true);
             ((DecorationPane)p).setRoot(oldRoot);
         }
         

controlsfx/src/main/java/org/controlsfx/control/decoration/GraphicDecoration.java

     
     /** {@inheritDoc} */
     @Override public Node applyDecoration(Node targetNode) {
-        List<Node> targetNodeChildren = ImplUtils.getChildren((Parent)targetNode);
+        List<Node> targetNodeChildren = ImplUtils.getChildren((Parent)targetNode, true);
         updateGraphicPosition(targetNode);
         if (!targetNodeChildren.contains(decorationNode)) {
             targetNodeChildren.add(decorationNode);
     
     /** {@inheritDoc} */
     @Override public void removeDecoration(Node targetNode) {
-        List<Node> targetNodeChildren = ImplUtils.getChildren((Parent)targetNode);
+        List<Node> targetNodeChildren = ImplUtils.getChildren((Parent)targetNode, true);
         
         if (targetNodeChildren.contains(decorationNode)) {
             targetNodeChildren.remove(decorationNode);

controlsfx/src/main/java/org/controlsfx/dialog/DefaultDialogAction.java

-/**
- * Copyright (c) 2013, 2014 ControlsFX
- * All rights reserved.
- *
- * 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 ControlsFX, any associated website, 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 CONTROLSFX 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 org.controlsfx.dialog;
-
-import java.util.Arrays;
-import java.util.EnumSet;
-
-import javafx.event.ActionEvent;
-
-import org.controlsfx.control.action.AbstractAction;
-import org.controlsfx.control.action.Action;
-import org.controlsfx.dialog.Dialog.ActionTrait;
-import org.controlsfx.dialog.Dialog.DialogAction;
-
-/**
- * A convenience class that implements the {@link Action} and {@link DialogAction} interfaces and provides
- * a simpler API. It is highly recommended to use this class rather than 
- * implement the {@link Action} or the {@link DialogAction} interfaces directly.
- * 
- * <p>To better understand how to use actions, and where they fit within the
- * JavaFX ecosystem, refer to the {@link Action} class documentation.
- * 
- * @see Action
- * @see DialogAction
- */
-public class DefaultDialogAction extends AbstractAction implements DialogAction {
-    
-    private final EnumSet<ActionTrait> traits;
-
-    /**
-     * Creates a dialog action with given text and traits
-     * @param text
-     * @param traits
-     */
-    public DefaultDialogAction(String text, ActionTrait... traits) {
-        super(text);
-        this.traits = (traits == null || traits.length == 0) ? 
-                EnumSet.noneOf(ActionTrait.class) : 
-                EnumSet.copyOf(Arrays.asList(traits));
-    }
-
-    /**
-     * Creates a dialog action with given text and common set of traits: CLOSING and DEFAULT
-     * @param text
-     */
-    public DefaultDialogAction(String text) {
-        this(text, ActionTrait.CLOSING, ActionTrait.DEFAULT);
-    }
-    
-    
-    /** {@inheritDoc} */
-    @Override public boolean hasTrait(ActionTrait trait) {
-        return traits.contains(trait);
-    }
-
-    
-    /** {@inheritDoc} */
-    @Override public void handle(ActionEvent ae) {
-    	DialogAction.super.handle(ae);
-    }
-
-}

controlsfx/src/main/java/org/controlsfx/dialog/Dialog.java

 import impl.org.controlsfx.i18n.Localization;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.EnumSet;
 import java.util.List;
 
 import javafx.beans.binding.DoubleBinding;
 import javafx.beans.property.StringProperty;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
-import javafx.collections.ObservableMap;
 import javafx.css.PseudoClass;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
 import javafx.scene.control.Hyperlink;
 import javafx.scene.control.Label;
 import javafx.scene.effect.Effect;
-import javafx.scene.input.KeyCombination;
 import javafx.scene.layout.BorderPane;
 import javafx.scene.layout.ColumnConstraints;
 import javafx.scene.layout.GridPane;
 
 import org.controlsfx.control.ButtonBar;
 import org.controlsfx.control.ButtonBar.ButtonType;
-import org.controlsfx.control.action.AbstractAction;
 import org.controlsfx.control.action.Action;
 import org.controlsfx.control.action.ActionUtils;
+import org.controlsfx.tools.Utils;
 
 /**
  * A lower-level API for creating standardized dialogs consisting of the following
      * 
      **************************************************************************/
     
+    /**
+     * Defines a native dialog style.
+     * The dialogs rendered using this style will have a native title bar.
+     */
+    public static final String STYLE_CLASS_NATIVE = "native";
+    
+    /**
+     * Defines a cross-platform dialog style.
+     * The dialogs rendered using this style will have a cross-platform title bar.
+     */
+    public static final String STYLE_CLASS_CROSS_PLATFORM = "cross-platform";
+    
+    /**
+     * Defines a dialog style with no decorations.
+     * The dialogs rendered using this style will not have a title bar.
+     */
+    public static final String STYLE_CLASS_UNDECORATED = "undecorated";
+    
     // enable to turn on grid lines, etc
     private static final boolean DEBUG = false;
     
     static int MIN_DIALOG_WIDTH = 426;
-
+    
     
     
     /**************************************************************************
      *      the difference between heavyweight and lightweight dialogs.
      */
     public Dialog(Object owner, String title, boolean lightweight) {
-        this(owner, title, lightweight, DialogStyle.CROSS_PLATFORM_DARK);
-    }
-    
-    /**
-     * Creates a dialog using specified owner, title and {@code DialogStyle}
-     * which may be rendered in either a heavyweight or lightweight fashion.
-     * 
-     * @param owner The dialog window owner - if specified the dialog will be
-     *      centered over the owner, otherwise the dialog will be shown in the 
-     *      middle of the screen.
-     * @param title The dialog title to be shown at the top of the dialog.
-     * @param lightweight If true this dialog will be rendered inside the given
-     *      owner, rather than in a separate window (as heavyweight dialogs are).
-     *      Refer to the {@link Dialogs} class documentation for more details on
-     *      the difference between heavyweight and lightweight dialogs.
-     * @param style The {@code DialogStyle} of the dialog. Refer to the 
-     *      {@link Dialogs} class javadoc for more information.
-     */
-    public Dialog(Object owner, String title, boolean lightweight, DialogStyle style) {
-        this.dialog = DialogFactory.createDialog(lightweight, title, owner, true, style);
+        if (lightweight) {
+            this.dialog = new LightweightDialog(title, owner);
+        } else {
+            Window window = Utils.getWindow(owner);
+            this.dialog = new HeavyweightDialog(title, window);
+            this.dialog.setModal(true);
+        }
+        
+        // by default we show the cross platform style. If there is not one
+        // of the tree pre-defined styleclasses set, then we install the
+        // cross platform style.
+        // FIXME we need to of course consider the case where a custom, external
+        // styleclass is set, which we overwrite here and force in cross-platform.
+        List<String> styleClass = dialog.getStyleClass();
+        if (! styleClass.contains(STYLE_CLASS_CROSS_PLATFORM) ||
+            ! styleClass.contains(STYLE_CLASS_NATIVE) ||
+            ! styleClass.contains(STYLE_CLASS_UNDECORATED)) {
+            this.dialog.getStyleClass().add(STYLE_CLASS_CROSS_PLATFORM);
+        }
         
         this.contentPane = new GridPane();
         this.contentPane.getStyleClass().add("content-pane"); //$NON-NLS-1$
      * Public API
      * 
      **************************************************************************/
-
+    
     /**
      * Shows the dialog and waits for the user response (in other words, brings 
      * up a modal dialog, with the returned value the users input).
     }
     
     /**
-     * Returns this dialog's window. For lightweight dialogs,
-     * this is the window in which this dialog is displayed. 
-     * @return This dialog's window.
-     */
-    public Window getWindow() {
-        return dialog.getWindow();
-    }
-
-    /**
      * Assigns the resulting action. If action is a {@link DialogAction} and has either CANCEL or CLOSING traits
      * the dialog will be closed.
      * @param result
      */
     public void setResult(Action result) {
-    
         this.result = result;
         
-        if ( result instanceof DialogAction ) {
+        if (result instanceof DialogAction) {
             DialogAction dlgAction = (DialogAction) result;
-            if ( dlgAction.hasTrait(ActionTrait.CANCEL) || dlgAction.hasTrait(ActionTrait.CLOSING) ) {
+            if (dlgAction.hasTrait(ActionTrait.CANCEL) || dlgAction.hasTrait(ActionTrait.CLOSING)) {
                 hide();
             }
         }
-
     }
     
     /**
      * Return the StyleSheets associated with the scene used in the Dialog (see {@link Scene#getStylesheets()}
      * This allow you to specify custom CSS rules to be applied on your dialog's elements.
-     * @return and ObservableList of String. 
      */
     public ObservableList<String> getStylesheets(){
         return dialog.getStylesheets();
     }
     
+    /**
+     * Return the style classes specified on this dialog instance.
+     */
+    public ObservableList<String> getStyleClass() {
+        return dialog.getStyleClass();
+    }
+    
+    
+    
     /**************************************************************************
      * 
      * Properties
     }
     
     /**
-     *  Interface for specialized dialog {@link Action}, which can have a set of traits {@link ActionTrait}
-     */
-    public interface DialogAction extends Action {
-        
-        /**
-         * Returns true if {@link Action} has given trait 
-         */
-        boolean hasTrait( ActionTrait trait);
-        
-        /**
-         * Implementation of default dialog action execution logic:
-         * if action is enabled set it as dialog result.
-         */
-        default public void handle(ActionEvent ae) {
-            if (! disabledProperty().get()) {
-                if (ae.getSource() instanceof Dialog ) {
-                    ((Dialog) ae.getSource()).setResult(this);
-                }
-            }
-        }
-        
-    }
-    
-    /**
      * Possible traits of {@link DialogAction}
      */
     public enum ActionTrait {
      * @see Dialog
      * @see Action
      */
-    public enum Actions implements DialogAction {
+    public static final class Actions {
 
+    	
+    	
         /**
          * An action that, by default, will show 'Cancel'.
          */
-        CANCEL( Localization.asKey("dlg.cancel.button"), ButtonType.CANCEL_CLOSE ), //$NON-NLS-1$
+        public static final Action CANCEL = new DialogAction( Localization.asKey("dlg.cancel.button"), ButtonType.CANCEL_CLOSE ){ //$NON-NLS-1$
+        	{ lock();}
+        	public String toString() { return "DialogAction.CANCEL";} //$NON-NLS-1$
+        }; 
         
         /**
          * An action that, by default, will show 'Close'.
          */
-        CLOSE ( Localization.asKey("dlg.close.button"),  ButtonType.CANCEL_CLOSE ), //$NON-NLS-1$
+        public static final Action CLOSE = new DialogAction( Localization.asKey("dlg.close.button"), ButtonType.CANCEL_CLOSE ){ //$NON-NLS-1$
+        	{ lock();}
+        	public String toString() { return "DialogAction.CLOSE";} //$NON-NLS-1$
+        }; 
         
         /**
          * An action that, by default, will show 'No'.
          */
-        NO    ( Localization.asKey("dlg.no.button"),     ButtonType.NO ), //$NON-NLS-1$
+        public static final Action NO = new DialogAction( Localization.asKey("dlg.no.button"), ButtonType.NO ){ //$NON-NLS-1$
+        	{ lock();}
+        	public String toString() { return "DialogAction.NO";} //$NON-NLS-1$
+        }; 
         
         /**
          * An action that, by default, will show 'OK'.
          */
-        OK    ( Localization.asKey("dlg.ok.button"),     ButtonType.OK_DONE,  ActionTrait.DEFAULT, ActionTrait.CLOSING), //$NON-NLS-1$
+        public static final Action OK = new DialogAction( Localization.asKey("dlg.ok.button"), ButtonType.OK_DONE,  ActionTrait.DEFAULT, ActionTrait.CLOSING){ //$NON-NLS-1$
+        	{ lock();}
+        	public String toString() { return "DialogAction.OK";} //$NON-NLS-1$
+        }; 
         
         /**
          * An action that, by default, will show 'Yes'.
          */
-        YES   ( Localization.asKey("dlg.yes.button"),    ButtonType.YES,  ActionTrait.DEFAULT, ActionTrait.CLOSING ); //$NON-NLS-1$
+        public static final Action YES = new DialogAction( Localization.asKey("dlg.yes.button"), ButtonType.YES,  ActionTrait.DEFAULT, ActionTrait.CLOSING ){ //$NON-NLS-1$
+        	{ lock();}
+        	public String toString() { return "DialogAction.YES";} //$NON-NLS-1$
+        }; 
+        
 
-        private final AbstractAction action;
-        private final EnumSet<ActionTrait> traits;
-
-        /**
-         * Creates common dialog action
-         * @param title action title
-         * @param isDefault true if it should be default action on the dialog. Only one can be, so the first us used.
-         * @param isCancel true if action produces the dialog cancellation. 
-         * @param isClosing true if action is closing the dialog
-         */
-        private Actions(String title, ButtonType type, ActionTrait... traits) {
-            this.action = new AbstractAction(title) {
-                @Override public void handle(ActionEvent ae) {
-                    Actions.this.handle(ae);
-                }
-            };
-            this.traits = EnumSet.copyOf(Arrays.asList(traits));
-            ButtonBar.setType(this, type);
-        }
-        
-        private Actions(String title, ButtonType type) {
-            this( title, type, ActionTrait.CANCEL, ActionTrait.CLOSING, ActionTrait.DEFAULT );
-        }
-
-        /** {@inheritDoc} */
-        @Override public StringProperty textProperty() {
-            return action.textProperty();
-        }
-
-        /** {@inheritDoc} */
-        @Override public BooleanProperty disabledProperty() {
-            return action.disabledProperty();
-        }
-        
-        /** {@inheritDoc} */
-        @Override public StringProperty longTextProperty() {
-            return action.longTextProperty();
-        }
-        
-        /** {@inheritDoc} */
-        @Override public ObjectProperty<Node> graphicProperty() {
-            return action.graphicProperty();
-        }
-        
-        /** {@inheritDoc} */
-        @Override public ObjectProperty<KeyCombination> acceleratorProperty() {
-            return action.acceleratorProperty();
-        }
-        
-        /** {@inheritDoc} */
-        @Override public ObservableMap<Object, Object> getProperties() {
-            return action.getProperties();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void handle(ActionEvent ae) {
-        	DialogAction.super.handle(ae);
-        }
-        
-        /** {@inheritDoc} */
-        @Override public boolean hasTrait(ActionTrait trait) {
-            return traits.contains(trait);
-        }
     }
 
     

controlsfx/src/main/java/org/controlsfx/dialog/DialogAction.java

+/**
+ * Copyright (c) 2013, 2014 ControlsFX
+ * All rights reserved.
+ *
+ * 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 ControlsFX, any associated website, 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 CONTROLSFX 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 org.controlsfx.dialog;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+
+import javafx.event.ActionEvent;
+
+import org.controlsfx.control.ButtonBar;
+import org.controlsfx.control.ButtonBar.ButtonType;
+import org.controlsfx.control.action.Action;
+import org.controlsfx.dialog.Dialog.ActionTrait;
+
+/**
+ * A specialized dialog {@link Action}, which can have a set of traits {@link ActionTrait}
+ * 
+ * <p>To better understand how to use actions, and where they fit within the
+ * JavaFX ecosystem, refer to the {@link Action} class documentation.
+ * 
+ * @see Action
+ */
+public class DialogAction extends Action {
+    
+    private final EnumSet<ActionTrait> traits;
+
+    /**
+     * Creates a dialog action with given text and traits
+     * @param text
+     * @param traits
+     */
+    public DialogAction(String text, ButtonType buttonType, ActionTrait... traits) {
+        super(text);
+        this.traits = (traits == null || traits.length == 0) ? 
+                EnumSet.noneOf(ActionTrait.class) : 
+                EnumSet.copyOf(Arrays.asList(traits));
+               
+        if ( buttonType != null ) {        
+        	ButtonBar.setType(this, buttonType);
+        }
+    }
+    
+    public DialogAction(String text, ActionTrait... traits) {
+    	this( text, null, traits);
+    }
+    
+    public DialogAction(String title, ButtonType buttonType) {
+        this( title, buttonType, ActionTrait.CANCEL, ActionTrait.CLOSING, ActionTrait.DEFAULT );
+    }
+
+    /**
+     * Creates a dialog action with given text and common set of traits: CLOSING and DEFAULT
+     * @param text
+     */
+    public DialogAction(String text) {
+        this(text, ActionTrait.CLOSING, ActionTrait.DEFAULT);
+    }
+    
+    /**
+     * Returns true if {@link Action} has given trait 
+     */
+    public boolean hasTrait(ActionTrait trait) {
+        return traits.contains(trait);
+    }
+
+    
+    /**
+     * Implementation of default dialog action execution logic:
+     * if action is enabled set it as dialog result.
+     */
+    @Override public void handle(ActionEvent ae) {
+        if (! disabledProperty().get()) {
+            if (ae.getSource() instanceof Dialog ) {
+                ((Dialog) ae.getSource()).setResult(this);
+            }
+        }
+    }
+
+}

controlsfx/src/main/java/org/controlsfx/dialog/DialogFactory.java

-/**
- * Copyright (c) 2013, 2014 ControlsFX
- * All rights reserved.
- *
- * 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 ControlsFX, any associated website, 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 CONTROLSFX 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 org.controlsfx.dialog;
-
-import org.controlsfx.tools.Utils;
-
-import javafx.stage.Window;
-
-class DialogFactory {
-
-    static FXDialog createDialog(String title) {
-        return createDialog(false, title);
-    }
-
-    static FXDialog createDialog(boolean useLightweight, String title) {
-        return createDialog(false, title, null, false);
-    }
-
-    static FXDialog createDialog(boolean useLightweight, String title, Object owner, boolean modal) {
-        return createDialog(useLightweight, title, owner, modal, DialogStyle.CROSS_PLATFORM_DARK);
-    }
-
-    static FXDialog createDialog(boolean useLightweight, String title, Object owner, boolean modal, DialogStyle style) {
-        if (style == null) {
-            style = DialogStyle.CROSS_PLATFORM_DARK;
-        }
-        
-        if (useLightweight) {
-            return new LightweightDialog(title, owner, style);
-        } else {
-
-            Window window = Utils.getWindow(owner);
-
-            return new HeavyweightDialog(title, window, modal, style);
-        }
-    }
-}

controlsfx/src/main/java/org/controlsfx/dialog/DialogStyle.java

-/**
- * Copyright (c) 2014, ControlsFX
- * All rights reserved.
- *
- * 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 ControlsFX, any associated website, 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 CONTROLSFX BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES