Added Attachments implementation
authorAntonio Moreno <antonio.moreno@openbravo.com>
Wed, 06 Apr 2011 19:41:38 +0200
changeset 11954 246760650b05
parent 11522 0649b6a37a1e
child 11955 ade74e621022
Added Attachments implementation
modules/org.openbravo.client.application/src-db/database/sourcedata/AD_MESSAGE.xml
modules/org.openbravo.client.application/src/org/openbravo/client/application/ApplicationComponentProvider.java
modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl
modules/org.openbravo.client.application/src/org/openbravo/client/application/window/AttachmentsAH.java
modules/org.openbravo.client.application/src/org/openbravo/client/application/window/FormInitializationComponent.java
modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-standard-view.js
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-toolbar.js
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form-attachments.js
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form.js
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/images/toolbar/iconButton-attach-box.png
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-toolbar-styles.css
modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/BaseActionHandler.java
modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/StyleSheetResourceComponent.java
modules/org.openbravo.service.datasource/src/org/openbravo/service/datasource/DefaultDataSourceService.java
src/index.jsp
src/org/openbravo/erpCommon/businessUtility/TabAttachments.java
--- a/modules/org.openbravo.client.application/src-db/database/sourcedata/AD_MESSAGE.xml	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/src-db/database/sourcedata/AD_MESSAGE.xml	Wed Apr 06 19:41:38 2011 +0200
@@ -882,6 +882,116 @@
 <!--FF8080812EDE8228012EE38E0C69007E-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
 <!--FF8080812EDE8228012EE38E0C69007E--></AD_MESSAGE>
 
+<!--FF8080812F05D96C012F061C68C1002A--><AD_MESSAGE>
+<!--FF8080812F05D96C012F061C68C1002A-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F061C68C1002A]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F061C68C1002A-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F061C68C1002A-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F061C68C1002A-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F061C68C1002A-->  <VALUE><![CDATA[OBUIAPP_DownloadAttachments]]></VALUE>
+<!--FF8080812F05D96C012F061C68C1002A-->  <MSGTEXT><![CDATA[Download attachments]]></MSGTEXT>
+<!--FF8080812F05D96C012F061C68C1002A-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F061C68C1002A-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F061C68C1002A--></AD_MESSAGE>
+
+<!--FF8080812F05D96C012F061D1E150035--><AD_MESSAGE>
+<!--FF8080812F05D96C012F061D1E150035-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F061D1E150035]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F061D1E150035-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F061D1E150035-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F061D1E150035-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F061D1E150035-->  <VALUE><![CDATA[OBUIAPP_CreateAttachments]]></VALUE>
+<!--FF8080812F05D96C012F061D1E150035-->  <MSGTEXT><![CDATA[Upload new attachment]]></MSGTEXT>
+<!--FF8080812F05D96C012F061D1E150035-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F061D1E150035-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F061D1E150035--></AD_MESSAGE>
+
+<!--FF8080812F05D96C012F061D5EC20039--><AD_MESSAGE>
+<!--FF8080812F05D96C012F061D5EC20039-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F061D5EC20039]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F061D5EC20039-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F061D5EC20039-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F061D5EC20039-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F061D5EC20039-->  <VALUE><![CDATA[OBUIAPP_AttachmentTitle]]></VALUE>
+<!--FF8080812F05D96C012F061D5EC20039-->  <MSGTEXT><![CDATA[Attachments]]></MSGTEXT>
+<!--FF8080812F05D96C012F061D5EC20039-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F061D5EC20039-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F061D5EC20039--></AD_MESSAGE>
+
+<!--FF8080812F05D96C012F061E0100003D--><AD_MESSAGE>
+<!--FF8080812F05D96C012F061E0100003D-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F061E0100003D]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F061E0100003D-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F061E0100003D-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F061E0100003D-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F061E0100003D-->  <VALUE><![CDATA[OBUIAPP_AttachmentAdd]]></VALUE>
+<!--FF8080812F05D96C012F061E0100003D-->  <MSGTEXT><![CDATA[Add]]></MSGTEXT>
+<!--FF8080812F05D96C012F061E0100003D-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F061E0100003D-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F061E0100003D--></AD_MESSAGE>
+
+<!--FF8080812F05D96C012F061F798B0041--><AD_MESSAGE>
+<!--FF8080812F05D96C012F061F798B0041-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F061F798B0041]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F061F798B0041-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F061F798B0041-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F061F798B0041-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F061F798B0041-->  <VALUE><![CDATA[OBUIAPP_AttachmentDownloadAll]]></VALUE>
+<!--FF8080812F05D96C012F061F798B0041-->  <MSGTEXT><![CDATA[Download All]]></MSGTEXT>
+<!--FF8080812F05D96C012F061F798B0041-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F061F798B0041-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F061F798B0041--></AD_MESSAGE>
+
+<!--FF8080812F05D96C012F061FA9A70045--><AD_MESSAGE>
+<!--FF8080812F05D96C012F061FA9A70045-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F061FA9A70045]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F061FA9A70045-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F061FA9A70045-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F061FA9A70045-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F061FA9A70045-->  <VALUE><![CDATA[OBUIAPP_AttachmentDownload]]></VALUE>
+<!--FF8080812F05D96C012F061FA9A70045-->  <MSGTEXT><![CDATA[Download]]></MSGTEXT>
+<!--FF8080812F05D96C012F061FA9A70045-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F061FA9A70045-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F061FA9A70045--></AD_MESSAGE>
+
+<!--FF8080812F05D96C012F061FE61C0049--><AD_MESSAGE>
+<!--FF8080812F05D96C012F061FE61C0049-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F061FE61C0049]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F061FE61C0049-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F061FE61C0049-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F061FE61C0049-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F061FE61C0049-->  <VALUE><![CDATA[OBUIAPP_AttachmentRemoveAll]]></VALUE>
+<!--FF8080812F05D96C012F061FE61C0049-->  <MSGTEXT><![CDATA[Remove All]]></MSGTEXT>
+<!--FF8080812F05D96C012F061FE61C0049-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F061FE61C0049-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F061FE61C0049--></AD_MESSAGE>
+
+<!--FF8080812F05D96C012F0620171E004D--><AD_MESSAGE>
+<!--FF8080812F05D96C012F0620171E004D-->  <AD_MESSAGE_ID><![CDATA[FF8080812F05D96C012F0620171E004D]]></AD_MESSAGE_ID>
+<!--FF8080812F05D96C012F0620171E004D-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F05D96C012F0620171E004D-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F05D96C012F0620171E004D-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F05D96C012F0620171E004D-->  <VALUE><![CDATA[OBUIAPP_AttachmentRemove]]></VALUE>
+<!--FF8080812F05D96C012F0620171E004D-->  <MSGTEXT><![CDATA[Remove]]></MSGTEXT>
+<!--FF8080812F05D96C012F0620171E004D-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F05D96C012F0620171E004D-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F05D96C012F0620171E004D--></AD_MESSAGE>
+
+<!--FF8080812F062060012F062A78FE0010--><AD_MESSAGE>
+<!--FF8080812F062060012F062A78FE0010-->  <AD_MESSAGE_ID><![CDATA[FF8080812F062060012F062A78FE0010]]></AD_MESSAGE_ID>
+<!--FF8080812F062060012F062A78FE0010-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F062060012F062A78FE0010-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F062060012F062A78FE0010-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F062060012F062A78FE0010-->  <VALUE><![CDATA[OBUIAPP_AttachmentBy]]></VALUE>
+<!--FF8080812F062060012F062A78FE0010-->  <MSGTEXT><![CDATA[by]]></MSGTEXT>
+<!--FF8080812F062060012F062A78FE0010-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F062060012F062A78FE0010-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F062060012F062A78FE0010--></AD_MESSAGE>
+
+<!--FF8080812F062060012F063D35C20026--><AD_MESSAGE>
+<!--FF8080812F062060012F063D35C20026-->  <AD_MESSAGE_ID><![CDATA[FF8080812F062060012F063D35C20026]]></AD_MESSAGE_ID>
+<!--FF8080812F062060012F063D35C20026-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F062060012F063D35C20026-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F062060012F063D35C20026-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F062060012F063D35C20026-->  <VALUE><![CDATA[OBUIAPP_ConfirmDownloadMultiple]]></VALUE>
+<!--FF8080812F062060012F063D35C20026-->  <MSGTEXT><![CDATA[Do you want to download all attachments of the selected records as attachments.zip?]]></MSGTEXT>
+<!--FF8080812F062060012F063D35C20026-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F062060012F063D35C20026-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F062060012F063D35C20026--></AD_MESSAGE>
+
 <!--FF8080812F10C577012F1138306C0027--><AD_MESSAGE>
 <!--FF8080812F10C577012F1138306C0027-->  <AD_MESSAGE_ID><![CDATA[FF8080812F10C577012F1138306C0027]]></AD_MESSAGE_ID>
 <!--FF8080812F10C577012F1138306C0027-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
@@ -893,6 +1003,39 @@
 <!--FF8080812F10C577012F1138306C0027-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
 <!--FF8080812F10C577012F1138306C0027--></AD_MESSAGE>
 
+<!--FF8080812F24EB26012F2555232E005C--><AD_MESSAGE>
+<!--FF8080812F24EB26012F2555232E005C-->  <AD_MESSAGE_ID><![CDATA[FF8080812F24EB26012F2555232E005C]]></AD_MESSAGE_ID>
+<!--FF8080812F24EB26012F2555232E005C-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F24EB26012F2555232E005C-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F24EB26012F2555232E005C-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F24EB26012F2555232E005C-->  <VALUE><![CDATA[OBUIAPP_AttachmentUploading]]></VALUE>
+<!--FF8080812F24EB26012F2555232E005C-->  <MSGTEXT><![CDATA[Uploading...]]></MSGTEXT>
+<!--FF8080812F24EB26012F2555232E005C-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F24EB26012F2555232E005C-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F24EB26012F2555232E005C--></AD_MESSAGE>
+
+<!--FF8080812F2690B3012F2699D15D000E--><AD_MESSAGE>
+<!--FF8080812F2690B3012F2699D15D000E-->  <AD_MESSAGE_ID><![CDATA[FF8080812F2690B3012F2699D15D000E]]></AD_MESSAGE_ID>
+<!--FF8080812F2690B3012F2699D15D000E-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F2690B3012F2699D15D000E-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F2690B3012F2699D15D000E-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F2690B3012F2699D15D000E-->  <VALUE><![CDATA[OBUIAPP_AttachmentPrompt]]></VALUE>
+<!--FF8080812F2690B3012F2699D15D000E-->  <MSGTEXT><![CDATA[This section shows all files attached to this record, and allows you to add new ones, or remove existing ones.]]></MSGTEXT>
+<!--FF8080812F2690B3012F2699D15D000E-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F2690B3012F2699D15D000E-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F2690B3012F2699D15D000E--></AD_MESSAGE>
+
+<!--FF8080812F2B0FC2012F2B6F65D10054--><AD_MESSAGE>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <AD_MESSAGE_ID><![CDATA[FF8080812F2B0FC2012F2B6F65D10054]]></AD_MESSAGE_ID>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <VALUE><![CDATA[OBUIAPP_ConfirmUploadOverwrite]]></VALUE>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <MSGTEXT><![CDATA[The file you are trying to upload already exists, so it will be replaced by the new one. Are you sure you want to continue?]]></MSGTEXT>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--FF8080812F2B0FC2012F2B6F65D10054-->  <AD_MODULE_ID><![CDATA[9BA0836A3CD74EE4AB48753A47211BCC]]></AD_MODULE_ID>
+<!--FF8080812F2B0FC2012F2B6F65D10054--></AD_MESSAGE>
+
 <!--FF8081812D6761CF012D676DF2A70045--><AD_MESSAGE>
 <!--FF8081812D6761CF012D676DF2A70045-->  <AD_MESSAGE_ID><![CDATA[FF8081812D6761CF012D676DF2A70045]]></AD_MESSAGE_ID>
 <!--FF8081812D6761CF012D676DF2A70045-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/ApplicationComponentProvider.java	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/ApplicationComponentProvider.java	Wed Apr 06 19:41:38 2011 +0200
@@ -129,6 +129,8 @@
     globalResources.add(createStaticResource(
         "web/org.openbravo.client.application/js/ob-view-form-notes.js", false));
     globalResources.add(createStaticResource(
+        "web/org.openbravo.client.application/js/ob-view-form-attachments.js", false));
+    globalResources.add(createStaticResource(
         "web/org.openbravo.client.application/js/ob-view-form.js", false));
     globalResources.add(createStaticResource(
         "web/org.openbravo.client.application/js/ob-view-grid.js", false));
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl	Wed Apr 06 19:41:38 2011 +0200
@@ -61,7 +61,7 @@
           firstFocusedField: true,
           </#if>
         </#if>
-        <#if fieldDefinition.type = "OBSectionItem" || fieldDefinition.type = "OBNoteSectionItem" || fieldDefinition.type = "OBLinkedItemSectionItem" >
+        <#if fieldDefinition.type = "OBSectionItem" || fieldDefinition.type = "OBNoteSectionItem" || fieldDefinition.type = "OBLinkedItemSectionItem" || fieldDefinition.type = "OBAttachmentsSectionItem" >
         sectionExpanded: false,
         defaultValue: '${fieldDefinition.label?js_string}',
         itemIds: [
@@ -73,4 +73,4 @@
         ${fieldDefinition.fieldProperties}
         dummy: "dummy"
     }
-</#macro>
\ No newline at end of file
+</#macro>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/AttachmentsAH.java	Wed Apr 06 19:41:38 2011 +0200
@@ -0,0 +1,131 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html 
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License. 
+ * The Original Code is Openbravo ERP. 
+ * The Initial Developer of the Original Code is Openbravo SLU 
+ * All portions are Copyright (C) 2011 Openbravo SLU 
+ * All Rights Reserved. 
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+package org.openbravo.client.application.window;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.hibernate.criterion.Expression;
+import org.openbravo.base.exception.OBException;
+import org.openbravo.base.session.OBPropertiesProvider;
+import org.openbravo.client.kernel.BaseActionHandler;
+import org.openbravo.dal.core.DalUtil;
+import org.openbravo.dal.core.OBContext;
+import org.openbravo.dal.service.OBCriteria;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.dal.service.OBDao;
+import org.openbravo.model.ad.ui.Tab;
+import org.openbravo.model.ad.utility.Attachment;
+import org.openbravo.service.json.JsonUtils;
+import org.openbravo.utils.FileUtility;
+
+public class AttachmentsAH extends BaseActionHandler {
+
+  private static final Logger log = Logger.getLogger(AttachmentsAH.class);
+
+  @Override
+  protected JSONObject execute(Map<String, Object> parameters, String content) {
+    OBContext.setAdminMode();
+    try {
+      if (parameters.get("Command").equals("DELETE")) {
+        String tabId = parameters.get("tabId").toString();
+        String recordIds = parameters.get("recordIds").toString();
+        String attachmentId = (String) parameters.get("attachId");
+        Tab tab = OBDal.getInstance().get(Tab.class, tabId);
+        String tableId = (String) DalUtil.getId(tab.getTable());
+        OBCriteria<Attachment> attachmentFiles = OBDao.getFilteredCriteria(Attachment.class,
+            Expression.eq("table.id", tableId), Expression.in("record", recordIds.split(",")));
+        if (attachmentId != null) {
+          attachmentFiles.add(Expression.eq(Attachment.PROPERTY_ID, attachmentId));
+        }
+        for (Attachment attachment : attachmentFiles.list()) {
+          deleteFile(attachment);
+        }
+        JSONObject obj = getAttachmentJSONObject(tab, recordIds);
+        obj.put("buttonId", parameters.get("buttonId"));
+        return obj;
+      } else {
+        return new JSONObject();
+      }
+    } catch (JSONException e) {
+      throw new OBException("Error while removing file", e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  private void deleteFile(Attachment attachment) {
+    String attachmentFolder = OBPropertiesProvider.getInstance().getOpenbravoProperties()
+        .getProperty("attach.path");
+    String fileDirPath = attachmentFolder + "/" + DalUtil.getId(attachment.getTable()) + "-"
+        + attachment.getRecord();
+    FileUtility f = new FileUtility();
+    final File file = new File(fileDirPath, attachment.getName());
+    if (file.exists()) {
+      try {
+        f = new FileUtility(fileDirPath, attachment.getName(), false);
+        f.deleteFile();
+      } catch (Exception e) {
+        throw new OBException("//Error while removing file", e);
+      }
+
+    } else {
+      log.warn("No file was removed as file could not be found");
+    }
+
+    OBDal.getInstance().remove(attachment);
+    OBDal.getInstance().flush();
+
+  }
+
+  public static JSONObject getAttachmentJSONObject(Tab tab, String recordIds) {
+    String tableId = (String) DalUtil.getId(tab.getTable());
+    OBCriteria<Attachment> attachmentFiles = OBDao.getFilteredCriteria(Attachment.class, Expression
+        .eq("table.id", tableId), Expression.in("record", recordIds.split(",")));
+    List<JSONObject> attachments = new ArrayList<JSONObject>();
+    for (Attachment attachment : attachmentFiles.list()) {
+      JSONObject attachmentobj = new JSONObject();
+      try {
+        attachmentobj.put("id", attachment.getId());
+        attachmentobj.put("name", attachment.getName());
+        SimpleDateFormat xmlDateTimeFormat = JsonUtils.createDateTimeFormat();
+        attachmentobj.put("creationDate", xmlDateTimeFormat.format(attachment.getCreationDate()));
+        attachmentobj.put("createdby", attachment.getCreatedBy().getName());
+      } catch (Exception e) {
+        throw new OBException("Error while reading attachments:", e);
+      }
+      attachments.add(attachmentobj);
+    }
+    JSONObject jsonobj = new JSONObject();
+    try {
+      jsonobj.put("attachments", new JSONArray(attachments));
+    } catch (JSONException e) {
+      throw new OBException(e);
+    }
+    return jsonobj;
+
+  }
+}
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/FormInitializationComponent.java	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/FormInitializationComponent.java	Wed Apr 06 19:41:38 2011 +0200
@@ -22,6 +22,7 @@
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -55,6 +56,7 @@
 import org.openbravo.client.kernel.reference.ForeignKeyUIDefinition;
 import org.openbravo.client.kernel.reference.UIDefinition;
 import org.openbravo.client.kernel.reference.UIDefinitionController;
+import org.openbravo.dal.core.DalUtil;
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.dal.service.OBCriteria;
 import org.openbravo.dal.service.OBDal;
@@ -68,6 +70,7 @@
 import org.openbravo.model.ad.ui.Field;
 import org.openbravo.model.ad.ui.Tab;
 import org.openbravo.model.ad.ui.Window;
+import org.openbravo.model.ad.utility.Attachment;
 import org.openbravo.service.db.DalConnectionProvider;
 import org.openbravo.service.json.JsonConstants;
 import org.openbravo.service.json.JsonToDataConverter;
@@ -111,6 +114,8 @@
       String tabId = (String) parameters.get("TAB_ID");
       // The ID of the record. Only relevant on EDIT, CHANGE and SETSESSION modes
       String rowId = (String) parameters.get("ROW_ID");
+      // The IDs of the selected records in case more than one
+      String multipleRowIds[] = (String[]) parameters.get("MULTIPLE_ROW_IDS");
       // The column changed by the user. Only relevant on CHANGE mode
       String changedColumn = (String) parameters.get("CHANGED_COLUMN");
       Tab tab = OBDal.getInstance().get(Tab.class, tabId);
@@ -202,19 +207,24 @@
         subsequentComboReload(tab, columnValues, changedCols, columnsInValidation);
       }
 
+      // Attachment information
+      long t7 = System.currentTimeMillis();
+      List<JSONObject> attachments = attachmentForRows(tab, rowId, multipleRowIds);
+
       if (mode.equals("NEW")) {
         // In the case of NEW mode, we compute auxiliary inputs again to take into account that
         // auxiliary inputs could depend on a default value
         computeAuxiliaryInputs(mode, tab, columnValues);
       }
       // Construction of the final JSONObject
-      long t7 = System.currentTimeMillis();
+      long t8 = System.currentTimeMillis();
       JSONObject finalObject = buildJSONObject(mode, tab, columnValues, row, changeEventCols,
-          calloutMessages);
-      long t8 = System.currentTimeMillis();
+          calloutMessages, attachments);
+      long t9 = System.currentTimeMillis();
       log.debug("Elapsed time: " + (System.currentTimeMillis() - iniTime) + "(" + (t2 - t1) + ","
           + (t3 - t2) + "," + (t4 - t3) + "," + (t5 - t4) + "," + (t6 - t5) + "," + (t7 - t6) + ","
-          + (t8 - t7) + ")");
+          + (t8 - t7) + "," + (t9 - t8) + ")");
+      log.info("Attachment exists: " + finalObject.getBoolean("attachmentExists"));
       return finalObject;
     } catch (Throwable t) {
       t.printStackTrace(System.err);
@@ -230,8 +240,36 @@
     return null;
   }
 
+  private List<JSONObject> attachmentForRows(Tab tab, String rowId, String[] multipleRowIds) {
+    String tableId = (String) DalUtil.getId(tab.getTable());
+    List<JSONObject> attachmentList = new ArrayList<JSONObject>();
+    OBCriteria<Attachment> attachments;
+    if (multipleRowIds == null) {
+      attachments = OBDao.getFilteredCriteria(Attachment.class, Expression.eq("table.id", tableId),
+          Expression.eq("record", rowId));
+    } else {
+      attachments = OBDao.getFilteredCriteria(Attachment.class, Expression.eq("table.id", tableId),
+          Expression.in("record", multipleRowIds));
+    }
+    for (Attachment attachment : attachments.list()) {
+      JSONObject obj = new JSONObject();
+      try {
+        obj.put("name", attachment.getName());
+        obj.put("id", attachment.getId());
+        SimpleDateFormat xmlDateTimeFormat = JsonUtils.createDateTimeFormat();
+        obj.put("creationDate", xmlDateTimeFormat.format(attachment.getCreationDate()));
+        obj.put("createdby", attachment.getCreatedBy().getName());
+      } catch (JSONException e) {
+        log.error("Error while reading attachments", e);
+      }
+      attachmentList.add(obj);
+    }
+    return attachmentList;
+  }
+
   private JSONObject buildJSONObject(String mode, Tab tab, Map<String, JSONObject> columnValues,
-      BaseOBObject row, List<String> changeEventCols, List<String> calloutMessages) {
+      BaseOBObject row, List<String> changeEventCols, List<String> calloutMessages,
+      List<JSONObject> attachments) {
     JSONObject finalObject = new JSONObject();
     try {
       if (mode.equals("NEW") || mode.equals("CHANGE")) {
@@ -319,6 +357,8 @@
           }
         }
       }
+      finalObject.put("attachments", new JSONArray(attachments));
+      finalObject.put("attachmentExists", attachments.size() > 0);
 
       log.debug(finalObject.toString(1));
       return finalObject;
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java	Wed Apr 06 19:41:38 2011 +0200
@@ -195,6 +195,13 @@
     fields.add(linkedItemsField);
     fields.add(linkedItemsCanvasFieldDefinition);
 
+    // add the attachments part
+    final AttachmentsCanvasField attachmentsCanvas = new AttachmentsCanvasField();
+    final AttachmentsField attachmentDefinition = new AttachmentsField();
+    attachmentDefinition.setChildField(attachmentsCanvas);
+    fields.add(attachmentDefinition);
+    fields.add(attachmentsCanvas);
+
     return fields;
   }
 
@@ -552,6 +559,60 @@
 
   }
 
+  public class AttachmentsCanvasField extends DefaultVirtualField {
+
+    public String getName() {
+      return "_attachments_Canvas";
+    }
+
+    public String getType() {
+      return "OBAttachmentCanvasItem";
+    }
+  }
+
+  public class AttachmentsField extends DefaultVirtualField {
+
+    private OBViewFieldDefinition childField;
+
+    public String getLabel() {
+      // is set at runtime
+      return "dummy";
+    }
+
+    public boolean getEndRow() {
+      return true;
+    }
+
+    public List<OBViewFieldDefinition> getChildren() {
+      return Collections.singletonList(childField);
+
+    }
+
+    public String getType() {
+      return "OBAttachmentsSectionItem";
+    }
+
+    public boolean getStartRow() {
+      return true;
+    }
+
+    public boolean getRedrawOnChange() {
+      return false;
+    }
+
+    public String getName() {
+      return "_attachments_";
+    }
+
+    public OBViewFieldDefinition getChildField() {
+      return childField;
+    }
+
+    public void setChildField(OBViewFieldDefinition childField) {
+      this.childField = childField;
+    }
+  }
+
   public class LinkedItemsField extends DefaultVirtualField {
 
     private OBViewFieldDefinition childField;
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-standard-view.js	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-standard-view.js	Wed Apr 06 19:41:38 2011 +0200
@@ -200,7 +200,8 @@
                    isc.OBToolbarIconButton.create(isc.OBToolbar.UNDO_BUTTON_PROPERTIES), 
                    isc.OBToolbarIconButton.create(isc.OBToolbar.DELETE_BUTTON_PROPERTIES), 
                    isc.OBToolbarIconButton.create(isc.OBToolbar.REFRESH_BUTTON_PROPERTIES),
-                   isc.OBToolbarIconButton.create(isc.OBToolbar.EXPORT_BUTTON_PROPERTIES)];
+                   isc.OBToolbarIconButton.create(isc.OBToolbar.EXPORT_BUTTON_PROPERTIES),
+                   isc.OBToolbarIconButton.create(isc.OBToolbar.ATTACHMENTS_BUTTON_PROPERTIES)];
     
     // Look for specific toolabr buttons for this tab
     if (this.iconToolbarButtons) {
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-toolbar.js	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-toolbar.js	Wed Apr 06 19:41:38 2011 +0200
@@ -26,6 +26,7 @@
   TYPE_UNDO: 'undo',
   TYPE_REFRESH: 'refresh',
   TYPE_EXPORT: 'export',
+  TYPE_ATTACHMENTS: 'attach',
   
   SAVE_BUTTON_PROPERTIES: {
     action: function(){
@@ -219,10 +220,107 @@
     buttonType: 'export',
     prompt: OB.I18N.getLabel('OBUIAPP_ExportGrid'),
     updateState: function(){
-      this.setDisabled(this.view.isShowingForm || this.view.viewGrid.getTotalRows()===0);
+      this.setDisabled(this.view.isShowingForm || this.view.viewGrid.getTotalRows() === 0);
     },
     keyboardShortcutId: 'ToolBar_Export'
   },
+  ATTACHMENTS_BUTTON_PROPERTIES: {
+    action: function(){
+      var selectedRows = this.view.viewGrid.getSelectedRecords();
+      var attachmentExists = this.view.attachmentExists;
+      if(this.view.isShowingForm){
+          this.view.viewForm.getItem('_attachments_').expandSection();
+        this.view.viewForm.scrollToBottom();
+        return;
+      }
+      if(attachmentExists){
+        if(selectedRows.size() === 1){
+            this.view.editRecord(selectedRows[0]);
+            this.view.viewForm.getItem('_attachments_').expandSection();
+            this.view.viewForm.ignoreFirstFocusEvent = true;
+            this.view.viewForm.scrollToBottom();
+        } else {
+          var recordIds = "";
+          for(var i=0; i<selectedRows.size(); i++){
+            if(i>0){
+              recordIds = recordIds + ",";  
+            }
+            recordIds=recordIds + selectedRows[i].id;
+          }
+          var vTabId = this.view.tabId;
+          var vbuttonId = this.ID;
+             isc.confirm(OB.I18N.getLabel('OBUIAPP_ConfirmDownloadMultiple'), function(clickedOK){
+            if(clickedOK){
+              var d = {
+                Command: 'GET_MULTIPLE_RECORDS_OB3',
+                tabId: vTabId,
+                buttonId: vbuttonId,
+                recordIds: recordIds
+              };
+              OB.Utilities.postThroughHiddenForm('./businessUtility/TabAttachments_FS.html', d);
+            }
+          });
+        }
+      }else{
+        var form = isc.DynamicForm.create({
+          fields: [
+            {name: 'inpname', type: 'upload', change: function(form, item, value, oldvalue){
+                form.button.customState = 'Progress';
+                form.button.resetBaseStyle();
+            	form.submitForm();
+            	}},
+            {name: 'Command', type: 'hidden', value: 'SAVE_NEW_OB3'},
+            {name: 'buttonId', type: 'hidden', value: this.ID},
+            {name: 'inpKey', type: 'hidden', value: this.view.viewGrid.getSelectedRecord().id},
+            {name: 'inpTabId', type: 'hidden', value: this.view.tabId},
+            {name: 'inpwindowId', type: 'hidden', value: this.view.windowId}
+          ],
+          encoding: 'multipart',
+          action: './businessUtility/TabAttachments_FS.html',
+          target: "background_target",
+          position: 'absolute',
+          left: '-9000px',
+          button: this
+        });
+        this.oldForm = form;
+        form.show();
+        form.getItem('inpname').getElement().click();
+      }
+    },
+    callback: function(){
+    	if(this.oldForm){
+    	  this.oldForm.destroy();
+    	}
+        this.view.attachmentExists = true;
+        this.customState = '';
+        this.updateState();
+    },
+    disabled: false,
+    buttonType: 'attach',
+    updateState: function(){
+      var selectedRows = this.view.viewGrid.getSelectedRecords();
+      var attachmentExists = this.view.attachmentExists;
+      if(attachmentExists){
+        this.prompt = OB.I18N.getLabel('OBUIAPP_DownloadAttachments');
+        this.buttonType = 'attachExists';
+      }else{
+        this.prompt = OB.I18N.getLabel('OBUIAPP_CreateAttachments');  
+        this.buttonType = 'attach';
+      }
+      if(!selectedRows || selectedRows.size()===0){
+        // If there are now selected rows then attachments button will be disabled
+        this.setDisabled(true);  
+      }else if(selectedRows.size() > 1 && !this.view.attachmentExists){
+        // If there are more than one rows selected, and no one has attachments,
+        // then attachments button will be disabled
+        this.setDisabled(true);
+      }else{
+        this.setDisabled(false);  
+      }
+      this.resetBaseStyle();
+    },
+    keyboardShortcutId: 'ToolBar_Attachments'
+  },
   LINK_BUTTON_PROPERTIES: {
     action: function(){
       var url = this.view.getDirectLinkUrl();
@@ -382,6 +480,7 @@
   // NOTE: new buttons should implement the updateState method.
   //
   updateButtonState: function(noSetSession){
+
     for (i = 0; i < this.leftMembers.length; i++) {
       if (this.leftMembers[i].updateState) {
         this.leftMembers[i].updateState();
@@ -828,16 +927,21 @@
           me.rightMembers[i].enableShortcut();
         }
       }
+      for (i = 0; i < me.leftMembers.length; i++) {
+        if (me.leftMembers[i].updateState) {
+            me.leftMembers[i].updateState();
+        }
+      }
     }
     
     var buttons = this.getRightMembers(), numOfSelRecords = 0, isNew = this.view.viewForm.isNew, hideAllButtons = typeof(isNew) !== 'undefined' && !isNew &&
-    (!this.view.isShowingForm && (!this.view.viewGrid.getSelectedRecords() || this.view.viewGrid.getSelectedRecords().length !== 1)), currentValues = this.view.getCurrentValues();
-    
+    (!this.view.isShowingForm && (this.view.viewGrid.getSelectedRecords().size()===0)), currentValues = this.view.getCurrentValues();
+    var noneOrMultipleRecordsSelected = this.view.viewGrid.getSelectedRecords().length !== 1;
     if (this.view.viewGrid.getSelectedRecords()) {
       numOfSelRecords = this.view.viewGrid.getSelectedRecords().length;
     }
     
-    if (!noSetSession && this.view.buttonsHaveSessionLogic && !this.view.isShowingForm && !hideAllButtons && !isNew) {
+    if (!noSetSession && !this.view.isShowingForm && !isNew && !hideAllButtons) {
       var formView = this.view.viewForm, me = this;
       // Call FIC to obtain possible session attributes and set them in form
       requestParams = {
@@ -846,9 +950,17 @@
         TAB_ID: this.view.tabId,
         ROW_ID: currentValues.id
       };
+      var multipleSelectedRowIds = [];
+      var selectedRecords = this.view.viewGrid.getSelectedRecords();
+      if(selectedRecords.size() > 1){
+        for (i = 0; i < selectedRecords.size(); i++) {
+          multipleSelectedRowIds[i] = selectedRecords[i].id;
+        }
+        requestParams.MULTIPLE_ROW_IDS = multipleSelectedRowIds;
+      }
       var allProperties = this.view.getContextInfo(false, true, false, false);
       OB.RemoteCallManager.call('org.openbravo.client.application.window.FormInitializationComponent', allProperties, requestParams, function(response, data, request){
-        var sessionAttributes = data.sessionAttributes, auxInputs = data.auxiliaryInputValues;
+        var sessionAttributes = data.sessionAttributes, auxInputs = data.auxiliaryInputValues, attachmentExists = data.attachmentExists;
         if (sessionAttributes) {
           formView.sessionAttributes = sessionAttributes;
         }
@@ -862,12 +974,12 @@
             }
           }
         }
-        
-        doRefresh(buttons, currentValues, false, me);
+        formView.view.attachmentExists = attachmentExists;
+        doRefresh(buttons, currentValues, noneOrMultipleRecordsSelected, me);
       });
     } else {
       currentValues = this.view.getCurrentValues();
-      doRefresh(buttons, currentValues, hideAllButtons, this);
+      doRefresh(buttons, currentValues, hideAllButtons || noneOrMultipleRecordsSelected, this);
     }
   },
   
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form-attachments.js	Wed Apr 06 19:41:38 2011 +0200
@@ -0,0 +1,359 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License.
+ * The Original Code is Openbravo ERP.
+ * The Initial Developer of the Original Code is Openbravo SLU
+ * All portions are Copyright (C) 2011 Openbravo SLU
+ * All Rights Reserved.
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+// = OBAttachments =
+//
+// Represents the attachments section in the form.
+//
+
+isc.ClassFactory.defineClass('OBAttachmentsSectionItem', isc.OBSectionItem);
+
+isc.OBAttachmentsSectionItem.addProperties({
+  // as the name is always the same there should be at most
+  // one linked item section per form
+  name: '_attachments_',
+  
+  // note: setting these apparently completely hides the section
+  // width: '100%',
+  // height: '100%',
+  
+  overflow: 'hidden',
+  
+  canFocus: true,
+  
+  // don't expand as a default
+  sectionExpanded: false,
+  
+  prompt: OB.I18N.getLabel('OBUIAPP_AttachmentPrompt'),
+  
+  canvasItem: null,
+  
+  visible: false,
+  
+  // note formitems don't have an initWidget but an init method
+  init: function(){
+    // override the one passed in
+    this.defaultValue = OB.I18N.getLabel('OBUIAPP_AttachmentTitle');
+    this.sectionExpanded = false;
+    
+    // tell the form who we are
+    this.form.attachmentsSection = this;
+    
+    return this.Super('init', arguments);
+  },
+
+  getAttachmentPart: function(){
+    if (!this.canvasItem) {
+      this.canvasItem = this.form.getField(this.itemIds[0]);
+    }
+    return this.canvasItem.canvas;
+  },
+  
+  setRecordInfo: function(entity, id, tabId){
+    this.getAttachmentPart().setRecordInfo(entity, id, tabId);
+  },
+  
+  collapseSection: function(){
+    var ret = this.Super('collapseSection', arguments);
+    this.getAttachmentPart().setExpanded(false);
+    return ret;
+  },
+  
+  expandSection: function(){
+    // if this is not there then when clicking inside the 
+    // section item will visualize it
+    if (!this.isVisible()) {
+      return;
+    }
+    var ret = this.Super('expandSection', arguments);
+    this.getAttachmentPart().setExpanded(true);
+    return ret;
+  },
+  
+  fillAttachments: function(attachments){
+	this.getAttachmentPart().fillAttachments(attachments);  
+  }
+
+});
+
+
+isc.ClassFactory.defineClass('OBAttachmentCanvasItem', isc.CanvasItem);
+
+isc.OBAttachmentCanvasItem.addProperties({
+
+  canFocus: true,
+  
+  // setting width/height makes the canvasitem to be hidden after a few
+  // clicks on the section item, so don't do that for now
+  // width: '100%',
+  // height: '100%',
+  
+  showTitle: false,
+  overflow: 'auto',
+  // note that explicitly setting the canvas gives an error as not
+  // all props are set correctly on the canvas (for example the
+  // pointer back to this item: canvasItem
+  // for setting more properties use canvasProperties, etc. see
+  // the docs
+  canvasConstructor: 'OBAttachmentsLayout',
+
+  // never disable this one
+  isDisabled: function(){
+    return false;
+  }
+  
+});
+
+
+
+isc.ClassFactory.defineClass('OBAttachmentsLayout', isc.VLayout);
+
+isc.OBAttachmentsLayout.addProperties({
+
+  // set to true when the content has been created at first expand
+  isInitialized: false,
+  
+  layoutMargin: 5,
+
+  width: '50%',
+  
+  /** 
+   * Initializes the widget
+   **/
+  initWidget: function(){
+    var ret = this.Super('initWidget', arguments);
+    
+    return ret;
+  },
+  
+  
+  // never disable this item
+  isDisabled: function(){
+    return false;
+  },
+  
+  getForm: function(){
+    return this.canvasItem.form;
+  },
+  
+  setRecordInfo: function(entity, id, tabId){
+    this.entity = entity;
+    // use recordId instead of id, as id is often used to keep
+    // html ids
+    this.recordId = id;
+    this.tabId = tabId;
+    this.isInitialized = false;
+  },
+  
+  
+  setExpanded: function(expanded){
+    if (expanded && !this.isInitialized) {
+      this.isInitialized = true;
+    }
+  },
+  
+  addAttachmentInfo: function(attachmentLayout, attachment){
+  },
+
+  callback: function(attachmentsobj){
+    var button =  this.getForm().view.toolBar.getLeftMember(isc.OBToolbar.TYPE_ATTACHMENTS);
+    if(!button) {
+      button =  this.getForm().view.toolBar.getLeftMember("attachExists");
+    }
+    button.customState = '';
+    button.resetBaseStyle();
+	this.fillAttachments(attachmentsobj.attachments);  
+  },
+  
+  fileExists: function(fileName, attachments){
+	if(!attachments || attachments.length === 0){
+	  return false;
+	}
+	for(var i=0; i < attachments.length; i++){
+	  if(attachments[i].name === fileName){
+        return true;
+	  }
+	}
+	return false;
+  },
+  
+  fillAttachments: function(attachments){
+	this.savedAttachments = attachments;
+	this.removeMembers(this.getMembers());
+	var hLayout = isc.HLayout.create();
+    this.addMember(hLayout);
+    var me = this;
+    var addButton = isc.OBSectionItemControlLink.create({
+	  contents: '[ '+OB.I18N.getLabel('OBUIAPP_AttachmentAdd')+' ]',
+	  width: '50%',
+  	  canvas: me,
+	  action: function(){
+        var form = isc.DynamicForm.create({
+            fields: [
+              {name: 'inpname', type: 'upload', change: function(form, item, value, oldvalue){
+            	var addFunction = function(clickedOK){
+            	  if(clickedOK){
+                    var hTempLayout = isc.HLayout.create();
+            	    form.theCanvas.addMember(hTempLayout,form.theCanvas.getMembers().size());
+                    var uploading = isc.Label.create({
+                      contents: fileName + '    '+OB.I18N.getLabel('OBUIAPP_AttachmentUploading')
+                    });
+                    hTempLayout.addMember(uploading);
+                    var button =  form.theCanvas.getForm().view.toolBar.getLeftMember(isc.OBToolbar.TYPE_ATTACHMENTS);
+                    if(!button) {
+                      button =  form.theCanvas.getForm().view.toolBar.getLeftMember("attachExists");
+                    }
+                    button.customState = 'Progress';
+                    button.resetBaseStyle();
+                    form.show();
+                    form.submitForm();
+            	  }
+                }
+            	var lastChar=value.lastIndexOf("\\") + 1;
+              	var fileName = lastChar===-1?value:value.substring(lastChar);
+              	if(form.theCanvas.fileExists(fileName, attachments)){
+              		isc.confirm(OB.I18N.getLabel('OBUIAPP_ConfirmUploadOverwrite'), addFunction);
+              	}else{
+              	  addFunction(true);
+              	}
+              }},
+              {name: 'Command', type: 'hidden', value: 'SAVE_NEW_OB3'},
+              {name: 'buttonId', type: 'hidden', value: this.canvas.ID},
+              {name: 'inpKey', type: 'hidden', value: this.canvas.recordId},
+              {name: 'inpTabId', type: 'hidden', value: this.canvas.tabId},
+              {name: 'inpwindowId', type: 'hidden', value: this.canvas.windowId}
+            ],
+            encoding: 'multipart',
+            action: './businessUtility/TabAttachments_FS.html',
+            target: "background_target",
+            position: 'absolute',
+            left: '-9000px',
+            theCanvas: this.canvas
+          });
+        form.show();
+        form.getItem('inpname').getElement().click();
+      }
+	});
+	hLayout.addMember(addButton);
+	// If there are no attachments, we only display the "[Add]" button
+	if(!attachments || attachments.length === 0){
+      this.getForm().getItem('_attachments_').setValue(OB.I18N.getLabel('OBUIAPP_AttachmentTitle'));
+	  this.getForm().view.attachmentExists = false;
+	  this.getForm().view.toolBar.updateButtonState();
+	  return;
+	}
+	this.getForm().view.attachmentExists = true;
+	this.getForm().view.toolBar.updateButtonState();
+	isc_OBAttachmentsSectionItem_0.setValue(OB.I18N.getLabel('OBUIAPP_AttachmentTitle')+" ("+attachments.length+")");
+    var downloadAllButton = isc.OBSectionItemControlLink.create({
+  	  contents: '[ '+OB.I18N.getLabel('OBUIAPP_AttachmentDownloadAll')+' ]',
+  	  canvas: this,
+	  action: function(){
+    	var canvas = this.canvas;
+    	isc.confirm(OB.I18N.getLabel('OBUIAPP_ConfirmDownloadMultiple'), function(clickedOK){
+    	  if(clickedOK){
+            var d = {
+              Command: 'GET_MULTIPLE_RECORDS_OB3',
+              tabId: canvas.tabId,
+              recordIds: canvas.recordId
+            }
+            OB.Utilities.postThroughHiddenForm('./businessUtility/TabAttachments_FS.html', d);
+    	  }
+        });
+      }
+  	});
+    var removeAllButton = isc.OBSectionItemControlLink.create({
+      contents: '[ '+OB.I18N.getLabel('OBUIAPP_AttachmentRemoveAll')+' ]',
+  	  canvas: me,
+	  action: function(){
+        var d = {
+          Command: 'DELETE',
+          tabId: this.canvas.tabId,
+          buttonId: this.canvas.ID,
+          recordIds: this.canvas.recordId
+        };
+        var canvas = this.canvas;
+    	OB.RemoteCallManager.call('org.openbravo.client.application.window.AttachmentsAH', {}, d, function(response, data, request){
+    	      canvas.fillAttachments(data.attachments);
+    	});
+      }
+    });
+	hLayout.addMember(downloadAllButton);
+	hLayout.addMember(removeAllButton);
+	
+	for(var i=0; i < attachments.length; i++){
+      var attachment = attachments[i];
+	  var buttonLayout = isc.HLayout.create();
+      var attachmentLabel = isc.Label.create({
+  	    contents: attachment.name,
+  	    width: '35%',
+  	  });
+      var attachmentBy = isc.Label.create({
+    	contents: " <i>"+OB.I18N.getLabel('OBUIAPP_AttachmentBy')+" "+attachment.createdby+"</i>"
+      });
+      var attachmentCreationDate = isc.Label.create({
+      	contents: OB.Utilities.getTimePassed(new Date(attachment.creationDate))
+      });
+      var downloadAttachment = isc.OBSectionItemControlLink.create({
+  	    contents: '[ '+OB.I18N.getLabel('OBUIAPP_AttachmentDownload')+' ]',
+  	    attachmentName: attachment.name,
+  		action: function(){
+          var d = {
+            Command: 'DISPLAY_DATA',
+            inpcFileId: attachment.id
+          }
+          OB.Utilities.postThroughHiddenForm('./businessUtility/TabAttachments_FS.html', d);
+  	    }
+  	  });
+      var removeAttachment = isc.OBSectionItemControlLink.create({
+    	contents: '[ '+OB.I18N.getLabel('OBUIAPP_AttachmentRemove')+' ]',
+  	    attachmentName: attachment.name,
+  	    attachmentId: attachment.id,
+    	canvas: this,
+    	action: function(){
+          var d = {
+                  Command: 'DELETE',
+                  tabId: this.canvas.tabId,
+                  buttonId: this.canvas.ID,
+                  recordIds: this.canvas.recordId,
+                  attachId: this.attachmentId
+                };
+                var canvas = this.canvas;
+          OB.RemoteCallManager.call('org.openbravo.client.application.window.AttachmentsAH', {}, d, function(response, data, request){
+          	      canvas.fillAttachments(data.attachments);
+          });
+    	}
+      });
+      buttonLayout.addMember(attachmentLabel);
+      buttonLayout.addMember(attachmentCreationDate);
+      buttonLayout.addMember(attachmentBy);
+      buttonLayout.addMember(downloadAttachment);
+      buttonLayout.addMember(removeAttachment);
+      this.addMember(buttonLayout);
+	}
+  },
+  
+  // ensure that the view gets activated
+  focusChanged: function(){
+    var view = this.getForm().view;
+    if (view && view.setAsActiveView) {
+      view.setAsActiveView();
+    }
+    return this.Super('focusChanged', arguments);
+  }
+});
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form.js	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form.js	Wed Apr 06 19:41:38 2011 +0200
@@ -75,6 +75,9 @@
   
   // is set in the OBLinkedItemSectionItem.initWidget
   linkedItemSection: null,
+  
+  // is set in the OBAttachmentsSectionItem.initWidget
+  attachmentsSection: null,
 
   initWidget: function() {
     this._preventFocusChanges = true;
@@ -211,6 +214,15 @@
     }
   },
   
+  enableAttachmentsSection: function(){
+    if (!this.attachmentsSection) {
+      return;
+    }
+    this.attachmentsSection.collapseSection();
+    this.attachmentsSection.setRecordInfo(this.view.entity, this.getValue(OB.Constants.ID), this.view.tabId);
+    this.attachmentsSection.show();
+  },
+  
   // add the undo buttons to the clickmask so that no save happens when 
   // clicking undo
   showClickMask : function(clickAction, mode, unmaskedTargets) {
@@ -241,6 +253,7 @@
     this.view.updateTabTitle();
     this.enableNoteSection(!isNew);
     this.enableLinkedItemSection(!isNew);
+    this.enableAttachmentsSection();
 
     if (isNew) {
       this.view.statusBar.newIcon.prompt = OB.I18N.getLabel('OBUIAPP_NewIconPrompt');
@@ -483,6 +496,8 @@
         }
       }
     }
+    
+    this.attachmentsSection.fillAttachments(data.attachments);
 
     // apparently sometimes an empty string is returned
     if (calloutMessages && calloutMessages.length > 0 && calloutMessages[0] !== '') {
Binary file modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/images/toolbar/iconButton-attach-box.png has changed
--- a/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-toolbar-styles.css	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-toolbar-styles.css	Wed Apr 06 19:41:38 2011 +0200
@@ -214,6 +214,24 @@
   background-image: url(./images/toolbar/iconButton-attach.png);
 }
 
+.OBToolbarIconButton_icon_attachExists {
+  background-repeat: no-repeat;
+  background-position: center center;
+  background-image: url(./images/toolbar/iconButton-attach-box.png);
+}
+
+.OBToolbarIconButton_icon_attachProgress {
+  background-repeat: no-repeat;
+  background-position: center center;
+  background-image: url(./images/system/progress-indicator-toolbar.gif);
+}
+
+.OBToolbarIconButton_icon_attachExistsProgress {
+  background-repeat: no-repeat;
+  background-position: center center;
+  background-image: url(./images/system/progress-indicator-toolbar.gif);
+}
+
 .OBToolbarIconButton_icon_innerJoin {
   background-repeat: no-repeat;
   background-position: center center;
--- a/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/BaseActionHandler.java	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/BaseActionHandler.java	Wed Apr 06 19:41:38 2011 +0200
@@ -59,7 +59,11 @@
       final Map<String, Object> parameterMap = new HashMap<String, Object>();
       for (Enumeration keys = request.getParameterNames(); keys.hasMoreElements();) {
         final String key = (String) keys.nextElement();
-        parameterMap.put(key, request.getParameter(key));
+        if (request.getParameterValues(key) != null && request.getParameterValues(key).length > 1) {
+          parameterMap.put(key, request.getParameterValues(key));
+        } else {
+          parameterMap.put(key, request.getParameter(key));
+        }
       }
       // also add the Http Stuff
       parameterMap.put(KernelConstants.HTTP_SESSION, request.getSession(false));
--- a/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/StyleSheetResourceComponent.java	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/StyleSheetResourceComponent.java	Wed Apr 06 19:41:38 2011 +0200
@@ -22,6 +22,7 @@
 import java.io.File;
 import java.io.StringReader;
 import java.util.List;
+import java.util.Random;
 
 import javax.enterprise.inject.Any;
 import javax.enterprise.inject.Instance;
@@ -69,6 +70,8 @@
 
   @Override
   public String getETag() {
+    if (1 == 1)
+      return new Random().toString();
     final List<Module> modules = KernelUtils.getInstance().getModulesOrderedByDependency();
     final StringBuilder version = new StringBuilder();
     for (Module module : modules) {
--- a/modules/org.openbravo.service.datasource/src/org/openbravo/service/datasource/DefaultDataSourceService.java	Wed Apr 06 17:58:50 2011 +0200
+++ b/modules/org.openbravo.service.datasource/src/org/openbravo/service/datasource/DefaultDataSourceService.java	Wed Apr 06 19:41:38 2011 +0200
@@ -70,8 +70,9 @@
 
   private void addFetchParameters(Map<String, String> parameters) {
 
-    parameters.put(JsonConstants.ENTITYNAME, getEntity().getName());
-
+    if (getEntity() != null) {
+      parameters.put(JsonConstants.ENTITYNAME, getEntity().getName());
+    }
     if (getWhereClause() != null) {
       if (parameters.get(JsonConstants.WHERE_PARAMETER) != null) {
         final String currentWhere = parameters.get(JsonConstants.WHERE_PARAMETER);
--- a/src/index.jsp	Wed Apr 06 17:58:50 2011 +0200
+++ b/src/index.jsp	Wed Apr 06 19:41:38 2011 +0200
@@ -150,8 +150,8 @@
 <script type="text/javascript" src="./web/org.openbravo.userinterface.smartclient/isomorphic/ISC_Combined.js"></script>
 <script type="text/javascript" src="./web/org.openbravo.userinterface.smartclient/isomorphic/ISC_History.js"></script>
 <script type="text/javascript" src="./org.openbravo.client.kernel/OBCLKER_Kernel/StaticResources?_mode=3.00&_skinVersion=3.00"></script>
-<form name="OBGlobalHiddenForm" method="post" action="blank.html">
 <iframe id="background_target" height="0" width="0" style="display:none;"></iframe>
+<form name="OBGlobalHiddenForm" method="post" action="blank.html" target="background_target">
 </form>
 </body>
 </html>
\ No newline at end of file
--- a/src/org/openbravo/erpCommon/businessUtility/TabAttachments.java	Wed Apr 06 17:58:50 2011 +0200
+++ b/src/org/openbravo/erpCommon/businessUtility/TabAttachments.java	Wed Apr 06 19:41:38 2011 +0200
@@ -19,9 +19,14 @@
 package org.openbravo.erpCommon.businessUtility;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.Writer;
 import java.sql.Connection;
+import java.util.HashMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
@@ -29,11 +34,21 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.fileupload.FileItem;
+import org.codehaus.jettison.json.JSONObject;
+import org.hibernate.criterion.Expression;
 import org.openbravo.base.secureApp.HttpSecureAppServlet;
 import org.openbravo.base.secureApp.VariablesSecureApp;
+import org.openbravo.client.application.window.AttachmentsAH;
+import org.openbravo.dal.core.DalUtil;
+import org.openbravo.dal.core.OBContext;
+import org.openbravo.dal.service.OBCriteria;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.dal.service.OBDao;
 import org.openbravo.erpCommon.utility.OBError;
 import org.openbravo.erpCommon.utility.SequenceIdData;
 import org.openbravo.erpCommon.utility.Utility;
+import org.openbravo.model.ad.ui.Tab;
+import org.openbravo.model.ad.utility.Attachment;
 import org.openbravo.utils.FileUtility;
 import org.openbravo.xmlEngine.XmlDocument;
 
@@ -83,6 +98,19 @@
               + "?Command=EDIT&inpcFileId=" + strFileReference);
         } else if (vars.commandIn("SAVE_NEW_NEW")) {
           response.sendRedirect(strDireccion + request.getServletPath() + "?Command=NEW");
+        } else if (vars.commandIn("SAVE_NEW_OB3")) {
+          OBContext.setAdminMode();
+          try {
+            Tab tab = OBDal.getInstance().get(Tab.class, strTab);
+            JSONObject obj = AttachmentsAH.getAttachmentJSONObject(tab, key);
+            String buttonId = vars.getStringParameter("buttonId");
+            Writer writer = response.getWriter();
+            writer.write("<HTML><BODY><script type=\"text/javascript\">");
+            writer.write("top." + buttonId + ".callback(" + obj.toString() + ");");
+            writer.write("</SCRIPT></BODY></HTML>");
+          } finally {
+            OBContext.restorePreviousMode();
+          }
         }
       }
     } else if (vars.getCommand().startsWith("SAVE_EDIT")) {
@@ -155,6 +183,8 @@
     } else if (vars.commandIn("DISPLAY_DATA")) {
       final String strFileReference = vars.getStringParameter("inpcFileId");
       printPageFile(response, vars, strFileReference);
+    } else if (vars.getCommand().contains("GET_MULTIPLE_RECORDS_OB3")) {
+      printPageFileMultiple(response, vars);
     } else if (vars.commandIn("DEFAULT")) {
       vars.getGlobalVariable("inpTabId", "TabAttachments.tabId");
       vars.getGlobalVariable("inpwindowId", "TabAttachments.windowId");
@@ -192,6 +222,53 @@
       pageError(response);
   }
 
+  private void printPageFileMultiple(HttpServletResponse response, VariablesSecureApp vars)
+      throws IOException {
+    OBContext.setAdminMode(true);
+    try {
+      String tabId = vars.getStringParameter("tabId");
+      String recordIds = vars.getStringParameter("recordIds");
+      String buttonId = vars.getStringParameter("buttonId");
+      Tab tab = OBDal.getInstance().get(Tab.class, tabId);
+      String tableId = (String) DalUtil.getId(tab.getTable());
+      OBCriteria<Attachment> attachmentFiles = OBDao.getFilteredCriteria(Attachment.class,
+          Expression.eq("table.id", tableId), Expression.in("record", recordIds.split(",")));
+
+      response.setContentType("application/zip");
+      response.setHeader("Content-Disposition", "attachment; filename=attachments.zip");
+      final ZipOutputStream dest = new ZipOutputStream(response.getOutputStream());
+      attachmentFiles.list().toArray();
+      HashMap<String, Integer> writtenFiles = new HashMap<String, Integer>();
+      for (Attachment attachmentFile : attachmentFiles.list()) {
+        final File file = new File(globalParameters.strFTPDirectory + "/" + tableId + "-"
+            + attachmentFile.getRecord(), attachmentFile.getName());
+        String zipName = "";
+        if (!writtenFiles.containsKey(file.getName())) {
+          zipName = file.getName();
+          writtenFiles.put(file.getName(), new Integer(0));
+        } else {
+          int num = writtenFiles.get(file.getName()) + 1;
+          zipName = file.getName() + "." + num;
+          writtenFiles.put(file.getName(), new Integer(num));
+        }
+        byte[] buf = new byte[1024];
+        dest.putNextEntry(new ZipEntry(zipName));
+        FileInputStream in = new FileInputStream(file.toString());
+        int len;
+        while ((len = in.read(buf)) > 0) {
+          dest.write(buf, 0, len);
+        }
+        dest.closeEntry();
+        in.close();
+      }
+      dest.close();
+    } catch (Exception e) {
+      log4j.error("Error while downloading attachments", e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
   private OBError insert(VariablesSecureApp vars, String strFileReference, String tableId,
       String key, String strDataType, String strText) throws IOException, ServletException {
 
@@ -218,8 +295,19 @@
       } else if ((i = strName.lastIndexOf("/")) != -1) {
         strName = strName.substring(i + 1);
       }
-      TabAttachmentsData.insert(conn, this, strFileReference, vars.getClient(), vars.getOrg(), vars
-          .getUser(), tableId, key, strDataType, strText, strName);
+      boolean fileExists = false;
+      final TabAttachmentsData[] files = TabAttachmentsData.select(this, "'" + vars.getClient()
+          + "'", "'" + vars.getOrg() + "'", tableId, key);
+      for (TabAttachmentsData data : files) {
+        if (data.name.equals(strName)) {
+          fileExists = true;
+        }
+      }
+      if (!fileExists) {
+        // We only insert a new record if there is no record for this file
+        TabAttachmentsData.insert(conn, this, strFileReference, vars.getClient(), vars.getOrg(),
+            vars.getUser(), tableId, key, strDataType, strText, strName);
+      }
       try {
         // FIXME: Get the directory separator from Java runtime
         final File uploadedDir = new File(globalParameters.strFTPDirectory + "/" + tableId + "-"