[jbosstools-commits] JBoss Tools SVN: r39801 - in trunk/modeshape: plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/attributes and 4 other directories.

jbosstools-commits at lists.jboss.org jbosstools-commits at lists.jboss.org
Fri Mar 23 12:56:25 EDT 2012


Author: elvisisking
Date: 2012-03-23 12:56:24 -0400 (Fri, 23 Mar 2012)
New Revision: 39801

Added:
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/PropertyDialog.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameEditor.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/StringValueEditorDialog.java
Modified:
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/ChildNodeDialog.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndEditor.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndFormsEditorPage.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndMessages.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/NamespaceMappingDialog.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameDialog.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/cndMessages.properties
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/ChildNodeDefinition.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CndValidator.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CompactNodeTypeDefinition.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NamespaceMapping.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NodeTypeDefinition.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinition.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/attributes/ListAttributeState.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/UiUtils.java
   trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/actions/DelegateAction.java
   trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/CndValidatorTest.java
   trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/Constants.java
   trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinitionTest.java
Log:
JBIDE-10702 Editor for JCR Compact Node Definition (CND) files. Created a reusable qualified name editor and updated PropertyDialog, ChildNodeDialog, and CndFormsEditorPage to use it. Business objects now also return a QualifiedName type.

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/ChildNodeDefinition.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/ChildNodeDefinition.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/ChildNodeDefinition.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -36,19 +36,19 @@
     public static final String NOTATION_PREFIX = "+"; //$NON-NLS-1$
 
     /**
-     * @param childNodeToCopy the child node definition being copied (cannot be <code>null</code>)
+     * @param childNodeBeingCopied the child node definition being copied (cannot be <code>null</code>)
      * @return the copy (never <code>null</code>)
      */
-    public static ChildNodeDefinition copy( ChildNodeDefinition childNodeToCopy ) {
-        ChildNodeDefinition copy = new ChildNodeDefinition();
-        copy.setAutoCreated(childNodeToCopy.isAutoCreated());
-        copy.setMandatory(childNodeToCopy.isMandatory());
-        copy.setProtected(childNodeToCopy.isProtected());
-        copy.setOnParentVersion(childNodeToCopy.getOnParentVersion());
-        copy.setSameNameSiblings(childNodeToCopy.allowsSameNameSiblings());
-        copy.setName(childNodeToCopy.getName());
-        copy.setDefaultPrimaryTypeName(childNodeToCopy.getDefaultPrimaryTypeName());
-        copy.setRequiredPrimaryTypeNames(childNodeToCopy.getRequiredPrimaryTypeNames());
+    public static ChildNodeDefinition copy( final ChildNodeDefinition childNodeBeingCopied ) {
+        final ChildNodeDefinition copy = new ChildNodeDefinition();
+        copy.setAutoCreated(childNodeBeingCopied.isAutoCreated());
+        copy.setMandatory(childNodeBeingCopied.isMandatory());
+        copy.setProtected(childNodeBeingCopied.isProtected());
+        copy.setOnParentVersion(childNodeBeingCopied.getOnParentVersion());
+        copy.setSameNameSiblings(childNodeBeingCopied.allowsSameNameSiblings());
+        copy.setName(childNodeBeingCopied.getName());
+        copy.setDefaultPrimaryTypeName(childNodeBeingCopied.getDefaultPrimaryTypeName());
+        copy.setRequiredPrimaryTypeNames(childNodeBeingCopied.getRequiredPrimaryTypeNames());
         return copy;
     }
 
@@ -227,7 +227,7 @@
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override
-    public boolean equals( Object obj ) {
+    public boolean equals( final Object obj ) {
         if (this == obj) {
             return true;
         }
@@ -236,7 +236,7 @@
             return false;
         }
 
-        ChildNodeDefinition that = (ChildNodeDefinition)obj;
+        final ChildNodeDefinition that = (ChildNodeDefinition)obj;
 
         if (!this.attributes.equals(that.attributes)) {
             return false;
@@ -250,7 +250,7 @@
             return false;
         }
 
-        return Utils.equivalent(this.getRequiredPrimaryTypeNames(), that.getRequiredPrimaryTypeNames());
+        return this.requiredTypes.equals(that.requiredTypes);
     }
 
     /**
@@ -347,6 +347,13 @@
     }
 
     /**
+     * @return the qualified name (never <code>null</code>)
+     */
+    public QualifiedName getQualifiedName() {
+        return this.name;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see javax.jcr.nodetype.NodeDefinition#getRequiredPrimaryTypeNames()
@@ -368,13 +375,6 @@
     }
 
     /**
-     * @return the qualified name (never <code>null</code>)
-     */
-    public QualifiedName getQualifiedName() {
-        return this.name;
-    }
-
-    /**
      * @return the list of required types (never <code>null</code> but can be empty)
      */
     public List<QualifiedName> getRequiredTypes() {
@@ -730,7 +730,16 @@
         /**
          * The supports same name siblings indicator.
          */
-        SAME_NAME_SIBLINGS,
+        SAME_NAME_SIBLINGS;
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Enum#toString()
+         */
+        @Override
+        public String toString() {
+            return (getClass().getSimpleName() + super.toString());
+        }
     }
-
 }

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CndValidator.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CndValidator.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CndValidator.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -35,9 +35,13 @@
      */
     public static ValidationStatus isValid( final String value,
                                             final PropertyType propertyType,
-                                            final String propertyName ) {
+                                            String propertyName ) {
         Utils.verifyIsNotNull(propertyType, "propertyType"); //$NON-NLS-1$
 
+        if (Utils.isEmpty(propertyName)) {
+            propertyName = Messages.missingName;
+        }
+
         if (Utils.isEmpty(value)) {
             return ValidationStatus.createErrorMessage(NLS.bind(Messages.emptyValue, propertyName));
         }
@@ -122,9 +126,11 @@
 
     /**
      * @param childNodeDefinition the child node definition being validated (cannot be <code>null</code>)
+     * @param existingChildNodeNames the existing child node names used to check for a duplicate (can be <code>null</code> or empty)
      * @return the status (never <code>null</code>)
      */
-    public static MultiValidationStatus validateChildNodeDefinition( final ChildNodeDefinition childNodeDefinition ) {
+    public static MultiValidationStatus validateChildNodeDefinition( final ChildNodeDefinition childNodeDefinition,
+                                                                     final Collection<QualifiedName> existingChildNodeNames ) {
         Utils.verifyIsNotNull(childNodeDefinition, "childNodeDefinition"); //$NON-NLS-1$
 
         /**
@@ -146,7 +152,7 @@
         }
 
         // name
-        validateName(childNodeDefinition, status);
+        validateName(childNodeDefinition, existingChildNodeNames, status);
 
         // required types
         validateRequiredTypes(childNodeDefinition, status);
@@ -159,11 +165,13 @@
 
     /**
      * @param childNodeDefinition the child node definition being validated (cannot be <code>null</code>)
+     * @param existingChildNodeNames the existing child node names used to check for a duplicate (can be <code>null</code> or empty)
      * @param status the status to add the new status to (never <code>null</code>)
      */
     public static void validateChildNodeDefinition( final ChildNodeDefinition childNodeDefinition,
+                                                    final Collection<QualifiedName> existingChildNodeNames,
                                                     final MultiValidationStatus status ) {
-        final ValidationStatus newStatus = validateChildNodeDefinition(childNodeDefinition);
+        final ValidationStatus newStatus = validateChildNodeDefinition(childNodeDefinition, existingChildNodeNames);
 
         if (!newStatus.isOk()) {
             status.add(newStatus);
@@ -195,7 +203,7 @@
         final Collection<String> childNodeNames = new ArrayList<String>(childNodeDefinitions.size());
 
         for (final ChildNodeDefinition childNodeDefn : childNodeDefinitions) {
-            validateChildNodeDefinition(childNodeDefn, status);
+            validateChildNodeDefinition(childNodeDefn, null, status);
 
             { // ERROR - Duplicate child node definition names
                 final String childNodeName = childNodeDefn.getName();
@@ -290,25 +298,63 @@
 
     /**
      * @param childNodeDefinition the child node definition whose name is being validated (cannot be <code>null</code>)
+     * @param existingChildNodeNames the existing child node names used to check for a duplicate (can be <code>null</code> or empty)
      * @param status the status to add the new status to (cannot be <code>null</code>)
      */
     public static void validateName( final ChildNodeDefinition childNodeDefinition,
+                                     final Collection<QualifiedName> existingChildNodeNames,
                                      final MultiValidationStatus status ) {
         // ERROR - Empty or invalid child node definition name
         validateQualifiedName(childNodeDefinition.getQualifiedName(), Messages.childDefinitionName, status);
+
+        if (!Utils.isEmpty(existingChildNodeNames) && existingChildNodeNames.contains(childNodeDefinition.getQualifiedName())) {
+            status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateChildNodeDefinitionName,
+                                                                    childNodeDefinition.getName())));
+        }
     }
 
     /**
      * @param childNodeDefinition the child node definition whose name is being validated (cannot be <code>null</code>)
+     * @param existingChildNodeNames the existing child node names used to check for a duplicate (can be <code>null</code> or empty)
      * @return the status (never <code>null</code>)
      */
-    public static MultiValidationStatus validateName( final ChildNodeDefinition childNodeDefinition ) {
+    public static MultiValidationStatus validateName( final ChildNodeDefinition childNodeDefinition,
+                                                      final Collection<QualifiedName> existingChildNodeNames ) {
         final MultiValidationStatus status = new MultiValidationStatus();
-        validateName(childNodeDefinition, status);
+        validateName(childNodeDefinition, existingChildNodeNames, status);
         return status;
     }
 
     /**
+     * @param propertyDefinition the property definition whose name is being validated (cannot be <code>null</code>)
+     * @param existingPropertyNames the existing property names used to check for a duplicate (can be <code>null</code> or empty)
+     * @param status the status to add the new status to (cannot be <code>null</code>)
+     */
+    public static void validateName( final PropertyDefinition propertyDefinition,
+                                     final Collection<QualifiedName> existingPropertyNames,
+                                     final MultiValidationStatus status ) {
+        // ERROR - Empty or invalid child node definition name
+        validateQualifiedName(propertyDefinition.getQualifiedName(), Messages.propertyDefinitionName, status);
+
+        if (!Utils.isEmpty(existingPropertyNames) && existingPropertyNames.contains(propertyDefinition.getQualifiedName())) {
+            status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateChildNodeDefinitionName,
+                                                                    propertyDefinition.getName())));
+        }
+    }
+
+    /**
+     * @param propertyDefinition the property definition whose name is being validated (cannot be <code>null</code>)
+     * @param existingPropertyNames the existing property names used to check for a duplicate (can be <code>null</code> or empty)
+     * @return the status (never <code>null</code>)
+     */
+    public static MultiValidationStatus validateName( final PropertyDefinition propertyDefinition,
+                                                      final Collection<QualifiedName> existingPropertyNames ) {
+        final MultiValidationStatus status = new MultiValidationStatus();
+        validateName(propertyDefinition, existingPropertyNames, status);
+        return status;
+    }
+
+    /**
      * @param childNodeDefinition the child node definition whose default type is being validated (cannot be <code>null</code>)
      * @return the status (never <code>null</code>)
      */
@@ -717,9 +763,11 @@
 
     /**
      * @param propertyDefinition the property definition being validated (never <code>null</code>)
+     * @param existingPropertyNames the existing property names used to check for a duplicate (can be <code>null</code> or empty)
      * @return the status (never <code>null</code>)
      */
-    public static MultiValidationStatus validatePropertyDefinition( final PropertyDefinition propertyDefinition ) {
+    public static MultiValidationStatus validatePropertyDefinition( final PropertyDefinition propertyDefinition,
+                                                                    final Collection<QualifiedName> existingPropertyNames ) {
         Utils.verifyIsNotNull(propertyDefinition, "propertyDefinition"); //$NON-NLS-1$
 
         /**
@@ -748,7 +796,7 @@
 
         { // name
           // ERROR - Empty or invalid property definition name
-            validateLocalName(propertyDefinition.getName(), Messages.propertyDefinitionName, status);
+            validateName(propertyDefinition, existingPropertyNames, status);
         }
 
         { // property type
@@ -757,76 +805,11 @@
         }
 
         { // default values
-            final Collection<String> defaultValues = propertyDefinition.getDefaultValuesAsStrings();
-
-            if (Utils.isEmpty(defaultValues)) {
-                if (propertyDefinition.getState(PropertyDefinition.PropertyName.DEFAULT_VALUES) == Value.IS) {
-                    status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.emptyDefaultValues, propertyDefinitionName)));
-                }
-            } else {
-                // ERROR - Cannot have multiple default values when the property definition is single-valued
-                if ((defaultValues.size() > 1)
-                        && (propertyDefinition.getState(PropertyDefinition.PropertyName.MULTIPLE) == Value.IS_NOT)) {
-                    status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.multipleDefaultValuesForSingleValuedProperty,
-                                                                            propertyDefinitionName)));
-                }
-
-                final Collection<String> values = new ArrayList<String>(defaultValues.size());
-
-                for (final String defaultValue : defaultValues) {
-                    // ERROR - Default value is not valid for the property definition type
-                    isValid(defaultValue, propertyDefinition.getType(), Messages.defaultValue, status);
-
-                    if (!Utils.isEmpty(defaultValue)) {
-                        // ERROR - Duplicate default value
-                        if (values.contains(defaultValue)) {
-                            status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateDefaultValue,
-                                                                                    propertyDefinitionName, defaultValue)));
-                        } else {
-                            values.add(defaultValue);
-                        }
-                    }
-                }
-
-                // ERROR - Cannot have explicit default values when default values is marked as a variant
-                if (propertyDefinition.getState(PropertyDefinition.PropertyName.DEFAULT_VALUES) != Value.IS) {
-                    status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.defaultValuesExistButMarkedAsVariant,
-                                                                            propertyDefinition)));
-                }
-            }
+            validateDefaultValues(propertyDefinition, status);
         }
 
         { // value constraints
-            final String[] valueConstraints = propertyDefinition.getValueConstraints();
-
-            if (Utils.isEmpty(valueConstraints)) {
-                if (propertyDefinition.getState(PropertyDefinition.PropertyName.VALUE_CONSTRAINTS) == Value.IS) {
-                    status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.emptyValueConstraints, propertyDefinitionName)));
-                }
-            } else {
-                final Collection<String> constraints = new ArrayList<String>(valueConstraints.length);
-
-                for (final String constraint : valueConstraints) {
-                    // ERROR - Invalid value constraint
-                    validateValueConstraint(constraint, status);
-
-                    if (!Utils.isEmpty(constraint)) {
-                        // ERROR - Duplicate value constraint
-                        if (constraints.contains(constraint)) {
-                            status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateValueConstraint,
-                                                                                    propertyDefinitionName, constraint)));
-                        } else {
-                            constraints.add(constraint);
-                        }
-                    }
-                }
-
-                // ERROR - Cannot have explicit value constraints when value constraints is marked as a variant
-                if (propertyDefinition.getState(PropertyDefinition.PropertyName.VALUE_CONSTRAINTS) != Value.IS) {
-                    status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.valueConstraintsExistButMarkedAsVariant,
-                                                                            propertyDefinition)));
-                }
-            }
+            validateValueConstraints(propertyDefinition, status);
         }
 
         { // query operators
@@ -867,11 +850,13 @@
 
     /**
      * @param propertyDefinition the property definition being validated (never <code>null</code>)
+     * @param existingPropertyNames the existing property names used to check for a duplicate (can be <code>null</code> or empty)
      * @param status the status to add the new status to (never <code>null</code>)
      */
     public static void validatePropertyDefinition( final PropertyDefinition propertyDefinition,
+                                                   final Collection<QualifiedName> existingPropertyNames,
                                                    final MultiValidationStatus status ) {
-        final ValidationStatus newStatus = validatePropertyDefinition(propertyDefinition);
+        final ValidationStatus newStatus = validatePropertyDefinition(propertyDefinition, existingPropertyNames);
 
         if (!newStatus.isOk()) {
             status.add(newStatus);
@@ -903,7 +888,7 @@
         final Collection<String> propNames = new ArrayList<String>(propertyDefinitions.size());
 
         for (final PropertyDefinition propertyDefn : propertyDefinitions) {
-            validatePropertyDefinition(propertyDefn, status);
+            validatePropertyDefinition(propertyDefn, null, status);
 
             { // ERROR - Duplicate property definition names
                 final String propName = propertyDefn.getName();
@@ -1138,6 +1123,70 @@
     }
 
     /**
+     * @param propertyDefinition the property definition whose default values are being validated (cannot be <code>null</code>)
+     * @return the status (never <code>null</code>)
+     */
+    public static MultiValidationStatus validateDefaultValues( final PropertyDefinition propertyDefinition ) {
+        final MultiValidationStatus status = new MultiValidationStatus();
+        validateDefaultValues(propertyDefinition, status);
+        return status;
+    }
+
+    /**
+     * @param propertyDefinition the property definition whose default values are being validated (cannot be <code>null</code>)
+     * @param status the status to add the new status to (cannot be <code>null</code>)
+     */
+    public static void validateDefaultValues( final PropertyDefinition propertyDefinition,
+                                              final MultiValidationStatus status ) {
+        Utils.verifyIsNotNull(propertyDefinition, "propertyDefinition"); //$NON-NLS-1$
+        Utils.verifyIsNotNull(status, "status"); //$NON-NLS-1$
+
+        String propertyName = propertyDefinition.getName();
+
+        if (Utils.isEmpty(propertyName)) {
+            propertyName = Messages.missingName;
+        }
+
+        final Collection<String> defaultValues = propertyDefinition.getDefaultValuesAsStrings();
+
+        if (Utils.isEmpty(defaultValues)) {
+            if (propertyDefinition.getState(PropertyDefinition.PropertyName.DEFAULT_VALUES) == Value.IS) {
+                status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.emptyDefaultValues, propertyName)));
+            }
+        } else {
+            // ERROR - Cannot have multiple default values when the property definition is single-valued
+            if ((defaultValues.size() > 1)
+                    && (propertyDefinition.getState(PropertyDefinition.PropertyName.MULTIPLE) == Value.IS_NOT)) {
+                status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.multipleDefaultValuesForSingleValuedProperty,
+                                                                        propertyName)));
+            }
+
+            final Collection<String> values = new ArrayList<String>(defaultValues.size());
+
+            for (final String defaultValue : defaultValues) {
+                // ERROR - Default value is not valid for the property definition type
+                isValid(defaultValue, propertyDefinition.getType(), Messages.defaultValue, status);
+
+                if (!Utils.isEmpty(defaultValue)) {
+                    // ERROR - Duplicate default value
+                    if (values.contains(defaultValue)) {
+                        status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateDefaultValue, propertyName,
+                                                                                defaultValue)));
+                    } else {
+                        values.add(defaultValue);
+                    }
+                }
+            }
+
+            // ERROR - Cannot have explicit default values when default values is marked as a variant
+            if (propertyDefinition.getState(PropertyDefinition.PropertyName.DEFAULT_VALUES) != Value.IS) {
+                status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.defaultValuesExistButMarkedAsVariant,
+                                                                        propertyDefinition)));
+            }
+        }
+    }
+
+    /**
      * @param nodeTypeDefinitionName the node type name whose supertypes are being checked (cannot be <code>null</code> or empty)
      * @param superTypesState the supertypes property state (cannot be <code>null</code>)
      * @param superTypeNames the collection of a node type definition's supertypes to validate (can be <code>null</code> or empty)
@@ -1235,7 +1284,7 @@
     public static ValidationStatus validateValueConstraint( final String constraint ) {
         Utils.verifyIsNotEmpty(constraint, "constraint"); //$NON-NLS-1$
 
-        // TODO implement validateValueConstraint
+        // TODO implement validateValueConstraint to make sure constraint is property syntax
         return ValidationStatus.OK_STATUS;
     }
 
@@ -1253,6 +1302,63 @@
     }
 
     /**
+     * @param propertyDefinition the property definition whose value constraints are being validated (cannot be <code>null</code>)
+     * @return the status (never <code>null</code>)
+     */
+    public static MultiValidationStatus validateValueConstraints( final PropertyDefinition propertyDefinition ) {
+        final MultiValidationStatus status = new MultiValidationStatus();
+        validateValueConstraints(propertyDefinition, status);
+        return status;
+    }
+
+    /**
+     * @param propertyDefinition the property definition whose value constraints are being validated (cannot be <code>null</code>)
+     * @param status the status to add the new status to (cannot be <code>null</code>)
+     */
+    public static void validateValueConstraints( final PropertyDefinition propertyDefinition,
+                                                 final MultiValidationStatus status ) {
+        Utils.verifyIsNotNull(propertyDefinition, "propertyDefinition"); //$NON-NLS-1$
+        Utils.verifyIsNotNull(status, "status"); //$NON-NLS-1$
+
+        String propertyName = propertyDefinition.getName();
+
+        if (Utils.isEmpty(propertyName)) {
+            propertyName = Messages.missingName;
+        }
+
+        final String[] valueConstraints = propertyDefinition.getValueConstraints();
+
+        if (Utils.isEmpty(valueConstraints)) {
+            if (propertyDefinition.getState(PropertyDefinition.PropertyName.VALUE_CONSTRAINTS) == Value.IS) {
+                status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.emptyValueConstraints, propertyName)));
+            }
+        } else {
+            final Collection<String> constraints = new ArrayList<String>(valueConstraints.length);
+
+            for (final String constraint : valueConstraints) {
+                // ERROR - Invalid value constraint
+                validateValueConstraint(constraint, status);
+
+                if (!Utils.isEmpty(constraint)) {
+                    // ERROR - Duplicate value constraint
+                    if (constraints.contains(constraint)) {
+                        status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateValueConstraint,
+                                                                                propertyName, constraint)));
+                    } else {
+                        constraints.add(constraint);
+                    }
+                }
+            }
+
+            // ERROR - Cannot have explicit value constraints when value constraints is marked as a variant
+            if (propertyDefinition.getState(PropertyDefinition.PropertyName.VALUE_CONSTRAINTS) != Value.IS) {
+                status.add(ValidationStatus.createErrorMessage(NLS.bind(Messages.valueConstraintsExistButMarkedAsVariant,
+                                                                        propertyDefinition)));
+            }
+        }
+    }
+
+    /**
      * Don't allow construction.
      */
     private CndValidator() {

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CompactNodeTypeDefinition.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CompactNodeTypeDefinition.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/CompactNodeTypeDefinition.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -314,7 +314,17 @@
         /**
          * The node type definitions property.
          */
-        NODE_TYPE_DEFINITIONS
+        NODE_TYPE_DEFINITIONS;
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Enum#toString()
+         */
+        @Override
+        public String toString() {
+            return (getClass().getSimpleName() + super.toString());
+        }
     }
 
 }

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NamespaceMapping.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NamespaceMapping.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NamespaceMapping.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -227,7 +227,7 @@
 
     /**
      * {@inheritDoc}
-     *
+     * 
      * @see java.lang.Object#toString()
      */
     @Override
@@ -244,6 +244,7 @@
      * The property names whose <code>toString()</code> is used in {@link PropertyChangeEvent}s.
      */
     public enum PropertyName {
+
         /**
          * The namespace prefix.
          */
@@ -252,7 +253,16 @@
         /**
          * The namespace URI.
          */
-        URI
+        URI;
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Enum#toString()
+         */
+        @Override
+        public String toString() {
+            return (getClass().getSimpleName() + super.toString());
+        }
     }
-
 }

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NodeTypeDefinition.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NodeTypeDefinition.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/NodeTypeDefinition.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -416,6 +416,13 @@
         return new ArrayList<PropertyDefinitionTemplate>(getPropertyDefinitions());
     }
 
+    /**
+     * @return the node type definition's qualified name (never <code>null</code>)
+     */
+    public QualifiedName getQualifiedName() {
+        return this.name;
+    }
+
     private String getStartChildNodeDefinitionDelimiter() {
         return CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.CHILD_NODE_DEFINITION_START_DELIMITER);
     }
@@ -814,7 +821,17 @@
         /**
          * The collection for super types.
          */
-        SUPERTYPES
+        SUPERTYPES;
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Enum#toString()
+         */
+        @Override
+        public String toString() {
+            return (getClass().getSimpleName() + super.toString());
+        }
     }
 
 }

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinition.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinition.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinition.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -46,6 +46,27 @@
     public static final String RESIDUAL_PROPERTY_NAME = "*"; //$NON-NLS-1$
 
     /**
+     * @param propertyBeingCopied the property definition being copied (cannot be <code>null</code>)
+     * @return the copy (never <code>null</code>)
+     */
+    public static final PropertyDefinition copy( final PropertyDefinition propertyBeingCopied ) {
+        final PropertyDefinition copy = new PropertyDefinition();
+        copy.setName(propertyBeingCopied.getName());
+        copy.setAutoCreated(propertyBeingCopied.isAutoCreated());
+        copy.setAvailableQueryOperators(propertyBeingCopied.getAvailableQueryOperators());
+        copy.setDefaultValues(propertyBeingCopied.getDefaultValues());
+        copy.setFullTextSearchable(propertyBeingCopied.isFullTextSearchable());
+        copy.setMandatory(propertyBeingCopied.isMandatory());
+        copy.setMultiple(propertyBeingCopied.isMultiple());
+        copy.setOnParentVersion(propertyBeingCopied.getOnParentVersion());
+        copy.setProtected(propertyBeingCopied.isProtected());
+        copy.setQueryOrderable(propertyBeingCopied.isQueryOrderable());
+        copy.setRequiredType(propertyBeingCopied.getRequiredType());
+        copy.setValueConstraints(propertyBeingCopied.getValueConstraints());
+        return copy;
+    }
+
+    /**
      * The property attributes (never <code>null</code>).
      */
     private final PropertyAttributes attributes;
@@ -270,6 +291,44 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals( final Object obj ) {
+        if (this == obj) {
+            return true;
+        }
+
+        if ((obj == null) || !getClass().equals(obj.getClass())) {
+            return false;
+        }
+
+        final PropertyDefinition that = (PropertyDefinition)obj;
+        // this.defaultValues = new DefaultValues();
+        // this.valueConstraints = new ValueConstraints();
+
+        if (!this.attributes.equals(that.attributes)) {
+            return false;
+        }
+
+        if (!Utils.equals(getName(), that.getName())) {
+            return false;
+        }
+
+        if (this.type != that.type) {
+            return false;
+        }
+
+        if (!this.defaultValues.equals(that.defaultValues)) {
+            return false;
+        }
+
+        return this.valueConstraints.equals(that.valueConstraints);
+    }
+
+    /**
      * @param notationType the notation type being requested (cannot be <code>null</code>)
      * @return the CND notation (never <code>null</code>)
      */
@@ -355,6 +414,13 @@
     }
 
     /**
+     * @return the qualified name (never <code>null</code>)
+     */
+    public QualifiedName getQualifiedName() {
+        return this.name;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see javax.jcr.nodetype.PropertyDefinition#getRequiredType()
@@ -450,6 +516,16 @@
     /**
      * {@inheritDoc}
      * 
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return Utils.hashCode(this.attributes, this.name, this.defaultValues, this.type, this.valueConstraints);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see javax.jcr.nodetype.ItemDefinition#isAutoCreated()
      */
     @Override
@@ -897,7 +973,16 @@
         /**
          * The collection of property constraints.
          */
-        VALUE_CONSTRAINTS
+        VALUE_CONSTRAINTS;
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Enum#toString()
+         */
+        @Override
+        public String toString() {
+            return (getClass().getSimpleName() + super.toString());
+        }
     }
-
 }

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/attributes/ListAttributeState.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/attributes/ListAttributeState.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr/src/org/jboss/tools/modeshape/jcr/cnd/attributes/ListAttributeState.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -104,6 +104,15 @@
     }
 
     /**
+     * @param item the item being checked to see if it is already supported (cannot be <code>null</code>)
+     * @return <code>true</code> if already exists
+     */
+    public boolean exists( E item ) {
+        Utils.verifyIsNotNull(item, "item"); //$NON-NLS-1$
+        return getSupportedItems().contains(item);
+    }
+
+    /**
      * @param notationType the notation type whose CND notation prefix is being requested (cannot be <code>null</code>)
      * @return the CND notation prefix (can be <code>null</code> or empty)
      */
@@ -285,7 +294,7 @@
      */
     public boolean supports( final E item ) {
         Utils.verifyIsNotNull(item, "item"); //$NON-NLS-1$
-        return this.supported.contains(item);
+        return getSupportedItems().contains(item);
     }
 
     /**

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/ChildNodeDialog.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/ChildNodeDialog.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/ChildNodeDialog.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -42,8 +42,10 @@
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Group;
 import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.Text;
@@ -71,9 +73,9 @@
 import org.jboss.tools.modeshape.ui.forms.MessageFormDialog;
 
 /**
- * 
+ * A dialog used to create and edit {@link ChildNodeDefinition}s.
  */
-class ChildNodeDialog extends FormDialog {
+final class ChildNodeDialog extends FormDialog {
 
     private IAction addRequiredType;
     private Button btnOk;
@@ -81,17 +83,18 @@
     private final ErrorMessage defaultTypeError;
     private IAction deleteRequiredType;
     private IAction editRequiredType;
-
     /**
      * The existing child node definition names contained in the CND (never <code>null</code> but can be empty).
      */
-    private Collection<QualifiedName> existingChildNodeNames;
+    private final Collection<QualifiedName> existingChildNodeNames;
 
     /**
      * The existing namespace prefixes contained in the CND (never <code>null</code> but can be empty).
      */
-    private Collection<String> existingNamespacePrefixes;
+    private final Collection<String> existingNamespacePrefixes;
 
+    private QualifiedNameEditor nameEditor;
+
     private final ErrorMessage nameError;
 
     private ChildNodeDefinition originalChildNode;
@@ -123,19 +126,12 @@
     }
 
     /**
-     * @return the child node definition represented by the dialog UI controls (never <code>null</code>)
-     */
-    public ChildNodeDefinition getChildNodeDefinition() {
-        return this.childNodeBeingEdited;
-    }
-
-    /**
-     * Used to create a new child node definition.
+     * Used to edit a child node definition.
      * 
      * @param parentShell the parent shell (can be <code>null</code>)
      * @param existingChildNodeNames the existing child node names (can be <code>null</code> or empty)
-     * @param childNodeBeingEdited the child node definition being edited (cannot be <code>null</code>)
      * @param existingNamespacePrefixes the existing CND namespace prefixes (can be <code>null</code> or empty)
+     * @param childNodeBeingEdited the child node definition being edited (cannot be <code>null</code>)
      */
     public ChildNodeDialog( final Shell parentShell,
                             final Collection<QualifiedName> existingChildNodeNames,
@@ -151,7 +147,7 @@
 
         // remove name from existing names so that validation won't show it as a duplicate
         if (!Utils.isEmpty(this.childNodeBeingEdited.getName())) {
-            this.existingChildNodeNames.remove(this.childNodeBeingEdited.getName());
+            this.existingChildNodeNames.remove(this.childNodeBeingEdited.getQualifiedName());
         }
     }
 
@@ -216,35 +212,27 @@
             toolkit.paintBordersFor(leftContainer);
 
             { // name
-                toolkit.createLabel(leftContainer, CndMessages.nameLabel);
-                final Text txtName = toolkit.createText(leftContainer, Utils.EMPTY_STRING, Styles.TEXT_STYLE);
-                txtName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-                txtName.setToolTipText(CndMessages.childNodeNameToolTip);
+                this.nameEditor = new QualifiedNameEditor(leftContainer,
+                                                          SWT.NONE,
+                                                          toolkit,
+                                                          Messages.propertyDefinitionName,
+                                                          this.existingNamespacePrefixes,
+                                                          this.childNodeBeingEdited.getQualifiedName());
+                ((GridData)this.nameEditor.getLayoutData()).horizontalSpan = 2;
+                this.nameEditor.addListener(SWT.Modify, new Listener() {
 
-                if (isEditMode()) {
-                    String currentValue = this.childNodeBeingEdited.getName();
-
-                    if (currentValue == null) {
-                        currentValue = Utils.EMPTY_STRING;
-                    }
-
-                    txtName.setText(currentValue);
-                }
-
-                txtName.addModifyListener(new ModifyListener() {
-
                     /**
                      * {@inheritDoc}
                      * 
-                     * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+                     * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
                      */
                     @Override
-                    public void modifyText( final ModifyEvent e ) {
-                        handleNameChanged(((Text)e.widget).getText());
+                    public void handleEvent( final Event e ) {
+                        handleNameChanged(e.text);
                     }
                 });
 
-                this.nameError.setControl(txtName);
+                this.nameError.setControl(this.nameEditor);
             }
 
             { // default type
@@ -283,7 +271,7 @@
                 final Group attributesContainer = new Group(leftContainer, SWT.SHADOW_NONE);
                 attributesContainer.setText(CndMessages.attributesHeaderText);
                 attributesContainer.setLayout(new GridLayout(2, true));
-                GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
+                final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
                 gd.horizontalSpan = 2;
                 attributesContainer.setLayoutData(gd);
                 toolkit.adapt(attributesContainer);
@@ -374,11 +362,10 @@
                 });
                 btnSameNamedSiblings.setToolTipText(CndMessages.sameNamedSiblingsAttributeToolTip);
 
-                
                 { // opv
                     final Composite opvContainer = toolkit.createComposite(attributesContainer);
                     opvContainer.setLayout(new GridLayout(2, false));
-                    GridData gdOpv = new GridData(SWT.FILL, SWT.CENTER, true, false);
+                    final GridData gdOpv = new GridData(SWT.FILL, SWT.CENTER, true, false);
                     gdOpv.horizontalSpan = 2;
                     opvContainer.setLayoutData(gdOpv);
                     toolkit.paintBordersFor(opvContainer);
@@ -389,6 +376,7 @@
                     final CCombo cbxOpvs = new CCombo(opvContainer, Styles.COMBO_STYLE);
                     toolkit.adapt(cbxOpvs, true, false);
                     cbxOpvs.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+                    ((GridData)cbxOpvs.getLayoutData()).heightHint = cbxOpvs.getItemHeight() + 4;
                     cbxOpvs.setToolTipText(CndMessages.onParentVersionToolTip);
 
                     // populate opv values
@@ -613,6 +601,15 @@
     }
 
     /**
+     * <strong>Should only be called after the dialog's <code>OK</code> button has been selected.</strong>
+     * 
+     * @return the child node definition represented by the dialog UI controls (never <code>null</code>)
+     */
+    public ChildNodeDefinition getChildNodeDefinition() {
+        return this.childNodeBeingEdited;
+    }
+
+    /**
      * @return the selected required type or <code>null</code> if the viewer has an empty selection
      */
     private String getSelectedRequiredType() {
@@ -639,9 +636,7 @@
         if (dialog.open() == Window.OK) {
             final QualifiedName newQName = dialog.getQualifiedName();
 
-            if (this.childNodeBeingEdited.addRequiredType(newQName.get())) {
-                this.requiredTypesViewer.refresh();
-            } else {
+            if (!this.childNodeBeingEdited.addRequiredType(newQName.get())) {
                 MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
                                             NLS.bind(CndMessages.errorAddingRequiredType, newQName));
             }
@@ -764,26 +759,10 @@
     }
 
     private boolean isEditMode() {
-        return (this.childNodeBeingEdited != null);
+        return (this.originalChildNode != null);
     }
 
-    private void validateAttributes() {
-        // no validation required
-    }
-
-    private void validateDefaultType() {
-        updateMessage(CndValidator.validateDefaultType(this.childNodeBeingEdited), this.defaultTypeError);
-    }
-
-    private void validateName() {
-        updateMessage(CndValidator.validateName(this.childNodeBeingEdited), this.nameError);
-    }
-
-    private void validateRequiredTypes() {
-        updateMessage(CndValidator.validateRequiredTypes(this.childNodeBeingEdited), this.requiredTypesError);
-    }
-
-    private void updateMessage( final ValidationStatus status, 
+    private void updateMessage( final ValidationStatus status,
                                 final ErrorMessage errorMsg ) {
         JcrUiUtils.setMessage(status, errorMsg);
 
@@ -796,7 +775,7 @@
     }
 
     private void updateState() {
-        int messageType = this.scrolledForm.getMessageType();
+        final int messageType = this.scrolledForm.getMessageType();
         boolean enable = (messageType != IMessageProvider.ERROR);
 
         if (enable && isEditMode() && this.originalChildNode.equals(this.childNodeBeingEdited)) {
@@ -808,4 +787,20 @@
             this.btnOk.setEnabled(enable);
         }
     }
+
+    private void validateAttributes() {
+        // no validation required since user cannot enter an invalid value
+    }
+
+    private void validateDefaultType() {
+        updateMessage(CndValidator.validateDefaultType(this.childNodeBeingEdited), this.defaultTypeError);
+    }
+
+    private void validateName() {
+        updateMessage(this.nameEditor.getStatus(), this.nameError);
+    }
+
+    private void validateRequiredTypes() {
+        updateMessage(CndValidator.validateRequiredTypes(this.childNodeBeingEdited), this.requiredTypesError);
+    }
 }

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndEditor.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndEditor.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndEditor.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -24,7 +24,6 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.jface.action.IStatusLineManager;
 import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.osgi.util.NLS;
@@ -194,6 +193,7 @@
         List<Throwable> errors = new ArrayList<Throwable>();
         this.cndBeingEdited = importer.importFrom(getFile().getContents(), errors, getFile().getName());
         // TODO implement
+        this.cndBeingEdited.addListener(this);
     }
 
     /**
@@ -233,7 +233,7 @@
     @Override
     public void doSaveAs() {
         // TODO implement doSaveAs
-        final IProgressMonitor progressMonitor = getProgressMonitor();
+//        final IProgressMonitor progressMonitor = getProgressMonitor();
         // SaveAsDialog dialog = new SaveAsDialog(getShell());
         // dialog.setOriginalFile(getFile());
         // dialog.create();
@@ -299,12 +299,12 @@
     IMessageManager getMessageManager() {
         return this.scrolledForm.getMessageManager();
     }
+//
+//    private IProgressMonitor getProgressMonitor() {
+//        final IStatusLineManager statusLineMgr = getEditorSite().getActionBars().getStatusLineManager();
+//        return ((statusLineMgr == null) ? null : statusLineMgr.getProgressMonitor());
+//    }
 
-    private IProgressMonitor getProgressMonitor() {
-        final IStatusLineManager statusLineMgr = getEditorSite().getActionBars().getStatusLineManager();
-        return ((statusLineMgr == null) ? null : statusLineMgr.getProgressMonitor());
-    }
-
     /**
      * @return the editor's shell (never <code>null</code>)
      */
@@ -427,7 +427,6 @@
     public void propertyChange( final PropertyChangeEvent e ) {
         refreshDirtyState();
         this.formsPage.handlePropertyChanged(e);
-//        this.sourcePage.handlePropertyChanged(e);
     }
 
     void refreshCnd() {
@@ -444,7 +443,6 @@
                     createCnd();
 
                     this.formsPage.handleCndReloaded();
-//                    this.sourcePage.handleCndReloaded();
                 } catch (final Exception e) {
                     // TODO log this
                     MessageFormDialog.openError(getShell(), CndMessages.cndEditorRefreshErrorTitle,
@@ -481,9 +479,6 @@
 
             this.formsPage.setResourceReadOnly(this.readOnly);
             this.formsPage.getManagedForm().refresh();
-//
-//            this.sourcePage.setResourceReadOnly(this.readOnly);
-//            this.sourcePage.getManagedForm().refresh();
         }
     }
 

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndFormsEditorPage.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndFormsEditorPage.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndFormsEditorPage.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -38,7 +38,6 @@
 import org.eclipse.jface.window.Window;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.CCombo;
 import org.eclipse.swt.custom.SashForm;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
@@ -53,17 +52,20 @@
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Group;
 import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.ui.forms.IFormColors;
 import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.IMessageManager;
 import org.eclipse.ui.forms.widgets.ExpandableComposite;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.Section;
 import org.jboss.tools.modeshape.jcr.Messages;
 import org.jboss.tools.modeshape.jcr.MultiValidationStatus;
 import org.jboss.tools.modeshape.jcr.Utils;
+import org.jboss.tools.modeshape.jcr.ValidationStatus;
 import org.jboss.tools.modeshape.jcr.cnd.ChildNodeDefinition;
 import org.jboss.tools.modeshape.jcr.cnd.CndElement.NotationType;
 import org.jboss.tools.modeshape.jcr.cnd.CndValidator;
@@ -95,7 +97,6 @@
     private Button btnMixin;
     private Button btnOrderable;
     private Button btnQueryable;
-    private CCombo cbxNamePrefix;
     private Section childNodeSection;
     private final ErrorMessage childNodesError;
     private TableViewer childNodeViewer;
@@ -107,14 +108,13 @@
     private Section detailsSection;
     private IAction editChildNode;
     private IAction editNamespace;
-    private IAction editNodeType;
     private IAction editProperty;
     private IAction editSuperType;
+    private QualifiedNameEditor nameEditor;
     private final ErrorMessage namespacesError;
     private TableViewer namespaceViewer;
     private final ErrorMessage nodeTypeNameError;
     private String nodeTypeNameFilterPattern;
-    private final ErrorMessage nodeTypeNamePrefixError;
     private final ErrorMessage nodeTypesError;
     private TableViewer nodeTypeViewer;
     private final ErrorMessage propertiesError;
@@ -122,7 +122,6 @@
     private TableViewer propertyViewer;
     private final ErrorMessage superTypesError;
     private TableViewer superTypesViewer;
-    private Text txtName;
 
     /**
      * @param cndEditor the CND editor this page belongs to (cannot be <code>null</code>)
@@ -135,7 +134,6 @@
         this.namespacesError = new ErrorMessage();
         this.nodeTypesError = new ErrorMessage();
         this.nodeTypeNameError = new ErrorMessage();
-        this.nodeTypeNamePrefixError = new ErrorMessage();
         this.propertiesError = new ErrorMessage();
         this.superTypesError = new ErrorMessage();
     }
@@ -235,7 +233,7 @@
         ((GridData)table.getLayoutData()).heightHint = table.getItemHeight() * 5;
 
         // table context menu
-        MenuManager menuManager = new MenuManager();
+        final MenuManager menuManager = new MenuManager();
         menuManager.add(new DelegateAction(CndMessages.addChildNodeMenuText, this.addChildNode));
         menuManager.add(new DelegateAction(CndMessages.editChildNodeMenuText, this.editChildNode));
         menuManager.add(new DelegateAction(CndMessages.deleteChildNodeMenuText, this.deleteChildNode));
@@ -416,46 +414,29 @@
             leftContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
             toolkit.paintBordersFor(leftContainer);
 
-            { // name qualifier
-                toolkit.createLabel(leftContainer, CndMessages.namespaceLabel);
-                this.cbxNamePrefix = new CCombo(leftContainer, Styles.COMBO_STYLE);
-                toolkit.adapt(this.cbxNamePrefix, true, false);
-                this.nodeTypeNamePrefixError.setControl(this.cbxNamePrefix);
-                this.cbxNamePrefix.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-                ((GridData)this.cbxNamePrefix.getLayoutData()).heightHint = this.cbxNamePrefix.getItemHeight() + 4;
-
-                this.cbxNamePrefix.addModifyListener(new ModifyListener() {
-
-                    /**
-                     * {@inheritDoc}
-                     * 
-                     * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
-                     */
-                    @Override
-                    public void modifyText( final ModifyEvent e ) {
-                        handleNameQualifierChanged(((CCombo)e.widget).getText());
-                    }
-                });
-            }
-
             { // name
-                toolkit.createLabel(leftContainer, CndMessages.nameLabel);
-                this.txtName = toolkit.createText(leftContainer, Utils.EMPTY_STRING, Styles.TEXT_STYLE);
-                this.txtName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-                this.txtName.addModifyListener(new ModifyListener() {
+                this.nameEditor = new QualifiedNameEditor(leftContainer,
+                                                          SWT.NONE,
+                                                          toolkit,
+                                                          Messages.propertyDefinitionName,
+                                                          getNamespacePrefixes(),
+                                                          null);
+                ((GridData)this.nameEditor.getLayoutData()).horizontalSpan = 2;
+                this.nameEditor.addListener(SWT.Modify, new Listener() {
 
                     /**
                      * {@inheritDoc}
                      * 
-                     * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+                     * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
                      */
                     @Override
-                    public void modifyText( final ModifyEvent e ) {
-                        handleNodeTypeNameChanged(((Text)e.widget).getText());
+                    public void handleEvent( final Event e ) {
+                        handleNodeTypeNameChanged(e.text);
                     }
                 });
 
-                this.nodeTypeNameError.setControl(this.txtName);
+                this.nodeTypeNameError.setControl(this.nameEditor);
+                refreshNameControls(); // populate name editor controls
             }
 
             { // attributes
@@ -533,7 +514,6 @@
                 this.btnQueryable.setToolTipText(CndMessages.queryableAttributeToolTip);
 
                 // fill with data from CND
-                refreshNameControls();
                 refreshAttributeControls();
             }
         }
@@ -552,12 +532,13 @@
             table.setHeaderVisible(false);
             table.setLinesVisible(false);
             ((GridData)table.getLayoutData()).heightHint = table.getItemHeight() * 2;
+            table.setToolTipText(CndMessages.supertypesToolTip);
             this.superTypesError.setControl(table);
 
             createSuperTypesActions();
 
             // table context menu
-            MenuManager menuManager = new MenuManager();
+            final MenuManager menuManager = new MenuManager();
             menuManager.add(new DelegateAction(CndMessages.addSuperTypeMenuText, this.addSuperType));
             menuManager.add(new DelegateAction(CndMessages.editSuperTypeMenuText, this.editSuperType));
             menuManager.add(new DelegateAction(CndMessages.deleteSuperTypeMenuText, this.deleteSuperType));
@@ -658,7 +639,7 @@
         ((GridData)table.getLayoutData()).heightHint = table.getItemHeight() * 5;
 
         // table context menu
-        MenuManager menuManager = new MenuManager();
+        final MenuManager menuManager = new MenuManager();
         menuManager.add(new DelegateAction(CndMessages.addNamespaceMenuText, this.addNamespace));
         menuManager.add(new DelegateAction(CndMessages.editNamespaceMenuText, this.editNamespace));
         menuManager.add(new DelegateAction(CndMessages.deleteNamespaceMenuText, this.deleteNamespace));
@@ -819,22 +800,6 @@
         this.deleteNodeType.setEnabled(false);
         this.deleteNodeType.setToolTipText(CndMessages.deleteNodeTypeToolTip);
         this.deleteNodeType.setImageDescriptor(JcrUiUtils.getDeleteImageDescriptor());
-
-        this.editNodeType = new Action(Utils.EMPTY_STRING) {
-
-            /**
-             * {@inheritDoc}
-             * 
-             * @see org.eclipse.jface.action.Action#run()
-             */
-            @Override
-            public void run() {
-                handleEditNodeType();
-            }
-        };
-        this.editNodeType.setEnabled(false);
-        this.editNodeType.setToolTipText(CndMessages.editNodeTypeToolTip);
-        this.editNodeType.setImageDescriptor(JcrUiUtils.getEditImageDescriptor());
     }
 
     @SuppressWarnings("unused")
@@ -851,7 +816,7 @@
         createNodeTypeActions();
 
         // create toolbar
-        FormUtils.createSectionToolBar(section, toolkit, new IAction[] { this.addNodeType, this.editNodeType, this.deleteNodeType });
+        FormUtils.createSectionToolBar(section, toolkit, new IAction[] { this.addNodeType, this.deleteNodeType });
 
         // splitter has node type table on left and node type detail, properties, and child nodes on right
         final SashForm splitter = new SashForm(section, SWT.HORIZONTAL);
@@ -896,9 +861,8 @@
             table.setLinesVisible(false);
 
             // table context menu
-            MenuManager menuManager = new MenuManager();
+            final MenuManager menuManager = new MenuManager();
             menuManager.add(new DelegateAction(CndMessages.addNodeTypeMenuText, this.addNodeType));
-            menuManager.add(new DelegateAction(CndMessages.editNodeTypeMenuText, this.editNodeType));
             menuManager.add(new DelegateAction(CndMessages.deleteNodeTypeMenuText, this.deleteNodeType));
             table.setMenu(menuManager.createContextMenu(table));
 
@@ -981,20 +945,6 @@
             }
         });
 
-        // open edit namespace on double click
-        this.nodeTypeViewer.addDoubleClickListener(new IDoubleClickListener() {
-
-            /**
-             * {@inheritDoc}
-             * 
-             * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
-             */
-            @Override
-            public void doubleClick( final DoubleClickEvent event ) {
-                handleEditNodeType();
-            }
-        });
-
         // add selection listener
         this.nodeTypeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
 
@@ -1140,7 +1090,7 @@
         ((GridData)table.getLayoutData()).heightHint = table.getItemHeight() * 5;
 
         // table context menu
-        MenuManager menuManager = new MenuManager();
+        final MenuManager menuManager = new MenuManager();
         menuManager.add(new DelegateAction(CndMessages.addPropertyMenuText, this.addProperty));
         menuManager.add(new DelegateAction(CndMessages.editPropertyMenuText, this.editProperty));
         menuManager.add(new DelegateAction(CndMessages.deletePropertyMenuText, this.deleteProperty));
@@ -1176,7 +1126,7 @@
                 final NotationType notationType = NotationType.LONG;
 
                 if (this.columnIndex == PropertyColumnIndexes.TYPE) {
-                    return propertyDefinition.getType().toCndNotation(notationType);
+                    return propertyDefinition.getType().toString();
                 }
 
                 if (this.columnIndex == PropertyColumnIndexes.ATTRIBUTES) {
@@ -1184,7 +1134,13 @@
                 }
 
                 if (this.columnIndex == PropertyColumnIndexes.DEFAULT_VALUES) {
-                    return propertyDefinition.getType().toCndNotation(NotationType.LONG);
+                    final List<String> defaultValues = propertyDefinition.getDefaultValuesAsStrings();
+
+                    if (Utils.isEmpty(defaultValues)) {
+                        return Utils.EMPTY_STRING;
+                    }
+
+                    return UiUtils.join(defaultValues, null);
                 }
 
                 assert (this.columnIndex == PropertyColumnIndexes.CONSTRAINTS) : "Unexpected property column index"; //$NON-NLS-1$
@@ -1432,6 +1388,25 @@
         });
     }
 
+    Collection<QualifiedName> getChildNodeNames() {
+        assert (getSelectedNodeType() != null) : "getChildNodeNames called but no selected node type"; //$NON-NLS-1$
+        final Collection<ChildNodeDefinition> childNodes = getSelectedNodeType().getChildNodeDefinitions();
+
+        if (childNodes.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final Collection<QualifiedName> childNodeNames = new ArrayList<QualifiedName>(childNodes.size());
+
+        for (final ChildNodeDefinition childNode : childNodes) {
+            if (!Utils.isEmpty(childNode.getName())) {
+                childNodeNames.add(childNode.getQualifiedName());
+            }
+        }
+
+        return childNodeNames;
+    }
+
     private List<String> getNamespacePrefixes() {
         final List<NamespaceMapping> namespaces = getCnd().getNamespaceMappings();
 
@@ -1455,6 +1430,43 @@
         return this.nodeTypeNameFilterPattern;
     }
 
+    Collection<QualifiedName> getNodeTypeNames() {
+        final Collection<NodeTypeDefinition> nodeTypes = getCnd().getNodeTypeDefinitions();
+
+        if (nodeTypes.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final Collection<QualifiedName> nodeTypeNames = new ArrayList<QualifiedName>(nodeTypes.size());
+
+        for (final NodeTypeDefinition nodeType : nodeTypes) {
+            if (!Utils.isEmpty(nodeType.getName())) {
+                nodeTypeNames.add(nodeType.getQualifiedName());
+            }
+        }
+
+        return nodeTypeNames;
+    }
+
+    Collection<QualifiedName> getPropertyNames() {
+        assert (getSelectedNodeType() != null) : "getPropertyNames called but no selected node type"; //$NON-NLS-1$
+        final Collection<PropertyDefinition> propDefns = getSelectedNodeType().getPropertyDefinitions();
+
+        if (propDefns.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final Collection<QualifiedName> propDefnNames = new ArrayList<QualifiedName>(propDefns.size());
+
+        for (final PropertyDefinition propDefn : propDefns) {
+            if (!Utils.isEmpty(propDefn.getName())) {
+                propDefnNames.add(propDefn.getQualifiedName());
+            }
+        }
+
+        return propDefnNames;
+    }
+
     /**
      * @return the selected child node definition or <code>null</code> if the viewer has an empty selection
      */
@@ -1534,38 +1546,22 @@
         getSelectedNodeType().setAbstract(newValue);
     }
 
-    Collection<QualifiedName> getChildNodeNames() {
-        assert (getSelectedNodeType() != null) : "Add child node handler called but no selected node type"; //$NON-NLS-1$
-        Collection<ChildNodeDefinition> childNodes = getSelectedNodeType().getChildNodeDefinitions();
-
-        if (childNodes.isEmpty()) {
-            return Collections.emptyList();
-        }
-
-        Collection<QualifiedName> childNodeNames = new ArrayList<QualifiedName>(childNodes.size());
-
-        for (ChildNodeDefinition childNode : childNodes) {
-            if (!Utils.isEmpty(childNode.getName())) {
-                childNodeNames.add(childNode.getQualifiedName());
-            }
-        }
-
-        return childNodeNames;
-    }
-
     void handleAddChildNode() {
         assert (getSelectedNodeType() != null) : "add child node handler called but there is no selected node type"; //$NON-NLS-1$
 
-        ChildNodeDialog dialog = new ChildNodeDialog(getShell(), getChildNodeNames(), getNamespacePrefixes());
+        final ChildNodeDialog dialog = new ChildNodeDialog(getShell(), getChildNodeNames(), getNamespacePrefixes());
         dialog.create();
         dialog.getShell().pack();
 
         if (dialog.open() == Window.OK) {
-            ChildNodeDefinition newChildNodeDefinition = dialog.getChildNodeDefinition();
+            final ChildNodeDefinition newChildNodeDefinition = dialog.getChildNodeDefinition();
 
-            // select new child node definition
+            // add and select new child node definition
             if (getSelectedNodeType().addChildNodeDefinition(newChildNodeDefinition)) {
                 this.childNodeViewer.setSelection(new StructuredSelection(newChildNodeDefinition));
+            } else {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorAddingChildNode, newChildNodeDefinition.getName()));
             }
         }
     }
@@ -1576,25 +1572,59 @@
         dialog.getShell().pack();
 
         if (dialog.open() == Window.OK) {
-            final NamespaceMapping namespaceMapping = dialog.getNamespaceMapping();
+            final NamespaceMapping newNamespaceMapping = dialog.getNamespaceMapping();
 
-            if (getCnd().addNamespaceMapping(namespaceMapping)) {
-                this.namespaceViewer.refresh();
+            if (getCnd().addNamespaceMapping(newNamespaceMapping)) {
+                this.namespaceViewer.setSelection(new StructuredSelection(newNamespaceMapping));
             } else {
                 MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
-                                            NLS.bind(CndMessages.errorAddingNamespaceMapping, namespaceMapping));
+                                            NLS.bind(CndMessages.errorAddingNamespaceMapping, newNamespaceMapping));
             }
         }
     }
 
     void handleAddNodeType() {
-        // TODO handleAddNodeType
-        MessageFormDialog.openInfo(getShell(), "Not Implemented Yet", null, "method has not be implemented"); //$NON-NLS-1$ //$NON-NLS-2$
+        final QualifiedNameDialog dialog = new QualifiedNameDialog(getShell(),
+                                                                   CndMessages.newNodeTypeDialogTitle,
+                                                                   Messages.nodeTypeDefinitionName,
+                                                                   getNamespacePrefixes());
+        dialog.setExistingQNames(getNodeTypeNames());
+        dialog.create();
+        dialog.getShell().pack();
+
+        if (dialog.open() == Window.OK) {
+            final QualifiedName newNodeTypeName = dialog.getQualifiedName();
+            final NodeTypeDefinition newNodeTypeDefinition = new NodeTypeDefinition();
+            newNodeTypeDefinition.setName(newNodeTypeName.get());
+
+            // add and select new node type definition
+            if (getCnd().addNodeTypeDefinition(newNodeTypeDefinition)) {
+                this.nodeTypeViewer.setSelection(new StructuredSelection(newNodeTypeDefinition));
+            } else {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorAddingNodeType, newNodeTypeName));
+            }
+        }
     }
 
     void handleAddProperty() {
-        // TODO handleAddProperty
-        MessageFormDialog.openInfo(getShell(), "Not Implemented Yet", null, "method has not be implemented"); //$NON-NLS-1$ //$NON-NLS-2$
+        assert (getSelectedNodeType() != null) : "add property handler called but there is no selected node type"; //$NON-NLS-1$
+
+        final PropertyDialog dialog = new PropertyDialog(getShell(), getPropertyNames(), getNamespacePrefixes());
+        dialog.create();
+        dialog.getShell().pack();
+
+        if (dialog.open() == Window.OK) {
+            final PropertyDefinition newPropertyDefinition = dialog.getPropertyDefinition();
+
+            // add and select new property definition
+            if (getSelectedNodeType().addPropertyDefinition(newPropertyDefinition)) {
+                this.propertyViewer.setSelection(new StructuredSelection(newPropertyDefinition));
+            } else {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorAddingProperty, newPropertyDefinition.getName()));
+            }
+        }
     }
 
     void handleAddSuperType() {
@@ -1610,13 +1640,14 @@
 
         if (dialog.open() == Window.OK) {
             final NodeTypeDefinition nodeTypeDefinition = getSelectedNodeType();
-            final QualifiedName newQName = dialog.getQualifiedName();
+            final QualifiedName newSupertype = dialog.getQualifiedName();
 
-            if (nodeTypeDefinition.addSuperType(newQName.get())) {
-                this.superTypesViewer.refresh();
+            // add and select new supertype
+            if (nodeTypeDefinition.addSuperType(newSupertype.get())) {
+                this.superTypesViewer.setSelection(new StructuredSelection(newSupertype.get()));
             } else {
                 MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
-                                            NLS.bind(CndMessages.errorAddingSupertype, newQName));
+                                            NLS.bind(CndMessages.errorAddingSupertype, newSupertype));
             }
         }
     }
@@ -1671,7 +1702,10 @@
         // show confirmation dialog
         if (MessageFormDialog.openQuestion(getShell(), CndMessages.deleteChildNodeDialogTitle, JcrUiUtils.getCndEditorImage(),
                                            NLS.bind(CndMessages.deleteChildNodeDialogMessage, name))) {
-            getSelectedNodeType().removeChildNodeDefinition(childNodeDefinition);
+            if (!getSelectedNodeType().removeChildNodeDefinition(childNodeDefinition)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorDeletingChildNode, name));
+            }
         }
     }
 
@@ -1688,7 +1722,10 @@
         // show confirmation dialog
         if (MessageFormDialog.openQuestion(getShell(), CndMessages.deleteNamespaceDialogTitle, JcrUiUtils.getCndEditorImage(),
                                            NLS.bind(CndMessages.deleteNamespaceDialogMessage, prefix))) {
-            getCnd().removeNamespaceMapping(namespaceMapping);
+            if (!getCnd().removeNamespaceMapping(namespaceMapping)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorDeletingNamespace, prefix));
+            }
         }
     }
 
@@ -1705,7 +1742,10 @@
         // show confirmation dialog
         if (MessageFormDialog.openQuestion(getShell(), CndMessages.deleteNodeTypeDialogTitle, JcrUiUtils.getCndEditorImage(),
                                            NLS.bind(CndMessages.deleteNodeTypeDialogMessage, name))) {
-            getCnd().removeNodeTypeDefinition(nodeTypeDefinition);
+            if (!getCnd().removeNodeTypeDefinition(nodeTypeDefinition)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorDeletingNodeType, name));
+            }
         }
     }
 
@@ -1723,7 +1763,10 @@
         // show confirmation dialog
         if (MessageFormDialog.openQuestion(getShell(), CndMessages.deletePropertyDialogTitle, JcrUiUtils.getCndEditorImage(),
                                            NLS.bind(CndMessages.deletePropertyDialogMessage, name))) {
-            getSelectedNodeType().removePropertyDefinition(propertyDefinition);
+            if (!getSelectedNodeType().removePropertyDefinition(propertyDefinition)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorDeletingProperty, name));
+            }
         }
     }
 
@@ -1741,7 +1784,10 @@
         // show confirmation dialog
         if (MessageFormDialog.openQuestion(getShell(), CndMessages.deleteSuperTypeDialogTitle, JcrUiUtils.getCndEditorImage(),
                                            NLS.bind(CndMessages.deleteSuperTypeDialogMessage, superTypeName))) {
-            getSelectedNodeType().removeSuperType(superTypeName);
+            if (!getSelectedNodeType().removeSuperType(superTypeName)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorDeletingSupertype, superTypeName));
+            }
         }
     }
 
@@ -1749,16 +1795,35 @@
         assert (getSelectedNodeType() != null) : "edit child node handler called but there is no selected node type"; //$NON-NLS-1$
         assert (getSelectedChildNode() != null) : "edit child node handler has been called when there is no child node selected"; //$NON-NLS-1$
 
-        ChildNodeDefinition childNodeBeingEdited = getSelectedChildNode();
-        ChildNodeDialog dialog = new ChildNodeDialog(getShell(), getChildNodeNames(), getNamespacePrefixes(), childNodeBeingEdited);
+        final ChildNodeDefinition childNodeBeingEdited = getSelectedChildNode();
+        final ChildNodeDialog dialog = new ChildNodeDialog(getShell(),
+                                                           getChildNodeNames(),
+                                                           getNamespacePrefixes(),
+                                                           childNodeBeingEdited);
         dialog.create();
         dialog.getShell().pack();
 
         if (dialog.open() == Window.OK) {
-            NodeTypeDefinition nodeTypeDefinition = getSelectedNodeType();
-            ChildNodeDefinition newChildNodeDefinition = dialog.getChildNodeDefinition();
-            nodeTypeDefinition.removeChildNodeDefinition(childNodeBeingEdited);
-            nodeTypeDefinition.addChildNodeDefinition(newChildNodeDefinition);
+            final NodeTypeDefinition nodeTypeDefinition = getSelectedNodeType();
+            final ChildNodeDefinition newChildNodeDefinition = dialog.getChildNodeDefinition();
+            boolean removed = false;
+            boolean added = false;
+
+            if (nodeTypeDefinition.removeChildNodeDefinition(childNodeBeingEdited)) {
+                removed = true;
+
+                if (nodeTypeDefinition.addChildNodeDefinition(newChildNodeDefinition)) {
+                    added = true;
+                }
+            }
+
+            if (!removed || !added) {
+                MessageFormDialog.openError(getShell(),
+                                            UiMessages.errorDialogTitle,
+                                            JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorEditingChildNode,
+                                                     new Object[] { childNodeBeingEdited.getName(), removed, added }));
+            }
         }
     }
 
@@ -1797,16 +1862,40 @@
         }
     }
 
-    void handleEditNodeType() {
-        assert (getSelectedNodeType() != null) : "Edit node type handler has been called when there is no node type selected"; //$NON-NLS-1$
-        // TODO handleEditNodeType
-        MessageFormDialog.openInfo(getShell(), "Not Implemented Yet", null, "method has not be implemented"); //$NON-NLS-1$ //$NON-NLS-2$
-    }
-
     void handleEditProperty() {
+        assert (getSelectedNodeType() != null) : "Edit property handler called but there is no selected node type"; //$NON-NLS-1$
         assert (getSelectedProperty() != null) : "Edit property handler has been called when there is no property selected"; //$NON-NLS-1$
-        // TODO handleEditProperty
-        MessageFormDialog.openInfo(getShell(), "Not Implemented Yet", null, "method has not be implemented"); //$NON-NLS-1$ //$NON-NLS-2$
+
+        final PropertyDefinition propertyBeingEdited = getSelectedProperty();
+        final PropertyDialog dialog = new PropertyDialog(getShell(),
+                                                         getPropertyNames(),
+                                                         getNamespacePrefixes(),
+                                                         propertyBeingEdited);
+        dialog.create();
+        dialog.getShell().pack();
+
+        if (dialog.open() == Window.OK) {
+            final NodeTypeDefinition nodeTypeDefinition = getSelectedNodeType();
+            final PropertyDefinition newPropertyDefinition = dialog.getPropertyDefinition();
+            boolean removed = false;
+            boolean added = false;
+
+            if (nodeTypeDefinition.removePropertyDefinition(propertyBeingEdited)) {
+                removed = true;
+
+                if (nodeTypeDefinition.addPropertyDefinition(newPropertyDefinition)) {
+                    added = true;
+                }
+            }
+
+            if (!removed || !added) {
+                MessageFormDialog.openError(getShell(),
+                                            UiMessages.errorDialogTitle,
+                                            JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorEditingProperty, new Object[] {
+                                                    propertyBeingEdited.getName(), removed, added }));
+            }
+        }
     }
 
     void handleEditSuperType() {
@@ -1851,23 +1940,6 @@
         getSelectedNodeType().setMixin(newValue);
     }
 
-    /**
-     * @param newQualifier the new node type definition qualifier/prefix (can be <code>null</code> or empty
-     */
-    protected void handleNameQualifierChanged( String newQualifier ) {
-        if (!Utils.isEmpty(newQualifier) && (getSelectedNodeType() != null)) {
-            final String name = this.txtName.getText();
-
-            // if prefix indicates no qualifier should be used just use the name otherwise use prefix and name
-            if (CndMessages.noNameQualifierChoice.equals(newQualifier)) {
-                newQualifier = Utils.EMPTY_STRING;
-            }
-
-            final String newName = new QualifiedName(newQualifier, name).get();
-            getSelectedNodeType().setName(newName);
-        }
-    }
-
     void handleNamespaceSelected() {
         // update button enablements
         final boolean enable = (getSelectedNamespace() != null);
@@ -1885,15 +1957,7 @@
 
     void handleNodeTypeNameChanged( final String newNodeTypeName ) {
         if (getSelectedNodeType() != null) {
-            String qualifier = this.cbxNamePrefix.getText();
-
-            // if prefix indicates no qualifier should be used just use the name otherwise use prefix and name
-            if (CndMessages.noNameQualifierChoice.equals(qualifier)) {
-                qualifier = Utils.EMPTY_STRING;
-            }
-
-            final String newName = new QualifiedName(qualifier, newNodeTypeName).get();
-            getSelectedNodeType().setName(newName);
+            getSelectedNodeType().setName(newNodeTypeName);
         }
     }
 
@@ -1917,24 +1981,12 @@
                 name = Messages.missingName;
             }
 
+            this.nameEditor.setNameBeingEdited(getSelectedNodeType().getQualifiedName());
             this.detailsSection.setDescription(NLS.bind(CndMessages.cndEditorChildNodeSectionDescriptionWithNodeTypeName, name));
             this.propertiesSection.setDescription(NLS.bind(CndMessages.cndEditorChildNodeSectionDescriptionWithNodeTypeName, name));
             this.childNodeSection.setDescription(NLS.bind(CndMessages.cndEditorPropertySectionDescriptionWithNodeTypeName, name));
         }
 
-        // update button enablements
-        final boolean enable = (getSelectedNodeType() != null);
-
-        // this.addNodeType always enabled
-
-        if (this.editNodeType.isEnabled() != enable) {
-            this.editNodeType.setEnabled(enable);
-        }
-
-        if (this.deleteNodeType.isEnabled() != enable) {
-            this.deleteNodeType.setEnabled(enable);
-        }
-
         // populate details section
         refreshNameControls();
         refreshAttributeControls();
@@ -1959,27 +2011,34 @@
             return;
         }
 
-        // TODO implement handlePropertyChanged
+        final Object source = e.getSource();
         final String propName = e.getPropertyName();
 
-        if (NodeTypeDefinition.PropertyName.ABSTRACT.toString().equals(propName)) {
-
-        } else if (NodeTypeDefinition.PropertyName.CHILD_NODES.toString().equals(propName)) {
-
-        } else if (NodeTypeDefinition.PropertyName.MIXIN.toString().equals(propName)) {
-
-        } else if (NodeTypeDefinition.PropertyName.NAME.toString().equals(propName)) {
-
-        } else if (NodeTypeDefinition.PropertyName.ORDERABLE.toString().equals(propName)) {
-
-        } else if (NodeTypeDefinition.PropertyName.PRIMARY_ITEM.toString().equals(propName)) {
-            // TODO primary item has not been code for in this class yet
-        } else if (NodeTypeDefinition.PropertyName.PROPERTY_DEFINITIONS.toString().equals(propName)) {
-
-        } else if (NodeTypeDefinition.PropertyName.QUERYABLE.toString().equals(propName)) {
-
-        } else if (NodeTypeDefinition.PropertyName.SUPERTYPES.toString().equals(propName)) {
-
+        if (source instanceof NodeTypeDefinition) {
+            if (NodeTypeDefinition.PropertyName.ABSTRACT.toString().equals(propName)
+                    || NodeTypeDefinition.PropertyName.MIXIN.toString().equals(propName)
+                    || NodeTypeDefinition.PropertyName.ORDERABLE.toString().equals(propName)
+                    || NodeTypeDefinition.PropertyName.QUERYABLE.toString().equals(propName)
+                    || NodeTypeDefinition.PropertyName.PRIMARY_ITEM.toString().equals(propName)) {
+                validateAttributes();
+            } else if (NodeTypeDefinition.PropertyName.CHILD_NODES.toString().equals(propName)) {
+                validateChildNodes();
+                this.childNodeViewer.refresh();
+            } else if (NodeTypeDefinition.PropertyName.NAME.toString().equals(propName)) {
+                validateName();
+            } else if (NodeTypeDefinition.PropertyName.PROPERTY_DEFINITIONS.toString().equals(propName)) {
+                validateProperties();
+                this.propertyViewer.refresh();
+            } else if (NodeTypeDefinition.PropertyName.SUPERTYPES.toString().equals(propName)) {
+                validateSuperTypes();
+                this.superTypesViewer.refresh();
+            }
+        } else if (source instanceof NamespaceMapping) {
+            this.namespaceViewer.refresh(source);
+        } else if (source instanceof PropertyDefinition) {
+            this.propertyViewer.refresh(source);
+        } else if (source instanceof ChildNodeDefinition) {
+            this.childNodeViewer.refresh(source);
         }
     }
 
@@ -2078,60 +2137,20 @@
         if (this.childNodeViewer != null) {
             this.childNodeViewer.setInput(this);
             UiUtils.pack(this.childNodeViewer);
-            validateChildNodeDefinitions();
+            validateChildNodes();
         }
     }
 
     private void refreshNameControls() {
         final NodeTypeDefinition nodeTypeDefinition = getSelectedNodeType();
 
-        if ((nodeTypeDefinition == null) || Utils.isEmpty(nodeTypeDefinition.getName())) {
-            this.cbxNamePrefix.removeAll();
-            this.txtName.setText(Utils.EMPTY_STRING);
+        if (nodeTypeDefinition == null) {
+            this.nameEditor.setNameBeingEdited(null);
         } else {
-            // load qualifiers with namespace prefixes
-            final List<NamespaceMapping> namespaceMappings = getCnd().getNamespaceMappings();
-            final List<String> prefixes = new ArrayList<String>(namespaceMappings.size() + 1); // add one for empty qualifier
-            prefixes.add(CndMessages.noNameQualifierChoice);
-
-            for (final NamespaceMapping namespaceMapping : namespaceMappings) {
-                prefixes.add(namespaceMapping.getPrefix());
-            }
-
-            // set qualifier choices if they have changed
-            final String[] currentItems = this.cbxNamePrefix.getItems();
-
-            // only reload qualifiers if different
-            if ((prefixes.size() != currentItems.length) || !prefixes.containsAll(Arrays.asList(currentItems))) {
-                this.cbxNamePrefix.setItems(prefixes.toArray(new String[prefixes.size()]));
-            }
-
-            // load name
-            final String name = nodeTypeDefinition.getName();
-            final QualifiedName qname = QualifiedName.parse(name);
-
-            // set qualifier
-            final String qualifier = ((qname.getQualifier() == null) ? Utils.EMPTY_STRING : qname.getQualifier());
-
-            if (!Utils.isEmpty(qualifier)) {
-                int index = this.cbxNamePrefix.indexOf(qualifier);
-
-                if (index == -1) {
-                    index = this.cbxNamePrefix.getItemCount();
-                    this.cbxNamePrefix.add(qualifier);
-                    this.cbxNamePrefix.select(index);
-                } else if (this.cbxNamePrefix.getSelectionIndex() != index) { // only select if currently not selected
-                    this.cbxNamePrefix.select(index);
-                }
-            }
-
-            // set unqualified name
-            final String unqualifiedName = ((qname.getUnqualifiedName() == null) ? Utils.EMPTY_STRING : qname.getUnqualifiedName());
-
-            // only set text field if different
-            if (!this.txtName.getText().equals(unqualifiedName)) {
-                this.txtName.setText(unqualifiedName);
-            }
+            // load name editor with current namespace prefixes, current node type names, and selected node type name
+            this.nameEditor.setNameBeingEdited(nodeTypeDefinition.getQualifiedName());
+            this.nameEditor.setValidQualifiers(getNamespacePrefixes());
+            this.nameEditor.setExistingQNames(getNodeTypeNames());
         }
     }
 
@@ -2168,7 +2187,7 @@
      */
     @Override
     protected void updateAllMessages() {
-        validateChildNodeDefinitions();
+        validateChildNodes();
         validateNamespaces();
         validateNodeTypes();
         validateProperties();
@@ -2212,24 +2231,16 @@
                 this.nodeTypeViewer.getTable().setEnabled(cndWritable);
             }
 
-            if (this.editNodeType.isEnabled() != enableWithNodeTypeSelected) {
-                this.editNodeType.setEnabled(enableWithNodeTypeSelected);
-            }
-
             if (this.deleteNodeType.isEnabled() != enableWithNodeTypeSelected) {
                 this.deleteNodeType.setEnabled(enableWithNodeTypeSelected);
             }
         }
 
         { // details section
-            if (this.cbxNamePrefix.isEnabled() != enableWithNodeTypeSelected) {
-                this.cbxNamePrefix.setEnabled(enableWithNodeTypeSelected);
+            if (this.nameEditor.isEnabled() != enableWithNodeTypeSelected) {
+                this.nameEditor.setEnabled(enableWithNodeTypeSelected);
             }
 
-            if (this.txtName.isEnabled() != enableWithNodeTypeSelected) {
-                this.txtName.setEnabled(enableWithNodeTypeSelected);
-            }
-
             if (this.btnAbstract.isEnabled() != enableWithNodeTypeSelected) {
                 this.btnAbstract.setEnabled(enableWithNodeTypeSelected);
             }
@@ -2306,24 +2317,56 @@
         }
     }
 
-    private void validateChildNodeDefinitions() {
+    private void updateMessage( final ValidationStatus status,
+                                final ErrorMessage errorMessage ) {
+        final IMessageManager msgMgr = getCndEditor().getMessageManager();
+        JcrUiUtils.setMessage(status, errorMessage);
+
+        if (errorMessage.isOk()) {
+            if (errorMessage.getControl() == null) {
+                msgMgr.removeMessage(errorMessage.getKey());
+            } else {
+                msgMgr.removeMessage(errorMessage.getKey(), errorMessage.getControl());
+            }
+        } else {
+            if (errorMessage.getControl() == null) {
+                msgMgr.addMessage(errorMessage.getKey(), errorMessage.getMessage(), errorMessage.getData(),
+                                  errorMessage.getMessageType());
+            } else {
+                msgMgr.addMessage(errorMessage.getKey(), errorMessage.getMessage(), errorMessage.getData(),
+                                  errorMessage.getMessageType(), errorMessage.getControl());
+            }
+        }
+    }
+
+    private void validateAttributes() {
+        // TODO primary item
+    }
+
+    private void validateChildNodes() {
         final NodeTypeDefinition nodeTypeDefinition = getSelectedNodeType();
 
         if (nodeTypeDefinition == null) {
             this.nodeTypesError.setOkMessage(null);
         } else {
-            // CndValidator.validateChildNodeDefinitions(nodeTypeDefinition.getChildNodeDefinitions());
+            final MultiValidationStatus status = CndValidator.validateChildNodeDefinitions(nodeTypeDefinition.getName(),
+                                                                                           nodeTypeDefinition.getChildNodeDefinitions());
+            updateMessage(status, this.nodeTypesError);
         }
     }
 
+    private void validateName() {
+        updateMessage(this.nameEditor.getStatus(), this.nodeTypeNameError);
+    }
+
     private void validateNamespaces() {
         final MultiValidationStatus status = CndValidator.validateNamespaceMappings(getCnd().getNamespaceMappings());
-        JcrUiUtils.setMessage(status, this.namespacesError);
+        updateMessage(status, this.namespacesError);
     }
 
     private void validateNodeTypes() {
         final MultiValidationStatus status = CndValidator.validateNodeTypeDefinitions(getCnd().getNodeTypeDefinitions());
-        JcrUiUtils.setMessage(status, this.nodeTypesError);
+        updateMessage(status, this.nodeTypesError);
     }
 
     private void validateProperties() {
@@ -2334,7 +2377,7 @@
         } else {
             final MultiValidationStatus status = CndValidator.validatePropertyDefinitions(nodeTypeDefinition.getName(),
                                                                                           nodeTypeDefinition.getPropertyDefinitions());
-            JcrUiUtils.setMessage(status, this.propertiesError);
+            updateMessage(status, this.propertiesError);
         }
     }
 
@@ -2353,7 +2396,7 @@
             final MultiValidationStatus status = CndValidator.validateSuperTypes(nodeTypeName,
                                                                                  nodeTypeDefinition.getState(PropertyName.SUPERTYPES),
                                                                                  nodeTypeDefinition.getDeclaredSupertypeNames());
-            JcrUiUtils.setMessage(status, this.superTypesError);
+            updateMessage(status, this.superTypesError);
         }
     }
 

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndMessages.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndMessages.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/CndMessages.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -26,6 +26,12 @@
     public static String abstractAttributeToolTip;
 
     /**
+     * A dialog message indicating the default value has been changed and asks the user to OK the dialog. One parameter, the default
+     * value, is required.
+     */
+    public static String acceptDefaultValueDialogMsg;
+
+    /**
      * A dialog message indicating the namespace mapping has been changed and asks the user to OK the dialog.
      */
     public static String acceptNamespaceDialogMsg;
@@ -37,6 +43,12 @@
     public static String acceptQualifiedNameDialogMsg;
 
     /**
+     * A dialog message indicating the value constraint has been changed and asks the user to OK the dialog. One parameter, the
+     * value constraint, is required.
+     */
+    public static String acceptValueConstraintDialogMsg;
+
+    /**
      * The context menu item text for the add child node definition action.
      */
     public static String addChildNodeMenuText;
@@ -47,6 +59,16 @@
     public static String addChildNodeToolTip;
 
     /**
+     * The context menu item text for the add default value action.
+     */
+    public static String addDefaultValueMenuText;
+
+    /**
+     * The tool tip message of the add default value action.
+     */
+    public static String addDefaultValueToolTip;
+
+    /**
      * The context menu item text for the add namespace mapping action.
      */
     public static String addNamespaceMenuText;
@@ -97,6 +119,16 @@
     public static String addSuperTypeToolTip;
 
     /**
+     * The context menu item text for the add value constraint action.
+     */
+    public static String addValueConstraintMenuText;
+
+    /**
+     * The tool tip message of the add value constraint action.
+     */
+    public static String addValueConstraintToolTip;
+
+    /**
      * The column header text for attributes.
      */
     public static String attributesHeaderText;
@@ -277,11 +309,46 @@
     public static String defaultTypeHeaderText;
 
     /**
+     * The message area title of the default value dialog when creating a new default value.
+     */
+    public static String defaultValueDialogCreateMsg;
+
+    /**
+     * The message area title of the default value dialog when an existing default value is being edited.
+     */
+    public static String defaultValueDialogEditMsg;
+
+    /**
+     * The message displayed in the default value dialog when first displayed.
+     */
+    public static String defaultValueDialogMsg;
+
+    /**
+     * A label for a default value control.
+     */
+    public static String defaultValueLabel;
+
+    /**
      * The column header text of the default values of a property definition.
      */
     public static String defaultValuesHeaderText;
 
     /**
+     * A label for a default values control.
+     */
+    public static String defaultValuesLabel;
+
+    /**
+     * A tool tip message of a property definition's default value.
+     */
+    public static String defaultValuesToolTip;
+
+    /**
+     * A tool tip message for one default value of a property definition.
+     */
+    public static String defaultValueToolTip;
+
+    /**
      * The question message of the dialog for deleting a child node definition. One parameter, the child node definition name, is
      * required.
      */
@@ -303,6 +370,26 @@
     public static String deleteChildNodeToolTip;
 
     /**
+     * The question message of the dialog for deleting a default value. One parameter, the default value, is required.
+     */
+    public static String deleteDefaultValueDialogMessage;
+
+    /**
+     * The title of the dialog for deleting a default value.
+     */
+    public static String deleteDefaultValueDialogTitle;
+
+    /**
+     * The context menu item text for the delete default value action.
+     */
+    public static String deleteDefaultValueMenuText;
+
+    /**
+     * The tool tip message of the delete default value action.
+     */
+    public static String deleteDefaultValueToolTip;
+
+    /**
      * The question message of the dialog for deleting a namespace mapping. One parameter, the namespace prefix, is required.
      */
     public static String deleteNamespaceDialogMessage;
@@ -405,6 +492,26 @@
     public static String deleteSuperTypeToolTip;
 
     /**
+     * The question message of the dialog for deleting a value constraint. One parameter, the value constraint, is required.
+     */
+    public static String deleteValueConstraintDialogMessage;
+
+    /**
+     * The title of the dialog for deleting a value constraint.
+     */
+    public static String deleteValueConstraintDialogTitle;
+
+    /**
+     * The context menu item text for the delete value constraint action.
+     */
+    public static String deleteValueConstraintMenuText;
+
+    /**
+     * The tool tip message of the delete value constraint action.
+     */
+    public static String deleteValueConstraintToolTip;
+
+    /**
      * The context menu item text for the edit child node definition action.
      */
     public static String editChildNodeMenuText;
@@ -415,6 +522,16 @@
     public static String editChildNodeToolTip;
 
     /**
+     * The context menu item text for the edit default value action.
+     */
+    public static String editDefaultValueMenuText;
+
+    /**
+     * The tool tip message of the edit default value action.
+     */
+    public static String editDefaultValueToolTip;
+
+    /**
      * The namespace editor dialog message area title when editing an existing namespace mapping.
      */
     public static String editNamespaceDialogTitle;
@@ -480,12 +597,46 @@
     public static String editSuperTypeToolTip;
 
     /**
+     * The context menu item text for the edit value constraint action.
+     */
+    public static String editValueConstraintMenuText;
+
+    /**
+     * The tool tip message of the edit value constraint action.
+     */
+    public static String editValueConstraintToolTip;
+
+    /**
+     * An error message indicating the new child node definition was not added to the node type definition. One parameter, the child
+     * definition name, is required.
+     */
+    public static String errorAddingChildNode;
+
+    /**
+     * An error message indicating the new default value was not added to the property definition. One parameter, the default value,
+     * is required.
+     */
+    public static String errorAddingDefaultValue;
+
+    /**
      * An error message indicating the new namespace mapping was not added to the CND. One parameter, the namespace mapping, is
      * required.
      */
     public static String errorAddingNamespaceMapping;
 
     /**
+     * An error message indicating the new node type definition was not added to the CND. One parameter, the node type definition
+     * name, is required.
+     */
+    public static String errorAddingNodeType;
+
+    /**
+     * An error message indicating the new property definition was not added to the node type definition. One parameter, the
+     * property name, is required.
+     */
+    public static String errorAddingProperty;
+
+    /**
      * An error message indicating the new required type was not added to the child node definition. One parameter, the required
      * type, is required.
      */
@@ -498,12 +649,78 @@
     public static String errorAddingSupertype;
 
     /**
+     * An error message indicating the new value constraint was not added to the property definition. One parameter, the value
+     * constraint, is required.
+     */
+    public static String errorAddingValueConstraint;
+
+    /**
+     * An error message indicating deleting the child node definition did not get saved. One parameter, the child node definition
+     * name, is required.
+     */
+    public static String errorDeletingChildNode;
+
+    /**
+     * An error message indicating deleting the default value did not get saved. One parameter, the default value, is required.
+     */
+    public static String errorDeletingDefaultValue;
+
+    /**
+     * An error message indicating deleting the namespace mapping did not get saved. One parameter, the namespace prefix, is
+     * required.
+     */
+    public static String errorDeletingNamespace;
+
+    /**
+     * An error message indicating deleting the node type definition did not get saved. One parameter, the node type definition
+     * name, is required.
+     */
+    public static String errorDeletingNodeType;
+
+    /**
+     * An error message indicating deleting the property definition did not get saved. One parameter, the property definition name,
+     * is required.
+     */
+    public static String errorDeletingProperty;
+
+    /**
+     * An error message indicating deleting the supertype did not get saved. One parameter, the supertype name, is required.
+     */
+    public static String errorDeletingSupertype;
+
+    /**
+     * An error message indicating deleting the value constraint did not get saved. One parameter, the value constraint, is
+     * required.
+     */
+    public static String errorDeletingValueConstraint;
+
+    /**
+     * An error message indicating the updated child node definition did not get saved to the node type definition. Three
+     * parameters, the child node definition name, a flag indicating if the remove succeeded, and a flag indicating if the add
+     * succeeded, are required.
+     */
+    public static String errorEditingChildNode;
+
+    /**
+     * An error message indicating the updated default value did not get saved to the CND. Three parameters, the default value, a
+     * flag indicating if the remove succeeded, and a flag indicating if the add succeeded, are required.
+     */
+    public static String errorEditingDefaultValue;
+
+    /**
      * An error message indicating the updated namespace mapping did not get saved to the CND. Three parameters, the namespace
      * mapping, a flag indicating if the remove succeeded, and a flag indicating if the add succeeded, are required.
      */
     public static String errorEditingNamespaceMapping;
 
     /**
+     * An error message indicating the updated property definition did not get saved to the node type definition. Three parameters,
+     * the property definition name, a flag indicating if the remove succeeded, and a flag indicating if the add succeeded, are
+     * required.
+     */
+    public static String errorEditingProperty;
+
+    /**
      * An error message indicating the updated required type did not get saved to the CND. Three parameters, the required type, a
      * flag indicating if the remove succeeded, and a flag indicating if the add succeeded, are required.
      */
@@ -516,6 +733,12 @@
     public static String errorEditingSupertype;
 
     /**
+     * An error message indicating the updated value constraint did not get saved to the CND. Three parameters, the value
+     * constraint, a flag indicating if the remove succeeded, and a flag indicating if the add succeeded, are required.
+     */
+    public static String errorEditingValueConstraint;
+
+    /**
      * The error message when the CND editor could not be opened.
      */
     public static String errorOpeningCndEditor;
@@ -546,6 +769,16 @@
     public static String mixinAttributeToolTip;
 
     /**
+     * A name for the multiple attribute suitable for a radio or check button.
+     */
+    public static String multipleAttribute;
+
+    /**
+     * A tool tip message of the property definition's multiple attribute.
+     */
+    public static String multipleAttributeToolTip;
+
+    /**
      * The column header text for a generic name property or attribute.
      */
     public static String nameHeaderText;
@@ -601,6 +834,11 @@
     public static String newNamespaceDialogTitle;
 
     /**
+     * The qualified name editor dialog message area title when creating a new node type definition.
+     */
+    public static String newNodeTypeDialogTitle;
+
+    /**
      * The qualified name editor dialog message area title when creating a new required type.
      */
     public static String newRequiredTypeDialogTitle;
@@ -626,11 +864,31 @@
     public static String nodeTypeNameToolTip;
 
     /**
+     * A name for the noFullText attribute suitable for a radio or check button.
+     */
+    public static String noFullTextAttribute;
+
+    /**
+     * A tool tip message of the property definition's noFullText attribute.
+     */
+    public static String noFullTextAttributeToolTip;
+
+    /**
      * The text indicating the qualified name does not have a qualifier.
      */
     public static String noNameQualifierChoice;
 
     /**
+     * A name for the noQueryOrder attribute suitable for a radio or check button.
+     */
+    public static String noQueryOrderAttribute;
+
+    /**
+     * A tool tip message of the property definition's noQueryOrder attribute.
+     */
+    public static String noQueryOrderAttributeToolTip;
+
+    /**
      * A label for an on parent version attribute control.
      */
     public static String onParentVersionLabel;
@@ -661,6 +919,26 @@
     public static String propertyDefaultValuesToolTip;
 
     /**
+     * The message area title of the property definition dialog when creating a new property.
+     */
+    public static String propertyDialogCreateTitle;
+
+    /**
+     * The message area title of the property definition dialog when an existing property is being edited.
+     */
+    public static String propertyDialogEditTitle;
+
+    /**
+     * The message displayed in the property dialog when first displayed.
+     */
+    public static String propertyDialogMsg;
+
+    /**
+     * The title of the property definition dialog.
+     */
+    public static String propertyDialogTitle;
+
+    /**
      * The tool tip for a property definition name.
      */
     public static String propertyNameToolTip;
@@ -737,11 +1015,21 @@
     public static String supertypesLabel;
 
     /**
+     * A tool tip message of a node type definition's supertypes property.
+     */
+    public static String supertypesToolTip;
+
+    /**
      * The column header text for a type.
      */
     public static String typeHeaderText;
 
     /**
+     * A label for a type control.
+     */
+    public static String typeLabel;
+
+    /**
      * A tooltip message for the control where the name of the qualified name is being edited.
      */
     public static String unqualifiedNameToolTip;
@@ -752,10 +1040,50 @@
     public static String validQualifiersToolTip;
 
     /**
+     * The message area title of the value constraint dialog when creating a new value constraint.
+     */
+    public static String valueConstraintDialogCreateMsg;
+
+    /**
+     * The message area title of the value constraint dialog when an existing value constraint is being edited.
+     */
+    public static String valueConstraintDialogEditMsg;
+
+    /**
+     * The message displayed in the value constraint dialog when first displayed.
+     */
+    public static String valueConstraintDialogMsg;
+
+    /**
+     * A label for a value constraint control.
+     */
+    public static String valueConstraintLabel;
+
+    /**
      * The column header text for the value constraints of a property definition.
      */
     public static String valueConstraintsHeaderText;
 
+    /**
+     * A label for a value constraints control.
+     */
+    public static String valueConstraintsLabel;
+
+    /**
+     * A tool tip message of a property definition's value constraints.
+     */
+    public static String valueConstraintsToolTip;
+
+    /**
+     * A tool tip message for one value constraint of a property definition.
+     */
+    public static String valueConstraintToolTip;
+
+    /**
+     * The title of the string value editor dialog.
+     */
+    public static String valueEditorDialogTitle;
+
     static {
         NLS.initializeMessages("org.jboss.tools.modeshape.jcr.ui.cnd.cndMessages", CndMessages.class); //$NON-NLS-1$
     }

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/NamespaceMappingDialog.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/NamespaceMappingDialog.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/NamespaceMappingDialog.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -38,7 +38,7 @@
 /**
  * The <code>NamespaceMappingDialog</code> is used to create or edit a namespace mapping.
  */
-class NamespaceMappingDialog extends FormDialog {
+final class NamespaceMappingDialog extends FormDialog {
 
     private Button btnOk;
 

Added: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/PropertyDialog.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/PropertyDialog.java	                        (rev 0)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/PropertyDialog.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -0,0 +1,1315 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ *
+ * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
+ *
+ * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
+ */
+package org.jboss.tools.modeshape.jcr.ui.cnd;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.forms.FormDialog;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.jboss.tools.modeshape.jcr.Messages;
+import org.jboss.tools.modeshape.jcr.Utils;
+import org.jboss.tools.modeshape.jcr.ValidationStatus;
+import org.jboss.tools.modeshape.jcr.cnd.CndValidator;
+import org.jboss.tools.modeshape.jcr.cnd.PropertyDefinition;
+import org.jboss.tools.modeshape.jcr.cnd.PropertyDefinition.PropertyName;
+import org.jboss.tools.modeshape.jcr.cnd.QualifiedName;
+import org.jboss.tools.modeshape.jcr.cnd.attributes.OnParentVersion;
+import org.jboss.tools.modeshape.jcr.cnd.attributes.PropertyType;
+import org.jboss.tools.modeshape.jcr.ui.Activator;
+import org.jboss.tools.modeshape.jcr.ui.JcrUiConstants;
+import org.jboss.tools.modeshape.jcr.ui.JcrUiUtils;
+import org.jboss.tools.modeshape.ui.UiMessages;
+import org.jboss.tools.modeshape.ui.actions.DelegateAction;
+import org.jboss.tools.modeshape.ui.forms.ErrorMessage;
+import org.jboss.tools.modeshape.ui.forms.FormUtils;
+import org.jboss.tools.modeshape.ui.forms.FormUtils.Styles;
+import org.jboss.tools.modeshape.ui.forms.MessageFormDialog;
+
+/**
+ * A dialog used to create and edit {@link PropertyDefinition}s.
+ */
+final class PropertyDialog extends FormDialog {
+
+    private IAction addDefaultValue;
+    private IAction addValueConstraint;
+    private Button btnOk;
+    private final ErrorMessage defaultValuesError;
+    private TableViewer defaultValuesViewer;
+    private IAction deleteDefaultValue;
+    private IAction deleteValueConstraint;
+    private IAction editDefaultValue;
+    private IAction editValueConstraint;
+    /**
+     * The existing namespace prefixes contained in the CND (never <code>null</code> but can be empty).
+     */
+    private final Collection<String> existingNamespacePrefixes;
+    /**
+     * The existing child node definition names contained in the CND (never <code>null</code> but can be empty).
+     */
+    private final Collection<QualifiedName> existingPropertyNames;
+    private QualifiedNameEditor nameEditor;
+    private final ErrorMessage nameError;
+    private PropertyDefinition originalProperty;
+    private PropertyDefinition propertyBeingEdited;
+    private ScrolledForm scrolledForm;
+    private final ErrorMessage valueConstraintsError;
+    private TableViewer valueConstraintsViewer;
+
+    /**
+     * Used to create a new property definition.
+     * 
+     * @param parentShell the parent shell (can be <code>null</code>)
+     * @param existingPropertyNames the existing property names (can be <code>null</code> or empty)
+     * @param existingNamespacePrefixes the existing CND namespace prefixes (can be <code>null</code> or empty)
+     */
+    public PropertyDialog( final Shell parentShell,
+                           final Collection<QualifiedName> existingPropertyNames,
+                           final Collection<String> existingNamespacePrefixes ) {
+        super(parentShell);
+        this.existingPropertyNames = ((existingPropertyNames == null) ? Collections.<QualifiedName> emptyList()
+                                                                     : new ArrayList<QualifiedName>(existingPropertyNames));
+        this.existingNamespacePrefixes = ((existingNamespacePrefixes == null) ? Collections.<String> emptyList()
+                                                                             : new ArrayList<String>(existingNamespacePrefixes));
+        this.defaultValuesError = new ErrorMessage();
+        this.nameError = new ErrorMessage();
+        this.valueConstraintsError = new ErrorMessage();
+        this.propertyBeingEdited = new PropertyDefinition();
+    }
+
+    /**
+     * Used to edit a property definition.
+     * 
+     * @param parentShell the parent shell (can be <code>null</code>)
+     * @param existingPropertyNames the existing property names (can be <code>null</code> or empty)
+     * @param existingNamespacePrefixes the existing CND namespace prefixes (can be <code>null</code> or empty)
+     * @param propertyDefinitionBeingEdited the proeprty definition being edited (cannot be <code>null</code>)
+     */
+    public PropertyDialog( final Shell parentShell,
+                           final Collection<QualifiedName> existingPropertyNames,
+                           final Collection<String> existingNamespacePrefixes,
+                           final PropertyDefinition propertyDefinitionBeingEdited ) {
+        this(parentShell, existingPropertyNames, existingNamespacePrefixes);
+
+        Utils.verifyIsNotNull(propertyDefinitionBeingEdited, "propertyDefinitionBeingEdited"); //$NON-NLS-1$
+        this.originalProperty = propertyDefinitionBeingEdited;
+
+        // create copy of property being edited
+        this.propertyBeingEdited = PropertyDefinition.copy(this.originalProperty);
+
+        // remove name from existing names so that validation won't show it as a duplicate
+        if (!Utils.isEmpty(this.propertyBeingEdited.getName())) {
+            this.existingPropertyNames.remove(this.propertyBeingEdited.getQualifiedName());
+        }
+    }
+
+    PropertyDefinition accessModel() {
+        return this.propertyBeingEdited;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
+     */
+    @Override
+    protected void configureShell( final Shell newShell ) {
+        super.configureShell(newShell);
+        newShell.setText(CndMessages.propertyDialogTitle);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.eclipse.jface.dialogs.Dialog#createButton(org.eclipse.swt.widgets.Composite, int, java.lang.String, boolean)
+     */
+    @Override
+    protected Button createButton( final Composite parent,
+                                   final int id,
+                                   final String label,
+                                   final boolean defaultButton ) {
+        final Button btn = super.createButton(parent, id, label, defaultButton);
+
+        if (id == IDialogConstants.OK_ID) {
+            // disable OK button initially
+            this.btnOk = btn;
+            btn.setEnabled(false);
+        }
+
+        return btn;
+    }
+
+    void createDefaultValuesActions() {
+        this.addDefaultValue = new Action(Utils.EMPTY_STRING) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.action.Action#run()
+             */
+            @Override
+            public void run() {
+                handleAddDefaultValue();
+            }
+        };
+        this.addDefaultValue.setToolTipText(CndMessages.addDefaultValueToolTip);
+        this.addDefaultValue.setImageDescriptor(JcrUiUtils.getNewImageDescriptor());
+
+        this.deleteDefaultValue = new Action(Utils.EMPTY_STRING) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.action.Action#run()
+             */
+            @Override
+            public void run() {
+                handleDeleteDefaultValue();
+            }
+        };
+        this.deleteDefaultValue.setEnabled(false);
+        this.deleteDefaultValue.setToolTipText(CndMessages.deleteDefaultValueToolTip);
+        this.deleteDefaultValue.setImageDescriptor(JcrUiUtils.getDeleteImageDescriptor());
+
+        this.editDefaultValue = new Action(Utils.EMPTY_STRING) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.action.Action#run()
+             */
+            @Override
+            public void run() {
+                handleEditDefaultValue();
+            }
+        };
+        this.editDefaultValue.setEnabled(false);
+        this.editDefaultValue.setToolTipText(CndMessages.editDefaultValueToolTip);
+        this.editDefaultValue.setImageDescriptor(JcrUiUtils.getEditImageDescriptor());
+    }
+
+    private void createDefaultValuesViewer( final Table defaultValuesTable ) {
+        this.defaultValuesViewer = new TableViewer(defaultValuesTable);
+        this.defaultValuesViewer.setLabelProvider(new LabelProvider());
+        this.defaultValuesViewer.setContentProvider(new IStructuredContentProvider() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+             */
+            @Override
+            public void dispose() {
+                // nothing to do
+            }
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+             */
+            @Override
+            public Object[] getElements( final Object inputElement ) {
+                final PropertyDefinition propDefn = accessModel();
+                return propDefn.getDefaultValuesAsStrings().toArray();
+            }
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object,
+             *      java.lang.Object)
+             */
+            @Override
+            public void inputChanged( final Viewer viewer,
+                                      final Object oldInput,
+                                      final Object newInput ) {
+                // nothing to do
+            }
+        });
+
+        this.defaultValuesViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
+             */
+            @Override
+            public void doubleClick( final DoubleClickEvent event ) {
+                handleEditDefaultValue();
+            }
+        });
+
+        this.defaultValuesViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
+             */
+            @Override
+            public void selectionChanged( final SelectionChangedEvent event ) {
+                handleDefaultValueSelected();
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.eclipse.ui.forms.FormDialog#createFormContent(org.eclipse.ui.forms.IManagedForm)
+     */
+    @Override
+    protected void createFormContent( final IManagedForm managedForm ) {
+        this.scrolledForm = managedForm.getForm();
+        this.scrolledForm.setText(isEditMode() ? CndMessages.propertyDialogEditTitle : CndMessages.propertyDialogCreateTitle);
+        this.scrolledForm.setImage(Activator.getSharedInstance().getImage(JcrUiConstants.Images.CND_EDITOR));
+        this.scrolledForm.setMessage(CndMessages.propertyDialogMsg, IMessageProvider.NONE);
+
+        final FormToolkit toolkit = managedForm.getToolkit();
+        toolkit.decorateFormHeading(this.scrolledForm.getForm());
+
+        final Composite body = this.scrolledForm.getBody();
+        body.setLayout(new GridLayout(2, false));
+
+        { // top (name editor)
+            final Composite topContainer = toolkit.createComposite(body);
+            topContainer.setLayout(new GridLayout(2, false));
+            topContainer.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+            ((GridData)topContainer.getLayoutData()).horizontalSpan = 2;
+            toolkit.paintBordersFor(topContainer);
+
+            { // name
+                this.nameEditor = new QualifiedNameEditor(topContainer,
+                                                          SWT.NONE,
+                                                          toolkit,
+                                                          Messages.propertyDefinitionName,
+                                                          this.existingNamespacePrefixes,
+                                                          this.propertyBeingEdited.getQualifiedName());
+                ((GridData)this.nameEditor.getLayoutData()).horizontalSpan = 2;
+                this.nameEditor.addListener(SWT.Modify, new Listener() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
+                     */
+                    @Override
+                    public void handleEvent( final Event e ) {
+                        handleNameChanged(e.text);
+                    }
+                });
+
+                this.nameError.setControl(this.nameEditor);
+            }
+
+            { // type
+                final Label lblType = toolkit.createLabel(topContainer, CndMessages.typeLabel, SWT.NONE);
+                lblType.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+                final CCombo cbxType = new CCombo(topContainer, Styles.COMBO_STYLE);
+                toolkit.adapt(cbxType, true, false);
+                cbxType.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+                ((GridData)cbxType.getLayoutData()).heightHint = cbxType.getItemHeight() + 4;
+                cbxType.setToolTipText(CndMessages.propertyTypeToolTip);
+
+                // populate property type values
+                for (final PropertyType type : PropertyType.values()) {
+                    if (type != PropertyType.VARIANT) {
+                        cbxType.add(type.toString());
+                    }
+                }
+
+                // select the current type
+                if (isEditMode()) {
+                    final String currentType = OnParentVersion.findUsingJcrValue(this.propertyBeingEdited.getOnParentVersion())
+                                                              .toString();
+                    final int index = cbxType.indexOf(currentType);
+
+                    if (index == -1) {
+                        // select default type
+                        cbxType.setText(PropertyType.DEFAULT_VALUE.toString());
+                    } else {
+                        cbxType.select(index);
+                    }
+                } else {
+                    // select default type
+                    cbxType.setText(PropertyType.DEFAULT_VALUE.toString());
+                }
+
+                cbxType.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        final String newOpv = ((CCombo)e.widget).getText();
+                        handleTypeChanged(newOpv);
+                    }
+                });
+            }
+        }
+
+        { // middle (attributes)
+            final Group attributesContainer = new Group(body, SWT.SHADOW_NONE);
+            attributesContainer.setText(CndMessages.attributesHeaderText);
+            attributesContainer.setLayout(new GridLayout(2, true));
+            final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
+            gd.horizontalSpan = 2;
+            attributesContainer.setLayoutData(gd);
+            toolkit.adapt(attributesContainer);
+            toolkit.paintBordersFor(attributesContainer);
+
+            { // autocreated
+                final Button btnAutocreated = toolkit.createButton(attributesContainer, CndMessages.autocreatedAttribute, SWT.CHECK);
+                btnAutocreated.setBackground(attributesContainer.getBackground());
+
+                if (isEditMode() && this.propertyBeingEdited.isAutoCreated()) {
+                    btnAutocreated.setSelection(true);
+                }
+
+                btnAutocreated.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        handleAutocreatedChanged(((Button)e.widget).getSelection());
+                    }
+                });
+                btnAutocreated.setToolTipText(CndMessages.autocreatedAttributeToolTip);
+            }
+
+            { // mandatory
+                final Button btnMandatory = toolkit.createButton(attributesContainer, CndMessages.mandatoryAttribute, SWT.CHECK);
+                btnMandatory.setBackground(attributesContainer.getBackground());
+
+                if (isEditMode() && this.propertyBeingEdited.isMandatory()) {
+                    btnMandatory.setSelection(true);
+                }
+
+                btnMandatory.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        handleMandatoryChanged(((Button)e.widget).getSelection());
+                    }
+                });
+                btnMandatory.setToolTipText(CndMessages.mandatoryAttributeToolTip);
+            }
+
+            { // protected
+                final Button btnProtected = toolkit.createButton(attributesContainer, CndMessages.protectedAttribute, SWT.CHECK);
+                btnProtected.setBackground(attributesContainer.getBackground());
+
+                if (isEditMode() && this.propertyBeingEdited.isProtected()) {
+                    btnProtected.setSelection(true);
+                }
+
+                btnProtected.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        handleProtectedChanged(((Button)e.widget).getSelection());
+                    }
+                });
+                btnProtected.setToolTipText(CndMessages.protectedAttributeToolTip);
+            }
+
+            { // multiple
+                final Button btnMultiple = toolkit.createButton(attributesContainer, CndMessages.multipleAttribute, SWT.CHECK);
+                btnMultiple.setBackground(attributesContainer.getBackground());
+
+                if (isEditMode() && this.propertyBeingEdited.isMultiple()) {
+                    btnMultiple.setSelection(true);
+                }
+
+                btnMultiple.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        handleMultipleChanged(((Button)e.widget).getSelection());
+                    }
+                });
+                btnMultiple.setToolTipText(CndMessages.multipleAttributeToolTip);
+            }
+
+            { // nofulltext
+                final Button btnNoFullText = toolkit.createButton(attributesContainer, CndMessages.noFullTextAttribute, SWT.CHECK);
+                btnNoFullText.setBackground(attributesContainer.getBackground());
+
+                if (isEditMode() && !this.propertyBeingEdited.isFullTextSearchable()) {
+                    btnNoFullText.setSelection(true);
+                }
+
+                btnNoFullText.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        handleNoFullTextChanged(((Button)e.widget).getSelection());
+                    }
+                });
+                btnNoFullText.setToolTipText(CndMessages.noFullTextAttributeToolTip);
+            }
+
+            { // noQueryOrder
+                final Button btnNoQueryOrder = toolkit.createButton(attributesContainer, CndMessages.noQueryOrderAttribute,
+                                                                    SWT.CHECK);
+                btnNoQueryOrder.setBackground(attributesContainer.getBackground());
+
+                if (isEditMode() && !this.propertyBeingEdited.isQueryOrderable()) {
+                    btnNoQueryOrder.setSelection(true);
+                }
+
+                btnNoQueryOrder.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        handleNoQueryOrderChanged(((Button)e.widget).getSelection());
+                    }
+                });
+                btnNoQueryOrder.setToolTipText(CndMessages.noQueryOrderAttributeToolTip);
+            }
+
+            { // opv
+                final Composite opvContainer = toolkit.createComposite(attributesContainer);
+                opvContainer.setLayout(new GridLayout(2, false));
+                opvContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+                toolkit.paintBordersFor(opvContainer);
+
+                final Label lblOpv = toolkit.createLabel(opvContainer, CndMessages.onParentVersionLabel, SWT.NONE);
+                lblOpv.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+                final CCombo cbxOpvs = new CCombo(opvContainer, Styles.COMBO_STYLE);
+                cbxOpvs.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+                ((GridData)cbxOpvs.getLayoutData()).heightHint = cbxOpvs.getItemHeight() + 4;
+                cbxOpvs.setToolTipText(CndMessages.onParentVersionToolTip);
+                toolkit.adapt(cbxOpvs, true, false);
+
+                // populate opv values
+                for (final OnParentVersion opv : OnParentVersion.values()) {
+                    if (opv != OnParentVersion.VARIANT) {
+                        cbxOpvs.add(opv.toString());
+                    }
+                }
+
+                // select the current qualifier
+                if (isEditMode()) {
+                    final String currentOpv = OnParentVersion.findUsingJcrValue(this.propertyBeingEdited.getOnParentVersion())
+                                                             .toString();
+                    final int index = cbxOpvs.indexOf(currentOpv);
+
+                    if (index != -1) {
+                        cbxOpvs.select(index);
+                    }
+                }
+
+                cbxOpvs.addSelectionListener(new SelectionAdapter() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+                     */
+                    @Override
+                    public void widgetSelected( final SelectionEvent e ) {
+                        final String newOpv = ((CCombo)e.widget).getText();
+                        handleOnParentVersionChanged(newOpv);
+                    }
+                });
+            }
+
+            { // queryOps
+              // TODO implement queryOps controls
+            }
+        }
+
+        { // bottom (default values, value constraints)
+            final Composite bottomContainer = toolkit.createComposite(body);
+            bottomContainer.setLayout(new GridLayout(2, true));
+            bottomContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+            toolkit.paintBordersFor(bottomContainer);
+
+            { // default values
+                final Composite defaultValuesContainer = toolkit.createComposite(bottomContainer);
+                defaultValuesContainer.setLayout(new GridLayout(2, false));
+                defaultValuesContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+                toolkit.paintBordersFor(defaultValuesContainer);
+
+                final Label label = toolkit.createLabel(defaultValuesContainer, CndMessages.defaultValuesLabel);
+                label.setLayoutData(new GridData(SWT.BEGINNING, SWT.TOP, false, false));
+                ((GridData)label.getLayoutData()).horizontalSpan = 2;
+
+                final Table table = FormUtils.createTable(toolkit, defaultValuesContainer);
+                table.setHeaderVisible(false);
+                table.setLinesVisible(false);
+                ((GridData)table.getLayoutData()).heightHint = table.getItemHeight() * 4;
+                table.setToolTipText(CndMessages.defaultValuesToolTip);
+                this.defaultValuesError.setControl(table);
+
+                createDefaultValuesActions();
+
+                // table context menu
+                final MenuManager menuManager = new MenuManager();
+                menuManager.add(new DelegateAction(CndMessages.addDefaultValueMenuText, this.addDefaultValue));
+                menuManager.add(new DelegateAction(CndMessages.editDefaultValueMenuText, this.editDefaultValue));
+                menuManager.add(new DelegateAction(CndMessages.deleteDefaultValueMenuText, this.deleteDefaultValue));
+                table.setMenu(menuManager.createContextMenu(table));
+
+                createDefaultValuesViewer(table);
+
+                // add toolbar buttons (add, edit, delete)
+                final ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT | SWT.VERTICAL);
+                final ToolBar toolBar = toolBarManager.createControl(defaultValuesContainer);
+                toolkit.adapt(toolBar);
+
+                final Cursor handCursor = new Cursor(Display.getCurrent(), SWT.CURSOR_HAND);
+                toolBar.setCursor(handCursor);
+                toolBarManager.add(this.addDefaultValue);
+                toolBarManager.add(this.editDefaultValue);
+                toolBarManager.add(this.deleteDefaultValue);
+                toolBarManager.update(true);
+
+                // fill with data
+                this.defaultValuesViewer.setInput(this);
+            }
+
+            { // value constraints
+                final Composite valueConstraintsContainer = toolkit.createComposite(bottomContainer);
+                valueConstraintsContainer.setLayout(new GridLayout(2, false));
+                valueConstraintsContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+                toolkit.paintBordersFor(valueConstraintsContainer);
+
+                final Label label = toolkit.createLabel(valueConstraintsContainer, CndMessages.valueConstraintsLabel);
+                label.setLayoutData(new GridData(SWT.BEGINNING, SWT.TOP, false, false));
+                ((GridData)label.getLayoutData()).horizontalSpan = 2;
+
+                final Table table = FormUtils.createTable(toolkit, valueConstraintsContainer);
+                table.setHeaderVisible(false);
+                table.setLinesVisible(false);
+                ((GridData)table.getLayoutData()).heightHint = table.getItemHeight() * 4;
+                table.setToolTipText(CndMessages.valueConstraintsToolTip);
+                this.valueConstraintsError.setControl(table);
+
+                createValueConstraintsActions();
+
+                // table context menu
+                final MenuManager menuManager = new MenuManager();
+                menuManager.add(new DelegateAction(CndMessages.addValueConstraintMenuText, this.addValueConstraint));
+                menuManager.add(new DelegateAction(CndMessages.editValueConstraintMenuText, this.editValueConstraint));
+                menuManager.add(new DelegateAction(CndMessages.deleteValueConstraintMenuText, this.deleteValueConstraint));
+                table.setMenu(menuManager.createContextMenu(table));
+
+                createValueConstraintsViewer(table);
+
+                // add toolbar buttons (add, edit, delete)
+                final ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT | SWT.VERTICAL);
+                final ToolBar toolBar = toolBarManager.createControl(valueConstraintsContainer);
+                toolkit.adapt(toolBar);
+
+                final Cursor handCursor = new Cursor(Display.getCurrent(), SWT.CURSOR_HAND);
+                toolBar.setCursor(handCursor);
+                toolBarManager.add(this.addValueConstraint);
+                toolBarManager.add(this.editValueConstraint);
+                toolBarManager.add(this.deleteValueConstraint);
+                toolBarManager.update(true);
+
+                // fill with data
+                this.valueConstraintsViewer.setInput(this);
+            }
+        }
+
+        // must be done after constructor
+        this.propertyBeingEdited.addListener(new PropertyChangeListener() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
+             */
+            @Override
+            public void propertyChange( final PropertyChangeEvent e ) {
+                handlePropertyChanged(e);
+            }
+        });
+
+        // set messages
+        validateAttributes();
+        validateName();
+        validateDefaultValues();
+        validateValueConstraints();
+        validateType();
+    }
+
+    void createValueConstraintsActions() {
+        this.addValueConstraint = new Action(Utils.EMPTY_STRING) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.action.Action#run()
+             */
+            @Override
+            public void run() {
+                handleAddValueConstraint();
+            }
+        };
+        this.addValueConstraint.setToolTipText(CndMessages.addValueConstraintToolTip);
+        this.addValueConstraint.setImageDescriptor(JcrUiUtils.getNewImageDescriptor());
+
+        this.deleteValueConstraint = new Action(Utils.EMPTY_STRING) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.action.Action#run()
+             */
+            @Override
+            public void run() {
+                handleDeleteValueConstraint();
+            }
+        };
+        this.deleteValueConstraint.setEnabled(false);
+        this.deleteValueConstraint.setToolTipText(CndMessages.deleteValueConstraintToolTip);
+        this.deleteValueConstraint.setImageDescriptor(JcrUiUtils.getDeleteImageDescriptor());
+
+        this.editValueConstraint = new Action(Utils.EMPTY_STRING) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.action.Action#run()
+             */
+            @Override
+            public void run() {
+                handleEditValueConstraint();
+            }
+        };
+        this.editValueConstraint.setEnabled(false);
+        this.editValueConstraint.setToolTipText(CndMessages.editValueConstraintToolTip);
+        this.editValueConstraint.setImageDescriptor(JcrUiUtils.getEditImageDescriptor());
+    }
+
+    private void createValueConstraintsViewer( final Table valueConstraintsTable ) {
+        this.valueConstraintsViewer = new TableViewer(valueConstraintsTable);
+        this.valueConstraintsViewer.setLabelProvider(new LabelProvider());
+        this.valueConstraintsViewer.setContentProvider(new IStructuredContentProvider() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+             */
+            @Override
+            public void dispose() {
+                // nothing to do
+            }
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+             */
+            @Override
+            public Object[] getElements( final Object inputElement ) {
+                final PropertyDefinition propDefn = accessModel();
+                final String[] valueConstraints = propDefn.getValueConstraints();
+
+                if (valueConstraints == null) {
+                    return Utils.EMPTY_OBJECT_ARRAY;
+                }
+
+                return valueConstraints;
+            }
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object,
+             *      java.lang.Object)
+             */
+            @Override
+            public void inputChanged( final Viewer viewer,
+                                      final Object oldInput,
+                                      final Object newInput ) {
+                // nothing to do
+            }
+        });
+
+        this.valueConstraintsViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
+             */
+            @Override
+            public void doubleClick( final DoubleClickEvent event ) {
+                handleEditValueConstraint();
+            }
+        });
+
+        this.valueConstraintsViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
+             */
+            @Override
+            public void selectionChanged( final SelectionChangedEvent event ) {
+                handleValueConstraintSelected();
+            }
+        });
+    }
+
+    /**
+     * <strong>Should only be called after the dialog's <code>OK</code> button has been selected.</strong>
+     * 
+     * @return the property definition represented by the dialog UI controls (never <code>null</code>)
+     */
+    public PropertyDefinition getPropertyDefinition() {
+        return this.propertyBeingEdited;
+    }
+
+    String getSelectedDefaultValue() {
+        final IStructuredSelection selection = (IStructuredSelection)this.defaultValuesViewer.getSelection();
+
+        if (selection.isEmpty()) {
+            return null;
+        }
+
+        assert (selection.size() == 1) : "default values viewer should not allow multiple selections"; //$NON-NLS-1$
+        assert (selection.getFirstElement() instanceof String) : "selection was not a string"; //$NON-NLS-1$
+        return (String)selection.getFirstElement();
+    }
+
+    String getSelectedValueConstraint() {
+        final IStructuredSelection selection = (IStructuredSelection)this.valueConstraintsViewer.getSelection();
+
+        if (selection.isEmpty()) {
+            return null;
+        }
+
+        assert (selection.size() == 1) : "value constraints viewer should not allow multiple selections"; //$NON-NLS-1$
+        assert (selection.getFirstElement() instanceof String) : "selection was not a string"; //$NON-NLS-1$
+        return (String)selection.getFirstElement();
+    }
+
+    void handleAddDefaultValue() {
+        final PropertyDefinition propDefn = getPropertyDefinition();
+        final Collection<String> currentDefaultValues = propDefn.getDefaultValuesAsStrings();
+        final StringValueEditorDialog dialog = new StringValueEditorDialog(getShell()) {
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog#getSettings()
+             */
+            @Override
+            protected Settings getSettings() {
+                final StringValueEditorDialog.Settings settings = new StringValueEditorDialog.Settings();
+                settings.acceptMessage = CndMessages.acceptDefaultValueDialogMsg;
+                settings.initialMessage = CndMessages.defaultValueDialogMsg;
+                settings.labelText = CndMessages.defaultValueLabel;
+                settings.messageAreaTitle = CndMessages.defaultValueDialogCreateMsg;
+                settings.valueToolTip = CndMessages.defaultValueToolTip;
+                settings.validator = new Validator() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog.Validator#validate(java.lang.String)
+                     */
+                    @Override
+                    public ValidationStatus validate( final String newValue ) {
+                        final ValidationStatus status = CndValidator.isValid(newValue, propDefn.getType(), propDefn.getName());
+
+                        if (status.isError()) {
+                            return status;
+                        }
+
+                        // check for duplicate
+                        if (currentDefaultValues.contains(newValue)) {
+                            return ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateDefaultValue, propDefn.getName(),
+                                                                                newValue));
+                        }
+
+                        return ValidationStatus.OK_STATUS;
+                    }
+                };
+
+                return settings;
+            }
+        };
+
+        dialog.create();
+        dialog.getShell().pack();
+
+        if (dialog.open() == Window.OK) {
+            final String newDefaultValue = dialog.getValue();
+
+            if (!this.propertyBeingEdited.addValueConstraint(newDefaultValue)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorAddingDefaultValue, newDefaultValue));
+            }
+        }
+    }
+
+    void handleAddValueConstraint() {
+        final PropertyDefinition propDefn = getPropertyDefinition();
+        final Collection<String> currentConstraints = Arrays.asList(propDefn.getValueConstraints());
+        final StringValueEditorDialog dialog = new StringValueEditorDialog(getShell()) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog#getSettings()
+             */
+            @Override
+            protected Settings getSettings() {
+                final StringValueEditorDialog.Settings settings = new StringValueEditorDialog.Settings();
+                settings.acceptMessage = CndMessages.acceptValueConstraintDialogMsg;
+                settings.initialMessage = CndMessages.valueConstraintDialogMsg;
+                settings.labelText = CndMessages.valueConstraintLabel;
+                settings.messageAreaTitle = CndMessages.valueConstraintDialogCreateMsg;
+                settings.valueToolTip = CndMessages.valueConstraintToolTip;
+                settings.validator = new Validator() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog.Validator#validate(java.lang.String)
+                     */
+                    @Override
+                    public ValidationStatus validate( final String newValue ) {
+                        final ValidationStatus status = CndValidator.validateValueConstraint(newValue);
+
+                        if (status.isError()) {
+                            return status;
+                        }
+
+                        // check for duplicate
+                        if (currentConstraints.contains(newValue)) {
+                            return ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateValueConstraint,
+                                                                                propDefn.getName(), newValue));
+                        }
+
+                        return ValidationStatus.OK_STATUS;
+                    }
+                };
+
+                return settings;
+            }
+        };
+        dialog.create();
+        dialog.getShell().pack();
+
+        if (dialog.open() == Window.OK) {
+            final String newValueConstraint = dialog.getValue();
+
+            if (!this.propertyBeingEdited.addValueConstraint(newValueConstraint)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorAddingValueConstraint, newValueConstraint));
+            }
+        }
+    }
+
+    void handleAutocreatedChanged( final boolean newAutocreated ) {
+        this.propertyBeingEdited.setAutoCreated(newAutocreated);
+    }
+
+    void handleDefaultValueSelected() {
+        // update button enablements
+        final boolean enable = (getSelectedDefaultValue() != null);
+
+        if (this.editDefaultValue.isEnabled() != enable) {
+            this.editDefaultValue.setEnabled(enable);
+        }
+
+        if (this.deleteDefaultValue.isEnabled() != enable) {
+            this.deleteDefaultValue.setEnabled(enable);
+        }
+    }
+
+    void handleDeleteDefaultValue() {
+        assert (getSelectedDefaultValue() != null) : "Delete default value handler called and there is no default value selected"; //$NON-NLS-1$
+        final String defaultValue = getSelectedDefaultValue();
+
+        // show confirmation dialog
+        if (MessageFormDialog.openQuestion(getShell(), CndMessages.deleteDefaultValueDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                           NLS.bind(CndMessages.deleteDefaultValueDialogMessage, defaultValue))) {
+            if (!this.propertyBeingEdited.removeDefaultValue(defaultValue)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorDeletingDefaultValue, defaultValue));
+            }
+        }
+    }
+
+    void handleDeleteValueConstraint() {
+        assert (getSelectedValueConstraint() != null) : "Delete value constraint handler called and there is no value constraint selected"; //$NON-NLS-1$
+        final String valueConstraint = getSelectedValueConstraint();
+
+        // show confirmation dialog
+        if (MessageFormDialog.openQuestion(getShell(), CndMessages.deleteValueConstraintDialogTitle,
+                                           JcrUiUtils.getCndEditorImage(),
+                                           NLS.bind(CndMessages.deleteValueConstraintDialogMessage, valueConstraint))) {
+            if (!this.propertyBeingEdited.removeValueConstraint(valueConstraint)) {
+                MessageFormDialog.openError(getShell(), UiMessages.errorDialogTitle, JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorDeletingValueConstraint, valueConstraint));
+            }
+        }
+    }
+
+    void handleEditDefaultValue() {
+        assert (getSelectedDefaultValue() != null) : "Edit default value handler called but there is not a default value selected"; //$NON-NLS-1$
+
+        final PropertyDefinition propDefn = getPropertyDefinition();
+        final String selectedDefaultValue = getSelectedDefaultValue();
+        final Collection<String> currentDefaultValues = new ArrayList<String>(propDefn.getDefaultValuesAsStrings());
+        currentDefaultValues.remove(selectedDefaultValue); // remove selected so validation doesn't flag it as a duplicate
+
+        final StringValueEditorDialog dialog = new StringValueEditorDialog(getShell()) {
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog#getSettings()
+             */
+            @Override
+            protected Settings getSettings() {
+                final StringValueEditorDialog.Settings settings = new StringValueEditorDialog.Settings();
+                settings.acceptMessage = CndMessages.acceptDefaultValueDialogMsg;
+                settings.initialMessage = CndMessages.defaultValueDialogMsg;
+                settings.labelText = CndMessages.defaultValueLabel;
+                settings.messageAreaTitle = CndMessages.defaultValueDialogEditMsg;
+                settings.valueToolTip = CndMessages.defaultValueToolTip;
+                settings.valueBeingEdited = selectedDefaultValue;
+                settings.validator = new Validator() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog.Validator#validate(java.lang.String)
+                     */
+                    @Override
+                    public ValidationStatus validate( final String newValue ) {
+                        final ValidationStatus status = CndValidator.isValid(newValue, propDefn.getType(), propDefn.getName());
+
+                        if (status.isError()) {
+                            return status;
+                        }
+
+                        // check for duplicate
+                        if (currentDefaultValues.contains(newValue)) {
+                            return ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateDefaultValue, propDefn.getName(),
+                                                                                newValue));
+                        }
+
+                        return ValidationStatus.OK_STATUS;
+                    }
+                };
+
+                return settings;
+            }
+        };
+
+        dialog.create();
+        dialog.getShell().pack();
+
+        if (dialog.open() == Window.OK) {
+            final String modifiedDefaultValue = dialog.getValue();
+            boolean removed = false;
+            boolean added = false;
+
+            // remove existing and add in new
+            if (this.propertyBeingEdited.removeDefaultValue(selectedDefaultValue)) {
+                removed = true;
+
+                if (this.propertyBeingEdited.addDefaultValue(modifiedDefaultValue)) {
+                    added = true;
+                }
+            }
+
+            if (!removed || !added) {
+                MessageFormDialog.openError(getShell(),
+                                            UiMessages.errorDialogTitle,
+                                            JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorEditingDefaultValue, new Object[] { modifiedDefaultValue,
+                                                    removed, added }));
+            }
+        }
+    }
+
+    void handleEditValueConstraint() {
+        assert (getSelectedValueConstraint() != null) : "Edit value constraint handler called but there is not a value constraint selected"; //$NON-NLS-1$
+
+        final PropertyDefinition propDefn = getPropertyDefinition();
+        final String selectedValueConstraint = getSelectedValueConstraint();
+        final Collection<String> currentConstraints = new ArrayList<String>(Arrays.asList(propDefn.getValueConstraints()));
+        currentConstraints.remove(selectedValueConstraint); // remove selected so validation doesn't flag it as a duplicate
+
+        final StringValueEditorDialog dialog = new StringValueEditorDialog(getShell()) {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog#getSettings()
+             */
+            @Override
+            protected Settings getSettings() {
+                final StringValueEditorDialog.Settings settings = new StringValueEditorDialog.Settings();
+                settings.acceptMessage = CndMessages.acceptValueConstraintDialogMsg;
+                settings.initialMessage = CndMessages.valueConstraintDialogMsg;
+                settings.labelText = CndMessages.valueConstraintLabel;
+                settings.messageAreaTitle = CndMessages.valueConstraintDialogEditMsg;
+                settings.valueToolTip = CndMessages.valueConstraintToolTip;
+                settings.valueBeingEdited = selectedValueConstraint;
+                settings.validator = new Validator() {
+
+                    /**
+                     * {@inheritDoc}
+                     * 
+                     * @see org.jboss.tools.modeshape.jcr.ui.cnd.StringValueEditorDialog.Validator#validate(java.lang.String)
+                     */
+                    @Override
+                    public ValidationStatus validate( final String newValue ) {
+                        final ValidationStatus status = CndValidator.validateValueConstraint(newValue);
+
+                        if (status.isError()) {
+                            return status;
+                        }
+
+                        // check for duplicate
+                        if (currentConstraints.contains(newValue)) {
+                            return ValidationStatus.createErrorMessage(NLS.bind(Messages.duplicateValueConstraint,
+                                                                                propDefn.getName(), newValue));
+                        }
+
+                        return ValidationStatus.OK_STATUS;
+                    }
+                };
+
+                return settings;
+            }
+        };
+        dialog.create();
+        dialog.getShell().pack();
+
+        if (dialog.open() == Window.OK) {
+            final String modifiedValueConstraint = dialog.getValue();
+            boolean removed = false;
+            boolean added = false;
+
+            // remove existing and add in new
+            if (this.propertyBeingEdited.removeValueConstraint(selectedValueConstraint)) {
+                removed = true;
+
+                if (this.propertyBeingEdited.addValueConstraint(modifiedValueConstraint)) {
+                    added = true;
+                }
+            }
+
+            if (!removed || !added) {
+                MessageFormDialog.openError(getShell(),
+                                            UiMessages.errorDialogTitle,
+                                            JcrUiUtils.getCndEditorImage(),
+                                            NLS.bind(CndMessages.errorEditingValueConstraint, new Object[] {
+                                                    modifiedValueConstraint, removed, added }));
+            }
+        }
+    }
+
+    void handleMandatoryChanged( final boolean newMandatory ) {
+        this.propertyBeingEdited.setMandatory(newMandatory);
+    }
+
+    void handleMultipleChanged( final boolean newMultiple ) {
+        this.propertyBeingEdited.setMultiple(newMultiple);
+    }
+
+    void handleNameChanged( final String newName ) {
+        this.propertyBeingEdited.setName(newName);
+    }
+
+    void handleNoFullTextChanged( final boolean newNoFullText ) {
+        this.propertyBeingEdited.setFullTextSearchable(!newNoFullText);
+    }
+
+    void handleNoQueryOrderChanged( final boolean newNoQueryOrder ) {
+        this.propertyBeingEdited.setQueryOrderable(!newNoQueryOrder);
+    }
+
+    void handleOnParentVersionChanged( final String newOpv ) {
+        this.propertyBeingEdited.setOnParentVersion(newOpv);
+    }
+
+    void handlePropertyChanged( final PropertyChangeEvent e ) {
+        final String propName = e.getPropertyName();
+
+        if (PropertyName.AUTOCREATED.toString().equals(propName) || PropertyName.MANDATORY.toString().equals(propName)
+                || PropertyName.MULTIPLE.toString().equals(propName) || PropertyName.NO_FULL_TEXT.toString().equals(propName)
+                || PropertyName.NO_QUERY_ORDER.toString().equals(propName) || PropertyName.PROTECTED.toString().equals(propName)
+                || PropertyName.ON_PARENT_VERSION.toString().equals(propName) || PropertyName.QUERY_OPS.toString().equals(propName)) {
+            validateAttributes();
+        } else if (PropertyName.DEFAULT_VALUES.toString().equals(propName)) {
+            validateDefaultValues();
+            this.defaultValuesViewer.refresh();
+        } else if (PropertyName.NAME.toString().equals(propName)) {
+            validateName();
+        } else if (PropertyName.TYPE.toString().equals(propName)) {
+            validateType();
+        } else if (PropertyName.VALUE_CONSTRAINTS.toString().equals(propName)) {
+            validateValueConstraints();
+            this.valueConstraintsViewer.refresh();
+        }
+
+        updateState();
+    }
+
+    void handleProtectedChanged( final boolean newProtected ) {
+        this.propertyBeingEdited.setProtected(newProtected);
+    }
+
+    void handleTypeChanged( final String newType ) {
+        this.propertyBeingEdited.setType(PropertyType.valueOf(newType));
+    }
+
+    void handleValueConstraintSelected() {
+        // update button enablements
+        final boolean enable = (getSelectedValueConstraint() != null);
+
+        if (this.editValueConstraint.isEnabled() != enable) {
+            this.editValueConstraint.setEnabled(enable);
+        }
+
+        if (this.deleteValueConstraint.isEnabled() != enable) {
+            this.deleteValueConstraint.setEnabled(enable);
+        }
+    }
+
+    private boolean isEditMode() {
+        return (this.originalProperty != null);
+    }
+
+    private void updateMessage( final ValidationStatus status,
+                                final ErrorMessage errorMsg ) {
+        JcrUiUtils.setMessage(status, errorMsg);
+
+        if (errorMsg.isOk()) {
+            this.scrolledForm.getMessageManager().removeMessage(errorMsg.getKey(), errorMsg.getControl());
+        } else {
+            this.scrolledForm.getMessageManager().addMessage(errorMsg.getKey(), errorMsg.getMessage(), null,
+                                                             errorMsg.getMessageType(), errorMsg.getControl());
+        }
+    }
+
+    private void updateState() {
+        final int messageType = this.scrolledForm.getMessageType();
+        boolean enable = (messageType != IMessageProvider.ERROR);
+
+        if (enable && isEditMode() && this.originalProperty.equals(this.propertyBeingEdited)) {
+            enable = false;
+        }
+
+        // set enabled state of OK button
+        if (this.btnOk.getEnabled() != enable) {
+            this.btnOk.setEnabled(enable);
+        }
+    }
+
+    private void validateAttributes() {
+        // TODO primary item
+    }
+
+    private void validateDefaultValues() {
+        updateMessage(CndValidator.validateDefaultValues(this.propertyBeingEdited), this.defaultValuesError);
+    }
+
+    private void validateName() {
+        updateMessage(this.nameEditor.getStatus(), this.nameError);
+    }
+
+    private void validateType() {
+        // no validation required since user cannot enter an invalid value
+    }
+
+    private void validateValueConstraints() {
+        updateMessage(CndValidator.validateValueConstraints(this.propertyBeingEdited), this.valueConstraintsError);
+    }
+}


Property changes on: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/PropertyDialog.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameDialog.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameDialog.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameDialog.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -15,34 +15,26 @@
 import org.eclipse.jface.dialogs.IMessageProvider;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.CCombo;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.forms.FormDialog;
 import org.eclipse.ui.forms.IManagedForm;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.ScrolledForm;
-import org.jboss.tools.modeshape.jcr.MultiValidationStatus;
 import org.jboss.tools.modeshape.jcr.Utils;
-import org.jboss.tools.modeshape.jcr.cnd.CndValidator;
+import org.jboss.tools.modeshape.jcr.ValidationStatus;
 import org.jboss.tools.modeshape.jcr.cnd.QualifiedName;
 import org.jboss.tools.modeshape.jcr.ui.Activator;
 import org.jboss.tools.modeshape.jcr.ui.JcrUiConstants;
-import org.jboss.tools.modeshape.ui.forms.FormUtils.Styles;
 
 /**
  * The <code>QualifiedNameDialog</code> is used to create or edit a qualified name.
  */
-class QualifiedNameDialog extends FormDialog {
+final class QualifiedNameDialog extends FormDialog {
 
     private Button btnOk;
 
@@ -59,19 +51,17 @@
 
     private final String qualifiedNameType;
 
-    private String qualifier;
-
     private ScrolledForm scrolledForm;
 
     private final String title;
 
-    private String unqualifiedName;
-
     /**
      * A collection of known qualifiers/namespace prefixes to the CND (never <code>null</code>).
      */
     private final List<String> validQualifiers;
 
+    private QualifiedNameEditor nameEditor;
+
     /**
      * Used to construct a new qualified name.
      * 
@@ -111,8 +101,6 @@
         Utils.verifyIsNotNull(qnameBeingEdited, "qnameBeingEdited"); //$NON-NLS-1$
 
         this.qnameBeingEdited = qnameBeingEdited;
-        this.qualifier = this.qnameBeingEdited.getQualifier();
-        this.unqualifiedName = this.qnameBeingEdited.getUnqualifiedName();
     }
 
     /**
@@ -165,86 +153,25 @@
         final Composite body = this.scrolledForm.getBody();
         body.setLayout(new GridLayout(2, false));
 
-        { // qualifier
-            final Label lblQualifier = toolkit.createLabel(body, CndMessages.qualifierLabel, SWT.NONE);
-            lblQualifier.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+        this.nameEditor = new QualifiedNameEditor(body,
+                                                  SWT.NONE,
+                                                  toolkit,
+                                                  this.qualifiedNameType,
+                                                  this.validQualifiers,
+                                                  this.qnameBeingEdited);
+        this.nameEditor.setExistingQNames(this.existingQNames);
+        this.nameEditor.addListener(SWT.Modify, new Listener() {
 
-            final CCombo cbxQualifiers = new CCombo(body, Styles.COMBO_STYLE);
-            toolkit.adapt(cbxQualifiers, true, false);
-            cbxQualifiers.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-            cbxQualifiers.setToolTipText(CndMessages.validQualifiersToolTip);
-
-            // populate qualifiers
-            for (final String validQualifier : this.validQualifiers) {
-                cbxQualifiers.add(validQualifier);
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
+             */
+            @Override
+            public void handleEvent( final Event e ) {
+                handleNameChanged(e.text);
             }
-
-            // select the current qualifier
-            if (isEditMode()) {
-                final String currentQualifier = this.qnameBeingEdited.getQualifier();
-
-                if (Utils.isEmpty(currentQualifier)) {
-                    cbxQualifiers.select(0);
-                } else {
-                    final int index = cbxQualifiers.indexOf(currentQualifier);
-
-                    if (index == -1) {
-                        // not a valid qualifier but add and select
-                        cbxQualifiers.add(currentQualifier);
-                        cbxQualifiers.select(cbxQualifiers.getItemCount() - 1);
-                    } else {
-                        cbxQualifiers.select(index);
-                    }
-                }
-            } else {
-                cbxQualifiers.select(0);
-            }
-
-            cbxQualifiers.addSelectionListener(new SelectionAdapter() {
-
-                /**
-                 * {@inheritDoc}
-                 * 
-                 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
-                 */
-                @Override
-                public void widgetSelected( final SelectionEvent e ) {
-                    final String newQualifier = ((CCombo)e.widget).getText();
-                    handleQualifierChanged(newQualifier);
-                }
-            });
-        }
-
-        { // unqualified name
-            final Label lblName = toolkit.createLabel(body, CndMessages.nameLabel, SWT.NONE);
-            lblName.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
-
-            final Text txtName = toolkit.createText(body, null, Styles.TEXT_STYLE);
-            txtName.setToolTipText(CndMessages.unqualifiedNameToolTip);
-
-            final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
-            gd.verticalIndent += ((GridLayout)body.getLayout()).verticalSpacing;
-            txtName.setLayoutData(gd);
-
-            if (isEditMode()) {
-                txtName.setText(this.qnameBeingEdited.getUnqualifiedName());
-            }
-
-            txtName.addModifyListener(new ModifyListener() {
-
-                /**
-                 * {@inheritDoc}
-                 * 
-                 * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
-                 */
-                @Override
-                public void modifyText( final ModifyEvent e ) {
-                    handleNameChanged(((Text)e.widget).getText());
-                }
-            });
-
-            txtName.setFocus();
-        }
+        });
     }
 
     /**
@@ -253,19 +180,13 @@
      * @return the new or edited qualified name (never <code>null</code>)
      */
     public QualifiedName getQualifiedName() {
-        return new QualifiedName(this.qualifier, this.unqualifiedName);
+        return this.nameEditor.getQualifiedName();
     }
 
     void handleNameChanged( final String newName ) {
-        this.unqualifiedName = newName;
         updateState();
     }
 
-    void handleQualifierChanged( final String newQualifier ) {
-        this.qualifier = newQualifier;
-        updateState();
-    }
-
     private boolean isEditMode() {
         return (this.qnameBeingEdited != null);
     }
@@ -274,23 +195,16 @@
      * @param existingQNames used to check against for duplicate qualified names (can be <code>null</code> or empty)
      */
     void setExistingQNames( final Collection<QualifiedName> existingQNames ) {
-        if (Utils.isEmpty(existingQNames)) {
-            this.existingQNames = null;
+        if (this.nameEditor == null) {
+            this.existingQNames = existingQNames;
         } else {
-            this.existingQNames = new ArrayList<QualifiedName>(existingQNames);
-
-            // so that validating won't show it as a duplicate
-            if (isEditMode()) {
-                this.existingQNames.remove(this.qnameBeingEdited);
-            }
+            this.nameEditor.setExistingQNames(existingQNames);
         }
     }
 
     private void updateState() {
-        // validate qname
-        final QualifiedName currentQName = new QualifiedName(this.qualifier, this.unqualifiedName);
-        final MultiValidationStatus status = CndValidator.validateQualifiedName(currentQName, this.qualifiedNameType,
-                                                                                this.validQualifiers, this.existingQNames);
+        final QualifiedName modifiedQName = this.nameEditor.getQualifiedName();
+        final ValidationStatus status = this.nameEditor.getStatus();
         boolean enable = !status.isError();
 
         // a bug in Eclipse doesn't reset the font color going from an error to NONE so first set to INFORMATION to get the
@@ -299,8 +213,8 @@
 
         if (!enable) {
             this.scrolledForm.setMessage(status.getMessage(), IMessageProvider.ERROR);
-        } else if ((isEditMode() && currentQName.equals(this.qnameBeingEdited))
-                || (!isEditMode() && Utils.isEmpty(this.qualifier) && Utils.isEmpty(this.unqualifiedName))) {
+        } else if ((isEditMode() && modifiedQName.equals(this.qnameBeingEdited))
+                || (!isEditMode() && Utils.isEmpty(modifiedQName.getQualifier()) && Utils.isEmpty(modifiedQName.getUnqualifiedName()))) {
             enable = false;
             this.scrolledForm.setMessage(NLS.bind(CndMessages.qualifiedNameDialogMsg, this.qualifiedNameType),
                                          IMessageProvider.NONE);

Added: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameEditor.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameEditor.java	                        (rev 0)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameEditor.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -0,0 +1,292 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ *
+ * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
+ *
+ * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
+ */
+package org.jboss.tools.modeshape.jcr.ui.cnd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.jboss.tools.modeshape.jcr.Utils;
+import org.jboss.tools.modeshape.jcr.ValidationStatus;
+import org.jboss.tools.modeshape.jcr.cnd.CndValidator;
+import org.jboss.tools.modeshape.jcr.cnd.QualifiedName;
+import org.jboss.tools.modeshape.ui.forms.FormUtils.Styles;
+
+/**
+ * A UI container that can be used to edit or create a qualified name. To receive notification of when a change was made in the
+ * editor, register using {@link #addListener(int, org.eclipse.swt.widgets.Listener)} using {@link SWT#Modify} as the event type.
+ * After notification, a call to {@link #getStatus()} will have the latest validation results.
+ */
+final class QualifiedNameEditor extends Composite {
+
+    private CCombo cbxQualifiers;
+
+    /**
+     * An optional collection of existing qualified names. When this is non-empty, it is checked to make sure the qualified name
+     * being edited is not a duplicate.
+     */
+    private Collection<QualifiedName> existingQNames;
+
+    private Label lblName;
+
+    private Label lblQualifier;
+
+    /**
+     * The qualified name being edited or <code>null</code> when creating a qualified name.
+     */
+    private QualifiedName qnameBeingEdited;
+
+    private final String qualifiedNameType;
+
+    private String qualifier;
+
+    private ValidationStatus status;
+
+    private final FormToolkit toolkit;
+
+    private Text txtName;
+
+    private String unqualifiedName;
+
+    /**
+     * A collection of known qualifiers/namespace prefixes to the CND (never <code>null</code>).
+     */
+    private List<String> validQualifiers;
+
+    /**
+     * Used to edit an existing or create a new qualified name.
+     * 
+     * @param parent the parent container (cannot be <code>null</code>)
+     * @param style the composite style
+     * @param toolkit the toolkit (cannot be <code>null</code>)
+     * @param qualifiedNameType a word describing what the qualified name represents (cannot be <code>null</code> or empty)
+     * @param existingQualifiers the existing qualifies (can be <code>null</code> or empty)
+     * @param qnameBeingEdited the qualified name being edited or <code>null</code> if creating a new name
+     */
+    public QualifiedNameEditor( final Composite parent,
+                                final int style,
+                                final FormToolkit toolkit,
+                                final String qualifiedNameType,
+                                final Collection<String> existingQualifiers,
+                                final QualifiedName qnameBeingEdited ) {
+        super(parent, style);
+        Utils.verifyIsNotNull(qualifiedNameType, "qualifiedNameType"); //$NON-NLS-1$
+        Utils.verifyIsNotNull(toolkit, "toolkit"); //$NON-NLS-1$
+
+        this.qualifiedNameType = qualifiedNameType;
+        this.toolkit = toolkit;
+        this.toolkit.adapt(this);
+
+        this.toolkit.adapt(this);
+        this.toolkit.paintBordersFor(this);
+
+        setLayout(new GridLayout(2, false));
+        setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+        constructEditor();
+        setValidQualifiers(existingQualifiers);
+        setNameBeingEdited(qnameBeingEdited);
+    }
+
+    private void constructEditor() {
+        { // qualifier
+            this.lblQualifier = this.toolkit.createLabel(this, CndMessages.qualifierLabel, SWT.NONE);
+            this.lblQualifier.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+            this.cbxQualifiers = new CCombo(this, Styles.COMBO_STYLE);
+            this.toolkit.adapt(this.cbxQualifiers, true, false);
+            this.cbxQualifiers.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+            ((GridData)this.cbxQualifiers.getLayoutData()).heightHint = this.cbxQualifiers.getItemHeight() + 4;
+            this.cbxQualifiers.setToolTipText(CndMessages.validQualifiersToolTip);
+
+            this.cbxQualifiers.addModifyListener(new ModifyListener() {
+
+                /**
+                 * {@inheritDoc}
+                 * 
+                 * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+                 */
+                @Override
+                public void modifyText( final ModifyEvent e ) {
+                    final String newQualifier = ((CCombo)e.widget).getText();
+                    handleQualifierChanged(newQualifier);
+                }
+            });
+        }
+
+        { // unqualified name
+            this.lblName = this.toolkit.createLabel(this, CndMessages.nameLabel, SWT.NONE);
+            this.lblName.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+            this.txtName = this.toolkit.createText(this, null, Styles.TEXT_STYLE);
+            this.txtName.setToolTipText(CndMessages.unqualifiedNameToolTip);
+            this.txtName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+            this.txtName.addModifyListener(new ModifyListener() {
+
+                /**
+                 * {@inheritDoc}
+                 * 
+                 * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+                 */
+                @Override
+                public void modifyText( final ModifyEvent e ) {
+                    handleNameChanged(((Text)e.widget).getText());
+                }
+            });
+
+            this.txtName.setFocus();
+        }
+    }
+
+    /**
+     * @return the new or edited qualified name (never <code>null</code>)
+     */
+    public QualifiedName getQualifiedName() {
+        return new QualifiedName(this.qualifier, this.unqualifiedName);
+    }
+
+    /**
+     * @return the latest validation results (never <code>null</code>)
+     */
+    public ValidationStatus getStatus() {
+        return this.status;
+    }
+
+    void handleNameChanged( final String newName ) {
+        this.unqualifiedName = newName;
+        validate();
+    }
+
+    void handleQualifierChanged( final String newQualifier ) {
+        this.qualifier = newQualifier;
+        validate();
+    }
+
+    private boolean isEditMode() {
+        return (this.qnameBeingEdited != null);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.eclipse.swt.widgets.Control#setEnabled(boolean)
+     */
+    @Override
+    public void setEnabled( final boolean enable ) {
+        super.setEnabled(enable);
+
+        // all controls have the same enablement
+        if (this.txtName.getEnabled() != enable) {
+            this.lblQualifier.setEnabled(enable);
+            this.cbxQualifiers.setEnabled(enable);
+            this.lblName.setEnabled(enable);
+            this.txtName.setEnabled(enable);
+        }
+    }
+
+    /**
+     * @param existingQNames used to check against for duplicate qualified names (can be <code>null</code> or empty)
+     */
+    void setExistingQNames( final Collection<QualifiedName> existingQNames ) {
+        if (Utils.isEmpty(existingQNames)) {
+            this.existingQNames = null;
+        } else {
+            this.existingQNames = new ArrayList<QualifiedName>(existingQNames);
+
+            // so that validating won't show it as a duplicate
+            if (isEditMode()) {
+                this.existingQNames.remove(this.qnameBeingEdited);
+            }
+        }
+    }
+
+    public void setNameBeingEdited( final QualifiedName qnameBeingEdited ) {
+        this.qnameBeingEdited = qnameBeingEdited;
+
+        if (this.qnameBeingEdited == null) {
+            this.qualifier = null;
+            this.unqualifiedName = null;
+        } else {
+            this.qualifier = this.qnameBeingEdited.getQualifier();
+            this.unqualifiedName = this.qnameBeingEdited.getUnqualifiedName();
+        }
+
+        updateUi();
+        validate();
+    }
+
+    /**
+     * @param validQualifiers the valid qualifiers (can be <code>null</code> or empty)
+     */
+    void setValidQualifiers( final Collection<String> validQualifiers ) {
+        this.validQualifiers = ((validQualifiers == null) ? new ArrayList<String>(1) : new ArrayList<String>(validQualifiers));
+        this.validQualifiers.add(0, CndMessages.noNameQualifierChoice); // include empty qualifier at index 0
+        updateUi();
+    }
+
+    private void updateUi() {
+        // set qualifier choices if they have changed
+        final String[] currentItems = this.cbxQualifiers.getItems();
+
+        // only reload qualifiers if different
+        if ((this.validQualifiers.size() != currentItems.length) || !this.validQualifiers.containsAll(Arrays.asList(currentItems))) {
+            this.cbxQualifiers.setItems(this.validQualifiers.toArray(new String[this.validQualifiers.size()]));
+        }
+
+        // select the current qualifier
+        if (isEditMode()) {
+            final String currentQualifier = this.qnameBeingEdited.getQualifier();
+
+            if (Utils.isEmpty(currentQualifier)) {
+                this.cbxQualifiers.select(0);
+            } else {
+                final int index = this.cbxQualifiers.indexOf(currentQualifier);
+
+                if (index == -1) {
+                    // not a valid qualifier but add and select
+                    this.cbxQualifiers.add(currentQualifier);
+                    this.cbxQualifiers.select(this.cbxQualifiers.getItemCount() - 1);
+                } else {
+                    this.cbxQualifiers.select(index);
+                }
+            }
+        } else {
+            this.cbxQualifiers.select(0);
+        }
+
+        if (isEditMode()) {
+            final String name = this.qnameBeingEdited.getUnqualifiedName();
+            this.txtName.setText(Utils.isEmpty(name) ? Utils.EMPTY_STRING : name);
+        } else {
+            this.txtName.setText(Utils.EMPTY_STRING);
+        }
+    }
+
+    private void validate() {
+        final QualifiedName currentQName = new QualifiedName(this.qualifier, this.unqualifiedName);
+        this.status = CndValidator.validateQualifiedName(currentQName, this.qualifiedNameType, this.validQualifiers,
+                                                         this.existingQNames);
+        final Event e = new Event();
+        e.widget = this;
+        e.type = SWT.Modify;
+        e.text = getQualifiedName().get();
+        notifyListeners(SWT.Modify, e);
+    }
+}


Property changes on: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/QualifiedNameEditor.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/StringValueEditorDialog.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/StringValueEditorDialog.java	                        (rev 0)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/StringValueEditorDialog.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -0,0 +1,270 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ *
+ * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
+ *
+ * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
+ */
+package org.jboss.tools.modeshape.jcr.ui.cnd;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.FormDialog;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.jboss.tools.modeshape.jcr.Utils;
+import org.jboss.tools.modeshape.jcr.ValidationStatus;
+import org.jboss.tools.modeshape.jcr.ui.Activator;
+import org.jboss.tools.modeshape.jcr.ui.JcrUiConstants;
+import org.jboss.tools.modeshape.ui.forms.FormUtils.Styles;
+
+/**
+ * The <code>StringValueEditorDialog</code> is used to create or edit a string value.
+ */
+abstract class StringValueEditorDialog extends FormDialog {
+
+    private Button btnOk;
+
+    /**
+     * The original value (<code>null</code> when creating a new value).
+     */
+    private String originalValue;
+
+    private ScrolledForm scrolledForm;
+
+    private final Settings settings;
+
+    /**
+     * The value being edited (never <code>null</code>).
+     */
+    private String valueBeingEdited;
+
+    /**
+     * Used to construct a new value.
+     * 
+     * @param parentShell the parent shell (may be <code>null</code>)
+     */
+    protected StringValueEditorDialog( final Shell parentShell ) {
+        super(parentShell);
+
+        this.settings = getSettings();
+        assert (this.settings != null) : "settings is null"; //$NON-NLS-1$
+        assert (this.settings.acceptMessage != null) : "settings.acceptMessage is null"; //$NON-NLS-1$
+        assert (this.settings.initialMessage != null) : "settings.initialMessage is null"; //$NON-NLS-1$
+        assert (this.settings.labelText != null) : "settings.labelText is null"; //$NON-NLS-1$
+        assert (this.settings.messageAreaTitle != null) : "settings.messageAreaTitle is null"; //$NON-NLS-1$
+
+        if (this.settings.valueBeingEdited == null) {
+            this.valueBeingEdited = Utils.EMPTY_STRING;
+        } else {
+            this.originalValue = this.settings.valueBeingEdited;
+            this.valueBeingEdited = this.settings.valueBeingEdited;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
+     */
+    @Override
+    protected void configureShell( final Shell newShell ) {
+        super.configureShell(newShell);
+        newShell.setText(CndMessages.valueEditorDialogTitle);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.eclipse.jface.dialogs.Dialog#createButton(org.eclipse.swt.widgets.Composite, int, java.lang.String, boolean)
+     */
+    @Override
+    protected Button createButton( final Composite parent,
+                                   final int id,
+                                   final String label,
+                                   final boolean defaultButton ) {
+        final Button btn = super.createButton(parent, id, label, defaultButton);
+
+        if (id == IDialogConstants.OK_ID) {
+            // disable OK button initially
+            this.btnOk = btn;
+            btn.setEnabled(false);
+        }
+
+        return btn;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.eclipse.ui.forms.FormDialog#createFormContent(org.eclipse.ui.forms.IManagedForm)
+     */
+    @Override
+    protected void createFormContent( final IManagedForm managedForm ) {
+        this.scrolledForm = managedForm.getForm();
+        this.scrolledForm.setText(this.settings.messageAreaTitle);
+        this.scrolledForm.setImage(Activator.getSharedInstance().getImage(JcrUiConstants.Images.CND_EDITOR));
+        this.scrolledForm.setMessage(this.settings.initialMessage, IMessageProvider.NONE);
+
+        final FormToolkit toolkit = managedForm.getToolkit();
+        toolkit.decorateFormHeading(this.scrolledForm.getForm());
+
+        final Composite body = this.scrolledForm.getBody();
+        body.setLayout(new GridLayout(2, false));
+
+        final Label lblValue = toolkit.createLabel(body, this.settings.labelText, SWT.NONE);
+        lblValue.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+        final Text txtValue = toolkit.createText(body, null, Styles.TEXT_STYLE);
+        txtValue.setToolTipText(this.settings.valueToolTip);
+
+        final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
+        gd.verticalIndent += ((GridLayout)body.getLayout()).verticalSpacing;
+        txtValue.setLayoutData(gd);
+
+        if (isEditMode()) {
+            txtValue.setText(this.valueBeingEdited);
+        }
+
+        txtValue.addModifyListener(new ModifyListener() {
+
+            /**
+             * {@inheritDoc}
+             * 
+             * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+             */
+            @Override
+            public void modifyText( final ModifyEvent e ) {
+                handleValueChanged(((Text)e.widget).getText());
+            }
+        });
+
+        txtValue.setFocus();
+    }
+
+    /**
+     * @return the dialog settings (never <code>null</code>)
+     */
+    protected abstract Settings getSettings();
+
+    /**
+     * <strong>Should only be called after the OK button has been pressed.</strong>
+     * 
+     * @return the new or edited value (never <code>null</code>)
+     */
+    public String getValue() {
+        return this.valueBeingEdited;
+    }
+
+    void handleValueChanged( final String newValue ) {
+        this.valueBeingEdited = newValue;
+        updateState();
+    }
+
+    private boolean isEditMode() {
+        return (this.originalValue != null);
+    }
+
+    private void updateState() {
+        boolean enable = true;
+        ValidationStatus status = ValidationStatus.OK_STATUS;
+
+        // validate value
+        if (this.settings.validator != null) {
+            status = this.settings.validator.validate(this.valueBeingEdited);
+            enable = !status.isError();
+        }
+
+        // a bug in Eclipse doesn't reset the font color going from an error to NONE so first set to INFORMATION to get the
+        // font color to change
+        this.scrolledForm.setMessage(Utils.EMPTY_STRING, IMessageProvider.INFORMATION);
+
+        if (!enable) {
+            this.scrolledForm.setMessage(status.getMessage(), IMessageProvider.ERROR);
+        } else if ((isEditMode() && this.originalValue.equals(this.valueBeingEdited))
+                || (!isEditMode() && Utils.isEmpty(this.valueBeingEdited))) {
+            enable = false;
+            this.scrolledForm.setMessage(this.settings.initialMessage, IMessageProvider.NONE);
+        } else {
+            int severity = IMessageProvider.NONE; // OK severity
+            String message = status.getMessage();
+
+            if (status.isWarning()) {
+                severity = IMessageProvider.WARNING;
+            } else if (status.isInfo()) {
+                severity = IMessageProvider.INFORMATION;
+            } else {
+                message = this.settings.initialMessage;
+            }
+
+            this.scrolledForm.setMessage(message, severity);
+        }
+
+        // set enabled state of OK button
+        if (this.btnOk.getEnabled() != enable) {
+            this.btnOk.setEnabled(enable);
+        }
+    }
+
+    class Settings {
+
+        /**
+         * Message area message when OK button is enabled and value is valid (cannot be <code>null</code> or empty).
+         */
+        String acceptMessage;
+
+        /**
+         * Message area message when the dialog is first displayed or when the value is changed back to the initial value (cannot be
+         * <code>null</code> or empty).
+         */
+        String initialMessage;
+
+        /**
+         * Text of the label to the left of the textfield (cannot be <code>null</code> or empty).
+         */
+        String labelText;
+
+        /**
+         * Message area title (cannot be <code>null</code> or empty).
+         */
+        String messageAreaTitle;
+
+        /**
+         * A validator used to determine if the current value is valid (<code>null</code> if no validation is needed).
+         */
+        Validator validator;
+
+        /**
+         * The existing value being edited (can be <code>null</code> if creating a new value).
+         */
+        String valueBeingEdited;
+
+        /**
+         * A tooltip for the textfield where the value is being edited (can be <code>null</code> or empty).
+         */
+        String valueToolTip;
+    }
+
+    /**
+     * Validator of the values.
+     */
+    interface Validator {
+
+        /**
+         * @param newValue the value being validated (can be <code>null</code> or empty)
+         * @return the validation status (never be <code>null</code>)
+         */
+        ValidationStatus validate( String newValue );
+    }
+}


Property changes on: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/StringValueEditorDialog.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/cndMessages.properties
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/cndMessages.properties	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.jcr.ui/src/org/jboss/tools/modeshape/jcr/ui/cnd/cndMessages.properties	2012-03-23 16:56:24 UTC (rev 39801)
@@ -6,10 +6,14 @@
 
 abstractAttribute = Abstract
 abstractAttributeToolTip = Indicates if the node type definition cannot be instantiated
+acceptDefaultValueDialogMsg = Select OK to accept the changes to the "{0}" default value.
 acceptNamespaceDialogMsg = Select OK to accept the changes to the namespace mapping.
 acceptQualifiedNameDialogMsg = Select OK to accept the changes to the "{0}" qualified name.
+acceptValueConstraintDialogMsg = Select OK to accept the changes to the "{0}" value constraint.
 addChildNodeMenuText = Add Child Node
 addChildNodeToolTip = Add a child node definition to the node type definition
+addDefaultValueMenuText = Add Default Value
+addDefaultValueToolTip = Add a default value to the property definition
 addNamespaceMenuText = Add Namespace
 addNamespaceToolTip = Add a namespace mapping to the CND
 addNodeTypeMenuText = Add Node Type
@@ -20,9 +24,11 @@
 addRequiredTypeToolTip = Add a required type to the child node definition
 addSuperTypeMenuText = Add Supertype
 addSuperTypeToolTip = Add a supertype to the node type definition
+addValueConstraintMenuText = Add Value Constraint
+addValueConstraintToolTip = Add a value constraint to the property definition
 attributesHeaderText = Attributes
 autocreatedAttribute = Autocreated
-autocreatedAttributeToolTip = Indicates if the child node definition is autocreated when it's node type definition is created
+autocreatedAttributeToolTip = Indicates if the child node definition/property definition is autocreated when it's node type definition is created
 childNodeAttributesToolTip = The attributes of a child node definition (autocreated, mandatory, abstract, opv, sns)
 childNodeDefaultTypeLabel = Default Type:
 childNodeDefaultTypeToolTip = The default type of a child node definition
@@ -59,12 +65,23 @@
 cndEditorSourcePageTitle = Source
 cndEditorTitle = JCR Compact Node Definition
 defaultTypeHeaderText = Default Type
+defaultValueDialogCreateMsg = Create Default Value
+defaultValueDialogEditMsg = Edit Default Value
+defaultValueDialogMsg = Specify the default value then select OK when finished.
+defaultValueLabel = Default Value:
 defaultValuesHeaderText = Default Values
+defaultValuesLabel = Default Values:
+defaultValuesToolTip = The default values of a property. Single-valued properties are only allowed one default value while multi-valued properties may have more than one.
+defaultValueToolTip = A default value of a property
 # 0 = child node definition name
 deleteChildNodeDialogMessage = Are you sure you want to delete the "{0}" child node definition?
 deleteChildNodeDialogTitle = Delete Child Node
 deleteChildNodeMenuText = Delete Child Node
 deleteChildNodeToolTip = Delete the selected child node definition from the node type definition
+deleteDefaultValueDialogMessage = Are you sure you want to delete the "{0}" default value?
+deleteDefaultValueDialogTitle = Delete Default Value
+deleteDefaultValueMenuText = Delete Default Value
+deleteDefaultValueToolTip = Delete the selected default value from the property definition
 # 0 = namespace mapping prefix
 deleteNamespaceDialogMessage = Are you sure you want to delete the namespace mapping with prefix "{0}"?
 deleteNamespaceDialogTitle = Delete Namespace
@@ -90,33 +107,60 @@
 deleteSuperTypeDialogTitle = Delete Supertype
 deleteSuperTypeMenuText = Delete Supertype
 deleteSuperTypeToolTip = Delete the selected supertype from the node type definition
+deleteValueConstraintDialogMessage = Are you sure you want to delete the "{0}" value constraint?
+deleteValueConstraintDialogTitle = Delete Value Constraint
+deleteValueConstraintMenuText = Delete Value Constraint
+deleteValueConstraintToolTip = Delete the selected value constraint from the property definition
 editChildNodeMenuText = Edit Child Node
-editChildNodeToolTip = Edit the selected child node definition of the selected node type definition
+editChildNodeToolTip = Edit the selected child node definition of the node type definition
+editDefaultValueMenuText = Edit Default Value
+editDefaultValueToolTip = Edit the selected default value of the property definition
 editNamespaceDialogTitle = Edit Namespace
 editNamespaceMenuText = Edit Namespace
 editNamespaceToolTip = Edit the selected namespace mapping of the CND
 editNodeTypeMenuText = Edit Node Type
 editNodeTypeToolTip = Edit the selected node type definition of the CND
 editPropertyMenuText = Edit Property
-editPropertyToolTip = Edit the selected property definition of the selected node type definition
+editPropertyToolTip = Edit the selected property definition of the node type definition
 editRequiredTypeDialogTitle = Edit Required Type
 editRequiredTypeMenuText = Edit Required Type
-editRequiredTypeToolTip = Edit the selected required type of the selected child node definition
+editRequiredTypeToolTip = Edit the selected required type of the child node definition
 editSuperTypeDialogTitle = Edit Supertype
 editSuperTypeMenuText = Edit Supertype
-editSuperTypeToolTip = Edit the selected supertype of the selected node type definition
+editSuperTypeToolTip = Edit the selected supertype of the node type definition
+editSuperTypeMenuText = Edit Supertype
+editValueConstraintMenuText = Edit Value Constraint
+editValueConstraintToolTip = Edit the selected value constraint of the property definition
+errorAddingChildNode = There was an unexpected error adding child node "{0}" to the node type definition.
+errorAddingDefaultValue = There was an unexpected error adding default value "{0}" to the property definition.
 errorAddingNamespaceMapping = There was an unexpected error adding namespace mapping "{0}" to the CND.
+errorAddingNodeType = There was an unexpected error adding node type "{0}" to the CND.
+errorAddingProperty = There was an unexpected error adding property "{0}" to the node type definition.
 errorAddingRequiredType = There was an unexpected error adding required type "{0}" to the child node definition.
 errorAddingSupertype = There was an unexpected error adding supertype "{0}" to the CND.
+errorAddingValueConstraint = There was an unexpected error adding value constraint "{0}" to the property definition.
+errorDeletingChildNode = There was an unexpected error deleting child node "{0}" from the node type definition.
+errorDeletingDefaultValue = There was an unexpected error deleting default value "{0}" from the property definition.
+errorDeletingNamespace = There was an unexpected error deleting namespace with prefix "{0}" from the CND.
+errorDeletingNodeType = There was an unexpected error deleting node type definition "{0}" from the CND.
+errorDeletingProperty = There was an unexpected error deleting property "{0}" from the node type definition.
+errorDeletingSupertype = There was an unexpected error supertype "{0}" from the node type definition.
+errorDeletingValueConstraint = There was an unexpected error deleting value constraint "{0}" from the property definition.
+errorEditingChildNode = There was an unexpected error updating child node "{0}" to the node type definition.\nThe remove command result: {1}. The add command result: {2}.
+errorEditingDefaultValue = There was an unexpected error updating default value "{0}" to the property definition.\nThe remove command result: {1}. The add command result: {2}.
 errorEditingNamespaceMapping = There was an unexpected error updating namespace mapping "{0}" to the CND.\nThe remove command result: {1}. The add command result: {2}.
+errorEditingProperty = There was an unexpected error updating property "{0}" to the node type definition.\nThe remove command result: {1}. The add command result: {2}.
 errorEditingRequiredType = There was an unexpected error updating required type "{0}" to the CND.\nThe remove command result: {1}. The add command result: {2}.
 errorEditingSupertype = There was an unexpected error updating supertype "{0}" to the CND.\nThe remove command result: {1}. The add command result: {2}.
+errorEditingValueConstraint = There was an unexpected error updating value constraint "{0}" to the property definition.\nThe remove command result: {1}. The add command result: {2}.
 errorOpeningCndEditor = There was a problem creating the CND editor.
 mandatoryAttribute = Mandatory
-mandatoryAttributeToolTip = Indicates if the child node must exist
+mandatoryAttributeToolTip = Indicates if the child node/property must exist
 missingValue = <missing>
 mixinAttribute = Mixin
 mixinAttributeToolTip = Indicates if the node type definition is a mixin and not a primary node type
+multipleAttribute = Multiple
+multipleAttributeToolTip = Indicates if the property is multi-valued
 nameLabel = Name:
 nameHeaderText = Name
 namespaceDialogMsg = Enter a unique prefix and a unique URI.
@@ -124,30 +168,39 @@
 namespaceLabel = Namespace:
 namespacePrefixHeaderText = Prefix
 namespacePrefixLabel = Prefix:
-namespacePrefixToolTip = The prefix of the namespace mapping. Must be unique within a CND.
+namespacePrefixToolTip = The prefix of the namespace mapping. Must be unique within a CND
 namespaceUriHeaderText = URI
-namespaceUriToolTip = The URI of the namespace mapping. Must be unique with a CND.
+namespaceUriToolTip = The URI of the namespace mapping. Must be unique with a CND
 newNamespaceDialogTitle = New Namespace
+newNodeTypeDialogTitle = New Node Type
 newRequiredTypeDialogTitle = New Required Type
 newSuperTypeDialogTitle = New Supertype
 nodeTypeNamePatternMessage = enter name pattern
 nodeTypeNameHeaderText = Node Type Name
 nodeTypeNameToolTip = The name of the node type definition
+noFullTextAttribute = Not Full Text Searchable
+noFullTextAttributeToolTip = Indicates if the property does not support full text search
 noNameQualifierChoice = <no qualifier>
+noQueryOrderAttribute = Not Query Orderable
+noQueryOrderAttributeToolTip = Indicates if query results of this property cannot be ordered
 onParentVersionLabel = On Parent Version:
-onParentVersionToolTip = Indicates what happens to the child node when the parent is created
+onParentVersionToolTip = Indicates what happens to the child node/property when the parent is created
 orderableAttribute = Orderable
 orderableAttributeToolTip = Indicates if the node type definition's are ordered
 propertyAttributesToolTip = The attributes of a property definition (autocreated, mandatory, multiple, nofulltext, noqueryorder, abstract, opv, queryops)
 propertyDefaultValuesToolTip = The default values of a property definition
+propertyDialogCreateTitle = Create Property
+propertyDialogEditTitle = Edit Property
+propertyDialogMsg = Specify property definition properties then select OK when finished.
+propertyDialogTitle = Property Definition Editor
 propertyNameToolTip = The name or identifier of the property definition
 propertyTypeToolTip = The data type of the property definition
 propertyValueConstraintsToolTip = The value constraints of a property definition
 protectedAttribute = Protected
-protectedAttributeToolTip = Indicates if child nodes of this type are protected from being deleted.
+protectedAttributeToolTip = Indicates if child node/property is protected from being deleted
 qualifiedNameDialogMsg = Select a qualifier and edit the name value of the {0}.
 qualifiedNameDialogTitle = Qualified Name Editor
-qualifierLabel = Qualifier:
+qualifierLabel = Namespace:
 queryableAttribute = Queryable
 queryableAttributeToolTip = Indicates if the child node definition supports siblings of the same name
 requiredTypesHeaderText = Required Types
@@ -155,9 +208,18 @@
 sameNamedSiblingsAttribute = Same Named Siblings
 sameNamedSiblingsAttributeToolTip = Indicates if the node type can be queried
 supertypesLabel = Supertypes:
+supertypesToolTip = The supertypes (node types and mixins) whose property definitions and child node definitions are inherited
 typeHeaderText = Type
+typeLabel = Type:
 unqualifiedNameToolTip = The name part of the qualified name (cannot be empty)
 validQualifiersToolTip = The qualifiers known to this CND
+valueConstraintDialogCreateMsg = Create Value Constraint
+valueConstraintDialogEditMsg = Edit Value Constraint
+valueConstraintDialogMsg = Specify the value constraint then select OK when finished.
+valueConstraintLabel = Value Constraint:
 valueConstraintsHeaderText = Value Constraints
+valueConstraintsLabel = Value Constraints:
+valueConstraintsToolTip = The value constraints of a property are used to limit the allowed values
+valueConstraintToolTip = A value constraint is used to limit the allowed values of a property
+valueEditorDialogTitle = Value Editor
 
-

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/UiUtils.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/UiUtils.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/UiUtils.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -7,6 +7,9 @@
  */
 package org.jboss.tools.modeshape.ui;
 
+import java.util.Collection;
+import java.util.Iterator;
+
 import org.eclipse.jface.viewers.CellLabelProvider;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.viewers.TableViewerColumn;
@@ -23,6 +26,11 @@
     public static final String EMPTY_STRING = ""; //$NON-NLS-1$
 
     /**
+     * A delimiter used to join a collection of object string representations. Default value is "{@value} ".
+     */
+    public static final String DEFAULT_JOIN_DELIMITER = ","; //$NON-NLS-1$
+
+    /**
      * The column will be packed using the header text.
      * 
      * @param viewerColumn the viewer column (cannot be <code>null</code>)
@@ -58,6 +66,42 @@
     }
 
     /**
+     * An item within the items that are <code>null</code> are treated like an empty string. If a delimiter is not passed in the
+     * {@link #DEFAULT_JOIN_DELIMITER default delimiter} is used.
+     * 
+     * @param items the items whose string representation are being joined (cannot be <code>null</code>)
+     * @param delimiter the delimiter separating the items (can be <code>null</code> or empty)
+     * @return the string representation of each item separated by the specified delimiter (never <code>null</code>)
+     * @throws IllegalArgumentException if items is <code>null</code>
+     */
+    public static String join( Collection<?> items,
+                               String delimiter ) {
+        if (items == null) {
+            throw new IllegalArgumentException("items is null"); //$NON-NLS-1$
+        }
+
+        delimiter = (((delimiter == null) || delimiter.isEmpty()) ? DEFAULT_JOIN_DELIMITER : delimiter);
+        StringBuilder builder = new StringBuilder();
+
+        for (Iterator<?> itr = items.iterator(); itr.hasNext();) {
+            Object item = itr.next();
+
+            if (item == null) {
+                item = EMPTY_STRING;
+            }
+
+            builder.append(item.toString());
+
+            // add delimiter
+            if (itr.hasNext()) {
+                builder.append(delimiter);
+            }
+        }
+
+        return builder.toString();
+    }
+
+    /**
      * @param viewers the viewers whose columns will be packed (cannot be <code>null</code>)
      */
     public static void pack( final TableViewer... viewers ) {

Modified: trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/actions/DelegateAction.java
===================================================================
--- trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/actions/DelegateAction.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/plugins/org.jboss.tools.modeshape.ui/src/org/jboss/tools/modeshape/ui/actions/DelegateAction.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -27,25 +27,46 @@
      * The delegate action (never <code>null</code>).
      */
     private final IAction delegate;
+    
+    private final boolean styleOverridden;
 
     /**
      * @param delegate the delegate action (cannot be <code>null</code>)
      */
     public DelegateAction( final IAction delegate ) {
         this.delegate = delegate;
+        this.styleOverridden = false;
     }
 
     /**
-     * @param text
-     * @param delegate
+     * Overrides the delegate action's text.
+     * 
+     * @param text the action text (can be <code>null</code> or empty)
+     * @param delegate the action delegate (cannot be <code>null</code>)
      */
     public DelegateAction( final String text,
                            final IAction delegate ) {
         super(text);
         this.delegate = delegate;
+        this.styleOverridden = false;
     }
 
     /**
+     * Overrides the delegate action's text and style.
+     * 
+     * @param text the action text (can be <code>null</code> or empty)
+     * @param style the action style
+     * @param delegate the action delegate (cannot be <code>null</code>)
+     */
+    public DelegateAction( final String text,
+                           final int style,
+                           final IAction delegate ) {
+        super(text, style);
+        this.delegate = delegate;
+        this.styleOverridden = true;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see org.eclipse.jface.action.IAction#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
@@ -62,7 +83,7 @@
      */
     @Override
     public int getAccelerator() {
-        if (super.getAccelerator() == -1) {
+        if (super.getAccelerator() == 0) {
             return this.delegate.getAccelerator();
         }
 
@@ -188,11 +209,11 @@
      */
     @Override
     public int getStyle() {
-        if (super.getStyle() == IAction.AS_PUSH_BUTTON) {
-            return this.delegate.getStyle();
+        if (this.styleOverridden) {
+            return super.getStyle();
         }
 
-        return super.getStyle();
+        return this.delegate.getStyle();
     }
 
     /**
@@ -211,7 +232,31 @@
 
     /**
      * {@inheritDoc}
+     *
+     * @see org.eclipse.jface.action.Action#isChecked()
+     */
+    @Override
+    public boolean isChecked() {
+        if (this.styleOverridden) {
+            return super.isChecked();
+        }
+
+        return this.delegate.isChecked();
+    }
+    
+    /**
+     * {@inheritDoc}
      * 
+     * @see org.eclipse.jface.action.Action#isEnabled()
+     */
+    @Override
+    public boolean isEnabled() {
+        return this.delegate.isEnabled();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see org.eclipse.jface.action.IAction#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
      */
     @Override

Modified: trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/CndValidatorTest.java
===================================================================
--- trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/CndValidatorTest.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/CndValidatorTest.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -38,30 +38,30 @@
     @Test
     public void childNodeDefinitionWithEmptyNameShouldBeAnError() {
         this.childNodeDefinition.setName(null);
-        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition).isError());
+        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition, null).isError());
 
         this.childNodeDefinition.setName(Utils.EMPTY_STRING);
-        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition).isError());
+        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition, null).isError());
     }
 
     @Test
     public void childNodeDefinitionWithInvalidDefaultTypeNameShouldBeAnError() {
         this.childNodeDefinition.setName("name"); //$NON-NLS-1$
         this.childNodeDefinition.setDefaultPrimaryTypeName("missingName:"); //$NON-NLS-1$
-        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition).isError());
+        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition, null).isError());
     }
 
     @Test
     public void childNodeDefinitionWithInvalidNameShouldBeAnError() {
         this.childNodeDefinition.setName("invalid/name"); //$NON-NLS-1$
-        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition).isError());
+        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition, null).isError());
     }
 
     @Test
     public void childNodeDefinitionWithInvalidRequiredTypeNameShouldBeAnError() {
         this.childNodeDefinition.setName("name"); //$NON-NLS-1$
         this.childNodeDefinition.addRequiredType("missingName:"); //$NON-NLS-1$
-        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition).isError());
+        assertTrue(CndValidator.validateChildNodeDefinition(this.childNodeDefinition, null).isError());
     }
 
     @Test
@@ -210,10 +210,10 @@
     @Test
     public void propertyDefinitionWithEmptyNameShouldNotBeValid() {
         this.propertyDefinition.setName(null);
-        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition).isError());
+        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition, null).isError());
 
         this.propertyDefinition.setName(Utils.EMPTY_STRING);
-        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition).isError());
+        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition, null).isError());
     }
 
     @Test
@@ -222,13 +222,13 @@
         this.propertyDefinition.setType(PropertyType.LONG);
         this.propertyDefinition.addDefaultValue("notALongValue"); //$NON-NLS-1$
 
-        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition).isError());
+        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition, null).isError());
     }
 
     @Test
     public void propertyDefinitionWithInvalidNameShouldBeAnError() {
         this.propertyDefinition.setName("invalid/name"); //$NON-NLS-1$
-        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition).isError());
+        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition, null).isError());
     }
 
     @Test
@@ -237,7 +237,7 @@
         this.propertyDefinition.addDefaultValue("defaultValue1"); //$NON-NLS-1$
         this.propertyDefinition.addDefaultValue("defaultValue2"); //$NON-NLS-1$
 
-        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition).isError());
+        assertTrue(CndValidator.validatePropertyDefinition(this.propertyDefinition, null).isError());
     }
 
     @Test

Modified: trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/Constants.java
===================================================================
--- trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/Constants.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/Constants.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -10,6 +10,8 @@
 import java.util.ArrayList;
 import java.util.Collection;
 
+import javax.jcr.PropertyType;
+
 import org.jboss.tools.modeshape.jcr.cnd.CndElement.NotationType;
 import org.jboss.tools.modeshape.jcr.cnd.CndNotationPreferences.Preference;
 import org.jboss.tools.modeshape.jcr.cnd.attributes.Abstract;
@@ -25,6 +27,7 @@
 import org.jboss.tools.modeshape.jcr.cnd.attributes.NoQueryOrder;
 import org.jboss.tools.modeshape.jcr.cnd.attributes.Orderable;
 import org.jboss.tools.modeshape.jcr.cnd.attributes.PrimaryItem;
+import org.jboss.tools.modeshape.jcr.cnd.attributes.PropertyValue;
 import org.jboss.tools.modeshape.jcr.cnd.attributes.Protected;
 import org.jboss.tools.modeshape.jcr.cnd.attributes.QueryOperators;
 import org.jboss.tools.modeshape.jcr.cnd.attributes.QueryOperators.QueryOperator;
@@ -215,24 +218,27 @@
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_ELEMENT_DELIMITER) + QUALIFIED_NAME2
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_ELEMENT_DELIMITER) + QUALIFIED_NAME3;
 
+    String VALUE_CONSTRAINT1 = "(19|20)\\d{2}"; //$NON-NLS-1$
+    String VALUE_CONSTRAINT2 = "[$]\\d{1,3}[,]?\\d{3}([.]\\d{2})?"; //$NON-NLS-1$
+    String VALUE_CONSTRAINT3 = "[1,5]"; //$NON-NLS-1$
     String VALUE_CONSTRAINTS_VARIANT = ValueConstraints.NOTATION_PREFIX
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_PREFIX_END_DELIMITER) + VARIANT;
     String VALUE_CONSTRAINTS_ONE_ITEM_FORM = ValueConstraints.NOTATION_PREFIX
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_PREFIX_END_DELIMITER)
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_QUOTE_CHAR)
-            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + ITEM_ONE
+            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + VALUE_CONSTRAINT1
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER)
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_QUOTE_CHAR);
     String VALUE_CONSTRAINTS_THREE_ITEM_FORM = ValueConstraints.NOTATION_PREFIX
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_PREFIX_END_DELIMITER)
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_QUOTE_CHAR)
-            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + ITEM_ONE
+            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + VALUE_CONSTRAINT1
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER)
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_ELEMENT_DELIMITER)
-            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + ITEM_TWO
+            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + VALUE_CONSTRAINT2
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER)
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_ELEMENT_DELIMITER)
-            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + ITEM_THREE
+            + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER) + VALUE_CONSTRAINT3
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.VALUE_CONSTRAINTS_ITEM_QUOTE_CHARACTER)
             + CndNotationPreferences.DEFAULT_PREFERENCES.get(Preference.ATTRIBUTE_LIST_QUOTE_CHAR);
 
@@ -275,5 +281,17 @@
             return qualifiers;
         }
 
+        public static String[] getDefaultQueryOperators() {
+            return new String[] { OPERATOR_ONE.toString(), OPERATOR_TWO.toString(), OPERATOR_THREE.toString() };
+        }
+
+        public static javax.jcr.Value[] getDefaultStringValues() {
+            return new PropertyValue[] { new PropertyValue(PropertyType.STRING, ITEM_ONE),
+                    new PropertyValue(PropertyType.STRING, ITEM_TWO), new PropertyValue(PropertyType.STRING, ITEM_THREE) };
+        }
+
+        public static String[] getDefaultValueConstraints() {
+            return new String[] { VALUE_CONSTRAINT1, VALUE_CONSTRAINT2, VALUE_CONSTRAINT3 };
+        }
     }
 }

Modified: trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinitionTest.java
===================================================================
--- trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinitionTest.java	2012-03-23 14:57:46 UTC (rev 39800)
+++ trunk/modeshape/tests/org.jboss.tools.modeshape.jcr.test/src/org/jboss/tools/modeshape/jcr/cnd/PropertyDefinitionTest.java	2012-03-23 16:56:24 UTC (rev 39801)
@@ -39,157 +39,168 @@
     }
 
     @Test
-    public void shouldNotHaveDefaultValuesAfterConstruction() {
-        assertEquals(0, this.propDefn.getDefaultValues().length);
-    }
+    public void copiesShouldBeEqual() {
+        PropertyDefinition thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldNotHaveValueConstraintsAfterConstruction() {
-        assertEquals(0, this.propDefn.getValueConstraints().length);
-    }
+        this.propDefn.setAvailableQueryOperators(Constants.Helper.getDefaultQueryOperators());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldNotHaveNameAfterConstruction() {
-        assertTrue(Utils.isEmpty(this.propDefn.getName()));
-    }
+        this.propDefn.setAutoCreated(!this.propDefn.isAutoCreated());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldAddDefaultValue() {
-        final String VALUE = "value"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addDefaultValue(VALUE));
-        assertEquals(1, this.propDefn.getDefaultValues().length);
-        assertEquals(VALUE, this.propDefn.getDefaultValuesAsStrings().iterator().next());
-    }
+        this.propDefn.setDefaultValues(Constants.Helper.getDefaultStringValues());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldRemoveDefaultValue() {
-        final String VALUE = "value"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addDefaultValue(VALUE));
-        assertTrue(this.propDefn.removeDefaultValue(VALUE));
-        assertEquals(0, this.propDefn.getDefaultValues().length);
-    }
+        this.propDefn.setFullTextSearchable(!this.propDefn.isFullTextSearchable());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldNotRemoveDefaultValueThatDoesNotExist() {
-        assertFalse(this.propDefn.removeDefaultValue("defaultValueDoesNotExist")); //$NON-NLS-1$
-    }
+        this.propDefn.setMandatory(!this.propDefn.isMandatory());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldReceiveEventAfterRemovingDefaultValue() {
-        final String VALUE = "value"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addDefaultValue(VALUE));
+        this.propDefn.setMultiple(!this.propDefn.isMultiple());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
+        this.propDefn.setName(Constants.QUALIFIED_NAME1.get());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-        assertTrue(this.propDefn.removeDefaultValue(VALUE));
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.DEFAULT_VALUES.toString(), l.getPropertyName());
-        assertEquals(VALUE, l.getOldValue());
-        assertNull(l.getNewValue());
-    }
+        this.propDefn.setOnParentVersion(OnParentVersion.COMPUTE.asJcrValue());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldReceiveEventAfterAddingDefaultValue() {
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
+        this.propDefn.setProtected(!this.propDefn.isProtected());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-        final String VALUE = "value"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addDefaultValue(VALUE));
+        this.propDefn.setQueryOrderable(!this.propDefn.isQueryOrderable());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
 
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.DEFAULT_VALUES.toString(), l.getPropertyName());
-        assertEquals(VALUE, l.getNewValue());
-        assertNull(l.getOldValue());
+        this.propDefn.setRequiredType(PropertyType.BINARY.asJcrValue());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setValueConstraints(Constants.Helper.getDefaultValueConstraints());
+        thatPropDefn = PropertyDefinition.copy(this.propDefn);
+        assertEquals(this.propDefn, thatPropDefn);
     }
 
     @Test
-    public void shouldNotReceiveEventAfterUnregistering() {
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
-        assertTrue(this.propDefn.removeListener(l));
+    public void differentInstancesWithSameValuesShouldBeEqual() {
+        final PropertyDefinition thatPropDefn = new PropertyDefinition();
+        assertEquals(this.propDefn, thatPropDefn);
 
-        final String VALUE = "value"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addDefaultValue(VALUE));
+        this.propDefn.setAvailableQueryOperators(Constants.Helper.getDefaultQueryOperators());
+        thatPropDefn.setAvailableQueryOperators(this.propDefn.getAvailableQueryOperators());
+        assertEquals(this.propDefn, thatPropDefn);
 
-        assertEquals(0, l.getCount());
-    }
+        this.propDefn.setAutoCreated(!this.propDefn.isAutoCreated());
+        thatPropDefn.setAutoCreated(this.propDefn.isAutoCreated());
+        assertEquals(this.propDefn, thatPropDefn);
 
-    @Test
-    public void shouldNotAddSameDefaultValue() {
-        final String VALUE = "value"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addDefaultValue(VALUE));
-        assertFalse(this.propDefn.addDefaultValue(VALUE));
+        this.propDefn.setDefaultValues(Constants.Helper.getDefaultStringValues());
+        thatPropDefn.setDefaultValues(this.propDefn.getDefaultValues());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setFullTextSearchable(!this.propDefn.isFullTextSearchable());
+        thatPropDefn.setFullTextSearchable(this.propDefn.isFullTextSearchable());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setMandatory(!this.propDefn.isMandatory());
+        thatPropDefn.setMandatory(this.propDefn.isMandatory());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setMultiple(!this.propDefn.isMultiple());
+        thatPropDefn.setMultiple(this.propDefn.isMultiple());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setName(Constants.QUALIFIED_NAME1.get());
+        thatPropDefn.setName(this.propDefn.getName());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setOnParentVersion(OnParentVersion.COMPUTE.asJcrValue());
+        thatPropDefn.setOnParentVersion(this.propDefn.getOnParentVersion());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setProtected(!this.propDefn.isProtected());
+        thatPropDefn.setProtected(this.propDefn.isProtected());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setQueryOrderable(!this.propDefn.isQueryOrderable());
+        thatPropDefn.setQueryOrderable(this.propDefn.isQueryOrderable());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setRequiredType(PropertyType.BINARY.asJcrValue());
+        thatPropDefn.setRequiredType(this.propDefn.getRequiredType());
+        assertEquals(this.propDefn, thatPropDefn);
+
+        this.propDefn.setValueConstraints(Constants.Helper.getDefaultValueConstraints());
+        thatPropDefn.setValueConstraints(this.propDefn.getValueConstraints());
+        assertEquals(this.propDefn, thatPropDefn);
     }
 
     @Test
-    public void shouldNotUnregisterAnUnregisteredListener() {
-        Listener l = new Listener();
-        assertFalse(this.propDefn.removeListener(l));
+    public void differentInstancesWithSameValuesShouldHaveSameHashCode() {
+        assertEquals(this.propDefn.hashCode(), new PropertyDefinition().hashCode());
     }
 
     @Test
-    public void shouldNotRegisterAnAlreadyRegisteredListener() {
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
-        assertFalse(this.propDefn.addListener(l));
+    public void onParentVersionDefaultValueShouldBeCopy() {
+        assertEquals(OnParentVersion.COPY, OnParentVersion.DEFAULT_VALUE);
     }
 
     @Test
-    public void shouldAddValueConstraint() {
-        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
-        assertEquals(1, this.propDefn.getValueConstraints().length);
-        assertEquals(CONSTRAINT, this.propDefn.getValueConstraints()[0]);
+    public void onParentVersionShouldBeSetToDefaultAfterConstruction() {
+        assertTrue(this.propDefn.getOnParentVersion() == OnParentVersion.DEFAULT_VALUE.asJcrValue());
     }
 
     @Test
-    public void shouldReceiveEventAfterAddingValueConstraint() {
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
-
-        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
-
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.VALUE_CONSTRAINTS.toString(), l.getPropertyName());
-        assertEquals(CONSTRAINT, l.getNewValue());
-        assertNull(l.getOldValue());
+    public void propertyTypeDefaultValueShouldBeString() {
+        assertEquals(PropertyType.STRING, PropertyType.DEFAULT_VALUE);
     }
 
     @Test
-    public void shouldNotAddSameValueConstraint() {
-        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
-        assertFalse(this.propDefn.addValueConstraint(CONSTRAINT));
+    public void propertyTypeShouldBeSetToDefaultAfterConstruction() {
+        assertTrue(this.propDefn.getType() == PropertyType.DEFAULT_VALUE);
+        assertEquals(PropertyType.DEFAULT_VALUE.asJcrValue(), this.propDefn.getRequiredType());
     }
 
     @Test
-    public void shouldRemoveValueConstraint() {
-        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
-        assertTrue(this.propDefn.removeValueConstraint(CONSTRAINT));
-        assertEquals(0, this.propDefn.getValueConstraints().length);
+    public void shouldAddDefaultValue() {
+        final String VALUE = "value"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addDefaultValue(VALUE));
+        assertEquals(1, this.propDefn.getDefaultValues().length);
+        assertEquals(VALUE, this.propDefn.getDefaultValuesAsStrings().iterator().next());
     }
 
     @Test
-    public void shouldNotRemoveValueConstraintThatDoesNotExist() {
-        assertFalse(this.propDefn.removeValueConstraint("valueConstraintdoesNotExist")); //$NON-NLS-1$
+    public void shouldAddQueryOperator() {
+        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
+        assertTrue(this.propDefn.addQueryOperator(OP));
+        assertEquals(1, this.propDefn.getAvailableQueryOperators().length);
+        assertEquals(OP.toString(), this.propDefn.getAvailableQueryOperators()[0]);
     }
 
     @Test
-    public void shouldReceiveEventAfterRemovingValueConstraint() {
+    public void shouldAddValueConstraint() {
         final String CONSTRAINT = "constraint"; //$NON-NLS-1$
         assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
+        assertEquals(1, this.propDefn.getValueConstraints().length);
+        assertEquals(CONSTRAINT, this.propDefn.getValueConstraints()[0]);
+    }
 
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
+    @Test
+    public void shouldAllowNullEmptyName() {
+        this.propDefn.setName(null);
+        this.propDefn.setName(""); //$NON-NLS-1$
 
-        assertTrue(this.propDefn.removeValueConstraint(CONSTRAINT));
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.VALUE_CONSTRAINTS.toString(), l.getPropertyName());
-        assertEquals(CONSTRAINT, l.getOldValue());
-        assertNull(l.getNewValue());
     }
 
     @Test
@@ -345,31 +356,36 @@
     }
 
     @Test
-    public void shouldNotClearDefaultValuesWhenEmpty() {
-        assertFalse(this.propDefn.clearDefaultValues());
+    public void shouldClearValueConstraints() {
+        assertTrue(this.propDefn.addValueConstraint("value")); //$NON-NLS-1$
+        assertTrue(this.propDefn.clearValueConstraints());
+        assertEquals(0, this.propDefn.getValueConstraints().length);
     }
 
     @Test
-    public void shouldReceiveEventAfterClearingDefaultValues() {
+    public void shouldNotAddDuplicateQueryOperator() {
+        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
+        assertTrue(this.propDefn.addQueryOperator(OP));
+        assertFalse(this.propDefn.addQueryOperator(OP));
+    }
+
+    @Test
+    public void shouldNotAddSameDefaultValue() {
         final String VALUE = "value"; //$NON-NLS-1$
         assertTrue(this.propDefn.addDefaultValue(VALUE));
-        Collection<String> oldValue = Collections.singletonList(VALUE);
+        assertFalse(this.propDefn.addDefaultValue(VALUE));
+    }
 
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
-
-        assertTrue(this.propDefn.clearDefaultValues());
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.DEFAULT_VALUES.toString(), l.getPropertyName());
-        assertNull(l.getNewValue());
-        assertEquals(oldValue, l.getOldValue());
+    @Test
+    public void shouldNotAddSameValueConstraint() {
+        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
+        assertFalse(this.propDefn.addValueConstraint(CONSTRAINT));
     }
 
     @Test
-    public void shouldClearValueConstraints() {
-        assertTrue(this.propDefn.addValueConstraint("value")); //$NON-NLS-1$
-        assertTrue(this.propDefn.clearValueConstraints());
-        assertEquals(0, this.propDefn.getValueConstraints().length);
+    public void shouldNotClearDefaultValuesWhenEmpty() {
+        assertFalse(this.propDefn.clearDefaultValues());
     }
 
     @Test
@@ -378,162 +394,192 @@
     }
 
     @Test
-    public void shouldReceiveEventAfterClearingValueConstraints() {
-        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
-        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
-        Collection<String> oldValue = Collections.singletonList(CONSTRAINT);
+    public void shouldNotHaveDefaultValuesAfterConstruction() {
+        assertEquals(0, this.propDefn.getDefaultValues().length);
+    }
 
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
+    @Test
+    public void shouldNotHaveNameAfterConstruction() {
+        assertTrue(Utils.isEmpty(this.propDefn.getName()));
+    }
 
-        assertTrue(this.propDefn.clearValueConstraints());
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.VALUE_CONSTRAINTS.toString(), l.getPropertyName());
-        assertNull(l.getNewValue());
-        assertEquals(oldValue, l.getOldValue());
+    @Test
+    public void shouldNotHaveValueConstraintsAfterConstruction() {
+        assertEquals(0, this.propDefn.getValueConstraints().length);
     }
 
     @Test
-    public void shouldSetAutoCreated() {
-        this.propDefn.setAutoCreated(true);
-        assertTrue(this.propDefn.isAutoCreated());
-        assertTrue(this.propDefn.getState(PropertyName.AUTOCREATED) == Value.IS);
+    public void shouldNotReceiveEventAfterUnregistering() {
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
+        assertTrue(this.propDefn.removeListener(l));
 
-        this.propDefn.setAutoCreated(false);
-        assertFalse(this.propDefn.isAutoCreated());
-        assertTrue(this.propDefn.getState(PropertyName.AUTOCREATED) == Value.IS_NOT);
+        final String VALUE = "value"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addDefaultValue(VALUE));
+
+        assertEquals(0, l.getCount());
     }
 
     @Test
-    public void shouldSetFullTextSearchable() {
-        this.propDefn.setFullTextSearchable(true);
-        assertTrue(this.propDefn.isFullTextSearchable());
-        assertTrue(this.propDefn.getState(PropertyName.NO_FULL_TEXT) == Value.IS_NOT);
+    public void shouldNotReceiveEventWhenNameIsNotChanged() {
+        final String NAME = "name"; //$NON-NLS-1$
+        this.propDefn.setName(NAME);
 
-        this.propDefn.setFullTextSearchable(false);
-        assertFalse(this.propDefn.isFullTextSearchable());
-        assertTrue(this.propDefn.getState(PropertyName.NO_FULL_TEXT) == Value.IS);
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
+
+        this.propDefn.setName(NAME); // same value
+        assertEquals(0, l.getCount());
     }
 
     @Test
-    public void shouldSetMandatory() {
-        this.propDefn.setMandatory(true);
-        assertTrue(this.propDefn.isMandatory());
-        assertTrue(this.propDefn.getState(PropertyName.MANDATORY) == Value.IS);
+    public void shouldNotRegisterAnAlreadyRegisteredListener() {
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
+        assertFalse(this.propDefn.addListener(l));
+    }
 
-        this.propDefn.setMandatory(false);
-        assertFalse(this.propDefn.isMandatory());
-        assertTrue(this.propDefn.getState(PropertyName.MANDATORY) == Value.IS_NOT);
+    @Test
+    public void shouldNotRemoveDefaultValueThatDoesNotExist() {
+        assertFalse(this.propDefn.removeDefaultValue("defaultValueDoesNotExist")); //$NON-NLS-1$
     }
 
     @Test
-    public void shouldSetMultiple() {
-        this.propDefn.setMultiple(true);
-        assertTrue(this.propDefn.isMultiple());
-        assertTrue(this.propDefn.getState(PropertyName.MULTIPLE) == Value.IS);
-
-        this.propDefn.setMultiple(false);
-        assertFalse(this.propDefn.isMultiple());
-        assertTrue(this.propDefn.getState(PropertyName.MULTIPLE) == Value.IS_NOT);
+    public void shouldNotRemoveQueryOperatorThatDoesNotExist() {
+        assertFalse(this.propDefn.removeQueryOperator(QueryOperator.GREATER_THAN_EQUALS));
     }
 
     @Test
-    public void shouldSetProtected() {
-        this.propDefn.setProtected(true);
-        assertTrue(this.propDefn.isProtected());
-        assertTrue(this.propDefn.getState(PropertyName.PROTECTED) == Value.IS);
-
-        this.propDefn.setProtected(false);
-        assertFalse(this.propDefn.isProtected());
-        assertTrue(this.propDefn.getState(PropertyName.PROTECTED) == Value.IS_NOT);
+    public void shouldNotRemoveValueConstraintThatDoesNotExist() {
+        assertFalse(this.propDefn.removeValueConstraint("valueConstraintdoesNotExist")); //$NON-NLS-1$
     }
 
     @Test
-    public void shouldSetQueryOrderable() {
-        this.propDefn.setQueryOrderable(true);
-        assertTrue(this.propDefn.isQueryOrderable());
-        assertTrue(this.propDefn.getState(PropertyName.NO_QUERY_ORDER) == Value.IS_NOT);
+    public void shouldNotSetInvalidQueryOperators() {
+        final String GOOD_OP = QueryOperator.EQUALS.toString();
+        final String BAD_OP = "badOp"; //$NON-NLS-1$
+        final String[] NEW_OPERATORS = new String[] { GOOD_OP, BAD_OP };
+        this.propDefn.setAvailableQueryOperators(NEW_OPERATORS);
 
-        this.propDefn.setQueryOrderable(false);
-        assertFalse(this.propDefn.isQueryOrderable());
-        assertTrue(this.propDefn.getState(PropertyName.NO_QUERY_ORDER) == Value.IS);
+        final String[] queryOperators = this.propDefn.getAvailableQueryOperators();
+        assertEquals((NEW_OPERATORS.length - 1), queryOperators.length);
+        assertEquals(NEW_OPERATORS[0], queryOperators[0]);
     }
 
     @Test
-    public void shouldSetName() {
-        final String NAME = "name"; //$NON-NLS-1$
-        this.propDefn.setName(NAME);
-        assertEquals(NAME, this.propDefn.getName());
-
+    public void shouldNotUnregisterAnUnregisteredListener() {
+        final Listener l = new Listener();
+        assertFalse(this.propDefn.removeListener(l));
     }
 
     @Test
-    public void shouldAllowNullEmptyName() {
-        this.propDefn.setName(null);
-        this.propDefn.setName(""); //$NON-NLS-1$
+    public void shouldReceiveEventAfterAddingDefaultValue() {
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
 
+        final String VALUE = "value"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addDefaultValue(VALUE));
+
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.DEFAULT_VALUES.toString(), l.getPropertyName());
+        assertEquals(VALUE, l.getNewValue());
+        assertNull(l.getOldValue());
     }
 
     @Test
-    public void shouldReceiveEventWhenNameIsChanged() {
-        Listener l = new Listener();
+    public void shouldReceiveEventAfterAddingValueConstraint() {
+        final Listener l = new Listener();
         assertTrue(this.propDefn.addListener(l));
 
-        final String NEW_NAME = "name"; //$NON-NLS-1$
-        this.propDefn.setName(NEW_NAME);
+        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
 
-        assertEquals(NEW_NAME, this.propDefn.getName());
         assertEquals(1, l.getCount());
-        assertEquals(PropertyName.NAME.toString(), l.getPropertyName());
-        assertEquals(NEW_NAME, l.getNewValue());
+        assertEquals(PropertyName.VALUE_CONSTRAINTS.toString(), l.getPropertyName());
+        assertEquals(CONSTRAINT, l.getNewValue());
         assertNull(l.getOldValue());
     }
 
     @Test
-    public void shouldNotReceiveEventWhenNameIsNotChanged() {
-        final String NAME = "name"; //$NON-NLS-1$
-        this.propDefn.setName(NAME);
+    public void shouldReceiveEventAfterClearingDefaultValues() {
+        final String VALUE = "value"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addDefaultValue(VALUE));
+        final Collection<String> oldValue = Collections.singletonList(VALUE);
 
-        Listener l = new Listener();
+        final Listener l = new Listener();
         assertTrue(this.propDefn.addListener(l));
 
-        this.propDefn.setName(NAME); // same value
-        assertEquals(0, l.getCount());
+        assertTrue(this.propDefn.clearDefaultValues());
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.DEFAULT_VALUES.toString(), l.getPropertyName());
+        assertNull(l.getNewValue());
+        assertEquals(oldValue, l.getOldValue());
     }
 
     @Test
-    public void onParentVersionShouldBeSetToDefaultAfterConstruction() {
-        assertTrue(this.propDefn.getOnParentVersion() == OnParentVersion.DEFAULT_VALUE.asJcrValue());
+    public void shouldReceiveEventAfterClearingValueConstraints() {
+        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
+        final Collection<String> oldValue = Collections.singletonList(CONSTRAINT);
+
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
+
+        assertTrue(this.propDefn.clearValueConstraints());
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.VALUE_CONSTRAINTS.toString(), l.getPropertyName());
+        assertNull(l.getNewValue());
+        assertEquals(oldValue, l.getOldValue());
     }
 
     @Test
-    public void onParentVersionDefaultValueShouldBeCopy() {
-        assertEquals(OnParentVersion.COPY, OnParentVersion.DEFAULT_VALUE);
+    public void shouldReceiveEventAfterRemovingDefaultValue() {
+        final String VALUE = "value"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addDefaultValue(VALUE));
+
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
+
+        assertTrue(this.propDefn.removeDefaultValue(VALUE));
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.DEFAULT_VALUES.toString(), l.getPropertyName());
+        assertEquals(VALUE, l.getOldValue());
+        assertNull(l.getNewValue());
     }
 
     @Test
-    public void shouldSetOnParentVersionUsingInt() {
-        for (OnParentVersion opv : OnParentVersion.values()) {
-            if (opv != OnParentVersion.VARIANT) {
-                this.propDefn.setOnParentVersion(opv.asJcrValue());
-                assertEquals(opv.asJcrValue(), this.propDefn.getOnParentVersion());
-            }
-        }
+    public void shouldReceiveEventAfterRemovingValueConstraint() {
+        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
+
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
+
+        assertTrue(this.propDefn.removeValueConstraint(CONSTRAINT));
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.VALUE_CONSTRAINTS.toString(), l.getPropertyName());
+        assertEquals(CONSTRAINT, l.getOldValue());
+        assertNull(l.getNewValue());
     }
 
     @Test
-    public void shouldSetOnParentVersionUsingString() {
-        for (OnParentVersion opv : OnParentVersion.values()) {
-            if (opv != OnParentVersion.VARIANT) {
-                assertTrue(this.propDefn.setOnParentVersion(opv.toString()));
-                assertEquals(opv.asJcrValue(), this.propDefn.getOnParentVersion());
-            }
-        }
+    public void shouldReceiveEventWhenNameIsChanged() {
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
+
+        final String NEW_NAME = "name"; //$NON-NLS-1$
+        this.propDefn.setName(NEW_NAME);
+
+        assertEquals(NEW_NAME, this.propDefn.getName());
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.NAME.toString(), l.getPropertyName());
+        assertEquals(NEW_NAME, l.getNewValue());
+        assertNull(l.getOldValue());
     }
 
     @Test
     public void shouldReceiveEventWhenOnParentVersionIsChanged() {
-        Listener l = new Listener();
+        final Listener l = new Listener();
         assertTrue(this.propDefn.addListener(l));
 
         final int OPV = OnParentVersion.COMPUTE.asJcrValue();
@@ -546,39 +592,8 @@
     }
 
     @Test
-    public void propertyTypeShouldBeSetToDefaultAfterConstruction() {
-        assertTrue(this.propDefn.getType() == PropertyType.DEFAULT_VALUE);
-        assertEquals(PropertyType.DEFAULT_VALUE.asJcrValue(), this.propDefn.getRequiredType());
-    }
-
-    @Test
-    public void propertyTypeDefaultValueShouldBeString() {
-        assertEquals(PropertyType.STRING, PropertyType.DEFAULT_VALUE);
-    }
-
-    @Test
-    public void shouldSetPropertyTypeUsingInt() {
-        for (PropertyType type : PropertyType.values()) {
-            if (type != PropertyType.VARIANT) {
-                this.propDefn.setRequiredType(type.asJcrValue());
-                assertEquals(type.asJcrValue(), this.propDefn.getRequiredType());
-            }
-        }
-    }
-
-    @Test
-    public void shouldSetPropertyType() {
-        for (PropertyType type : PropertyType.values()) {
-            if (type != PropertyType.VARIANT) {
-                assertTrue(this.propDefn.setType(type));
-                assertEquals(type.asJcrValue(), this.propDefn.getRequiredType());
-            }
-        }
-    }
-
-    @Test
     public void shouldReceiveEventWhenPropertyTypeIsChanged() {
-        Listener l = new Listener();
+        final Listener l = new Listener();
         assertTrue(this.propDefn.addListener(l));
 
         final PropertyType TYPE = PropertyType.BINARY;
@@ -591,48 +606,69 @@
     }
 
     @Test
-    public void shouldSetValueContraintsWithNull() {
-        this.propDefn.setValueConstraints(null);
-        assertEquals(0, this.propDefn.getValueConstraints().length);
-    }
+    public void shouldReceiveEventWhenQueryOperatorIsAdded() {
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
 
-    @Test
-    public void shouldSetValueContraintsWithEmptyArray() {
-        this.propDefn.setValueConstraints(new String[0]);
-        assertEquals(0, this.propDefn.getValueConstraints().length);
+        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
+        assertTrue(this.propDefn.addQueryOperator(OP));
+
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.QUERY_OPS.toString(), l.getPropertyName());
+        assertEquals(OP, l.getNewValue());
+        assertNull(l.getOldValue());
     }
 
     @Test
-    public void shouldSetValueContraints() {
-        assertTrue(this.propDefn.addValueConstraint("constraintBeingOverridden")); //$NON-NLS-1$
+    public void shouldReceiveEventWhenQueryOperatorIsRemoved() {
+        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
+        assertTrue(this.propDefn.addQueryOperator(OP));
 
-        final String CONSTRAINT1 = "constraint1"; //$NON-NLS-1$
-        final String CONSTRAINT2 = "constraint2"; //$NON-NLS-1$
-        final String CONSTRAINT3 = "constraint3"; //$NON-NLS-1$
-        final String[] NEW_CONSTRAINTS = new String[] { CONSTRAINT1, CONSTRAINT2, CONSTRAINT3 };
-        this.propDefn.setValueConstraints(NEW_CONSTRAINTS);
+        final Listener l = new Listener();
+        assertTrue(this.propDefn.addListener(l));
 
-        String[] constraints = this.propDefn.getValueConstraints();
-        assertEquals(NEW_CONSTRAINTS.length, constraints.length);
-
-        for (int i = 0; i < NEW_CONSTRAINTS.length; ++i) {
-            assertEquals(NEW_CONSTRAINTS[i], constraints[i]);
-        }
+        assertTrue(this.propDefn.removeQueryOperator(OP));
+        assertEquals(1, l.getCount());
+        assertEquals(PropertyName.QUERY_OPS.toString(), l.getPropertyName());
+        assertNull(l.getNewValue());
+        assertEquals(OP, l.getOldValue());
     }
 
     @Test
-    public void shouldSetDefaultValuesWithNull() {
-        this.propDefn.setDefaultValues(null);
+    public void shouldRemoveDefaultValue() {
+        final String VALUE = "value"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addDefaultValue(VALUE));
+        assertTrue(this.propDefn.removeDefaultValue(VALUE));
         assertEquals(0, this.propDefn.getDefaultValues().length);
     }
 
     @Test
-    public void shouldSetDefaultValuesWithEmptyArray() {
-        this.propDefn.setDefaultValues(new javax.jcr.Value[0]);
-        assertEquals(0, this.propDefn.getDefaultValues().length);
+    public void shouldRemoveQueryOperator() {
+        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
+        assertTrue(this.propDefn.addQueryOperator(OP));
+        assertTrue(this.propDefn.removeQueryOperator(OP));
     }
 
     @Test
+    public void shouldRemoveValueConstraint() {
+        final String CONSTRAINT = "constraint"; //$NON-NLS-1$
+        assertTrue(this.propDefn.addValueConstraint(CONSTRAINT));
+        assertTrue(this.propDefn.removeValueConstraint(CONSTRAINT));
+        assertEquals(0, this.propDefn.getValueConstraints().length);
+    }
+
+    @Test
+    public void shouldSetAutoCreated() {
+        this.propDefn.setAutoCreated(true);
+        assertTrue(this.propDefn.isAutoCreated());
+        assertTrue(this.propDefn.getState(PropertyName.AUTOCREATED) == Value.IS);
+
+        this.propDefn.setAutoCreated(false);
+        assertFalse(this.propDefn.isAutoCreated());
+        assertTrue(this.propDefn.getState(PropertyName.AUTOCREATED) == Value.IS_NOT);
+    }
+
+    @Test
     public void shouldSetDefaultValues() {
         assertTrue(this.propDefn.addDefaultValue("defaultValueBeingOverridden")); //$NON-NLS-1$
 
@@ -642,7 +678,7 @@
         final PropertyValue[] NEW_VALUES = new PropertyValue[] { VALUE1, VALUE2, VALUE3 };
         this.propDefn.setDefaultValues(NEW_VALUES);
 
-        javax.jcr.Value[] defaultValues = this.propDefn.getDefaultValues();
+        final javax.jcr.Value[] defaultValues = this.propDefn.getDefaultValues();
         assertEquals(NEW_VALUES.length, defaultValues.length);
 
         for (int i = 0; i < NEW_VALUES.length; ++i) {
@@ -653,71 +689,107 @@
     }
 
     @Test
-    public void shouldSetQueryOperatorsWithNull() {
-        this.propDefn.setAvailableQueryOperators(null);
-        assertEquals(0, this.propDefn.getAvailableQueryOperators().length);
+    public void shouldSetDefaultValuesWithEmptyArray() {
+        this.propDefn.setDefaultValues(new javax.jcr.Value[0]);
+        assertEquals(0, this.propDefn.getDefaultValues().length);
     }
 
     @Test
-    public void shouldSetQueryOperatorsWithEmptyArray() {
-        this.propDefn.setAvailableQueryOperators(new String[0]);
-        assertEquals(0, this.propDefn.getAvailableQueryOperators().length);
+    public void shouldSetDefaultValuesWithNull() {
+        this.propDefn.setDefaultValues(null);
+        assertEquals(0, this.propDefn.getDefaultValues().length);
     }
 
     @Test
-    public void shouldAddQueryOperator() {
-        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
-        assertTrue(this.propDefn.addQueryOperator(OP));
-        assertEquals(1, this.propDefn.getAvailableQueryOperators().length);
-        assertEquals(OP.toString(), this.propDefn.getAvailableQueryOperators()[0]);
+    public void shouldSetFullTextSearchable() {
+        this.propDefn.setFullTextSearchable(true);
+        assertTrue(this.propDefn.isFullTextSearchable());
+        assertTrue(this.propDefn.getState(PropertyName.NO_FULL_TEXT) == Value.IS_NOT);
+
+        this.propDefn.setFullTextSearchable(false);
+        assertFalse(this.propDefn.isFullTextSearchable());
+        assertTrue(this.propDefn.getState(PropertyName.NO_FULL_TEXT) == Value.IS);
     }
 
     @Test
-    public void shouldRemoveQueryOperator() {
-        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
-        assertTrue(this.propDefn.addQueryOperator(OP));
-        assertTrue(this.propDefn.removeQueryOperator(OP));
+    public void shouldSetMandatory() {
+        this.propDefn.setMandatory(true);
+        assertTrue(this.propDefn.isMandatory());
+        assertTrue(this.propDefn.getState(PropertyName.MANDATORY) == Value.IS);
+
+        this.propDefn.setMandatory(false);
+        assertFalse(this.propDefn.isMandatory());
+        assertTrue(this.propDefn.getState(PropertyName.MANDATORY) == Value.IS_NOT);
     }
 
     @Test
-    public void shouldNotRemoveQueryOperatorThatDoesNotExist() {
-        assertFalse(this.propDefn.removeQueryOperator(QueryOperator.GREATER_THAN_EQUALS));
+    public void shouldSetMultiple() {
+        this.propDefn.setMultiple(true);
+        assertTrue(this.propDefn.isMultiple());
+        assertTrue(this.propDefn.getState(PropertyName.MULTIPLE) == Value.IS);
+
+        this.propDefn.setMultiple(false);
+        assertFalse(this.propDefn.isMultiple());
+        assertTrue(this.propDefn.getState(PropertyName.MULTIPLE) == Value.IS_NOT);
     }
 
     @Test
-    public void shouldNotAddDuplicateQueryOperator() {
-        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
-        assertTrue(this.propDefn.addQueryOperator(OP));
-        assertFalse(this.propDefn.addQueryOperator(OP));
+    public void shouldSetName() {
+        final String NAME = "name"; //$NON-NLS-1$
+        this.propDefn.setName(NAME);
+        assertEquals(NAME, this.propDefn.getName());
+
     }
 
     @Test
-    public void shouldReceiveEventWhenQueryOperatorIsAdded() {
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
+    public void shouldSetOnParentVersionUsingInt() {
+        for (final OnParentVersion opv : OnParentVersion.values()) {
+            if (opv != OnParentVersion.VARIANT) {
+                this.propDefn.setOnParentVersion(opv.asJcrValue());
+                assertEquals(opv.asJcrValue(), this.propDefn.getOnParentVersion());
+            }
+        }
+    }
 
-        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
-        assertTrue(this.propDefn.addQueryOperator(OP));
+    @Test
+    public void shouldSetOnParentVersionUsingString() {
+        for (final OnParentVersion opv : OnParentVersion.values()) {
+            if (opv != OnParentVersion.VARIANT) {
+                assertTrue(this.propDefn.setOnParentVersion(opv.toString()));
+                assertEquals(opv.asJcrValue(), this.propDefn.getOnParentVersion());
+            }
+        }
+    }
 
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.QUERY_OPS.toString(), l.getPropertyName());
-        assertEquals(OP, l.getNewValue());
-        assertNull(l.getOldValue());
+    @Test
+    public void shouldSetPropertyType() {
+        for (final PropertyType type : PropertyType.values()) {
+            if (type != PropertyType.VARIANT) {
+                assertTrue(this.propDefn.setType(type));
+                assertEquals(type.asJcrValue(), this.propDefn.getRequiredType());
+            }
+        }
     }
 
     @Test
-    public void shouldReceiveEventWhenQueryOperatorIsRemoved() {
-        final QueryOperator OP = QueryOperator.GREATER_THAN_EQUALS;
-        assertTrue(this.propDefn.addQueryOperator(OP));
+    public void shouldSetPropertyTypeUsingInt() {
+        for (final PropertyType type : PropertyType.values()) {
+            if (type != PropertyType.VARIANT) {
+                this.propDefn.setRequiredType(type.asJcrValue());
+                assertEquals(type.asJcrValue(), this.propDefn.getRequiredType());
+            }
+        }
+    }
 
-        Listener l = new Listener();
-        assertTrue(this.propDefn.addListener(l));
+    @Test
+    public void shouldSetProtected() {
+        this.propDefn.setProtected(true);
+        assertTrue(this.propDefn.isProtected());
+        assertTrue(this.propDefn.getState(PropertyName.PROTECTED) == Value.IS);
 
-        assertTrue(this.propDefn.removeQueryOperator(OP));
-        assertEquals(1, l.getCount());
-        assertEquals(PropertyName.QUERY_OPS.toString(), l.getPropertyName());
-        assertNull(l.getNewValue());
-        assertEquals(OP, l.getOldValue());
+        this.propDefn.setProtected(false);
+        assertFalse(this.propDefn.isProtected());
+        assertTrue(this.propDefn.getState(PropertyName.PROTECTED) == Value.IS_NOT);
     }
 
     @Test
@@ -730,7 +802,7 @@
         final String[] NEW_OPERATORS = new String[] { OP1, OP2, OP3 };
         this.propDefn.setAvailableQueryOperators(NEW_OPERATORS);
 
-        String[] queryOperators = this.propDefn.getAvailableQueryOperators();
+        final String[] queryOperators = this.propDefn.getAvailableQueryOperators();
         assertEquals(NEW_OPERATORS.length, queryOperators.length);
 
         for (int i = 0; i < NEW_OPERATORS.length; ++i) {
@@ -739,15 +811,55 @@
     }
 
     @Test
-    public void shouldNotSetInvalidQueryOperators() {
-        final String GOOD_OP = QueryOperator.EQUALS.toString();
-        final String BAD_OP = "badOp"; //$NON-NLS-1$
-        final String[] NEW_OPERATORS = new String[] { GOOD_OP, BAD_OP };
-        this.propDefn.setAvailableQueryOperators(NEW_OPERATORS);
+    public void shouldSetQueryOperatorsWithEmptyArray() {
+        this.propDefn.setAvailableQueryOperators(new String[0]);
+        assertEquals(0, this.propDefn.getAvailableQueryOperators().length);
+    }
 
-        String[] queryOperators = this.propDefn.getAvailableQueryOperators();
-        assertEquals((NEW_OPERATORS.length - 1), queryOperators.length);
-        assertEquals(NEW_OPERATORS[0], queryOperators[0]);
+    @Test
+    public void shouldSetQueryOperatorsWithNull() {
+        this.propDefn.setAvailableQueryOperators(null);
+        assertEquals(0, this.propDefn.getAvailableQueryOperators().length);
     }
 
+    @Test
+    public void shouldSetQueryOrderable() {
+        this.propDefn.setQueryOrderable(true);
+        assertTrue(this.propDefn.isQueryOrderable());
+        assertTrue(this.propDefn.getState(PropertyName.NO_QUERY_ORDER) == Value.IS_NOT);
+
+        this.propDefn.setQueryOrderable(false);
+        assertFalse(this.propDefn.isQueryOrderable());
+        assertTrue(this.propDefn.getState(PropertyName.NO_QUERY_ORDER) == Value.IS);
+    }
+
+    @Test
+    public void shouldSetValueContraints() {
+        assertTrue(this.propDefn.addValueConstraint("constraintBeingOverridden")); //$NON-NLS-1$
+
+        final String CONSTRAINT1 = "constraint1"; //$NON-NLS-1$
+        final String CONSTRAINT2 = "constraint2"; //$NON-NLS-1$
+        final String CONSTRAINT3 = "constraint3"; //$NON-NLS-1$
+        final String[] NEW_CONSTRAINTS = new String[] { CONSTRAINT1, CONSTRAINT2, CONSTRAINT3 };
+        this.propDefn.setValueConstraints(NEW_CONSTRAINTS);
+
+        final String[] constraints = this.propDefn.getValueConstraints();
+        assertEquals(NEW_CONSTRAINTS.length, constraints.length);
+
+        for (int i = 0; i < NEW_CONSTRAINTS.length; ++i) {
+            assertEquals(NEW_CONSTRAINTS[i], constraints[i]);
+        }
+    }
+
+    @Test
+    public void shouldSetValueContraintsWithEmptyArray() {
+        this.propDefn.setValueConstraints(new String[0]);
+        assertEquals(0, this.propDefn.getValueConstraints().length);
+    }
+
+    @Test
+    public void shouldSetValueContraintsWithNull() {
+        this.propDefn.setValueConstraints(null);
+        assertEquals(0, this.propDefn.getValueConstraints().length);
+    }
 }



More information about the jbosstools-commits mailing list