Antoine Taillefer | 9 Feb 20:31

nuxeo-diff: NXP-8596: First step: add DiffDisplayService to allow diffDisplay contributions

Description:
    NXP-8596: First step: add DiffDisplayService to allow diffDisplay contributions

Repository: nuxeo-diff
Branch: master
Author: Antoine Taillefer <ataillefer <at> nuxeo.com>
Date: 2012-02-09T11:31:18-08:00
URL: https://github.com/nuxeo/nuxeo-diff/commit/3af23941d1404a44eb8d140d3dcea138396099a3
JIRA: https://jira.nuxeo.com/browse/NXP-8596
Files:
A src/main/java/org/nuxeo/ecm/diff/model/DiffBlockDefinition.java
A src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayBlock.java
A src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayField.java
A src/main/java/org/nuxeo/ecm/diff/model/DiffFieldDefinition.java
A src/main/java/org/nuxeo/ecm/diff/model/impl/ComplexDiffDisplayField.java
A src/main/java/org/nuxeo/ecm/diff/model/impl/DiffBlockDefinitionImpl.java
A src/main/java/org/nuxeo/ecm/diff/model/impl/DiffDisplayBlockImpl.java
A src/main/java/org/nuxeo/ecm/diff/model/impl/DiffFieldDefinitionImpl.java
A src/main/java/org/nuxeo/ecm/diff/model/impl/ListDiffDisplayField.java
A src/main/java/org/nuxeo/ecm/diff/model/impl/SimpleDiffDisplayField.java
A src/main/java/org/nuxeo/ecm/diff/service/DiffDisplayService.java
A src/main/java/org/nuxeo/ecm/diff/service/impl/DiffBlockDescriptor.java
A src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayDescriptor.java
A src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayServiceImpl.java
A src/main/java/org/nuxeo/ecm/diff/service/impl/DiffFieldDescriptor.java
A src/main/java/org/nuxeo/ecm/diff/web/DiffActionsBean.java
A src/main/resources/OSGI-INF/diff-actions-contrib.xml
A src/main/resources/OSGI-INF/diff-display-service.xml
A src/main/resources/OSGI-INF/diff-widgets-contrib.xml
A src/test/java/org/nuxeo/ecm/diff/service/TestDiffDisplayService.java
A src/test/resources/OSGI-INF/test-diff-display-contrib.xml
A src/test/resources/OSGI-INF/test-diff-widgets-contrib.xml
D src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffDisplayService.java
D src/main/java/org/nuxeo/ecm/diff/service/ComplexItemsDescriptor.java
D src/main/java/org/nuxeo/ecm/diff/service/impl/DocumentDiffDisplayServiceImpl.java
D src/main/java/org/nuxeo/ecm/diff/web/DocumentDiffActionsBean.java
D src/main/resources/OSGI-INF/document-diff-actions-contrib.xml
D src/main/resources/OSGI-INF/document-diff-display-service.xml
D src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiffDisplayService.java
D src/test/resources/OSGI-INF/test-document-diff-display-contrib.xml
M pom.xml
M src/main/java/org/nuxeo/ecm/diff/model/PropertyDiff.java
M src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffService.java
M src/main/java/org/nuxeo/ecm/diff/web/PropertyDiffDisplayHelperBean.java
M src/main/resources/META-INF/MANIFEST.MF
M src/main/resources/web/nuxeo.war/incl/diff/doc_diff_result.xhtml
M src/test/java/org/nuxeo/ecm/diff/DocumentDiffRepositoryInit.java
M src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiff.java
M src/test/java/org/nuxeo/ecm/diff/service/TestFieldDiffHelper.java
M src/test/java/org/nuxeo/ecm/diff/service/TestXMLDiff.java
M src/test/resources/META-INF/MANIFEST.MF
M src/test/resources/OSGI-INF/test-types-contrib.xml

diff --git a/pom.xml b/pom.xml
index b1a5fcd..1533654 100644
--- a/pom.xml
+++ b/pom.xml
 <at>  <at>  -27,6 +27,10  <at>  <at> 
       <groupId>org.nuxeo.ecm.platform</groupId>
       <artifactId>nuxeo-platform-webapp-base</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.nuxeo.ecm.platform</groupId>
+      <artifactId>nuxeo-platform-forms-layout-core</artifactId>
+    </dependency>
 
     <!-- xmlunit -->
     <dependency>
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/DiffBlockDefinition.java b/src/main/java/org/nuxeo/ecm/diff/model/DiffBlockDefinition.java
new file mode 100644
index 0000000..8b715d4
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/DiffBlockDefinition.java
 <at>  <at>  -0,0 +1,51  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Diff block definition interface.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public interface DiffBlockDefinition extends Serializable {
+
+    /**
+     * Gets the diff block name.
+     * 
+     *  <at> return the schema name
+     */
+    String getName();
+
+    /**
+     * Gets the diff block label.
+     * 
+     *  <at> return the label
+     */
+    String getLabel();
+
+    /**
+     * Gets the diff block fields.
+     * 
+     *  <at> return the schema fields
+     */
+    List<DiffFieldDefinition> getFields();
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayBlock.java b/src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayBlock.java
new file mode 100644
index 0000000..72eeee4
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayBlock.java
 <at>  <at>  -0,0 +1,46  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
+
+/**
+ * Diff block definition interface.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public interface DiffDisplayBlock extends Serializable {
+
+    String getLabel();
+
+    void setLabel(String label);
+
+    Map<String, DiffDisplayField> getValue();
+
+    void setValue(Map<String, DiffDisplayField> value);
+
+    LayoutDefinition getLayoutDefinition();
+
+    void setLayoutDefinition(LayoutDefinition layoutDefinition);
+
+    boolean isEmpty();
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayField.java b/src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayField.java
new file mode 100644
index 0000000..6faff5d
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/DiffDisplayField.java
 <at>  <at>  -0,0 +1,29  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model;
+
+import java.io.Serializable;
+
+/**
+ * Diff block definition interface.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public interface DiffDisplayField extends Serializable {
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/DiffFieldDefinition.java b/src/main/java/org/nuxeo/ecm/diff/model/DiffFieldDefinition.java
new file mode 100644
index 0000000..7a06d0d
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/DiffFieldDefinition.java
 <at>  <at>  -0,0 +1,46  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Diff field definition interface.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public interface DiffFieldDefinition extends Serializable {
+
+    String getSchema();
+
+    /**
+     * Gets the field name.
+     * 
+     *  <at> return the field name
+     */
+    String getName();
+
+    /**
+     * Gets the items.
+     * 
+     *  <at> return the items
+     */
+    List<String> getItems();
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/PropertyDiff.java b/src/main/java/org/nuxeo/ecm/diff/model/PropertyDiff.java
index 404a0b5..e1a92ac 100644
--- a/src/main/java/org/nuxeo/ecm/diff/model/PropertyDiff.java
+++ b/src/main/java/org/nuxeo/ecm/diff/model/PropertyDiff.java
 <at>  <at>  -19,8 +19,7  <at>  <at> 
 import java.io.Serializable;
 
 /**
- * <p>
- * Representation of a property (or field) diff.
+ * Representation of a property (field) diff.
  * 
  *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
  */
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/impl/ComplexDiffDisplayField.java b/src/main/java/org/nuxeo/ecm/diff/model/impl/ComplexDiffDisplayField.java
new file mode 100644
index 0000000..2a680ee
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/impl/ComplexDiffDisplayField.java
 <at>  <at>  -0,0 +1,33  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model.impl;
+
+import java.util.HashMap;
+
+import org.nuxeo.ecm.diff.model.DiffDisplayField;
+
+/**
+ * Implementation of PropertyDiff for a complex property.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ */
+public class ComplexDiffDisplayField extends HashMap<String, DiffDisplayField>
+        implements DiffDisplayField {
+
+    private static final long serialVersionUID = -2747517077065335351L;
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffBlockDefinitionImpl.java b/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffBlockDefinitionImpl.java
new file mode 100644
index 0000000..554bbc7
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffBlockDefinitionImpl.java
 <at>  <at>  -0,0 +1,107  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model.impl;
+
+import java.util.List;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.nuxeo.ecm.diff.model.DiffBlockDefinition;
+import org.nuxeo.ecm.diff.model.DiffFieldDefinition;
+
+/**
+ * Default implementation of a { <at> link DiffBlockDefinition}.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public class DiffBlockDefinitionImpl implements
+        DiffBlockDefinition {
+
+    private static final long serialVersionUID = 511776842683091931L;
+
+    protected static final String DIFF_DISPLAY_BLOCK_LABEL_PREFIX = "label.diffBlock.";
+
+    protected String name;
+
+    protected String label;
+
+    protected List<DiffFieldDefinition> fields;
+
+    public DiffBlockDefinitionImpl(String name, String label,
+            List<DiffFieldDefinition> fields) {
+        this.name = name;
+        this.label = label;
+        this.fields = fields;
+    }
+
+    public DiffBlockDefinitionImpl(String name,
+            List<DiffFieldDefinition> fields) {
+        this(name, DIFF_DISPLAY_BLOCK_LABEL_PREFIX + name, fields);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public List<DiffFieldDefinition> getFields() {
+        return fields;
+    }
+
+     <at> Override
+    public boolean equals(Object other) {
+
+        if (this == other) {
+            return true;
+        }
+        if (other == null || !(other instanceof DiffBlockDefinition)) {
+            return false;
+        }
+
+        String otherName = ((DiffBlockDefinition) other).getName();
+        if (name == null && otherName == null) {
+            return true;
+        }
+        if (name == null && otherName != null || name != null
+                && otherName == null || !name.equals(otherName)) {
+            return false;
+        }
+
+        List<DiffFieldDefinition> otherFields = ((DiffBlockDefinition) other).getFields();
+        if (CollectionUtils.isEmpty(fields)
+                && CollectionUtils.isEmpty(otherFields)) {
+            return true;
+        }
+        if (CollectionUtils.isEmpty(fields)
+                && !CollectionUtils.isEmpty(otherFields)
+                || !CollectionUtils.isEmpty(fields)
+                && CollectionUtils.isEmpty(otherFields)
+                || !fields.equals(otherFields)) {
+            return false;
+        }
+
+        return true;
+    }
+
+     <at> Override
+    public String toString() {
+        return name + fields;
+    }
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffDisplayBlockImpl.java b/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffDisplayBlockImpl.java
new file mode 100644
index 0000000..f536ae8
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffDisplayBlockImpl.java
 <at>  <at>  -0,0 +1,82  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.collections.MapUtils;
+import org.nuxeo.ecm.diff.model.DiffDisplayBlock;
+import org.nuxeo.ecm.diff.model.DiffDisplayField;
+import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
+
+/**
+ * Handles...
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ */
+public class DiffDisplayBlockImpl implements DiffDisplayBlock {
+
+    private static final long serialVersionUID = 5777784629522360126L;
+
+    protected String label;
+
+    protected Map<String, DiffDisplayField> value;
+
+    protected LayoutDefinition layoutDefinition;
+
+    public DiffDisplayBlockImpl(String label) {
+        this.label = label;
+        this.value = new HashMap<String, DiffDisplayField>();
+    }
+
+    public DiffDisplayBlockImpl(String label,
+            Map<String, DiffDisplayField> value,
+            LayoutDefinition layoutDefinition) {
+        this.label = label;
+        this.value = value;
+        this.layoutDefinition = layoutDefinition;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public Map<String, DiffDisplayField> getValue() {
+        return value;
+    }
+
+    public void setValue(Map<String, DiffDisplayField> value) {
+        this.value = value;
+    }
+
+    public LayoutDefinition getLayoutDefinition() {
+        return layoutDefinition;
+    }
+
+    public void setLayoutDefinition(LayoutDefinition layoutDefinition) {
+        this.layoutDefinition = layoutDefinition;
+    }
+
+    public boolean isEmpty() {
+        return MapUtils.isEmpty(this.value);
+    }
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffFieldDefinitionImpl.java b/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffFieldDefinitionImpl.java
new file mode 100644
index 0000000..c9a72f8
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/impl/DiffFieldDefinitionImpl.java
 <at>  <at>  -0,0 +1,107  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.nuxeo.ecm.diff.model.DiffFieldDefinition;
+
+/**
+ * Default implementation of a { <at> link DiffFieldDefinition}.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public class DiffFieldDefinitionImpl implements DiffFieldDefinition {
+
+    private static final long serialVersionUID = 6192730067253949180L;
+
+    protected String schema;
+
+    protected String name;
+
+    protected List<String> items;
+
+    public DiffFieldDefinitionImpl(String schema, String name) {
+        this(schema, name, new ArrayList<String>());
+    }
+
+    public DiffFieldDefinitionImpl(String schema, String name,
+            List<String> items) {
+        this.schema = schema;
+        this.name = name;
+        this.items = items;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<String> getItems() {
+        return items;
+    }
+
+     <at> Override
+    public boolean equals(Object other) {
+
+        if (this == other) {
+            return true;
+        }
+        if (other == null || !(other instanceof DiffFieldDefinition)) {
+            return false;
+        }
+
+        String otherSchema = ((DiffFieldDefinition) other).getSchema();
+        String otherName = ((DiffFieldDefinition) other).getName();
+        if (schema == null && otherSchema == null && name == null
+                && otherName == null) {
+            return true;
+        }
+        if (schema == null || otherSchema == null || name == null
+                || otherName == null || !schema.equals(otherSchema)
+                || !name.equals(otherName)) {
+            return false;
+        }
+
+        List<String> otherItems = ((DiffFieldDefinition) other).getItems();
+        if (CollectionUtils.isEmpty(items)
+                && CollectionUtils.isEmpty(otherItems)) {
+            return true;
+        }
+        if (CollectionUtils.isEmpty(items)
+                && !CollectionUtils.isEmpty(otherItems)
+                || !CollectionUtils.isEmpty(items)
+                && CollectionUtils.isEmpty(otherItems)
+                || !items.equals(otherItems)) {
+            return false;
+        }
+
+        return true;
+    }
+
+     <at> Override
+    public String toString() {
+        return schema + ":" + name
+                + (!CollectionUtils.isEmpty(items) ? items : "");
+    }
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/impl/ListDiffDisplayField.java b/src/main/java/org/nuxeo/ecm/diff/model/impl/ListDiffDisplayField.java
new file mode 100644
index 0000000..05891fb
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/impl/ListDiffDisplayField.java
 <at>  <at>  -0,0 +1,33  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model.impl;
+
+import java.util.ArrayList;
+
+import org.nuxeo.ecm.diff.model.DiffDisplayField;
+
+/**
+ * Implementation of PropertyDiff for a complex property.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ */
+public class ListDiffDisplayField extends ArrayList<ComplexDiffDisplayField>
+        implements DiffDisplayField {
+
+    private static final long serialVersionUID = 2430154781168699236L;
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/model/impl/SimpleDiffDisplayField.java b/src/main/java/org/nuxeo/ecm/diff/model/impl/SimpleDiffDisplayField.java
new file mode 100644
index 0000000..99dc05a
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/model/impl/SimpleDiffDisplayField.java
 <at>  <at>  -0,0 +1,97  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.model.impl;
+
+import java.io.Serializable;
+
+import org.nuxeo.ecm.diff.model.DiffDisplayField;
+
+/**
+ * Implementation of PropertyDiff for a simple property.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ */
+public class SimpleDiffDisplayField implements DiffDisplayField {
+
+    private static final long serialVersionUID = 4024413081969146478L;
+
+    protected Serializable leftValue;
+
+    protected Serializable rightValue;
+
+    /**
+     * Instantiates a new simple property diff.
+     * 
+     *  <at> param propertyType the property type
+     */
+    public SimpleDiffDisplayField(Serializable leftValue,
+            Serializable rightValue) {
+        this.leftValue = leftValue;
+        this.rightValue = rightValue;
+    }
+
+    public Serializable getLeftValue() {
+        return leftValue;
+    }
+
+    public void setLeftValue(Serializable leftValue) {
+        this.leftValue = leftValue;
+    }
+
+    public Serializable getRightValue() {
+        return rightValue;
+    }
+
+    public void setRightValue(Serializable rightValue) {
+        this.rightValue = rightValue;
+    }
+
+     <at> Override
+    public boolean equals(Object other) {
+
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof SimpleDiffDisplayField)) {
+            return false;
+        }
+
+        Serializable otherLeftValue = ((SimpleDiffDisplayField) other).getLeftValue();
+        Serializable otherRightValue = ((SimpleDiffDisplayField) other).getRightValue();
+
+        return (leftValue == null && otherLeftValue == null
+                && rightValue == null && otherRightValue == null)
+                || (leftValue == null && otherLeftValue == null
+                        && rightValue != null && rightValue.equals(otherRightValue))
+                || (rightValue == null && otherRightValue == null
+                        && leftValue != null && leftValue.equals(otherLeftValue))
+                || (leftValue != null && rightValue != null
+                        && leftValue.equals(otherLeftValue) && rightValue.equals(otherRightValue));
+    }
+
+     <at> Override
+    public String toString() {
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(leftValue);
+        sb.append(" --> ");
+        sb.append(rightValue);
+
+        return sb.toString();
+    }
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/ComplexItemsDescriptor.java b/src/main/java/org/nuxeo/ecm/diff/service/ComplexItemsDescriptor.java
deleted file mode 100644
index e75b942..0000000
--- a/src/main/java/org/nuxeo/ecm/diff/service/ComplexItemsDescriptor.java
+++ /dev/null
 <at>  <at>  -1,56 +0,0  <at>  <at> 
-/*
- * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public License
- * (LGPL) version 2.1 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * Contributors:
- *     ataillefer
- */
-package org.nuxeo.ecm.diff.service;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.nuxeo.common.xmap.annotation.XNode;
-import org.nuxeo.common.xmap.annotation.XNodeList;
-import org.nuxeo.common.xmap.annotation.XObject;
-
-/**
- * Complex items descriptor.
- * 
- *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
- */
- <at> XObject("complexItems")
-public class ComplexItemsDescriptor {
-
-     <at> XNode(" <at> property")
-    public String property;
-
-     <at> XNodeList(value = "item", type = ArrayList.class, componentType = String.class)
-    public List<String> items = new ArrayList<String>();
-
-    public String getProperty() {
-        return property;
-    }
-
-    public void setProperty(String property) {
-        this.property = property;
-    }
-
-    public List<String> getItems() {
-        return items;
-    }
-
-    public void setItems(List<String> items) {
-        this.items = items;
-    }
-
-}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/DiffDisplayService.java b/src/main/java/org/nuxeo/ecm/diff/service/DiffDisplayService.java
new file mode 100644
index 0000000..a6e0659
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/service/DiffDisplayService.java
 <at>  <at>  -0,0 +1,82  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.service;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.nuxeo.ecm.core.api.ClientException;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.nuxeo.ecm.diff.model.DiffBlockDefinition;
+import org.nuxeo.ecm.diff.model.DiffDisplayBlock;
+import org.nuxeo.ecm.diff.model.DocumentDiff;
+import org.nuxeo.ecm.diff.service.impl.DiffDisplayDescriptor;
+
+/**
+ * Handles the configuration of a document diff display.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public interface DiffDisplayService extends Serializable {
+
+    String DEFAULT_DIFF_DISPLAY_NAME = "default";
+
+    /**
+     * Gets the contributions.
+     * 
+     *  <at> return the contributions
+     */
+    Map<String, DiffDisplayDescriptor> getContributions();
+
+    /**
+     * Gets the diff block definitions.
+     * 
+     *  <at> param diffDisplayName the diff display name
+     *  <at> return the diff block definitions
+     *  <at> throws ClientException the client exception
+     */
+    List<DiffBlockDefinition> getDiffBlockDefinitions(String diffDisplayName);
+
+    /**
+     * Gets the default diff block definitions.
+     * 
+     *  <at> return the default diff block definitions
+     *  <at> throws ClientException the client exception
+     */
+    List<DiffBlockDefinition> getDefaultDiffBlockDefinitions();
+
+    List<DiffDisplayBlock> getDiffDisplayBlocks(String diffDisplayName,
+            DocumentDiff docDiff, DocumentModel leftDoc, DocumentModel rightDoc)
+            throws ClientException;
+
+    List<DiffDisplayBlock> getDefaultDiffDisplayBlocks(DocumentDiff docDiff,
+            DocumentModel leftDoc, DocumentModel rightDoc)
+            throws ClientException;
+
+    /**
+     * Apply complex items order.
+     * 
+     *  <at> param schemaName the schema name
+     *  <at> param fieldName the field name
+     *  <at> param complexItems the complex items
+     */
+    // void applyComplexItemsOrder(String schemaName, String fieldName,
+    // List<String> complexItems);
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffDisplayService.java b/src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffDisplayService.java
deleted file mode 100644
index 68fe5f8..0000000
--- a/src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffDisplayService.java
+++ /dev/null
 <at>  <at>  -1,56 +0,0  <at>  <at> 
-/*
- * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public License
- * (LGPL) version 2.1 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * Contributors:
- *     ataillefer
- */
-package org.nuxeo.ecm.diff.service;
-
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Handles the display of a diff between two documents.
- * 
- *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
- */
-public interface DocumentDiffDisplayService extends Serializable {
-
-    /**
-     * Gets the contributions.
-     * 
-     *  <at> return the contributions
-     */
-    Map<String, ComplexItemsDescriptor> getContributions();
-
-    /**
-     * Gets the complex items.
-     * 
-     *  <at> param schemaName the schema name
-     *  <at> param fieldName the field name
-     *  <at> return the complex items
-     */
-    List<String> getComplexItems(String schemaName, String fieldName);
-
-    /**
-     * Apply complex items order.
-     * 
-     *  <at> param schemaName the schema name
-     *  <at> param fieldName the field name
-     *  <at> param complexItems the complex items
-     */
-    void applyComplexItemsOrder(String schemaName, String fieldName,
-            List<String> complexItems);
-
-}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffService.java b/src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffService.java
index 3db8780..98109f3 100644
--- a/src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffService.java
+++ b/src/main/java/org/nuxeo/ecm/diff/service/DocumentDiffService.java
 <at>  <at>  -29,6 +29,7  <at>  <at> 
  * Handles a diff between two documents.
  * 
  *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
  */
 public interface DocumentDiffService extends Serializable {
 
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffBlockDescriptor.java b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffBlockDescriptor.java
new file mode 100644
index 0000000..d984ec3
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffBlockDescriptor.java
 <at>  <at>  -0,0 +1,67  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.nuxeo.common.xmap.annotation.XNode;
+import org.nuxeo.common.xmap.annotation.XNodeList;
+import org.nuxeo.common.xmap.annotation.XObject;
+
+/**
+ * Diff block descriptor.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+ <at> XObject("diffBlock")
+public class DiffBlockDescriptor {
+
+     <at> XNode(" <at> name")
+    public String name;
+
+     <at> XNode(" <at> label")
+    public String label;
+
+     <at> XNodeList(value = "fields/field", type = ArrayList.class, componentType = DiffFieldDescriptor.class)
+    public List<DiffFieldDescriptor> fields;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public List<DiffFieldDescriptor> getFields() {
+        return fields;
+    }
+
+    public void setFields(List<DiffFieldDescriptor> fields) {
+        this.fields = fields;
+    }
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayDescriptor.java b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayDescriptor.java
new file mode 100644
index 0000000..b4daeca
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayDescriptor.java
 <at>  <at>  -0,0 +1,56  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.nuxeo.common.xmap.annotation.XNode;
+import org.nuxeo.common.xmap.annotation.XNodeList;
+import org.nuxeo.common.xmap.annotation.XObject;
+
+/**
+ * Diff display descriptor.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+ <at> XObject("diffDisplay")
+public class DiffDisplayDescriptor {
+
+     <at> XNode(" <at> name")
+    public String name;
+
+     <at> XNodeList(value = "diffBlocks/diffBlock", type = ArrayList.class, componentType = DiffBlockDescriptor.class)
+    public List<DiffBlockDescriptor> diffBlocks = new ArrayList<DiffBlockDescriptor>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<DiffBlockDescriptor> getDiffBlocks() {
+        return diffBlocks;
+    }
+
+    public void setDiffBlocks(List<DiffBlockDescriptor> diffBlocks) {
+        this.diffBlocks = diffBlocks;
+    }
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayServiceImpl.java b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayServiceImpl.java
new file mode 100644
index 0000000..83dd921
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffDisplayServiceImpl.java
 <at>  <at>  -0,0 +1,376  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.service.impl;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.nuxeo.ecm.core.api.ClientException;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.nuxeo.ecm.diff.model.DiffBlockDefinition;
+import org.nuxeo.ecm.diff.model.DiffDisplayBlock;
+import org.nuxeo.ecm.diff.model.DiffDisplayField;
+import org.nuxeo.ecm.diff.model.DiffFieldDefinition;
+import org.nuxeo.ecm.diff.model.DocumentDiff;
+import org.nuxeo.ecm.diff.model.PropertyDiff;
+import org.nuxeo.ecm.diff.model.PropertyType;
+import org.nuxeo.ecm.diff.model.SchemaDiff;
+import org.nuxeo.ecm.diff.model.impl.DiffBlockDefinitionImpl;
+import org.nuxeo.ecm.diff.model.impl.DiffDisplayBlockImpl;
+import org.nuxeo.ecm.diff.model.impl.DiffFieldDefinitionImpl;
+import org.nuxeo.ecm.diff.model.impl.SimpleDiffDisplayField;
+import org.nuxeo.ecm.diff.service.DiffDisplayService;
+import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes;
+import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.LayoutRowDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.impl.FieldDefinitionImpl;
+import org.nuxeo.ecm.platform.forms.layout.api.impl.LayoutDefinitionImpl;
+import org.nuxeo.ecm.platform.forms.layout.api.impl.LayoutRowDefinitionImpl;
+import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
+import org.nuxeo.runtime.api.Framework;
+import org.nuxeo.runtime.model.ComponentInstance;
+import org.nuxeo.runtime.model.DefaultComponent;
+
+/**
+ * Default implementation of the { <at> link DiffDisplayService}.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+public class DiffDisplayServiceImpl extends DefaultComponent implements
+        DiffDisplayService {
+
+    private static final long serialVersionUID = 6608445970773402827L;
+
+    private static final Log LOGGER = LogFactory.getLog(DiffDisplayServiceImpl.class);
+
+    protected static final String DIFF_DISPLAY_POINT = "diffDisplay";
+
+    protected static final String DIFF_WIDGET_CATEGORY = "diff";
+
+    protected static final String DIFF_WIDGET_LABEL_PREFIX = "label.diff.widget.";
+
+    /** Diff display contributions. */
+    protected Map<String, DiffDisplayDescriptor> contributions = new HashMap<String, DiffDisplayDescriptor>();
+
+    protected Map<String, List<DiffBlockDefinition>> diffDisplayBlockDefinitions = new HashMap<String, List<DiffBlockDefinition>>();
+
+     <at> Override
+    public void registerContribution(Object contribution,
+            String extensionPoint, ComponentInstance contributor)
+            throws Exception {
+
+        if (DIFF_DISPLAY_POINT.equals(extensionPoint)) {
+            if (contribution instanceof DiffDisplayDescriptor) {
+                registerDiffDisplay((DiffDisplayDescriptor) contribution);
+            }
+        }
+        super.registerContribution(contribution, extensionPoint, contributor);
+    }
+
+    public Map<String, DiffDisplayDescriptor> getContributions() {
+        return contributions;
+    }
+
+    public List<DiffBlockDefinition> getDiffBlockDefinitions(
+            String diffDisplayName) {
+
+        return diffDisplayBlockDefinitions.get(diffDisplayName);
+    }
+
+    public List<DiffBlockDefinition> getDefaultDiffBlockDefinitions() {
+
+        return getDiffBlockDefinitions(DEFAULT_DIFF_DISPLAY_NAME);
+    }
+
+    public List<DiffDisplayBlock> getDiffDisplayBlocks(String diffDisplayName,
+            DocumentDiff docDiff, DocumentModel leftDoc, DocumentModel rightDoc)
+            throws ClientException {
+
+        List<DiffDisplayBlock> diffDisplayBlocks = new ArrayList<DiffDisplayBlock>();
+
+        List<DiffBlockDefinition> diffBlockDefinitions = getDiffBlockDefinitions(diffDisplayName);
+        if (diffBlockDefinitions != null) {
+            for (DiffBlockDefinition diffBlockDefinition : diffBlockDefinitions) {
+
+                DiffDisplayBlock diffDisplayBlock = getDiffDisplayBlock(
+                        diffBlockDefinition, docDiff, leftDoc, rightDoc);
+                if (!diffDisplayBlock.isEmpty()) {
+                    diffDisplayBlocks.add(diffDisplayBlock);
+                }
+            }
+        } else {
+            // TODO: Use schema/fields in random order...
+        }
+
+        return diffDisplayBlocks;
+    }
+
+    public List<DiffDisplayBlock> getDefaultDiffDisplayBlocks(
+            DocumentDiff docDiff, DocumentModel leftDoc, DocumentModel rightDoc)
+            throws ClientException {
+
+        return getDiffDisplayBlocks(DEFAULT_DIFF_DISPLAY_NAME, docDiff,
+                leftDoc, rightDoc);
+    }
+
+    /**
+     * Registers a diff display contrib.
+     * 
+     *  <at> param contribution the contribution
+     */
+    private void registerDiffDisplay(DiffDisplayDescriptor contribution) {
+        contributions.put(contribution.getName(), contribution);
+        registerDiffDisplayBlockDefinitions(contribution);
+    }
+
+    /**
+     * Register diff display block definitions.
+     * 
+     *  <at> param descriptor the descriptor
+     */
+    private void registerDiffDisplayBlockDefinitions(
+            DiffDisplayDescriptor descriptor) {
+
+        List<DiffBlockDefinition> diffBlockDefinitions = new ArrayList<DiffBlockDefinition>();
+
+        List<DiffBlockDescriptor> diffBlockDescriptors = descriptor.getDiffBlocks();
+        for (DiffBlockDescriptor diffBlockDescriptor : diffBlockDescriptors) {
+
+            String diffBlockName = diffBlockDescriptor.getName();
+            if (!StringUtils.isEmpty(diffBlockName)) {
+                List<DiffFieldDescriptor> fieldDescriptors = diffBlockDescriptor.getFields();
+                // No field descriptors => don't take diff block into account.
+                if (fieldDescriptors == null || fieldDescriptors.isEmpty()) {
+                    LOGGER.warn(String.format(
+                            "The diffBlock contribution named '%s' has no fields, it won't be taken into account.",
+                            diffBlockName));
+                } else {
+                    List<DiffFieldDefinition> fields = new ArrayList<DiffFieldDefinition>();
+                    // Some field descriptors were found => use them to add the
+                    // described fields, taking their order into account.
+                    for (DiffFieldDescriptor fieldDescriptor : fieldDescriptors) {
+                        String schema = fieldDescriptor.getSchema();
+                        String name = fieldDescriptor.getName();
+                        if (!StringUtils.isEmpty(schema)
+                                && !StringUtils.isEmpty(name)) {
+                            List<String> items = fieldDescriptor.getItems();
+                            fields.add(new DiffFieldDefinitionImpl(schema,
+                                    name, items));
+                        }
+                    }
+                    diffBlockDefinitions.add(new DiffBlockDefinitionImpl(
+                            diffBlockName, diffBlockDescriptor.getLabel(),
+                            fields));
+                }
+            }
+        }
+
+        diffDisplayBlockDefinitions.put(descriptor.getName(),
+                diffBlockDefinitions);
+    }
+
+    private DiffDisplayBlock getDiffDisplayBlock(
+            DiffBlockDefinition diffBlockDefinition, DocumentDiff docDiff,
+            DocumentModel leftDoc, DocumentModel rightDoc)
+            throws ClientException {
+
+        DiffDisplayBlock diffDisplayBlock = new DiffDisplayBlockImpl(
+                diffBlockDefinition.getLabel());
+
+        List<LayoutRowDefinition> layoutRowDefinitions = new ArrayList<LayoutRowDefinition>();
+        List<WidgetDefinition> widgetDefinitions = new ArrayList<WidgetDefinition>();
+
+        List<DiffFieldDefinition> fieldDefinitions = diffBlockDefinition.getFields();
+        for (DiffFieldDefinition fieldDefinition : fieldDefinitions) {
+
+            String schemaName = fieldDefinition.getSchema();
+            String fieldName = fieldDefinition.getName();
+
+            SchemaDiff schemaDiff = docDiff.getSchemaDiff(schemaName);
+            PropertyDiff fieldDiff = schemaDiff.getFieldDiff(fieldName);
+            if (fieldDiff != null) {
+
+                String propertyName = getPropertyName(schemaName, fieldName);
+                String propertyType = fieldDiff.getPropertyType();
+
+                // Set diff display field value
+                DiffDisplayField diffDisplayField = getDiffDisplayField(
+                        propertyType,
+                        leftDoc.getProperty(schemaName, fieldName),
+                        rightDoc.getProperty(schemaName, fieldName));
+                diffDisplayBlock.getValue().put(propertyName, diffDisplayField);
+
+                // Set layout row definition
+                LayoutRowDefinition layoutRowDefinition = new LayoutRowDefinitionImpl(
+                        propertyName, propertyName, DIFF_WIDGET_CATEGORY);
+                layoutRowDefinitions.add(layoutRowDefinition);
+
+                // Set widget definition
+                WidgetDefinition widgetDefinition = getWidgetDefinition(
+                        schemaName, fieldName, propertyType);
+                widgetDefinitions.add(widgetDefinition);
+
+            }
+        }
+
+        // Set diff display block layout definition
+        LayoutDefinition layoutDefinition = new LayoutDefinitionImpl(
+                diffBlockDefinition.getName(), null, null,
+                layoutRowDefinitions, widgetDefinitions);
+        diffDisplayBlock.setLayoutDefinition(layoutDefinition);
+
+        return diffDisplayBlock;
+    }
+
+    private DiffDisplayField getDiffDisplayField(String propertyType,
+            Object leftProperty, Object rightProperty) {
+
+        if (PropertyType.isSimpleType(propertyType)) {
+            return new SimpleDiffDisplayField((Serializable) leftProperty,
+                    (Serializable) rightProperty);
+        }
+        // TODO: list, complex, complex lists, content
+
+        return null;
+    }
+
+    private WidgetDefinition getWidgetDefinition(String schemaName,
+            String fieldName, String propertyType) throws ClientException {
+
+        String propertyName = getPropertyName(schemaName, fieldName);
+
+        // Look for a specific widget in the "diff" category named with the
+        // property name
+        WidgetDefinition wDef = getLayoutStore().getWidgetDefinition(
+                DIFF_WIDGET_CATEGORY, propertyName);
+        if (wDef == null) {
+            // Fallback on a generic widget in the "diff" category named with
+            // the property type
+            wDef = getLayoutStore().getWidgetDefinition(DIFF_WIDGET_CATEGORY,
+                    propertyType);
+        }
+        if (wDef == null) {
+            throw new ClientException(
+                    String.format(
+                            "Could not find any specific widget named '%s', nor any generic widget named '%s'. Please make sure at least a generic widget is defined for this type.",
+                            propertyName, propertyType));
+        }
+        // Clone widget definition
+        wDef = wDef.clone();
+
+        // Set name for the generic widget case
+        wDef.setName(propertyName);
+
+        // Set labels
+        Map<String, String> labels = new HashMap<String, String>();
+        labels.put(BuiltinModes.ANY, DIFF_WIDGET_LABEL_PREFIX + schemaName
+                + "." + fieldName);
+        wDef.setLabels(labels);
+
+        // Set translated
+        wDef.setTranslated(true);
+
+        // Set field definitions
+        FieldDefinition[] fieldDefinitions = { new FieldDefinitionImpl(
+                schemaName, fieldName) };
+        wDef.setFieldDefinitions(fieldDefinitions);
+
+        // TODO: set props ?
+
+        return wDef;
+    }
+
+    /**
+     * Gets the property name.
+     * 
+     *  <at> param schema the schema
+     *  <at> param field the field
+     *  <at> return the property name
+     */
+    protected final String getPropertyName(String schema, String field) {
+        return schema + ":" + field;
+    }
+
+    /**
+     * Gets the layout store service.
+     * 
+     *  <at> return the layout store service
+     *  <at> throws ClientException the client exception
+     */
+    protected final LayoutStore getLayoutStore() throws ClientException {
+
+        LayoutStore layoutStore;
+        try {
+            layoutStore = Framework.getService(LayoutStore.class);
+        } catch (Exception e) {
+            throw ClientException.wrap(e);
+        }
+        if (layoutStore == null) {
+            throw new ClientException("LayoutStore service is null.");
+        }
+        return layoutStore;
+    }
+
+    /**
+     * Gets the schema manager.
+     * 
+     *  <at> return the schema manager
+     *  <at> throws ClientException the client exception
+     */
+    // protected final SchemaManager getSchemaManager() throws ClientException {
+    //
+    // SchemaManager schemaManager;
+    //
+    // try {
+    // schemaManager = Framework.getService(SchemaManager.class);
+    // } catch (Exception e) {
+    // throw ClientException.wrap(e);
+    // }
+    // if (schemaManager == null) {
+    // throw new ClientException("SchemaManager is null.");
+    // }
+    // return schemaManager;
+    // }
+
+    // public void applyComplexItemsOrder(String schemaName, String fieldName,
+    // List<String> complexItems) {
+    //
+    // List<String> orderedComplexItems = getComplexItems(schemaName,
+    // fieldName);
+    // if (orderedComplexItems != null) {
+    // for (int i = 0; i < orderedComplexItems.size(); i++) {
+    // String orderedComplexItem = orderedComplexItems.get(i);
+    // if (complexItems.contains(orderedComplexItem)) {
+    // int complexItemIndex = complexItems.indexOf(orderedComplexItem);
+    // String tempItem = complexItems.get(i);
+    // complexItems.set(i, orderedComplexItem);
+    // complexItems.set(complexItemIndex, tempItem);
+    // }
+    // }
+    // }
+    // }
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffFieldDescriptor.java b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffFieldDescriptor.java
new file mode 100644
index 0000000..0621e49
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/service/impl/DiffFieldDescriptor.java
 <at>  <at>  -0,0 +1,67  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.nuxeo.common.xmap.annotation.XNode;
+import org.nuxeo.common.xmap.annotation.XNodeList;
+import org.nuxeo.common.xmap.annotation.XObject;
+
+/**
+ * Diff field descriptor.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ *  <at> since 5.6
+ */
+ <at> XObject("field")
+public class DiffFieldDescriptor {
+
+     <at> XNode(" <at> schema")
+    public String schema;
+
+     <at> XNode(" <at> name")
+    public String name;
+
+     <at> XNodeList(value = "items/item", type = ArrayList.class, componentType = String.class)
+    public List<String> items;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    public List<String> getItems() {
+        return items;
+    }
+
+    public void setItems(List<String> items) {
+        this.items = items;
+    }
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/service/impl/DocumentDiffDisplayServiceImpl.java b/src/main/java/org/nuxeo/ecm/diff/service/impl/DocumentDiffDisplayServiceImpl.java
deleted file mode 100644
index 82a59d4..0000000
--- a/src/main/java/org/nuxeo/ecm/diff/service/impl/DocumentDiffDisplayServiceImpl.java
+++ /dev/null
 <at>  <at>  -1,108 +0,0  <at>  <at> 
-/*
- * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public License
- * (LGPL) version 2.1 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * Contributors:
- *     ataillefer
- */
-package org.nuxeo.ecm.diff.service.impl;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.nuxeo.ecm.diff.service.ComplexItemsDescriptor;
-import org.nuxeo.ecm.diff.service.DocumentDiffDisplayService;
-import org.nuxeo.runtime.model.ComponentInstance;
-import org.nuxeo.runtime.model.DefaultComponent;
-
-/**
- * Implements DocumentDiffDisplayService.
- * 
- *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
- */
-public class DocumentDiffDisplayServiceImpl extends DefaultComponent implements
-        DocumentDiffDisplayService {
-
-    private static final long serialVersionUID = 6608445970773402827L;
-
-    private static final String COMPLEX_ITEMS_DISPLAY_POINT = "complexItemsDisplay";
-
-    private static final String PROPERTY_SCHEMA_FIELD_SEPARATOR = ":";
-
-    /** Complex items contributions. */
-    private Map<String, ComplexItemsDescriptor> contributions = new HashMap<String, ComplexItemsDescriptor>();
-
-     <at> Override
-    public void registerContribution(Object contribution,
-            String extensionPoint, ComponentInstance contributor)
-            throws Exception {
-
-        if (COMPLEX_ITEMS_DISPLAY_POINT.equals(extensionPoint)) {
-            if (contribution instanceof ComplexItemsDescriptor) {
-                registerComplexItems((ComplexItemsDescriptor) contribution);
-            }
-        }
-        super.registerContribution(contribution, extensionPoint, contributor);
-    }
-
-    /**
-     * Registers a complex items contrib.
-     * 
-     *  <at> param contribution the contribution
-     */
-    private void registerComplexItems(ComplexItemsDescriptor contribution) {
-        contributions.put(contribution.getProperty(), contribution);
-    }
-
-    /**
-     * { <at> inheritDoc}
-     */
-    public Map<String, ComplexItemsDescriptor> getContributions() {
-        return contributions;
-    }
-
-    /**
-     * { <at> inheritDoc}
-     */
-    public List<String> getComplexItems(String schemaName, String fieldName) {
-
-        ComplexItemsDescriptor descriptor = contributions.get(schemaName
-                + PROPERTY_SCHEMA_FIELD_SEPARATOR + fieldName);
-        if (descriptor == null) {
-            return null;
-        }
-        return descriptor.getItems();
-    }
-
-    /**
-     * { <at> inheritDoc}
-     */
-    public void applyComplexItemsOrder(String schemaName, String fieldName,
-            List<String> complexItems) {
-
-        List<String> orderedComplexItems = getComplexItems(schemaName,
-                fieldName);
-        if (orderedComplexItems != null) {
-            for (int i = 0; i < orderedComplexItems.size(); i++) {
-                String orderedComplexItem = orderedComplexItems.get(i);
-                if (complexItems.contains(orderedComplexItem)) {
-                    int complexItemIndex = complexItems.indexOf(orderedComplexItem);
-                    String tempItem = complexItems.get(i);
-                    complexItems.set(i, orderedComplexItem);
-                    complexItems.set(complexItemIndex, tempItem);
-                }
-            }
-        }
-    }
-
-}
diff --git a/src/main/java/org/nuxeo/ecm/diff/web/DiffActionsBean.java b/src/main/java/org/nuxeo/ecm/diff/web/DiffActionsBean.java
new file mode 100644
index 0000000..c528c62
--- /dev/null
+++ b/src/main/java/org/nuxeo/ecm/diff/web/DiffActionsBean.java
 <at>  <at>  -0,0 +1,260  <at>  <at> 
+/*
+ * (C) Copyright 20012 Nuxeo SAS (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ *
+ */
+
+package org.nuxeo.ecm.diff.web;
+
+import static org.jboss.seam.ScopeType.CONVERSATION;
+import static org.jboss.seam.ScopeType.PAGE;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.seam.annotations.Factory;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.nuxeo.ecm.core.api.ClientException;
+import org.nuxeo.ecm.core.api.CoreSession;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.nuxeo.ecm.core.api.VersionModel;
+import org.nuxeo.ecm.diff.model.DiffDisplayBlock;
+import org.nuxeo.ecm.diff.model.DocumentDiff;
+import org.nuxeo.ecm.diff.service.DiffDisplayService;
+import org.nuxeo.ecm.diff.service.DocumentDiffService;
+import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
+import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager;
+import org.nuxeo.runtime.api.Framework;
+
+/**
+ * Handles document diff actions.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ */
+ <at> Name("diffActions")
+ <at> Scope(CONVERSATION)
+public class DiffActionsBean implements Serializable {
+
+    private static final long serialVersionUID = -5507491210664361778L;
+
+    private static final String DOC_DIFF_VIEW = "view_doc_diff";
+
+     <at> In(create = true)
+    protected transient DocumentsListsManager documentsListsManager;
+
+     <at> In(create = true, required = false)
+    protected transient NavigationContext navigationContext;
+
+     <at> In(create = true, required = false)
+    protected transient CoreSession documentManager;
+
+    protected DocumentModel leftDoc;
+
+    protected DocumentModel rightDoc;
+
+    /**
+     * Checks if the diff action is available for the current document selection
+     * working list.
+     * <p>
+     * Condition: the working list has exactly 2 documents.
+     * 
+     *  <at> return true if can copy
+     */
+    public boolean getCanDiffCurrentSelection() {
+
+        List<DocumentModel> currentSelectionWorkingList = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SELECTION);
+        return currentSelectionWorkingList != null
+                && currentSelectionWorkingList.size() == 2;
+
+    }
+
+    /**
+     * Prepares a diff of the current selection.
+     * 
+     *  <at> return the view id
+     *  <at> throws ClientException the client exception
+     */
+    public String prepareCurrentSelectionDiff() throws ClientException {
+
+        List<DocumentModel> currentSelectionWorkingList = getCurrentSelectionWorkingList();
+
+        leftDoc = currentSelectionWorkingList.get(0);
+        rightDoc = currentSelectionWorkingList.get(1);
+
+        refresh();
+
+        return DOC_DIFF_VIEW;
+
+    }
+
+    /**
+     * Prepares a diff of the selected version with the live doc.
+     * 
+     *  <at> param version the version
+     *  <at> return the string
+     *  <at> throws ClientException the client exception
+     */
+    public String prepareCurrentVersionDiff(VersionModel selectedVersion)
+            throws ClientException {
+
+        DocumentModel currentDocument = navigationContext.getCurrentDocument();
+        if (currentDocument == null) {
+            throw new ClientException(
+                    "Cannot make a diff between selected version and current document since current document is null.");
+        }
+
+        DocumentModel docVersion = documentManager.getDocumentWithVersion(
+                currentDocument.getRef(), selectedVersion);
+        if (docVersion == null) {
+            throw new ClientException(
+                    "Cannot make a diff between selected version and current document since selected version document is null.");
+        }
+
+        leftDoc = currentDocument;
+        rightDoc = docVersion;
+
+        return DOC_DIFF_VIEW;
+
+    }
+
+    /**
+     * Refreshes the diff between leftDoc and rightDoc.
+     * 
+     *  <at> throws ClientException the client exception
+     */
+    public void refresh() throws ClientException {
+
+        // Fetch docs from repository
+        leftDoc = documentManager.getDocument(leftDoc.getRef());
+        rightDoc = documentManager.getDocument(rightDoc.getRef());
+
+    }
+
+    /**
+     * Checks if document diff is available.
+     * 
+     *  <at> return true, if is document diff available
+     */
+    public boolean isDocumentDiffAvailable() {
+        return leftDoc != null && rightDoc != null;
+    }
+
+    /**
+     * Gets the document diff.
+     * 
+     *  <at> return the document diff between leftDoc and rightDoc if leftDoc and
+     *         rightDoc aren't null, else null
+     *  <at> throws ClientException the client exception
+     */
+     <at> Factory(value = "defaultDiffDisplayBlocks", scope = PAGE)
+    public List<DiffDisplayBlock> getDefaultDiffDisplayBlocks()
+            throws ClientException {
+
+        if (leftDoc == null || rightDoc == null) {
+            return new ArrayList<DiffDisplayBlock>();
+        }
+
+        DocumentDiff docDiff = getDocumentDiffService().diff(documentManager,
+                leftDoc, rightDoc);
+        return getDiffDisplayService().getDefaultDiffDisplayBlocks(docDiff,
+                leftDoc, rightDoc);
+
+    }
+
+    /**
+     * Gets the current selection working list.
+     * 
+     *  <at> return the current selection working list
+     *  <at> throws ClientException the client exception
+     */
+    protected final List<DocumentModel> getCurrentSelectionWorkingList()
+            throws ClientException {
+
+        List<DocumentModel> currentSelectionWorkingList = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SELECTION);
+
+        if (currentSelectionWorkingList == null
+                || currentSelectionWorkingList.size() != 2) {
+            throw new ClientException(
+                    "Cannot make a diff of the current selection: need to have exactly 2 documents in the working list");
+        }
+        return currentSelectionWorkingList;
+    }
+
+    /**
+     * Gets the document diff service.
+     * 
+     *  <at> return the document diff service
+     *  <at> throws ClientException if cannot get the document diff service
+     */
+    protected final DocumentDiffService getDocumentDiffService()
+            throws ClientException {
+
+        DocumentDiffService documentDiffService;
+
+        try {
+            documentDiffService = Framework.getService(DocumentDiffService.class);
+        } catch (Exception e) {
+            throw ClientException.wrap(e);
+        }
+        if (documentDiffService == null) {
+            throw new ClientException("DocumentDiffService is null.");
+        }
+        return documentDiffService;
+
+    }
+
+    /**
+     * Gets the diff display service.
+     * 
+     *  <at> return the diff display service
+     *  <at> throws ClientException the client exception
+     */
+    protected final DiffDisplayService getDiffDisplayService()
+            throws ClientException {
+
+        DiffDisplayService diffDisplayService;
+
+        try {
+            diffDisplayService = Framework.getService(DiffDisplayService.class);
+        } catch (Exception e) {
+            throw ClientException.wrap(e);
+        }
+        if (diffDisplayService == null) {
+            throw new ClientException("DiffDisplayService is null.");
+        }
+        return diffDisplayService;
+
+    }
+
+    public DocumentModel getLeftDoc() {
+        return leftDoc;
+    }
+
+    public void setLeftDoc(DocumentModel leftDoc) {
+        this.leftDoc = leftDoc;
+    }
+
+    public DocumentModel getRightDoc() {
+        return rightDoc;
+    }
+
+    public void setRightDoc(DocumentModel rightDoc) {
+        this.rightDoc = rightDoc;
+    }
+
+}
diff --git a/src/main/java/org/nuxeo/ecm/diff/web/DocumentDiffActionsBean.java b/src/main/java/org/nuxeo/ecm/diff/web/DocumentDiffActionsBean.java
deleted file mode 100644
index f6d1492..0000000
--- a/src/main/java/org/nuxeo/ecm/diff/web/DocumentDiffActionsBean.java
+++ /dev/null
 <at>  <at>  -1,230 +0,0  <at>  <at> 
-/*
- * (C) Copyright 20012 Nuxeo SAS (http://nuxeo.com/) and contributors.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public License
- * (LGPL) version 2.1 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * Contributors:
- *     ataillefer
- *
- */
-
-package org.nuxeo.ecm.diff.web;
-
-import static org.jboss.seam.ScopeType.CONVERSATION;
-import static org.jboss.seam.ScopeType.PAGE;
-
-import java.io.Serializable;
-import java.util.List;
-
-import org.jboss.seam.annotations.Factory;
-import org.jboss.seam.annotations.In;
-import org.jboss.seam.annotations.Name;
-import org.jboss.seam.annotations.Scope;
-import org.nuxeo.ecm.core.api.ClientException;
-import org.nuxeo.ecm.core.api.CoreSession;
-import org.nuxeo.ecm.core.api.DocumentModel;
-import org.nuxeo.ecm.core.api.VersionModel;
-import org.nuxeo.ecm.diff.model.DocumentDiff;
-import org.nuxeo.ecm.diff.model.impl.DocumentDiffImpl;
-import org.nuxeo.ecm.diff.service.DocumentDiffService;
-import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
-import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager;
-import org.nuxeo.runtime.api.Framework;
-
-/**
- * Handles document diff actions.
- * 
- *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
- */
- <at> Name("documentDiffActions")
- <at> Scope(CONVERSATION)
-public class DocumentDiffActionsBean implements Serializable {
-
-    private static final long serialVersionUID = -5507491210664361778L;
-
-    private static final String DOC_DIFF_VIEW = "view_doc_diff";
-
-     <at> In(create = true)
-    protected transient DocumentsListsManager documentsListsManager;
-
-     <at> In(create = true, required = false)
-    protected transient NavigationContext navigationContext;
-
-     <at> In(create = true, required = false)
-    protected transient CoreSession documentManager;
-
-    protected DocumentModel leftDoc;
-
-    protected DocumentModel rightDoc;
-
-    /**
-     * Checks if the diff action is available for the current document selection
-     * working list.
-     * <p>
-     * Condition: the working list has exactly 2 documents.
-     * 
-     *  <at> return true if can copy
-     */
-    public boolean getCanDiffCurrentSelection() {
-
-        List<DocumentModel> currentSelectionWorkingList = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SELECTION);
-        return currentSelectionWorkingList != null
-                && currentSelectionWorkingList.size() == 2;
-
-    }
-
-    /**
-     * Prepares a diff of the current selection.
-     * 
-     *  <at> return the view id
-     *  <at> throws ClientException the client exception
-     */
-    public String prepareCurrentSelectionDiff() throws ClientException {
-
-        List<DocumentModel> currentSelectionWorkingList = getCurrentSelectionWorkingList();
-
-        leftDoc = currentSelectionWorkingList.get(0);
-        rightDoc = currentSelectionWorkingList.get(1);
-
-        refresh();
-
-        return DOC_DIFF_VIEW;
-
-    }
-
-    /**
-     * Prepares a diff of the selected version with the live doc.
-     * 
-     *  <at> param version the version
-     *  <at> return the string
-     *  <at> throws ClientException the client exception
-     */
-    public String prepareCurrentVersionDiff(VersionModel selectedVersion)
-            throws ClientException {
-
-        DocumentModel currentDocument = navigationContext.getCurrentDocument();
-        if (currentDocument == null) {
-            throw new ClientException(
-                    "Cannot make a diff between selected version and current document since current document is null.");
-        }
-
-        DocumentModel docVersion = documentManager.getDocumentWithVersion(
-                currentDocument.getRef(), selectedVersion);
-        if (docVersion == null) {
-            throw new ClientException(
-                    "Cannot make a diff between selected version and current document since selected version document is null.");
-        }
-
-        leftDoc = currentDocument;
-        rightDoc = docVersion;
-
-        return DOC_DIFF_VIEW;
-
-    }
-
-    /**
-     * Refreshes the diff between leftDoc and rightDoc.
-     * 
-     *  <at> throws ClientException the client exception
-     */
-    public void refresh() throws ClientException {
-
-        // Fetch docs from repository
-        leftDoc = documentManager.getDocument(leftDoc.getRef());
-        rightDoc = documentManager.getDocument(rightDoc.getRef());
-
-    }
-
-    /**
-     * Checks if document diff is available.
-     * 
-     *  <at> return true, if is document diff available
-     */
-    public boolean isDocumentDiffAvailable() {
-        return leftDoc != null && rightDoc != null;
-    }
-
-    /**
-     * Gets the document diff.
-     * 
-     *  <at> return the document diff between leftDoc and rightDoc if leftDoc and
-     *         rightDoc aren't null, else null
-     *  <at> throws ClientException the client exception
-     */
-     <at> Factory(value = "documentDiff", scope = PAGE)
-    public DocumentDiff getDocumentDiff() throws ClientException {
-
-        if (leftDoc == null || rightDoc == null) {
-            return new DocumentDiffImpl();
-        }
-        return getDocumentDiffService().diff(documentManager, leftDoc, rightDoc);
-
-    }
-
-    /**
-     * Gets the current selection working list.
-     * 
-     *  <at> return the current selection working list
-     *  <at> throws ClientException the client exception
-     */
-    protected final List<DocumentModel> getCurrentSelectionWorkingList()
-            throws ClientException {
-
-        List<DocumentModel> currentSelectionWorkingList = documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SELECTION);
-
-        if (currentSelectionWorkingList == null
-                || currentSelectionWorkingList.size() != 2) {
-            throw new ClientException(
-                    "Cannot make a diff of the current selection: need to have exactly 2 documents in the working list");
-        }
-        return currentSelectionWorkingList;
-    }
-
-    /**
-     * Gets the document diff service.
-     * 
-     *  <at> return the document diff service
-     *  <at> throws ClientException if cannot get the document diff service
-     */
-    protected final DocumentDiffService getDocumentDiffService()
-            throws ClientException {
-
-        DocumentDiffService documentDiffService;
-
-        try {
-            documentDiffService = Framework.getService(DocumentDiffService.class);
-        } catch (Exception e) {
-            throw ClientException.wrap(e);
-        }
-        if (documentDiffService == null) {
-            throw new ClientException("DocumentDiffService is null.");
-        }
-        return documentDiffService;
-
-    }
-
-    public DocumentModel getLeftDoc() {
-        return leftDoc;
-    }
-
-    public void setLeftDoc(DocumentModel leftDoc) {
-        this.leftDoc = leftDoc;
-    }
-
-    public DocumentModel getRightDoc() {
-        return rightDoc;
-    }
-
-    public void setRightDoc(DocumentModel rightDoc) {
-        this.rightDoc = rightDoc;
-    }
-
-}
diff --git a/src/main/java/org/nuxeo/ecm/diff/web/PropertyDiffDisplayHelperBean.java b/src/main/java/org/nuxeo/ecm/diff/web/PropertyDiffDisplayHelperBean.java
index 50e2a4f..5c4d86d 100644
--- a/src/main/java/org/nuxeo/ecm/diff/web/PropertyDiffDisplayHelperBean.java
+++ b/src/main/java/org/nuxeo/ecm/diff/web/PropertyDiffDisplayHelperBean.java
 <at>  <at>  -34,7 +34,7  <at>  <at> 
 import org.nuxeo.ecm.core.storage.sql.coremodel.SQLBlob;
 import org.nuxeo.ecm.diff.model.PropertyDiff;
 import org.nuxeo.ecm.diff.model.impl.ListPropertyDiff;
-import org.nuxeo.ecm.diff.service.DocumentDiffDisplayService;
+import org.nuxeo.ecm.diff.service.DiffDisplayService;
 import org.nuxeo.ecm.webapp.helpers.ResourcesAccessor;
 import org.nuxeo.runtime.api.Framework;
 
 <at>  <at>  -65,8 +65,7  <at>  <at>  public static Serializable getSimplePropertyValue(DocumentModel doc,
         List<String> complexItemNames = ComplexPropertyHelper.getComplexItemNames(
                 schemaName, fieldName);
 
-        getDocumentDiffDisplayService().applyComplexItemsOrder(schemaName,
-                fieldName, complexItemNames);
+        // getDocumentDiffDisplayService().applyComplexItemsOrders
 
         return complexItemNames;
 
 <at>  <at>  -100,8 +99,8  <at>  <at>  public Serializable getListItemValue(DocumentModel doc, String schemaName,
         List<String> complexListItemNames = ComplexPropertyHelper.getComplexListItemNames(
                 schemaName, fieldName);
 
-        getDocumentDiffDisplayService().applyComplexItemsOrder(schemaName,
-                fieldName, complexListItemNames);
+        // getDocumentDiffDisplayService().applyComplexItemsOrder(schemaName,
+        // fieldName, complexListItemNames);
 
         return complexListItemNames;
     }
 <at>  <at>  -190,13 +189,13  <at>  <at>  else if (propertyValue instanceof Binary) {
      *  <at> return the document diff display service
      *  <at> throws ClientException the client exception
      */
-    protected final DocumentDiffDisplayService getDocumentDiffDisplayService()
+    protected final DiffDisplayService getDocumentDiffDisplayService()
             throws ClientException {
 
-        DocumentDiffDisplayService docDiffDisplayService;
+        DiffDisplayService docDiffDisplayService;
 
         try {
-            docDiffDisplayService = Framework.getService(DocumentDiffDisplayService.class);
+            docDiffDisplayService = Framework.getService(DiffDisplayService.class);
         } catch (Exception e) {
             throw ClientException.wrap(e);
         }
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
index 046f812..b1ea070 100644
--- a/src/main/resources/META-INF/MANIFEST.MF
+++ b/src/main/resources/META-INF/MANIFEST.MF
 <at>  <at>  -9,5 +9,6  <at>  <at>  Bundle-ManifestVersion: 2
 Bundle-SymbolicName: org.nuxeo.diff;singleton:=true
 Nuxeo-Component: OSGI-INF/document-xml-export-service.xml,
  OSGI-INF/document-diff-service.xml,
- OSGI-INF/document-diff-actions-contrib.xml,
- OSGI-INF/document-diff-display-service.xml
+ OSGI-INF/diff-actions-contrib.xml,
+ OSGI-INF/diff-display-service.xml,
+ OSGI-INF/diff-widgets-contrib.xml
diff --git a/src/main/resources/OSGI-INF/diff-actions-contrib.xml b/src/main/resources/OSGI-INF/diff-actions-contrib.xml
new file mode 100644
index 0000000..1f92e26
--- /dev/null
+++ b/src/main/resources/OSGI-INF/diff-actions-contrib.xml
 <at>  <at>  -0,0 +1,26  <at>  <at> 
+<component name="org.nuxeo.ecm.diff.actions">
+
+  <extension target="org.nuxeo.ecm.platform.actions.ActionService"
+    point="actions">
+
+    <action id="CURRENT_SELECTION_DIFF" link="#{documentDiffActions.prepareCurrentSelectionDiff}"
+      label="command.clipboard.diff" order="100">
+      <category>CURRENT_SELECTION_LIST</category>
+      <filter-id>canDiffCurrentSelection</filter-id>
+    </action>
+
+  </extension>
+
+  <extension target="org.nuxeo.ecm.platform.actions.ActionService"
+    point="filters">
+
+    <filter id="canDiffCurrentSelection">
+      <rule grant="true">
+        <condition>#{documentDiffActions.canDiffCurrentSelection}
+        </condition>
+      </rule>
+    </filter>
+
+  </extension>
+
+</component>
diff --git a/src/main/resources/OSGI-INF/diff-display-service.xml b/src/main/resources/OSGI-INF/diff-display-service.xml
new file mode 100644
index 0000000..82cc567
--- /dev/null
+++ b/src/main/resources/OSGI-INF/diff-display-service.xml
 <at>  <at>  -0,0 +1,47  <at>  <at> 
+<component name="org.nuxeo.ecm.diff.service.DiffDisplayService">
+
+  <documentation>
+    This service provides an extension point to manage a
+    document diff display.
+
+     <at> author
+    Antoine Taillefer
+  </documentation>
+
+  <implementation
+    class="org.nuxeo.ecm.diff.service.impl.DiffDisplayServiceImpl" />
+
+  <service>
+    <provide interface="org.nuxeo.ecm.diff.service.DiffDisplayService" />
+  </service>
+
+  <extension-point name="diffDisplay">
+    <documentation>
+      <code>
+        <diffDisplay name="default">
+          <diffBlocks>
+            <diffBlock name="general" label="label.diffBlock.general">
+              <fields>
+                <field schema="dublincore" name="title" />
+                <field schema="dublincore" name="modified" />
+                <field schema="dublincore" name="subjects" />
+              </fields>
+            </diffBlock>
+            <diffBlock name="files" label="label.diffBlock.files">
+              <fields>
+                <field schema="files" name="files">
+                  <items>
+                    <item>filename</item>
+                    <item>file</item>
+                  </items>
+                </field>
+              </fields>
+            </diffBlock>
+          </diffBlocks>
+        </diffDisplay>
+      </code>
+    </documentation>
+    <object class="org.nuxeo.ecm.diff.service.impl.DiffDisplayDescriptor" />
+  </extension-point>
+
+</component>
diff --git a/src/main/resources/OSGI-INF/diff-widgets-contrib.xml b/src/main/resources/OSGI-INF/diff-widgets-contrib.xml
new file mode 100644
index 0000000..35d0098
--- /dev/null
+++ b/src/main/resources/OSGI-INF/diff-widgets-contrib.xml
 <at>  <at>  -0,0 +1,28  <at>  <at> 
+<?xml version="1.0"?>
+<component name="org.nuxeo.ecm.diff.widgets.contrib">
+
+  <extension target="org.nuxeo.ecm.platform.forms.layout.LayoutStore"
+    point="widgets">
+
+    <!-- Generic widgets binded to diff property types, see: org.nuxeo.ecm.diff.model.PropertyType -->
+    <widget name="string" type="text">
+      <categories>
+        <category>diff</category>
+      </categories>
+    </widget>
+
+    <widget name="scalarList" type="list">
+      <categories>
+        <category>diff</category>
+      </categories>
+    </widget>
+    
+    <widget name="complexList" type="list">
+      <categories>
+        <category>diff</category>
+      </categories>
+    </widget>
+
+  </extension>
+
+</component>
diff --git a/src/main/resources/OSGI-INF/document-diff-actions-contrib.xml b/src/main/resources/OSGI-INF/document-diff-actions-contrib.xml
deleted file mode 100644
index 1f92e26..0000000
--- a/src/main/resources/OSGI-INF/document-diff-actions-contrib.xml
+++ /dev/null
 <at>  <at>  -1,26 +0,0  <at>  <at> 
-<component name="org.nuxeo.ecm.diff.actions">
-
-  <extension target="org.nuxeo.ecm.platform.actions.ActionService"
-    point="actions">
-
-    <action id="CURRENT_SELECTION_DIFF" link="#{documentDiffActions.prepareCurrentSelectionDiff}"
-      label="command.clipboard.diff" order="100">
-      <category>CURRENT_SELECTION_LIST</category>
-      <filter-id>canDiffCurrentSelection</filter-id>
-    </action>
-
-  </extension>
-
-  <extension target="org.nuxeo.ecm.platform.actions.ActionService"
-    point="filters">
-
-    <filter id="canDiffCurrentSelection">
-      <rule grant="true">
-        <condition>#{documentDiffActions.canDiffCurrentSelection}
-        </condition>
-      </rule>
-    </filter>
-
-  </extension>
-
-</component>
diff --git a/src/main/resources/OSGI-INF/document-diff-display-service.xml b/src/main/resources/OSGI-INF/document-diff-display-service.xml
deleted file mode 100644
index c736d0d..0000000
--- a/src/main/resources/OSGI-INF/document-diff-display-service.xml
+++ /dev/null
 <at>  <at>  -1,34 +0,0  <at>  <at> 
-<component
-  name="org.nuxeo.ecm.diff.service.DocumentDiffDisplayService">
-
-  <documentation>
-    This service provides an extension point to manage
-    complex items order in a document diff display.
-
-     <at> author
-    Antoine
-    Taillefer
-  </documentation>
-
-  <implementation
-    class="org.nuxeo.ecm.diff.service.impl.DocumentDiffDisplayServiceImpl" />
-
-  <service>
-    <provide
-      interface="org.nuxeo.ecm.diff.service.DocumentDiffDisplayService" />
-  </service>
-
-  <extension-point name="complexItemsDisplay">
-    <documentation>
-      <code>
-        <complexItems property="complextypes:complex">
-          <item name="stringItem" />
-          <item name="booleanItem" />
-          <item name="integerItem" />
-        </complexItems>
-      </code>
-    </documentation>
-    <object class="org.nuxeo.ecm.diff.service.ComplexItemsDescriptor" />
-  </extension-point>
-
-</component>
diff --git a/src/main/resources/web/nuxeo.war/incl/diff/doc_diff_result.xhtml b/src/main/resources/web/nuxeo.war/incl/diff/doc_diff_result.xhtml
index bf135be..9145333 100644
--- a/src/main/resources/web/nuxeo.war/incl/diff/doc_diff_result.xhtml
+++ b/src/main/resources/web/nuxeo.war/incl/diff/doc_diff_result.xhtml
 <at>  <at>  -3,7 +3,8  <at>  <at> 
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:c="http://java.sun.com/jstl/core"
   xmlns:nxu="http://nuxeo.org/nxweb/util"
-  xmlns:nxd="http://nuxeo.org/nxweb/document">
+  xmlns:nxd="http://nuxeo.org/nxweb/document"
+  xmlns:nxl="http://nuxeo.org/nxforms/layout">
   
   <style type="text/css">
     .diffTable {width: 100%; border-collapse: collapse;}
 <at>  <at>  -22,15 +23,15  <at>  <at> 
     .italic {font-style: italic;}
   </style>
   
-  <c:if test="#{!documentDiffActions.documentDiffAvailable}">
+  <c:if test="#{!diffActions.documentDiffAvailable}">
     <h2>
       <h:outputText value="#{messages['document.diff.noDiffAvailable']}"/>
     </h2>
   </c:if>
-  <c:if test="#{documentDiffActions.documentDiffAvailable}">
+  <c:if test="#{diffActions.documentDAvailable}">
   
-  <nxu:set var="leftDoc" value="#{documentDiffActions.leftDoc}" cache="true">
-  <nxu:set var="rightDoc" value="#{documentDiffActions.rightDoc}" cache="true">
+  <nxu:set var="leftDoc" value="#{diffActions.leftDoc}" cache="true">
+  <nxu:set var="rightDoc" value="#{diffActions.rightDoc}" cache="true">
   
     <table class="diffHeader diffTable">
       <tr>
 <at>  <at>  -43,7 +44,7  <at>  <at> 
           <h2>
             [<nxd:restDocumentLink document="#{leftDoc}">
               <span id="title_#{leftDoc.ref}" title="#{leftDoc.dc.description}">
-                #{nxd:titleOrId(leftDoc)}
+                <h:outputText value="#{nxd:titleOrId(leftDoc)}" />
               </span>
             </nxd:restDocumentLink>]
           </h2>
 <at>  <at>  -52,7 +53,7  <at>  <at> 
           <h2>
             [<nxd:restDocumentLink document="#{rightDoc}">
               <span id="title_#{rightDoc.ref}" title="#{rightDoc.dc.description}">
-                #{nxd:titleOrId(rightDoc)}
+                <h:outputText value="#{nxd:titleOrId(rightDoc)}" />
               </span>
             </nxd:restDocumentLink>
             <c:if test="#{rightDoc.version}">
 <at>  <at>  -66,152 +67,32  <at>  <at> 
       </tr>
     </table>
     
-    <c:if test="#{documentDiff.docDiffEmpty}">
+    <c:if test="#{empty defaultDiffDisplayBlocks}">
       <h3>
         <h:outputText value="#{messages['document.diff.emptyDiff']}"/>
       </h3>
     </c:if>
     
-    <c:if test="#{!documentDiff.docDiffEmpty}">
-      <ui:repeat value="#{documentDiff.schemaNames}" var="schemaName">
-        <nxu:set var="schemaDiff" value="#{documentDiff.getSchemaDiff(schemaName)}" cache="false">
-  
-          <div class="foldableBox">
-            <h3 class="unfolded">
-              <a href="#nologo" onclick="return toggleBox(this)">
-                <h:outputText value="#{messages[schemaName]}" />
-              </a>
-              <span class="breaker"></span>
-            </h3>
-            <div class="boxBody">
-              <nxu:dataTable id="schemaDiffTable_#{schemaName}" styleClass="diffTable"
-                value="#{schemaDiff.fieldNames}" var="fieldName">
-                <nxu:column styleClass="fieldLabelColumn">
-                  <h:outputText value="#{messages[fieldName]}"/>
-                </nxu:column>
-                <nxu:column styleClass="fieldDiffColumn">
-                  <nxu:set var="fieldDiff" value="#{schemaDiff.getFieldDiff(fieldName)}">
-
-                    <!-- Simple or content property -->
-                    <f:subview rendered="#{fieldDiff.simpleType or fieldDiff.contentType}">
-                      <ui:include src="/incl/diff/simple_property_diff.xhtml">
-                        <ui:param name="propertyValue" value="#{propertyDiffDisplayHelper.getSimplePropertyValue(leftDoc, schemaName, fieldName)}"/>
-                        <ui:param name="propertyDiff" value="#{fieldDiff}"/>
-                        <ui:param name="side" value="left" />
-                      </ui:include>
-                    </f:subview>
-                  
-                    <!-- Complex property -->
-                    <f:subview rendered="#{fieldDiff.complexType and !fieldDiff.contentType}">
-                      <ui:include src="/incl/diff/complex_property_diff.xhtml">
-                        <ui:param name="doc" value="#{leftDoc}"/>
-                        <ui:param name="schema" value="#{schemaName}"/>
-                        <ui:param name="field" value="#{fieldName}"/>
-                        <ui:param name="propertyDiff" value="#{fieldDiff}"/>
-                        <ui:param name="side" value="left" />
-                      </ui:include>
-                    </f:subview>
-                    
-                    <!-- Simple list property -->
-                    <f:subview rendered="#{fieldDiff.scalarListType}">
-                      <nxu:dataTable
-                        value="#{propertyDiffDisplayHelper.getListItemIndexes(fieldDiff)}" var="listItemIndex">
-                        
-                        <nxu:column>
-                          <span class="listItemIndex">
-                            <h:outputText value="#{listItemIndex + 1}" />
-                          </span>
-                          <ui:include src="/incl/diff/simple_property_diff.xhtml">
-                            <ui:param name="propertyValue" value="#{propertyDiffDisplayHelper.getListItemValue(leftDoc, schemaName, fieldName, listItemIndex)}"/>
-                            <ui:param name="propertyDiff" value="#{fieldDiff.diffMap[listItemIndex]}"/>
-                            <ui:param name="side" value="left" />
-                          </ui:include>
-                        </nxu:column>
-                        
-                      </nxu:dataTable>
-                    </f:subview>
-                    
-                    <!-- Complex list property -->
-                    <f:subview rendered="#{fieldDiff.complexListType}">
-                      <ui:include src="/incl/diff/complex_list_property_diff.xhtml">
-                        <ui:param name="doc" value="#{leftDoc}"/>
-                        <ui:param name="schema" value="#{schemaName}"/>
-                        <ui:param name="field" value="#{fieldName}"/>
-                        <ui:param name="propertyDiff" value="#{fieldDiff}"/>
-                        <ui:param name="side" value="left" />
-                      </ui:include>
-                    </f:subview>
-                      
-                  </nxu:set>
-                </nxu:column>
-                <nxu:column styleClass="fieldDiffColumn">
-                  <nxu:set var="fieldDiff" value="#{schemaDiff.getFieldDiff(fieldName)}">
-                    
-                    <!-- Simple or content property -->
-                    <f:subview rendered="#{fieldDiff.simpleType or fieldDiff.contentType}">
-                      <div class="rightDiff">
-                        <ui:include src="/incl/diff/simple_property_diff.xhtml">
-                          <ui:param name="propertyValue" value="#{propertyDiffDisplayHelper.getSimplePropertyValue(rightDoc, schemaName, fieldName)}"/>
-                          <ui:param name="propertyDiff" value="#{fieldDiff}"/>
-                          <ui:param name="side" value="right" />
-                        </ui:include>
-                      </div>
-                    </f:subview>
-                    
-                    <!-- Complex property -->
-                    <f:subview rendered="#{fieldDiff.complexType and !fieldDiff.contentType}">
-                     <ui:include src="/incl/diff/complex_property_diff.xhtml">
-                        <ui:param name="doc" value="#{rightDoc}"/>
-                        <ui:param name="schema" value="#{schemaName}"/>
-                        <ui:param name="field" value="#{fieldName}"/>
-                        <ui:param name="propertyDiff" value="#{fieldDiff}"/>
-                        <ui:param name="side" value="right" />
-                      </ui:include>
-                    </f:subview>
-                    
-                    <!-- Simple list property -->
-                    <f:subview rendered="#{fieldDiff.scalarListType}">
-                      <nxu:dataTable
-                        value="#{propertyDiffDisplayHelper.getListItemIndexes(fieldDiff)}" var="listItemIndex">
-                        
-                        <nxu:column>
-                          <span class="listItemIndex">
-                            <h:outputText value="#{listItemIndex + 1}" />
-                          </span>
-                          <ui:include src="/incl/diff/simple_property_diff.xhtml">
-                            <ui:param name="propertyValue" value="#{propertyDiffDisplayHelper.getListItemValue(rightDoc, schemaName, fieldName, listItemIndex)}"/>
-                            <ui:param name="propertyDiff" value="#{fieldDiff.diffMap[listItemIndex]}"/>
-                            <ui:param name="side" value="right" />
-                          </ui:include>
-                        </nxu:column>
-                        
-                      </nxu:dataTable>
-                    </f:subview>
-                    
-                    <!-- Complex list property -->
-                    <f:subview rendered="#{fieldDiff.complexListType}">
-                      <ui:include src="/incl/diff/complex_list_property_diff.xhtml">
-                        <ui:param name="doc" value="#{rightDoc}"/>
-                        <ui:param name="schema" value="#{schemaName}"/>
-                        <ui:param name="field" value="#{fieldName}"/>
-                        <ui:param name="propertyDiff" value="#{fieldDiff}"/>
-                        <ui:param name="side" value="right" />
-                      </ui:include>
-                    </f:subview>
-                    
-                  </nxu:set>
-                </nxu:column>
-              </nxu:dataTable>
-            </div>
+    <c:if test="#{!empty defaultDiffDisplayBlocks}">
+      
+      <c:forEach value="#{defaultDiffDisplayBlocks}" var="diffDisplayBlock">
+        <div class="foldableBox">
+          <h3 class="unfolded">
+            <a href="#nologo" onclick="return toggleBox(this)">
+              <h:outputText value="#{messages[diffDisplayBlock.label]}" />
+            </a>
+            <span class="breaker"></span>
+          </h3>
+          <div class="boxBody">
+            <nxl:layout definition="#{diffDisplayBlock.layoutDefinition}" value="#{diffDisplayBlock.value}" />
           </div>
-          
-        </nxu:set>
-      </ui:repeat>
-    
+        </div>
+      </c:forEach>
+      
       <div>
         <h:form>
           <h:commandButton value="#{messages['document.diff.refresh']}"
-            action="#{documentDiffActions.refresh()}"
+            action="#{diffActions.refresh()}"
             styleClass="button" />
         </h:form>
       </div>    
diff --git a/src/test/java/org/nuxeo/ecm/diff/DocumentDiffRepositoryInit.java b/src/test/java/org/nuxeo/ecm/diff/DocumentDiffRepositoryInit.java
index 29495b7..1206dd4 100644
--- a/src/test/java/org/nuxeo/ecm/diff/DocumentDiffRepositoryInit.java
+++ b/src/test/java/org/nuxeo/ecm/diff/DocumentDiffRepositoryInit.java
 <at>  <at>  -18,9 +18,12  <at>  <at> 
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.TimeZone;
 
 import org.nuxeo.ecm.core.api.ClientException;
 import org.nuxeo.ecm.core.api.CoreSession;
 <at>  <at>  -63,9 +66,11  <at>  <at>  protected final DocumentModel createLeftDoc(CoreSession session)
         // -----------------------
         doc.setPropertyValue("dc:title", "My first sample");
         doc.setPropertyValue("dc:description", "description");
-        doc.setPropertyValue("dc:created", "2011-12-29T11:24:25Z");
+        doc.setPropertyValue("dc:created",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 29, 11, 24, 25));
         doc.setPropertyValue("dc:creator", "Administrator");
-        doc.setPropertyValue("dc:modified", "2011-12-29T11:24:25Z");
+        doc.setPropertyValue("dc:modified",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 29, 11, 24, 25));
         doc.setPropertyValue("dc:lastContributor", "Administrator");
         doc.setPropertyValue("dc:contributors", new String[] { "Administrator",
                 "joe", null });
 <at>  <at>  -79,7 +84,8  <at>  <at>  protected final DocumentModel createLeftDoc(CoreSession session)
         doc.setPropertyValue("st:textarea", "a textarea property");
         doc.setPropertyValue("st:boolean", true);
         doc.setPropertyValue("st:integer", 10);
-        doc.setPropertyValue("st:date", "2011-12-28T23:00:00Z");
+        doc.setPropertyValue("st:date",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 28, 23, 00, 00));
         doc.setPropertyValue(
                 "st:htmlText",
                 "&lt;p&gt;html text with &lt;strong&gt;&lt;span style=\"text-decoration: underline;\"&gt;styles&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;\n&lt;ul&gt;\n&lt;li&gt;and&lt;/li&gt;\n&lt;li&gt;nice&lt;/li&gt;\n&lt;li&gt;bullets&lt;/li&gt;\n&lt;/ul&gt;\n&lt;p&gt;&amp;nbsp;&lt;/p&gt;");
 <at>  <at>  -151,9 +157,11  <at>  <at>  protected final DocumentModel createRightDoc(CoreSession session)
         // dublincore
         // -----------------------
         doc.setPropertyValue("dc:title", "My second sample");
-        doc.setPropertyValue("dc:created", "2011-12-30T12:05:02Z");
+        doc.setPropertyValue("dc:created",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 30, 12, 05, 02));
         doc.setPropertyValue("dc:creator", "Administrator");
-        doc.setPropertyValue("dc:modified", "2011-12-30T12:05:02Z");
+        doc.setPropertyValue("dc:modified",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 30, 12, 05, 02));
         doc.setPropertyValue("dc:lastContributor", " Administrator ");
         doc.setPropertyValue("dc:contributors", new String[] {
                 "anotherAdministrator", "joe", "jack" });
 <at>  <at>  -165,7 +173,8  <at>  <at>  protected final DocumentModel createRightDoc(CoreSession session)
         doc.setPropertyValue("st:string", "a different string property");
         doc.setPropertyValue("st:textarea", "a textarea property");
         doc.setPropertyValue("st:integer", 10);
-        doc.setPropertyValue("st:date", "2011-12-28T23:00:00Z");
+        doc.setPropertyValue("st:date",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 28, 23, 00, 00));
         doc.setPropertyValue(
                 "st:htmlText",
                 "&lt;p&gt;html  text modified with &lt;span style=\"text-decoration: underline;\"&gt;styles&lt;/span&gt;&lt;/p&gt;\n&lt;ul&gt;\n&lt;li&gt;and&lt;/li&gt;\n&lt;li&gt;nice&lt;/li&gt;\n&lt;li&gt;bullets&lt;/li&gt;\n&lt;/ul&gt;\n&lt;p&gt;&amp;nbsp;&lt;/p&gt;");
 <at>  <at>  -176,14 +185,16  <at>  <at>  protected final DocumentModel createRightDoc(CoreSession session)
         Map<String, Serializable> complexPropValue = new HashMap<String, Serializable>();
         complexPropValue.put("stringItem", "string of a complex type");
         complexPropValue.put("booleanItem", false);
-        complexPropValue.put("dateItem", "2011-12-29T23:00:00Z");
+        complexPropValue.put("dateItem",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 29, 23, 00, 00));
         doc.setPropertyValue("ct:complex", (Serializable) complexPropValue);
 
         Map<String, Serializable> item1ComplexPropValue = new HashMap<String, Serializable>();
         item1ComplexPropValue.put("stringItem",
                 "first element of a complex list");
         item1ComplexPropValue.put("booleanItem", false);
-        item1ComplexPropValue.put("dateItem", "2011-12-30T23:00:00Z");
+        item1ComplexPropValue.put("dateItem",
+                getCalendarUTCNoMillis(2011, Calendar.DECEMBER, 30, 23, 00, 00));
 
         Map<String, Serializable> item2ComplexPropValue = new HashMap<String, Serializable>();
         item2ComplexPropValue.put("stringItem",
 <at>  <at>  -234,4 +245,25  <at>  <at>  protected final DocumentModel createRightDoc(CoreSession session)
         return session.createDocument(doc);
     }
 
+    /**
+     * Gets a calendar set on the UTC time zone with 0 milliseconds.
+     * 
+     *  <at> param year the year
+     *  <at> param month the month
+     *  <at> param day the day
+     *  <at> param hourOfDay the hour of day
+     *  <at> param minute the minute
+     *  <at> param second the second
+     *  <at> return the calendar
+     */
+    public static Calendar getCalendarUTCNoMillis(int year, int month, int day,
+            int hourOfDay, int minute, int second) {
+
+        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+        cal.set(year, month, day, hourOfDay, minute, second);
+        cal.set(Calendar.MILLISECOND, 0);
+
+        return cal;
+    }
+
 }
diff --git a/src/test/java/org/nuxeo/ecm/diff/service/TestDiffDisplayService.java b/src/test/java/org/nuxeo/ecm/diff/service/TestDiffDisplayService.java
new file mode 100644
index 0000000..f7d0b99
--- /dev/null
+++ b/src/test/java/org/nuxeo/ecm/diff/service/TestDiffDisplayService.java
 <at>  <at>  -0,0 +1,295  <at>  <at> 
+/*
+ * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Contributors:
+ *     ataillefer
+ */
+package org.nuxeo.ecm.diff.service;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.nuxeo.ecm.core.api.ClientException;
+import org.nuxeo.ecm.core.api.CoreSession;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.nuxeo.ecm.core.api.PathRef;
+import org.nuxeo.ecm.core.test.CoreFeature;
+import org.nuxeo.ecm.core.test.annotations.BackendType;
+import org.nuxeo.ecm.core.test.annotations.Granularity;
+import org.nuxeo.ecm.core.test.annotations.RepositoryConfig;
+import org.nuxeo.ecm.diff.DocumentDiffRepositoryInit;
+import org.nuxeo.ecm.diff.model.DiffBlockDefinition;
+import org.nuxeo.ecm.diff.model.DiffDisplayBlock;
+import org.nuxeo.ecm.diff.model.DiffDisplayField;
+import org.nuxeo.ecm.diff.model.DiffFieldDefinition;
+import org.nuxeo.ecm.diff.model.DocumentDiff;
+import org.nuxeo.ecm.diff.model.impl.ComplexDiffDisplayField;
+import org.nuxeo.ecm.diff.model.impl.DiffBlockDefinitionImpl;
+import org.nuxeo.ecm.diff.model.impl.DiffFieldDefinitionImpl;
+import org.nuxeo.ecm.diff.model.impl.ListDiffDisplayField;
+import org.nuxeo.ecm.diff.model.impl.SimpleDiffDisplayField;
+import org.nuxeo.ecm.diff.service.impl.DiffDisplayDescriptor;
+import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes;
+import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.LayoutRowDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
+import org.nuxeo.ecm.platform.forms.layout.api.WidgetReference;
+import org.nuxeo.runtime.test.runner.Deploy;
+import org.nuxeo.runtime.test.runner.Features;
+import org.nuxeo.runtime.test.runner.FeaturesRunner;
+
+import com.google.inject.Inject;
+
+/**
+ * Tests the { <at> link DiffDisplayService}.
+ * 
+ *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
+ */
+ <at> RunWith(FeaturesRunner.class)
+ <at> Features(CoreFeature.class)
+ <at> RepositoryConfig(repositoryName = "default", type = BackendType.H2, init = DocumentDiffRepositoryInit.class, user = "Administrator", cleanup = Granularity.METHOD)
+ <at> Deploy({
+        "org.nuxeo.ecm.platform.forms.layout.core:OSGI-INF/layouts-core-framework.xml",
+        "org.nuxeo.diff", "org.nuxeo.diff.test" })
+public class TestDiffDisplayService extends TestCase {
+
+     <at> Inject
+    protected CoreSession session;
+
+     <at> Inject
+    protected DiffDisplayService diffDisplayService;
+
+     <at> Inject
+    protected DocumentDiffService docDiffService;
+
+    /**
+     * Test diff display contrib.
+     * 
+     *  <at> throws ClientException the client exception
+     */
+     <at> Test
+    public void testDiffDisplayContrib() throws ClientException {
+
+        // Check service
+        assertNotNull(diffDisplayService);
+
+        // Check diffDisplay contribs
+        Map<String, DiffDisplayDescriptor> contribs = diffDisplayService.getContributions();
+        assertNotNull(contribs);
+        assertEquals(1, contribs.size());
+        assertTrue(contribs.containsKey("default"));
+
+        // Check a non existing diffDisplay contrib
+        List<DiffBlockDefinition> diffBlockDefinitions = diffDisplayService.getDiffBlockDefinitions("test");
+        assertNull(diffBlockDefinitions);
+
+        // Check default diffDisplay contrib
+        diffBlockDefinitions = diffDisplayService.getDefaultDiffBlockDefinitions();
+        assertNotNull(diffBlockDefinitions);
+
+        List<DiffBlockDefinition> expectedDiffBlockDefinitions = new ArrayList<DiffBlockDefinition>();
+
+        List<DiffFieldDefinition> fields = new ArrayList<DiffFieldDefinition>();
+        fields.add(new DiffFieldDefinitionImpl("dublincore", "title"));
+        fields.add(new DiffFieldDefinitionImpl("dublincore", "modified"));
+        fields.add(new DiffFieldDefinitionImpl("dublincore", "subjects"));
+        expectedDiffBlockDefinitions.add(new DiffBlockDefinitionImpl("general",
+                fields));
+
+        fields = new ArrayList<DiffFieldDefinition>();
+        List<String> items = new ArrayList<String>();
+        items.add("stringItem");
+        items.add("dateItem");
+        items.add("integerItem");
+        fields.add(new DiffFieldDefinitionImpl("complextypes", "complexList",
+                items));
+        expectedDiffBlockDefinitions.add(new DiffBlockDefinitionImpl(
+                "complexTypes", fields));
+
+        assertEquals(expectedDiffBlockDefinitions, diffBlockDefinitions);
+
+        // Check that order is taken into account
+        DiffBlockDefinition diffDisplayBlock = expectedDiffBlockDefinitions.get(0);
+        expectedDiffBlockDefinitions.remove(0);
+        expectedDiffBlockDefinitions.add(diffDisplayBlock);
+
+        assertFalse(expectedDiffBlockDefinitions.equals(diffBlockDefinitions));
+
+    }
+
+    /**
+     * Test diff display service.
+     * 
+     *  <at> throws ClientException the client exception
+     *  <at> throws ParseException
+     */
+     <at> Test
+    public void testDiffDisplayService() throws ClientException, ParseException {
+
+        // Get left and right docs
+        DocumentModel leftDoc = session.getDocument(new PathRef(
+                DocumentDiffRepositoryInit.LEFT_DOC_PATH));
+        DocumentModel rightDoc = session.getDocument(new PathRef(
+                DocumentDiffRepositoryInit.RIGHT_DOC_PATH));
+
+        // Do doc diff
+        DocumentDiff docDiff = docDiffService.diff(session, leftDoc, rightDoc);
+
+        // Check a non existing diffDisplay contrib
+        List<DiffDisplayBlock> diffDisplayBlocks = diffDisplayService.getDiffDisplayBlocks(
+                "test", docDiff, leftDoc, rightDoc);
+        assertNotNull(diffDisplayBlocks);
+        // TODO: should not be empty, with random schema fields...
+        assertTrue(diffDisplayBlocks.isEmpty());
+
+        // Check default diffDisplay contrib
+        diffDisplayBlocks = diffDisplayService.getDefaultDiffDisplayBlocks(
+                docDiff, leftDoc, rightDoc);
+        assertNotNull(diffDisplayBlocks);
+        assertEquals(2, diffDisplayBlocks.size());
+
+        // ------------------------------
+        // Check first diffDisplay block
+        // ------------------------------
+        DiffDisplayBlock diffDisplayBlock = diffDisplayBlocks.get(0);
+
+        // Check label
+        assertEquals("label.diffBlock.general", diffDisplayBlock.getLabel());
+
+        // Check value
+        Map<String, DiffDisplayField> expectedValue = new HashMap<String, DiffDisplayField>();
+        expectedValue.put("dublincore:title", new SimpleDiffDisplayField(
+                "My first sample", "My second sample"));
+        Calendar leftCal = DocumentDiffRepositoryInit.getCalendarUTCNoMillis(
+                2011, Calendar.DECEMBER, 29, 11, 24, 25);
+        Calendar rightCal = DocumentDiffRepositoryInit.getCalendarUTCNoMillis(
+                2011, Calendar.DECEMBER, 30, 12, 05, 02);
+        expectedValue.put("dublincore:modified", new SimpleDiffDisplayField(
+                leftCal, rightCal));
+        ListDiffDisplayField listField = new ListDiffDisplayField();
+        ComplexDiffDisplayField item1 = new ComplexDiffDisplayField();
+        item1.put("index", new SimpleDiffDisplayField("1", "1"));
+        item1.put("value", new SimpleDiffDisplayField("Architecture", "N/A"));
+        listField.add(item1);
+        // expectedValue.put("dublincore:subjects", listField);
+        expectedValue.put("dublincore:subjects", null);
+        assertEquals(expectedValue, diffDisplayBlock.getValue());
+
+        // Check layout definition
+        LayoutDefinition layoutDef = diffDisplayBlock.getLayoutDefinition();
+        assertEquals("general", layoutDef.getName());
+
+        // Check layout row definitions
+        LayoutRowDefinition[] layoutRowDefinitions = layoutDef.getRows();
+        assertEquals(3, layoutRowDefinitions.length);
+
+        LayoutRowDefinition layoutRowDef = layoutRowDefinitions[0];
+        assertEquals("dublincore:title", layoutRowDef.getName());
+        assertEquals(1, layoutRowDef.getSize());
+        WidgetReference[] widgetRefs = layoutRowDef.getWidgetReferences();
+        assertEquals(1, widgetRefs.length);
+        WidgetReference widgetRef = widgetRefs[0];
+        assertEquals("diff", widgetRef.getCategory());
+        assertEquals("dublincore:title", widgetRef.getName());
+
+        layoutRowDef = layoutRowDefinitions[1];
+        assertEquals("dublincore:modified", layoutRowDef.getName());
+        assertEquals(1, layoutRowDef.getSize());
+        widgetRefs = layoutRowDef.getWidgetReferences();
+        assertEquals(1, widgetRefs.length);
+        widgetRef = widgetRefs[0];
+        assertEquals("diff", widgetRef.getCategory());
+        assertEquals("dublincore:modified", widgetRef.getName());
+
+        layoutRowDef = layoutRowDefinitions[2];
+        assertEquals("dublincore:subjects", layoutRowDef.getName());
+        assertEquals(1, layoutRowDef.getSize());
+        widgetRefs = layoutRowDef.getWidgetReferences();
+        assertEquals(1, widgetRefs.length);
+        widgetRef = widgetRefs[0];
+        assertEquals("diff", widgetRef.getCategory());
+        assertEquals("dublincore:subjects", widgetRef.getName());
+
+        // Check layout widget definitions
+        WidgetDefinition wDef = layoutDef.getWidgetDefinition("dublincore:title");
+        assertNotNull(wDef);
+        assertEquals("dublincore:title", wDef.getName());
+        assertEquals("text", wDef.getType());
+        assertEquals("label.diff.widget.dublincore.title",
+                wDef.getLabel(BuiltinModes.ANY));
+        assertTrue(wDef.isTranslated());
+        FieldDefinition[] fieldDefs = wDef.getFieldDefinitions();
+        assertEquals(1, fieldDefs.length);
+        FieldDefinition fieldDef = fieldDefs[0];
+        assertEquals("dublincore:title", fieldDef.getPropertyName());
+
+        wDef = layoutDef.getWidgetDefinition("dublincore:modified");
+        assertNotNull(wDef);
+        assertEquals("dublincore:modified", wDef.getName());
+        assertEquals("dateTime", wDef.getType());
+        assertEquals("label.diff.widget.dublincore.modified",
+                wDef.getLabel(BuiltinModes.ANY));
+        assertTrue(wDef.isTranslated());
+        fieldDefs = wDef.getFieldDefinitions();
+        assertEquals(1, fieldDefs.length);
+        fieldDef = fieldDefs[0];
+        assertEquals("dublincore:modified", fieldDef.getPropertyName());
+
+        wDef = layoutDef.getWidgetDefinition("dublincore:subjects");
+        assertNotNull(wDef);
+        assertEquals("dublincore:subjects", wDef.getName());
+        assertEquals("list", wDef.getType());
+        assertEquals("label.diff.widget.dublincore.subjects",
+                wDef.getLabel(BuiltinModes.ANY));
+        assertTrue(wDef.isTranslated());
+        fieldDefs = wDef.getFieldDefinitions();
+        assertEquals(1, fieldDefs.length);
+        fieldDef = fieldDefs[0];
+        assertEquals("dublincore:subjects", fieldDef.getPropertyName());
+
+        // TODO: check props ?
+    }
+    /**
+     * Test apply complex items order.
+     */
+    //  <at> Test
+    // public void testApplyComplexItemsOrder() {
+    //
+    // List<String> complexItems = new ArrayList<String>();
+    // complexItems.add("stringItem");
+    // complexItems.add("booleanItem");
+    // complexItems.add("integerItem");
+    // complexItems.add("dateItem");
+    //
+    // docDiffDisplayService.applyComplexItemsOrder("complextypes", "complex",
+    // complexItems);
+    //
+    // List<String> expectedComplexItems = new ArrayList<String>();
+    // expectedComplexItems.add("integerItem");
+    // expectedComplexItems.add("dateItem");
+    // expectedComplexItems.add("stringItem");
+    // expectedComplexItems.add("booleanItem");
+    //
+    // assertEquals(expectedComplexItems, complexItems);
+    // }
+
+}
diff --git a/src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiff.java b/src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiff.java
index 7560438..936dcd0 100644
--- a/src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiff.java
+++ b/src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiff.java
 <at>  <at>  -39,7 +39,6  <at>  <at> 
 import org.nuxeo.ecm.diff.model.impl.ComplexPropertyDiff;
 import org.nuxeo.ecm.diff.model.impl.ListPropertyDiff;
 import org.nuxeo.ecm.diff.model.impl.SimplePropertyDiff;
-import org.nuxeo.ecm.diff.service.DocumentDiffService;
 import org.nuxeo.ecm.diff.xmlexport.DocumentXMLExporter;
 import org.nuxeo.runtime.test.runner.Deploy;
 import org.nuxeo.runtime.test.runner.Features;
 <at>  <at>  -48,14 +47,19  <at>  <at> 
 import com.google.inject.Inject;
 
 /**
- * Tests document diff using DocumentDiffService.
+ * Tests the { <at> link DocumentDiffService} on document XML exports.
+ * <p>
+ * The { <at> link DocumentDiffRepositoryInit} class initializes the repository with
+ * 2 documents for this purpose.
  * 
  *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
  */
  <at> RunWith(FeaturesRunner.class)
  <at> Features(CoreFeature.class)
  <at> RepositoryConfig(repositoryName = "default", type = BackendType.H2, init = DocumentDiffRepositoryInit.class, user = "Administrator", cleanup = Granularity.METHOD)
- <at> Deploy({ "org.nuxeo.diff", "org.nuxeo.diff.test" })
+ <at> Deploy({ "org.nuxeo.diff:OSGI-INF/document-xml-export-service.xml",
+        "org.nuxeo.diff:OSGI-INF/document-diff-service.xml",
+        "org.nuxeo.diff.test:OSGI-INF/test-types-contrib.xml" })
 public class TestDocumentDiff extends DiffTestCase {
 
      <at> Inject
diff --git a/src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiffDisplayService.java b/src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiffDisplayService.java
deleted file mode 100644
index 8d782fe..0000000
--- a/src/test/java/org/nuxeo/ecm/diff/service/TestDocumentDiffDisplayService.java
+++ /dev/null
 <at>  <at>  -1,107 +0,0  <at>  <at> 
-/*
- * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public License
- * (LGPL) version 2.1 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * Contributors:
- *     ataillefer
- */
-package org.nuxeo.ecm.diff.service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import junit.framework.TestCase;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.nuxeo.ecm.core.test.CoreFeature;
-import org.nuxeo.ecm.diff.service.ComplexItemsDescriptor;
-import org.nuxeo.ecm.diff.service.DocumentDiffDisplayService;
-import org.nuxeo.runtime.test.runner.Deploy;
-import org.nuxeo.runtime.test.runner.Features;
-import org.nuxeo.runtime.test.runner.FeaturesRunner;
-
-import com.google.inject.Inject;
-
-/**
- * Tests DocumentDiffDisplayService.
- * 
- *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
- */
- <at> RunWith(FeaturesRunner.class)
- <at> Features(CoreFeature.class)
- <at> Deploy({ "org.nuxeo.diff:OSGI-INF/document-diff-display-service.xml",
-        "org.nuxeo.diff.test:OSGI-INF/test-document-diff-display-contrib.xml" })
-public class TestDocumentDiffDisplayService extends TestCase {
-
-     <at> Inject
-    protected DocumentDiffDisplayService docDiffDisplayService;
-
-    /**
-     * Test document diff display contrib.
-     * 
-     *  <at> throws Exception the exception
-     */
-     <at> Test
-    public void testDocumentDiffDisplayService() {
-
-        // Check service
-        assertNotNull(docDiffDisplayService);
-
-        // Check contribs
-        Map<String, ComplexItemsDescriptor> contribs = docDiffDisplayService.getContributions();
-        assertNotNull(contribs);
-        assertEquals(1, contribs.size());
-
-        // Check a specific contrib
-        List<String> complexItems = docDiffDisplayService.getComplexItems(
-                "complextypes", "complex");
-        List<String> expectedComplexItems = new ArrayList<String>();
-        expectedComplexItems.add("integerItem");
-        expectedComplexItems.add("dateItem");
-        expectedComplexItems.add("stringItem");
-
-        assertEquals(expectedComplexItems, complexItems);
-
-        // Check that order is taken into account
-        expectedComplexItems.remove("integerItem");
-        expectedComplexItems.add("integerItem");
-
-        assertFalse(expectedComplexItems.equals(complexItems));
-    }
-
-    /**
-     * Test apply complex items order.
-     */
-     <at> Test
-    public void testApplyComplexItemsOrder() {
-
-        List<String> complexItems = new ArrayList<String>();
-        complexItems.add("stringItem");
-        complexItems.add("booleanItem");
-        complexItems.add("integerItem");
-        complexItems.add("dateItem");
-
-        docDiffDisplayService.applyComplexItemsOrder("complextypes", "complex",
-                complexItems);
-
-        List<String> expectedComplexItems = new ArrayList<String>();
-        expectedComplexItems.add("integerItem");
-        expectedComplexItems.add("dateItem");
-        expectedComplexItems.add("stringItem");
-        expectedComplexItems.add("booleanItem");
-
-        assertEquals(expectedComplexItems, complexItems);
-    }
-
-}
diff --git a/src/test/java/org/nuxeo/ecm/diff/service/TestFieldDiffHelper.java b/src/test/java/org/nuxeo/ecm/diff/service/TestFieldDiffHelper.java
index c7d8f87..2855d4e 100644
--- a/src/test/java/org/nuxeo/ecm/diff/service/TestFieldDiffHelper.java
+++ b/src/test/java/org/nuxeo/ecm/diff/service/TestFieldDiffHelper.java
 <at>  <at>  -34,7 +34,7  <at>  <at> 
 import org.w3c.dom.NodeList;
 
 /**
- * Tests the FieldDiffHelper class.
+ * Tests the { <at> link FieldDiffHelper}.
  * 
  *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
  */
diff --git a/src/test/java/org/nuxeo/ecm/diff/service/TestXMLDiff.java b/src/test/java/org/nuxeo/ecm/diff/service/TestXMLDiff.java
index 0357f60..de32054 100644
--- a/src/test/java/org/nuxeo/ecm/diff/service/TestXMLDiff.java
+++ b/src/test/java/org/nuxeo/ecm/diff/service/TestXMLDiff.java
 <at>  <at>  -36,7 +36,6  <at>  <at> 
 import org.nuxeo.ecm.diff.model.impl.ComplexPropertyDiff;
 import org.nuxeo.ecm.diff.model.impl.ListPropertyDiff;
 import org.nuxeo.ecm.diff.model.impl.SimplePropertyDiff;
-import org.nuxeo.ecm.diff.service.DocumentDiffService;
 import org.nuxeo.runtime.test.runner.Deploy;
 import org.nuxeo.runtime.test.runner.Features;
 import org.nuxeo.runtime.test.runner.FeaturesRunner;
 <at>  <at>  -44,7 +43,8  <at>  <at> 
 import com.google.inject.Inject;
 
 /**
- * Tests XML diff using DocumentDiffService.
+ * Tests the { <at> link DocumentDiffService} on hand-made pieces of XML similar to
+ * document XML exports.
  * 
  *  <at> author <a href="mailto:ataillefer <at> nuxeo.com">Antoine Taillefer</a>
  */
diff --git a/src/test/resources/META-INF/MANIFEST.MF b/src/test/resources/META-INF/MANIFEST.MF
index 0dde61f..91afbd4 100644
--- a/src/test/resources/META-INF/MANIFEST.MF
+++ b/src/test/resources/META-INF/MANIFEST.MF
 <at>  <at>  -8,4 +8,5  <at>  <at>  Bundle-Version: 5.6
 Bundle-ManifestVersion: 2
 Bundle-SymbolicName: org.nuxeo.diff.test;singleton:=true
 Nuxeo-Component: OSGI-INF/test-types-contrib.xml,
- OSGI-INF/test-document-diff-display-contrib.xml
+ OSGI-INF/test-diff-display-contrib.xml,
+ OSGI-INF/test-diff-widgets-contrib.xml
diff --git a/src/test/resources/OSGI-INF/test-diff-display-contrib.xml b/src/test/resources/OSGI-INF/test-diff-display-contrib.xml
new file mode 100644
index 0000000..379c712
--- /dev/null
+++ b/src/test/resources/OSGI-INF/test-diff-display-contrib.xml
 <at>  <at>  -0,0 +1,33  <at>  <at> 
+<?xml version="1.0"?>
+<component name="org.nuxeo.ecm.diff.service.DiffDisplayService.contrib.test">
+
+  <extension target="org.nuxeo.ecm.diff.service.DiffDisplayService"
+    point="diffDisplay">
+
+    <diffDisplay name="default">
+      <diffBlocks>
+        <diffBlock name="testNoFields" />
+        <diffBlock name="general" label="label.diffBlock.general">
+          <fields>
+            <field schema="dublincore" name="title" />
+            <field schema="dublincore" name="modified" />
+            <field schema="dublincore" name="subjects" />
+          </fields>
+        </diffBlock>
+        <diffBlock name="complexTypes" label="label.diffBlock.complexTypes">
+          <fields>
+            <field schema="complextypes" name="complexList">
+              <items>
+                <item>stringItem</item>
+                <item>dateItem</item>
+                <item>integerItem</item>
+              </items>
+            </field>
+          </fields>
+        </diffBlock>
+      </diffBlocks>
+    </diffDisplay>
+
+  </extension>
+
+</component>
diff --git a/src/test/resources/OSGI-INF/test-diff-widgets-contrib.xml b/src/test/resources/OSGI-INF/test-diff-widgets-contrib.xml
new file mode 100644
index 0000000..0bf09dc
--- /dev/null
+++ b/src/test/resources/OSGI-INF/test-diff-widgets-contrib.xml
 <at>  <at>  -0,0 +1,23  <at>  <at> 
+<?xml version="1.0"?>
+<component name="org.nuxeo.ecm.diff.widgets.contrib.test">
+
+  <extension target="org.nuxeo.ecm.platform.forms.layout.LayoutStore"
+    point="widgets">
+
+    <!-- Specific widgets binded to property names -->
+    <widget name="dublincore:modified" type="dateTime">
+      <categories>
+        <category>diff</category>
+      </categories>
+      <labels>
+        <label>label.diff.dublincore.modified</label>
+      </labels>
+      <translated>true</translated>
+      <properties widgetMode="any">
+        <property name="pattern">#{nxu:basicDateFormater()}</property>
+      </properties>
+    </widget>
+
+  </extension>
+
+</component>
diff --git a/src/test/resources/OSGI-INF/test-document-diff-display-contrib.xml b/src/test/resources/OSGI-INF/test-document-diff-display-contrib.xml
deleted file mode 100644
index 3ef4f0a..0000000
--- a/src/test/resources/OSGI-INF/test-document-diff-display-contrib.xml
+++ /dev/null
 <at>  <at>  -1,16 +0,0  <at>  <at> 
-<component
-  name="org.nuxeo.ecm.diff.service.DocumentDiffDisplayService.contrib">
-
-  <extension
-    target="org.nuxeo.ecm.diff.service.DocumentDiffDisplayService"
-    point="complexItemsDisplay">
-
-    <complexItems property="complextypes:complex">
-      <item>integerItem</item>
-      <item>dateItem</item>
-      <item>stringItem</item>
-    </complexItems>
-
-  </extension>
-
-</component>
diff --git a/src/test/resources/OSGI-INF/test-types-contrib.xml b/src/test/resources/OSGI-INF/test-types-contrib.xml
index 1a17c5c..e1984cc 100644
--- a/src/test/resources/OSGI-INF/test-types-contrib.xml
+++ b/src/test/resources/OSGI-INF/test-types-contrib.xml
 <at>  <at>  -1,7 +1,5  <at>  <at> 
 <?xml version="1.0"?>
-
-<component name="org.nuxeo.ecm.diff.test.types"
-  version="1.0">
+<component name="org.nuxeo.ecm.diff.types.contrib.test" version="1.0">
 
   <documentation>
     This component is contributing the test types and schemas needed for

_______________________________________________
ECM-checkins mailing list
ECM-checkins@...
http://lists.nuxeo.com/mailman/listinfo/ecm-checkins

Gmane