From 739b1e934fead8555d3e288521a02767a195e67d Mon Sep 17 00:00:00 2001
From: Arnaud Fontaine <arnaud.fontaine@nexedi.com>
Date: Wed, 22 Feb 2012 19:15:05 +0900
Subject: [PATCH] Set the Component state to modified upon modification, then
 check the consistency.

This allows to check consistency of reference and version as well (through
PropertyRecordableMixin rather than fiddling with the workflow history). Also,
split up state and error message into two separate fields.
---
 .../portal_skins/erp5_core/Component_view.xml |   3 +-
 .../Component_view/my_error_message_list.xml  | 313 ++++++++++++++++++
 ... my_translated_validation_state_title.xml} |   2 +-
 .../interactions/Component_modify.xml         | 129 ++++++++
 .../scripts/Component_setModifiedState.xml    |  67 ++++
 .../Component_validateAfterModified.xml       |  67 ++++
 .../states/validated.xml                      |   1 -
 .../transitions/modified.xml                  |   2 +-
 .../variables/text_content.xml                |  48 ---
 .../ERP5/bootstrap/erp5_core/bt/change_log    |   4 +
 product/ERP5/bootstrap/erp5_core/bt/revision  |   2 +-
 product/ERP5Type/dynamic/component_class.py   |   6 +-
 product/ERP5Type/mixin/component.py           | 252 ++++++++------
 13 files changed, 737 insertions(+), 159 deletions(-)
 create mode 100644 product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml
 rename product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/{my_translated_validation_state_title_with_error_message.xml => my_translated_validation_state_title.xml} (98%)
 create mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml
 create mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml
 create mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml
 delete mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml

diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml
index aeb33550fe..5a063ba309 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml
@@ -106,7 +106,8 @@
                     <value>
                       <list>
                         <string>my_description</string>
-                        <string>my_translated_validation_state_title_with_error_message</string>
+                        <string>my_translated_validation_state_title</string>
+                        <string>my_error_message_list</string>
                       </list>
                     </value>
                 </item>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml
new file mode 100644
index 0000000000..337c4f3b30
--- /dev/null
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml
@@ -0,0 +1,313 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="LinesField" module="Products.Formulator.StandardFields"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>my_error_message_list</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>The input failed the external validator.</string> </value>
+                </item>
+                <item>
+                    <key> <string>line_too_long</string> </key>
+                    <value> <string>A line was too long.</string> </value>
+                </item>
+                <item>
+                    <key> <string>required_not_found</string> </key>
+                    <value> <string>Input is required but no input given.</string> </value>
+                </item>
+                <item>
+                    <key> <string>too_long</string> </key>
+                    <value> <string>You entered too many characters.</string> </value>
+                </item>
+                <item>
+                    <key> <string>too_many_lines</string> </key>
+                    <value> <string>You entered too many lines.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>height</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_length</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_linelength</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_lines</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>view_separator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>width</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>height</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_length</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_linelength</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_lines</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>view_separator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>width</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value>
+                      <list/>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>height</string> </key>
+                    <value> <int>3</int> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>max_length</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_linelength</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>max_lines</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string>Errors</string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>view_separator</string> </key>
+                    <value> <string encoding="cdata"><![CDATA[
+
+<br />
+
+]]></string> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>width</string> </key>
+                    <value> <int>40</int> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="TALESMethod" module="Products.Formulator.TALESField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_text</string> </key>
+            <value> <string>python: here.getValidationState() == \'modified\'</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title_with_error_message.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title.xml
similarity index 98%
rename from product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title_with_error_message.xml
rename to product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title.xml
index 864a295d7f..f8bf5216b5 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title_with_error_message.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title.xml
@@ -14,7 +14,7 @@
         </item>
         <item>
             <key> <string>id</string> </key>
-            <value> <string>my_translated_validation_state_title_with_error_message</string> </value>
+            <value> <string>my_translated_validation_state_title</string> </value>
         </item>
         <item>
             <key> <string>message_values</string> </key>
diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml
new file mode 100644
index 0000000000..c466dede06
--- /dev/null
+++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>actbox_category</string> </key>
+            <value> <string>workflow</string> </value>
+        </item>
+        <item>
+            <key> <string>actbox_name</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>actbox_url</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>activate_script_name</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>after_script_name</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>before_commit_script_name</string> </key>
+            <value>
+              <list>
+                <string>Component_validateAfterModified</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>description</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>guard</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Component_modify</string> </value>
+        </item>
+        <item>
+            <key> <string>method_id</string> </key>
+            <value>
+              <list>
+                <string>_setTextContent*</string>
+                <string>_setReference*</string>
+                <string>_setVersion*</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>once_per_transaction</string> </key>
+            <value> <int>1</int> </value>
+        </item>
+        <item>
+            <key> <string>portal_type_filter</string> </key>
+            <value>
+              <list>
+                <string>Document Component</string>
+                <string>Extension Component</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>script_name</string> </key>
+            <value>
+              <list>
+                <string>Component_setModifiedState</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>temporary_document_disallowed</string> </key>
+            <value> <int>0</int> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>trigger_type</string> </key>
+            <value> <int>2</int> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="Guard" module="Products.DCWorkflow.Guard"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>expr</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="3" aka="AAAAAAAAAAM=">
+    <pickle>
+      <global name="Expression" module="Products.CMFCore.Expression"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>text</string> </key>
+            <value> <string>python: here.getValidationState() in (\'validated\', \'modified\')</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml
new file mode 100644
index 0000000000..3b9c284f3e
--- /dev/null
+++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>_body</string> </key>
+            <value> <string>state_change[\'object\'].modified()\n
+</string> </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string>state_change</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Component_setModifiedState</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml
new file mode 100644
index 0000000000..1661ae989b
--- /dev/null
+++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>_body</string> </key>
+            <value> <string>state_change[\'object\'].checkConsistencyAndValidate()\n
+</string> </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string>state_change</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Component_validateAfterModified</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml
index 219f67c417..ce42820726 100644
--- a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml
+++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml
@@ -31,7 +31,6 @@
                 <string>invalidate</string>
                 <string>invalidate_action</string>
                 <string>modified</string>
-                <string>validate</string>
               </tuple>
             </value>
         </item>
diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml
index 94ab3bb097..c3abfb4bd6 100644
--- a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml
+++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml
@@ -50,7 +50,7 @@
         </item>
         <item>
             <key> <string>title</string> </key>
-            <value> <string></string> </value>
+            <value> <string>Modified</string> </value>
         </item>
         <item>
             <key> <string>trigger_type</string> </key>
diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml
deleted file mode 100644
index 8ff402c78c..0000000000
--- a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0"?>
-<ZopeData>
-  <record id="1" aka="AAAAAAAAAAE=">
-    <pickle>
-      <global name="VariableDefinition" module="Products.DCWorkflow.Variables"/>
-    </pickle>
-    <pickle>
-      <dictionary>
-        <item>
-            <key> <string>default_expr</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>default_value</string> </key>
-            <value> <string></string> </value>
-        </item>
-        <item>
-            <key> <string>description</string> </key>
-            <value> <string></string> </value>
-        </item>
-        <item>
-            <key> <string>for_catalog</string> </key>
-            <value> <int>0</int> </value>
-        </item>
-        <item>
-            <key> <string>for_status</string> </key>
-            <value> <int>1</int> </value>
-        </item>
-        <item>
-            <key> <string>id</string> </key>
-            <value> <string>text_content</string> </value>
-        </item>
-        <item>
-            <key> <string>info_guard</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>update_always</string> </key>
-            <value> <int>1</int> </value>
-        </item>
-      </dictionary>
-    </pickle>
-  </record>
-</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/bt/change_log b/product/ERP5/bootstrap/erp5_core/bt/change_log
index 7f88fcb867..afd9e10bb6 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/change_log
+++ b/product/ERP5/bootstrap/erp5_core/bt/change_log
@@ -1,3 +1,7 @@
+2012-02-22 arnaud.fontaine
+* Split up state and error message into two separate fields.
+* Always set the Component state to modified upon modification, then check the consistency.
+
 2012-02-21 arnaud.fontaine
 * Do not update automatically the component module registry for reliability's sake.
 
diff --git a/product/ERP5/bootstrap/erp5_core/bt/revision b/product/ERP5/bootstrap/erp5_core/bt/revision
index 65466d1501..6123aa80b3 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/revision
+++ b/product/ERP5/bootstrap/erp5_core/bt/revision
@@ -1 +1 @@
-41004
\ No newline at end of file
+41005
\ No newline at end of file
diff --git a/product/ERP5Type/dynamic/component_class.py b/product/ERP5Type/dynamic/component_class.py
index 262e68f755..595c0456a6 100644
--- a/product/ERP5Type/dynamic/component_class.py
+++ b/product/ERP5Type/dynamic/component_class.py
@@ -111,9 +111,9 @@ class ComponentDynamicPackage(ModuleType):
         # be handled by component_validation_workflow which will take care of
         # updating the registry
         if component.getValidationState() in ('modified', 'validated'):
-          reference = component.getReference()
-          self.__registry_dict.setdefault(
-            reference, {})[component.getVersion()] = component
+          reference = component.getReference(validated_only=True)
+          version = component.getVersion(validated_only=True)
+          self.__registry_dict.setdefault(reference, {})[version] = component
 
     return self.__registry_dict
 
diff --git a/product/ERP5Type/mixin/component.py b/product/ERP5Type/mixin/component.py
index a3d9ecb1dc..996bba5358 100644
--- a/product/ERP5Type/mixin/component.py
+++ b/product/ERP5Type/mixin/component.py
@@ -32,6 +32,7 @@
 from __future__ import absolute_import
 
 from AccessControl import ClassSecurityInfo
+from Products.ERP5.mixin.property_recordable import PropertyRecordableMixin
 from Products.ERP5Type import Permissions
 from Products.ERP5Type.Base import Base
 from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
@@ -39,7 +40,7 @@ from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
 
 from zLOG import LOG, INFO
 
-class ComponentMixin(Base):
+class ComponentMixin(PropertyRecordableMixin, Base):
   isPortalContent = 1
   isRADContent = 1
   isDelivery = ConstantGetter('isDelivery', value=True)
@@ -58,121 +59,166 @@ class ComponentMixin(Base):
                      'TextDocument')
 
   security.declareProtected(Permissions.ModifyPortalContent, 'checkConsistency')
-  def checkConsistency(self, text_content=None, *args, **kw):
+  def checkConsistency(self, *args, **kw):
     """
     XXX-arnau: should probably be in a separate Constraint class?
     """
-    if text_content is None:
-      text_content = self.getTextContent()
-
+    error_list = []
+    object_relative_url = self.getRelativeUrl()
+
+    reference = self.getReference()
+    if not reference:
+      error_list.append(
+        ConsistencyMessage(self,
+                           object_relative_url,
+                           message="Reference must be set",
+                           mapping={}))
+
+    elif (reference.endswith('_version') or
+          reference[0] == '_' or
+          reference in ('find_module', 'load_module')):
+      error_list.append(
+        ConsistencyMessage(self,
+                           object_relative_url,
+                           message="Reference cannot end with '_version' or "\
+                             "start with '_' or be equal to find_module or "\
+                             "load_module",
+                           mapping={}))
+
+    version = self.getVersion()
+    if not version:
+      error_list.append(ConsistencyMessage(self,
+                                           object_relative_url,
+                                           message="Version must be set",
+                                           mapping={}))
+    elif version[0] == '_':
+      error_list.append(ConsistencyMessage(self,
+                                           object_relative_url,
+                                           message="Version cannot start with '_'",
+                                           mapping={}))
+
+    text_content = self.getTextContent()
     if not text_content:
-      return [ConsistencyMessage(self,
-                                 object_relative_url=self.getRelativeUrl(),
-                                 message="No source code",
-                                 mapping={})]
-
-    message = None
-    try:
-      self.load(text_content=text_content)
-    except SyntaxError, e:
-      mapping = dict(error_message=str(e),
-                     line_number=e.lineno,
-                     column_number=e.offset)
-
-      message = "Syntax error in source code: ${error_message} " \
-          "(line: ${line_number}, column: ${column_number})"
-
-    except Exception, e:
-      mapping = dict(message=str(e))
-      message = "Source code: ${error_message}"
-
-    if message:
-      return [ConsistencyMessage(self,
-                                 object_relative_url=self.getRelativeUrl(),
-                                 message=message,
-                                 mapping=mapping)]
-
-    return []
-
-  def _setTextContent(self, text_content):
+      error_list.append(
+          ConsistencyMessage(self,
+                             object_relative_url=object_relative_url,
+                             message="No source code",
+                             mapping={}))
+    else:
+      message = None
+      try:
+        self.load(text_content=text_content)
+      except SyntaxError, e:
+        mapping = dict(error_message=str(e),
+                       line_number=e.lineno,
+                       column_number=e.offset)
+
+        message = "Syntax error in source code: ${error_message} " \
+            "(line: ${line_number}, column: ${column_number})"
+
+      except Exception, e:
+        mapping = dict(error_message=str(e))
+        message = "Source code: ${error_message}"
+
+      if message:
+        error_list.append(
+          ConsistencyMessage(self,
+                             object_relative_url=self.getRelativeUrl(),
+                             message=message,
+                             mapping=mapping))
+
+    return error_list
+
+  def _recordPropertyDecorator(accessor_name, property_name):
+    def inner(self, property_value):
+      """
+      Everytime either 'reference', 'version' or 'text_content' are
+      modified when a Component is in modified or validated state, the
+      Component is set to modified state by component interaction
+      workflow, then in this method, the current property value is
+      recorded in order to handle any error returned when checking
+      consistency before the new value is set. At the end, through
+      component interaction workflow, the Component is validated only
+      if checkConsistency returns no error
+
+      The recorded property will be used upon loading the Component
+      whereas the new value set is displayed in Component view.
+      """
+      if self.getValidationState() in ('modified', 'validated'):
+        self.recordProperty(property_name)
+
+      return getattr(super(ComponentMixin, self), accessor_name)(property_value)
+
+    return inner
+
+  security.declareProtected(Permissions.ModifyPortalContent, '_setReference')
+  _setReference = _recordPropertyDecorator('_setReference', 'reference')
+
+  security.declareProtected(Permissions.ModifyPortalContent, '_setVersion')
+  _setVersion = _recordPropertyDecorator('_setVersion', 'version')
+
+  security.declareProtected(Permissions.ModifyPortalContent, '_setTextContent')
+  _setTextContent = _recordPropertyDecorator('_setTextContent', 'text_content')
+
+  def checkConsistencyAndValidate(self):
     """
-    When the validation state is already 'validated', set the new value to
-    'text_content_non_validated' property instead of 'text_content' for the
-    following reasons:
-
-    1/ It allows to validate the source code through Component validation
-       workflow rather than after each edition;
-
-    2/ It avoids dirty hacks to call checkConsistency upon edit and deal with
-       error messages, instead use workflow as it makes more sense.
-
-    Then, when the user revalidates the Component through a workflow action,
-    'text_content_non_validated' property is copied back to 'text_content'.
-
-    XXX-arnau: the workflow history bit is really ugly and should be moved to
-               an interaction workflow instead
+    When a Component is in validated or modified validation state and
+    it is modified, modified state is set then this checks whether the
+    Component can be validated again if checkConsistency returns no
+    error
     """
-    validation_state = self.getValidationState()
-    if validation_state in ('validated', 'modified'):
-      error_message_list = self.checkConsistency(text_content=text_content)
-      if error_message_list:
-        self.modified()
-
-        validation_workflow = self.workflow_history['component_validation_workflow']
-
-        last_validation_workflow = validation_workflow[-1]
-        last_validation_workflow['error_message'] = error_message_list[0]
-        last_validation_workflow['text_content'] = text_content
-
-        previous_validation_workflow = validation_workflow[-2]
-        previous_validation_workflow['error_message'] = ''
-        previous_validation_workflow['text_content'] = ''
-      else:
-        super(ComponentMixin, self)._setTextContent(text_content)
-        self.validate()
-
-        if validation_state == 'modified':
-          # XXX-arnau: copy/paste
-          validation_workflow = self.workflow_history['component_validation_workflow']
-          previous_validation_workflow = validation_workflow[-2]
-          previous_validation_workflow['error_message'] = ''
-          previous_validation_workflow['text_content'] = ''
+    error_list = self.checkConsistency()
+    if error_list:
+      workflow = self.workflow_history['component_validation_workflow'][-1]
+      workflow['error_list'] = error_list
     else:
-      return super(ComponentMixin, self)._setTextContent(text_content)
+      self.clearRecordedProperty('reference')
+      self.clearRecordedProperty('version')
+      self.clearRecordedProperty('text_content')
+      self.validate()
+
+  def _getRecordedPropertyDecorator(accessor_name, property_name):
+    def inner(self, validated_only=False):
+      """
+      When validated_only is True, then returns the property recorded if the
+      Component has been modified but there was an error upon consistency
+      checking
+      """
+      if validated_only:
+        try:
+          return self.getRecordedProperty(property_name)
+        # AttributeError when this property has never been recorded before
+        # (_recorded_property_dict) and KeyError if the property has been
+        # recorded before but is not anymore
+        except (AttributeError, KeyError):
+          pass
+
+      return getattr(super(ComponentMixin, self), accessor_name)()
+
+    return inner
 
   security.declareProtected(Permissions.AccessContentsInformation,
-                            'getTextContent')
-  def getTextContent(self, validated_only=False):
-    """
-    Return the source code of the validated source code (if validated_only is
-    True), meaningful when generating the Component, or the non-validated
-    source code (when a Component is modified when it has already been
-    validated), meaningful when editing a Component or checking consistency
-    """
-    if not validated_only:
-      text_content_non_validated = \
-          self.workflow_history['component_validation_workflow'][-1].get('text_content',
-                                                                         None)
-
-      if text_content_non_validated:
-        return text_content_non_validated
+                            'getReference')
+  getReference = _getRecordedPropertyDecorator('getReference', 'reference')
 
-    return super(ComponentMixin, self).getTextContent()
+  security.declareProtected(Permissions.AccessContentsInformation, 'getVersion')
+  getVersion = _getRecordedPropertyDecorator('getVersion', 'version')
 
-  def _getErrorMessage(self):
-    current_workflow = self.workflow_history['component_validation_workflow'][-1]
-    return current_workflow['error_message']
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getTextContent')
+  getTextContent = _getRecordedPropertyDecorator('getTextContent',
+                                                 'text_content')
 
   security.declareProtected(Permissions.AccessContentsInformation,
-                            'getTranslatedValidationStateTitleWithErrorMessage')
-  def getTranslatedValidationStateTitleWithErrorMessage(self):
-    validation_state_title = self.getTranslatedValidationStateTitle()
-    error_message = self._getErrorMessage()
-    if error_message:
-      return "%s (%s)" % (validation_state_title,
-                          str(error_message.getTranslatedMessage()))
-
-    return validation_state_title
+                            'getErrorMessageList')
+  def getErrorMessageList(self):
+    """
+    Return the checkConsistency errors which may have occurred when
+    the Component has been modified after being validated once
+    """
+    current_workflow = self.workflow_history['component_validation_workflow'][-1]
+    return [str(error.getTranslatedMessage())
+            for error in current_workflow['error_list']]
 
   security.declareProtected(Permissions.ModifyPortalContent, 'load')
   def load(self, namespace_dict={}, validated_only=False, text_content=None):
-- 
2.30.9