Implemented link button, converted double to single qoute, solved ignoring where clause
authorMartin Taal <martin.taal@openbravo.com>
Mon, 03 Jan 2011 21:44:36 +0100
changeset 9522 5f821bb399a9
parent 9521 dcbca5730e71
child 9523 befa79fc1364
Implemented link button, converted double to single qoute, solved ignoring where clause
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/OBViewFormComponent.java
modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewTab.java
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-formitem-widgets.js
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-grid.js
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-utilities.js
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form.js
modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-grid.js
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-application-styles.js
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-form-styles.css
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-form-styles.js
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-grid-styles.js
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-tab-styles.js
modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-toolbar-styles.js
modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/reference/FKSearchUIDefinition.java
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/templates/ob-view-field.js.ftl	Mon Jan 03 21:44:36 2011 +0100
@@ -22,11 +22,15 @@
         name: '${fieldDefinition.name?js_string}',
         title: '${fieldDefinition.label?js_string}',
         type: '${fieldDefinition.type}',
+        disabled: ${fieldDefinition.parentProperty?string},
+        parentProperty: ${fieldDefinition.parentProperty?string},
+        
         width: '*',
         <#if fieldDefinition.standardField>
         columnName: '${fieldDefinition.columnName?string}',
         inpColumnName: '${fieldDefinition.inpColumnName?string}',
         referencedKeyColumnName: '${fieldDefinition.referencedKeyColumnName?string}',
+        targetEntity: '${fieldDefinition.targetEntity?string}',
         required: ${fieldDefinition.required?string},
         colSpan: ${fieldDefinition.colSpan},
         rowSpan: ${fieldDefinition.rowSpan},
@@ -35,6 +39,7 @@
           <#if fieldDefinition.searchField>
           displayField: '${fieldDefinition.name?js_string}._identifier',
           valueField: '${fieldDefinition.name?js_string}',
+          showPickerIcon: ${(!fieldDefinition.parentProperty)?string},
           </#if>
         </#if>
         <#if fieldDefinition.type = "OBSectionItem">
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewFormComponent.java	Mon Jan 03 21:44:36 2011 +0100
@@ -51,6 +51,8 @@
   private static final String TEMPLATE_ID = "C1D176407A354A40815DC46D24D70EB8";
   private static Logger log = Logger.getLogger(OBViewFormComponent.class);
 
+  private String parentProperty;
+
   private static final long ONE_COLUMN_MAX_LENGTH = 60;
   private static final String TEXT_AD_REFERENCE_ID = "14";
 
@@ -148,6 +150,8 @@
 
     public String getReferencedKeyColumnName();
 
+    public String getTargetEntity();
+
     public String getStartRow();
 
     public String getEndRow();
@@ -156,6 +160,7 @@
 
     public long getRowSpan();
 
+    public boolean isParentProperty();
   }
 
   public class OBViewField implements OBViewFieldDefinition {
@@ -163,6 +168,14 @@
     private Property property;
     private String label;
     private UIDefinition uiDefinition;
+    private Boolean isParentProperty = null;
+
+    public boolean isParentProperty() {
+      if (isParentProperty == null) {
+        isParentProperty = OBViewFormComponent.this.getParentProperty().equals(property.getName());
+      }
+      return isParentProperty;
+    }
 
     public boolean isSearchField() {
       return uiDefinition instanceof FKSearchUIDefinition;
@@ -173,6 +186,7 @@
     }
 
     public String getFieldProperties() {
+
       String jsonString = getUIDefinition().getFieldProperties(field).trim();
       if (jsonString == null || jsonString.trim().length() == 0) {
         return "";
@@ -201,7 +215,7 @@
     }
 
     public String getColumnName() {
-      return property.getColumnName().toLowerCase();
+      return property.getColumnName();
     }
 
     public String getInpColumnName() {
@@ -221,6 +235,13 @@
       return prop.getColumnName();
     }
 
+    public String getTargetEntity() {
+      if (property.isOneToMany() || property.isPrimitive()) {
+        return "";
+      }
+      return property.getTargetEntity().getName();
+    }
+
     public String getLabel() {
       // compute the label
       if (label == null) {
@@ -295,6 +316,10 @@
       return "";
     }
 
+    public boolean isParentProperty() {
+      return false;
+    }
+
     public String getInpColumnName() {
       return "";
     }
@@ -303,6 +328,10 @@
       return "";
     }
 
+    public String getTargetEntity() {
+      return "";
+    }
+
     public String getLabel() {
       // compute the label
       if (label == null) {
@@ -370,6 +399,10 @@
       return "false";
     }
 
+    public boolean isParentProperty() {
+      return false;
+    }
+
     public String getFieldProperties() {
       return "";
     }
@@ -390,6 +423,10 @@
       return "";
     }
 
+    public String getTargetEntity() {
+      return "";
+    }
+
     public long getRowSpan() {
       return 1;
     }
@@ -424,4 +461,12 @@
     }
 
   }
+
+  public String getParentProperty() {
+    return parentProperty;
+  }
+
+  public void setParentProperty(String parentProperty) {
+    this.parentProperty = parentProperty;
+  }
 }
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewTab.java	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/window/OBViewTab.java	Mon Jan 03 21:44:36 2011 +0100
@@ -111,6 +111,7 @@
     final OBViewFormComponent viewFormComponent = createComponent(OBViewFormComponent.class);
     viewFormComponent.setParameters(getParameters());
     viewFormComponent.setTab(tab);
+    viewFormComponent.setParentProperty(getParentProperty());
     return viewFormComponent.generate();
   }
 
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-formitem-widgets.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-formitem-widgets.js	Mon Jan 03 21:44:36 2011 +0100
@@ -27,6 +27,7 @@
 // * OBDateTimeItem: FormItem for DateTime
 // * OBNumber: FormItem for numbers
 // * OBYesNoItem: combo box for yes/no values
+// * OBLinkTitleItem: an interface supporting a link button in the title.
 // * OBFKItem: combo box for foreign key references
 // * OBListItem: combo box for list references
 
@@ -34,20 +35,61 @@
 // Item used for Openbravo yes/no fields.
 isc.ClassFactory.defineClass('OBCheckboxItem', CheckboxItem);
 
+// == OBLinkTitleItem ==
+// Item used for creating a link button in the title
+isc.ClassFactory.defineInterface('OBLinkTitleItem');
+
+isc.OBLinkTitleItem.addProperties({
+  
+  LINKBUTTONSUFFIX: '_linkButton',
+  
+  getLinkTitleHTML: function(){    
+    var titleHtml = this.Super('getTitleHTML', arguments);
+    
+    if (this.parentProperty) {
+      return titleHtml;
+    }
+
+    var searchIconObj = {
+      src: this.newTabIconSrc,
+      height: this.newTabIconSize,
+      width: this.newTabIconSize,
+      align: 'absmiddle',
+      extraStuff: ' id="' + this.ID + this.LINKBUTTONSUFFIX + '" class="OBFormFieldLinkButton" onclick="window[\'' + this.ID + '\'].linkButtonClick();"'
+    };
+    
+    var imgHTML = isc.Canvas.imgHTML(searchIconObj);
+    
+    return titleHtml + '&nbsp;' + imgHTML;
+  },
+  
+  getLinkImageHtmlElement: function(){
+    return window[this.ID + this.LINKBUTTONSUFFIX];
+  },
+  
+  linkButtonClick: function(){
+    var sourceWindow = this.form.view.standardWindow.windowId;
+    OB.Utilities.openDirectView(sourceWindow, this.referencedKeyColumnName, this.targetEntity, this.getValue());
+  }
+});
+
 // == OBSearchItem ==
 // Item used for Openbravo search fields.
 isc.ClassFactory.defineClass('OBSearchItem', StaticTextItem);
 
+isc.ClassFactory.mixInInterface('OBSearchItem', 'OBLinkTitleItem');
+
+// a global function as it is called from classic windows
 function closeSearch(action, value, display, parameters, wait){
   var length, i, hiddenInputName, targetFld = isc.OBSearchItem.openSearchItem;
   if (action === 'SAVE') {
     targetFld.setValue(value);
     targetFld.form.setValue(targetFld.displayField, display);
- 
+    
     if (parameters && parameters.length > 0) {
       length = parameters.length;
       for (i = 0; i < length; i++) {
-        hiddenInputName = ((parameters[i].esRef) ? targetFld.inpColumnName : "") + parameters[i].campo;
+        hiddenInputName = ((parameters[i].esRef) ? targetFld.inpColumnName : '') + parameters[i].campo;
         targetFld.form.hiddenInputs[hiddenInputName] = parameters[i].valor;
       }
     }
@@ -60,12 +102,14 @@
 
 isc.OBSearchItem.addProperties({
   showPickerIcon: true,
-  pickerIconHeight: 21,
-  pickerIconWidth: 21,
-  pickerIconSrc: '[SKINIMG]../../org.openbravo.client.application/images/form/search_picker.png',
-      
+
+  getTitleHTML: function() {
+    // calls the method from the OBLinkTitleItem interface
+    return this.getLinkTitleHTML();
+  },
+
   changed: function(){
-    var ret = this.Super("changed", arguments);
+    var ret = this.Super('changed', arguments);
     if (this.form && this.form.handleItemChange) {
       this.form.handleItemChange(this);
     }
@@ -87,7 +131,7 @@
       inpName = this.inFields[i];
       fld = this.form.getFieldFromInpColumnName(inpName);
       if (fld && fld.getValue()) {
-        parameters[index++] = inpName;
+        parameters[index++] = 'inp' + fld.columnName;
         parameters[index++] = fld.getValue();
       }
     }
@@ -96,11 +140,11 @@
   
   openSearchWindow: function(url, parameters, strValueID){
     var height, width, top, left;
-    var complementsNS4 = "";
-    var auxField = "";
+    var complementsNS4 = '';
+    var auxField = '';
     var hidden;
     
-    if (url.indexOf("Location") != -1) {
+    if (url.indexOf('Location') !== -1) {
       height = 300;
       width = 600;
     } else {
@@ -117,31 +161,31 @@
     isc.OBSearchItem.openedWindow = null;
     
     if (strValueID) {
-      auxField = "inpNameValue=" + encodeURIComponent(this.form.getValue(this.displayField));
+      auxField = 'inpNameValue=' + encodeURIComponent(this.form.getValue(this.displayField));
     }
     if (parameters) {
       var total = parameters.length;
       for (var i = 0; i < total; i++) {
-        if (auxField !== "") {
-          auxField += "&";
+        if (auxField !== '') {
+          auxField += '&';
         }
         // TODO: check this
-        //        if (parameters[i] === "isMultiLine" && parameters[i + 1] == "Y") {
+        //        if (parameters[i] === 'isMultiLine' && parameters[i + 1] == 'Y') {
         //          gIsMultiLineSearch = true;
         //        }
-        auxField += parameters[i] + "=" + ((parameters[i + 1] !== null) ? encodeURIComponent(parameters[i + 1]) : "");
-        if (parameters[i] === "Command") {
+        auxField += parameters[i] + '=' + ((parameters[i + 1] !== null) ? encodeURIComponent(parameters[i + 1]) : '');
+        if (parameters[i] === 'Command') {
           hidden = true;
         }
         i++;
       }
     }
     
-    if (navigator.appName.indexOf("Netscape")) {
-      complementsNS4 = "alwaysRaised=1, dependent=1, directories=0, hotkeys=0, menubar=0, ";
+    if (navigator.appName.indexOf('Netscape')) {
+      complementsNS4 = 'alwaysRaised=1, dependent=1, directories=0, hotkeys=0, menubar=0, ';
     }
-    var complements = complementsNS4 + "height=" + height + ", width=" + width + ", left=" + left + ", top=" + top + ", screenX=" + left + ", screenY=" + top + ", location=0, resizable=1, scrollbars=1, status=0, toolbar=0, titlebar=0, modal='yes'";
-    isc.OBSearchItem.openedWindow = window.open(OB.Application.contextUrl + url + ((auxField === "") ? "" : "?" + auxField), 'SELECTOR', complements);
+    var complements = complementsNS4 + 'height=' + height + ', width=' + width + ', left=' + left + ', top=' + top + ', screenX=' + left + ', screenY=' + top + ', location=0, resizable=1, scrollbars=1, status=0, toolbar=0, titlebar=0, modal=\'yes\'';
+    isc.OBSearchItem.openedWindow = window.open(OB.Application.contextUrl + url + ((auxField === '') ? '' : '?' + auxField), 'SELECTOR', complements);
     if (isc.OBSearchItem.openedWindow) {
       isc.OBSearchItem.openedWindow.focus();
       this.setUnloadEventHandling();
@@ -207,8 +251,10 @@
 
   itemData: null,
   
+  cachePickListResults: false,
+  
   changed: function(){
-    var ret = this.Super("changed", arguments);
+    var ret = this.Super('changed', arguments);
     if (this.form && this.form.handleItemChange) {
       this.form.handleItemChange(this);
     }
@@ -228,6 +274,8 @@
 // Extends SelectItem with suggestion box behavior for foreign key references.
 isc.ClassFactory.defineClass('OBFKItem', SelectItem);
 
+isc.ClassFactory.mixInInterface('OBFKItem', 'OBLinkTitleItem');
+
 isc.OBFKItem.addProperties({
   selectOnFocus: true,
   autoFetchData: false,
@@ -236,15 +284,24 @@
   valueField: OB.Constants.ID,
   textMatchStyle: 'substring',
   
+  useClientFiltering: false,
+  
+  cachePickListResults: false,
+  
   itemData: null,
   optionDataSource: null,
   
+  getTitleHTML: function() {
+    // calls the method from the OBLinkTitleItem interface
+    return this.getLinkTitleHTML();
+  },
+
   getDataSource: function(){
     return this.getOptionDataSource();
   },
   
   changed: function(){
-    var ret = this.Super("changed", arguments);
+    var ret = this.Super('changed', arguments);
     if (this.form && this.form.handleItemChange) {
       this.form.handleItemChange(this);
     }
@@ -531,7 +588,7 @@
       this.checkOBDateItemValue();
       this.inBlur = false;
     }
-    return this.Super("blur", arguments);
+    return this.Super('blur', arguments);
   },
   
   // ** {{{ displayFormat }}} **
@@ -961,7 +1018,7 @@
   blur: function(form, item){
     item.blurNumberInput(item.maskNumeric, item.decSeparator, item.groupSeparator, item.groupInterval);
     item.validateOBNumberItem();
-    return this.Super("blur", arguments);
+    return this.Super('blur', arguments);
   },
   
   keyDown: function(item, form, keyName){
@@ -992,7 +1049,7 @@
   },
   
   changed: function(){
-    var ret = this.Super("changed", arguments);
+    var ret = this.Super('changed', arguments);
     this._doFICCall = true;
     return ret;
   },
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-grid.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-grid.js	Mon Jan 03 21:44:36 2011 +0100
@@ -1,196 +1,196 @@
-/*
- *************************************************************************
- * 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) 2010 Openbravo SLU
- * All Rights Reserved.
- * Contributor(s):  ______________________________________.
- ************************************************************************
- */
-isc.ClassFactory.defineClass('OBGrid', isc.ListGrid);
-
-// = OBGrid =
-// The OBGrid combines common grid functionality usefull for different 
-// grid implementations.
-isc.OBGrid.addProperties({
-
-  recordComponentPoolingMode: 'recycle',
-  showRecordComponentsByCell: true,
-  recordComponentPosition: 'within',
-  poolComponentsPerColumn: true,
-  showRecordComponents: true,
-  
-  createRecordComponent: function(record, colNum){
-    var field = this.getField(colNum), rowNum = this.getRecordIndex(record);
-    if (field.isLink && record[field.name]) {
-      var linkButton = isc.OBGridLinkLayout.create({
-        grid: this,
-        align: this.getCellAlign(record, rowNum, colNum),
-        title: this.formatLinkValue(record, field, colNum, rowNum, record[field.name]),
-        record: record,
-        rowNum: rowNum,
-        colNum: colNum
-      });
-      return linkButton;
-    }
-    return null;
-  },
-  
-  updateRecordComponent: function(record, colNum, component, recordChanged){
-    var field = this.getField(colNum), rowNum = this.getRecordIndex(record);
-    if (field.isLink && record[field.name]) {
-      component.setTitle(this.formatLinkValue(record, field, colNum, rowNum, record[field.name]));
-      component.record = record;
-      component.rowNum = rowNum;
-      component.colNum = colNum;
-      component.align = this.getCellAlign(record, rowNum, colNum);
-      return component;
-    }
-    return null;
-  },
-  
-  formatLinkValue: function(record, field, colNum, rowNum, value){
-    if (typeof value === 'undefined' || value === null) {
-      return '';
-    }
-    var simpleType = isc.SimpleType.getType(field.type, this.dataSource);
-    // note: originalFormatCellValue is set in the initWidget below
-    if (field && field.originalFormatCellValue) {
-      return field.originalFormatCellValue(value, record, rowNum, colNum, this);
-    } else if (simpleType.shortDisplayFormatter) {
-      return simpleType.shortDisplayFormatter(value, field, this, record, rowNum, colNum);
-    }
-    return value;
-  },
-  
-  initWidget: function(){
-    // prevent the value to be displayed in case of a link
-    var i, field, formatCellValueFunction = function(value, record, rowNum, colNum, grid){
-      return '';
-    };
-    for (i = 0; i < this.fields.length; i++) {
-      field = this.fields[i];
-      if (field.isLink) {
-        // store the originalFormatCellValue if not already set
-        if (field.formatCellValue && !field.formatCellValueFunctionReplaced) {
-          field.originalFormatCellValue = field.formatCellValue;
-        }
-        field.formatCellValueFunctionReplaced = true;
-        field.formatCellValue = formatCellValueFunction;
-      }
-    }
-    return this.Super('initWidget', arguments);
-  },
-  
-  showSummaryRow: function(){
-    var i, fld, fldsLength, newFields = [];
-    var ret = this.Super("showSummaryRow", arguments);
-    if (this.summaryRow && !this.summaryRowFieldRepaired) {
-      // the summaryrow shares the same field instances as the 
-      // original grid, this must be repaired as the grid and
-      // and the summary row need different behavior.
-      // copy the fields and repair specific parts
-      // don't support links in the summaryrow
-      fldsLength = this.summaryRow.fields.length;
-      for (i = 0; i < fldsLength; i++) {
-        fld = isc.addProperties({}, this.summaryRow.fields[i]);
-        newFields[i] = fld;
-        fld.isLink = false;
-        if (fld.originalFormatCellValue) {
-          fld.formatCellValue = fld.originalFormatCellValue;
-          fld.originalFormatCellValue = null;
-        } else {
-          fld.formatCellValue = null;
-        }
-      }
-      this.summaryRow.isSummaryRow = true;
-      this.summaryRowFieldRepaired = true;
-      this.summaryRow.setFields(newFields);
-    }
-    return ret;
-  },
-  
-  // = exportData =
-  // The exportData function exports the data of the grid to a file. The user will 
-  // be presented with a save-as dialog.
-  // Parameters:
-  // * {{{exportProperties}}} defines different properties used for controlling the export, currently only the 
-  // exportProperties.exportFormat is supported (which is defaulted to csv).
-  // * {{{data}}} the parameters to post to the server, in addition the filter criteria of the grid are posted.  
-  exportData: function(exportProperties, data){
-    var d = data || {}, expProp = exportProperties || {}, dsURL = this.dataSource.dataURL;
-    
-    isc.addProperties(d, {
-      _dataSource: this.dataSource.ID,
-      _operationType: 'fetch',
-      _noCount: true, // never do count for export
-      exportAs: expProp.exportAs || 'csv',
-      exportToFile: true
-    }, this.getCriteria());
-    
-    OB.Utilities.postThroughHiddenForm(dsURL, d);
-  }
-});
-
-isc.ClassFactory.defineClass('OBGridSummary', isc.OBGrid);
-
-isc.OBGridSummary.addProperties({
-  getCellStyle: function(record, rowNum, colNum){
-    var field = this.getField(colNum);
-    if (field.summaryFunction === "sum" && this.summaryRowStyle_sum) {
-      return this.summaryRowStyle_sum;
-    } else if (field.summaryFunction === "avg" && this.summaryRowStyle_avg) {
-      return this.summaryRowStyle_avg;
-    } else {
-      return this.summaryRowStyle;
-    }
-  }
-});
-
-isc.ClassFactory.defineClass('OBGridHeaderImgButton', isc.ImgButton);
-
-isc.ClassFactory.defineClass('OBGridLinkLayout', isc.HLayout);
-isc.OBGridLinkLayout.addProperties({
-  overflow: 'clip-h',
-  btn: null,
-  height: 1,
-  width: '100%',
-  
-  initWidget: function() {
-    this.btn = isc.OBGridLinkButton.create({});
-    this.btn.setTitle(this.title);
-    this.btn.owner = this;
-    this.addMember(this.btn);
-    return this.Super("initWidget", arguments);
-  },
-  
-  setTitle: function(title) {
-    this.btn.setTitle(title);
-  },
-  
-  doAction: function(){
-    if (this.grid && this.grid.doCellClick) {
-      this.grid.doCellClick(this.record, this.rowNum, this.colNum);
-    } else if (this.grid && this.grid.cellClick) {
-      this.grid.cellClick(this.record, this.rowNum, this.colNum);
-    }
-  }
-
-});
-
-isc.ClassFactory.defineClass('OBGridLinkButton', isc.Button);
-
-isc.OBGridLinkButton.addProperties({
-  action: function(){
-    this.owner.doAction();
-  }
-});
+/*
+ *************************************************************************
+ * 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) 2010 Openbravo SLU
+ * All Rights Reserved.
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+isc.ClassFactory.defineClass('OBGrid', isc.ListGrid);
+
+// = OBGrid =
+// The OBGrid combines common grid functionality usefull for different 
+// grid implementations.
+isc.OBGrid.addProperties({
+
+  recordComponentPoolingMode: 'recycle',
+  showRecordComponentsByCell: true,
+  recordComponentPosition: 'within',
+  poolComponentsPerColumn: true,
+  showRecordComponents: true,
+  
+  createRecordComponent: function(record, colNum){
+    var field = this.getField(colNum), rowNum = this.getRecordIndex(record);
+    if (field.isLink && record[field.name]) {
+      var linkButton = isc.OBGridLinkLayout.create({
+        grid: this,
+        align: this.getCellAlign(record, rowNum, colNum),
+        title: this.formatLinkValue(record, field, colNum, rowNum, record[field.name]),
+        record: record,
+        rowNum: rowNum,
+        colNum: colNum
+      });
+      return linkButton;
+    }
+    return null;
+  },
+  
+  updateRecordComponent: function(record, colNum, component, recordChanged){
+    var field = this.getField(colNum), rowNum = this.getRecordIndex(record);
+    if (field.isLink && record[field.name]) {
+      component.setTitle(this.formatLinkValue(record, field, colNum, rowNum, record[field.name]));
+      component.record = record;
+      component.rowNum = rowNum;
+      component.colNum = colNum;
+      component.align = this.getCellAlign(record, rowNum, colNum);
+      return component;
+    }
+    return null;
+  },
+  
+  formatLinkValue: function(record, field, colNum, rowNum, value){
+    if (typeof value === 'undefined' || value === null) {
+      return '';
+    }
+    var simpleType = isc.SimpleType.getType(field.type, this.dataSource);
+    // note: originalFormatCellValue is set in the initWidget below
+    if (field && field.originalFormatCellValue) {
+      return field.originalFormatCellValue(value, record, rowNum, colNum, this);
+    } else if (simpleType.shortDisplayFormatter) {
+      return simpleType.shortDisplayFormatter(value, field, this, record, rowNum, colNum);
+    }
+    return value;
+  },
+  
+  initWidget: function(){
+    // prevent the value to be displayed in case of a link
+    var i, field, formatCellValueFunction = function(value, record, rowNum, colNum, grid){
+      return '';
+    };
+    for (i = 0; i < this.fields.length; i++) {
+      field = this.fields[i];
+      if (field.isLink) {
+        // store the originalFormatCellValue if not already set
+        if (field.formatCellValue && !field.formatCellValueFunctionReplaced) {
+          field.originalFormatCellValue = field.formatCellValue;
+        }
+        field.formatCellValueFunctionReplaced = true;
+        field.formatCellValue = formatCellValueFunction;
+      }
+    }
+    return this.Super('initWidget', arguments);
+  },
+  
+  showSummaryRow: function(){
+    var i, fld, fldsLength, newFields = [];
+    var ret = this.Super('showSummaryRow', arguments);
+    if (this.summaryRow && !this.summaryRowFieldRepaired) {
+      // the summaryrow shares the same field instances as the 
+      // original grid, this must be repaired as the grid and
+      // and the summary row need different behavior.
+      // copy the fields and repair specific parts
+      // don't support links in the summaryrow
+      fldsLength = this.summaryRow.fields.length;
+      for (i = 0; i < fldsLength; i++) {
+        fld = isc.addProperties({}, this.summaryRow.fields[i]);
+        newFields[i] = fld;
+        fld.isLink = false;
+        if (fld.originalFormatCellValue) {
+          fld.formatCellValue = fld.originalFormatCellValue;
+          fld.originalFormatCellValue = null;
+        } else {
+          fld.formatCellValue = null;
+        }
+      }
+      this.summaryRow.isSummaryRow = true;
+      this.summaryRowFieldRepaired = true;
+      this.summaryRow.setFields(newFields);
+    }
+    return ret;
+  },
+  
+  // = exportData =
+  // The exportData function exports the data of the grid to a file. The user will 
+  // be presented with a save-as dialog.
+  // Parameters:
+  // * {{{exportProperties}}} defines different properties used for controlling the export, currently only the 
+  // exportProperties.exportFormat is supported (which is defaulted to csv).
+  // * {{{data}}} the parameters to post to the server, in addition the filter criteria of the grid are posted.  
+  exportData: function(exportProperties, data){
+    var d = data || {}, expProp = exportProperties || {}, dsURL = this.dataSource.dataURL;
+    
+    isc.addProperties(d, {
+      _dataSource: this.dataSource.ID,
+      _operationType: 'fetch',
+      _noCount: true, // never do count for export
+      exportAs: expProp.exportAs || 'csv',
+      exportToFile: true
+    }, this.getCriteria());
+    
+    OB.Utilities.postThroughHiddenForm(dsURL, d);
+  }
+});
+
+isc.ClassFactory.defineClass('OBGridSummary', isc.OBGrid);
+
+isc.OBGridSummary.addProperties({
+  getCellStyle: function(record, rowNum, colNum){
+    var field = this.getField(colNum);
+    if (field.summaryFunction === 'sum' && this.summaryRowStyle_sum) {
+      return this.summaryRowStyle_sum;
+    } else if (field.summaryFunction === 'avg' && this.summaryRowStyle_avg) {
+      return this.summaryRowStyle_avg;
+    } else {
+      return this.summaryRowStyle;
+    }
+  }
+});
+
+isc.ClassFactory.defineClass('OBGridHeaderImgButton', isc.ImgButton);
+
+isc.ClassFactory.defineClass('OBGridLinkLayout', isc.HLayout);
+isc.OBGridLinkLayout.addProperties({
+  overflow: 'clip-h',
+  btn: null,
+  height: 1,
+  width: '100%',
+  
+  initWidget: function() {
+    this.btn = isc.OBGridLinkButton.create({});
+    this.btn.setTitle(this.title);
+    this.btn.owner = this;
+    this.addMember(this.btn);
+    return this.Super('initWidget', arguments);
+  },
+  
+  setTitle: function(title) {
+    this.btn.setTitle(title);
+  },
+  
+  doAction: function(){
+    if (this.grid && this.grid.doCellClick) {
+      this.grid.doCellClick(this.record, this.rowNum, this.colNum);
+    } else if (this.grid && this.grid.cellClick) {
+      this.grid.cellClick(this.record, this.rowNum, this.colNum);
+    }
+  }
+
+});
+
+isc.ClassFactory.defineClass('OBGridLinkButton', isc.Button);
+
+isc.OBGridLinkButton.addProperties({
+  action: function(){
+    this.owner.doAction();
+  }
+});
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-standard-view.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-standard-view.js	Mon Jan 03 21:44:36 2011 +0100
@@ -454,7 +454,7 @@
     
     childView.tab = this.childTabSet.tabs[this.childTabSet.tabs.length - 1];
     
-    OB.TestRegistry.register('org.openbravo.client.application.ChildTab_' + this.tabId + "_" + childView.tabId, childView.tab);
+    OB.TestRegistry.register('org.openbravo.client.application.ChildTab_' + this.tabId + '_' + childView.tabId, childView.tab);
     
   },
   
@@ -584,6 +584,7 @@
     }
     var gridRecord = this.viewGrid.getSelectedRecord();
     this.editRecord(gridRecord);
+    this.recordSelected();
     
     // remove this info
     delete this.standardWindow.directTabInfo;
@@ -622,9 +623,9 @@
   // Is called when a record get's selected. Will refresh direct child views
   // which will again refresh their children.
   recordSelected: function(){
-    this.fireOnPause("recordSelected", {
+    this.fireOnPause('recordSelected', {
       target: this,
-      methodName: "doRecordSelected",
+      methodName: 'doRecordSelected',
       args: []
     }, this.fetchDelay);
   },
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-utilities.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-utilities.js	Mon Jan 03 21:44:36 2011 +0100
@@ -819,12 +819,12 @@
   }
   
   theView.setContextInfo(sessionProperties, function(){
-    OB.Layout.ViewManager.openView("OBPopupClassicWindow", o);
+    OB.Layout.ViewManager.openView('OBPopupClassicWindow', o);
   });
   
   
-  //	OB.Layout.ViewManager.openView("OBPopupClassicWindow", o);
-  //OB.Layout.ViewManager.openView("OBClassicPopup", o);
+  //	OB.Layout.ViewManager.openView('OBPopupClassicWindow', o);
+  //OB.Layout.ViewManager.openView('OBClassicPopup', o);
 
 
   //button.parentElement.parentElement.view.getContextInfo()
@@ -848,7 +848,7 @@
     }
   }
   
-  OB.Layout.ViewManager.openView("OBPopupClassicWindow", o);
+  OB.Layout.ViewManager.openView('OBPopupClassicWindow', o);
 };
 
 
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-form.js	Mon Jan 03 21:44:36 2011 +0100
@@ -32,11 +32,14 @@
   auxInputs: {},
   hiddenInputs: {},
   dynamicCols: [],
-
+  
   // ** {{ Layout Settings }} **
   numCols: 4,
   colWidths: ['24%', '24%', '24%', '24%'],
   
+  titleSuffix: '',
+  requiredTitleSuffix: '</b>',
+  
   fieldsByInpColumnName: null,
   fieldsByColumnName: null,
   
@@ -54,7 +57,7 @@
   },
   
   editRecord: function(record){
-    var ret = this.Super("editRecord", arguments);
+    var ret = this.Super('editRecord', arguments);
     this.retrieveInitialValues();
     return ret;
   },
@@ -63,7 +66,9 @@
     if (!this.fieldsByInpColumnName) {
       var localResult = [], fields = this.getFields();
       for (var i = 0; i < fields.length; i++) {
-        localResult[fields[i].inpColumnName] = fields[i];
+        if (fields[i].inpColumnName) {
+          localResult[fields[i].inpColumnName.toLowerCase()] = fields[i];
+        }
       }
       this.fieldsByInpColumnName = localResult;
     }
@@ -74,7 +79,9 @@
     if (!this.fieldsByColumnName) {
       var localResult = [], fields = this.getFields();
       for (var i = 0; i < fields.length; i++) {
-        localResult[fields[i].columnName] = fields[i];
+        if (fields[i].columnName) {
+          localResult[fields[i].columnName.toLowerCase()] = fields[i];
+        }
       }
       this.fieldsByColumnName = localResult;
     }
@@ -116,7 +123,7 @@
         }
       }
     }
-    if (calloutMessages && calloutMessages.length > 0) {
+    if (calloutMessages && calloutMessages.length > 0 && calloutMessages[0]) {
       // TODO: handle multiple messages
       this.view.standardWindow.messageBar.setMessage(calloutMessages[0]);
     }
@@ -135,7 +142,7 @@
   },
   
   processColumnValue: function(columnName, columnValue){
-    var isDate, i, valueMap = {}, field = this.getFieldFromColumnName(columnName), entries = columnValue.entries;
+    var data, record, length, valuePresent, currentValue, isDate, value, i, valueMap = {}, field = this.getFieldFromColumnName(columnName), entries = columnValue.entries;
     if (!field) {
       // ignore for now, the pk is also passed in
       //isc.warn('No field found using column name: ' + columnName + ' for tab ' + this.view.tabId);
@@ -150,11 +157,19 @@
         }
         field.setValueMap(valueMap);
       }
+      
+      // rereads the picklist      
+      if (field.pickList) {
+        field.pickList.invalidateCache();
+        field.pickList.deselectAllRecords();
+        field.selectItemFromValue(field.getValue());
+      }
     }
+    
     if (columnValue.value) {
       isDate = field.type &&
-        (isc.SimpleType.getType(field.type).inheritsFrom === 'date' ||
-        isc.SimpleType.getType(field.type).inheritsFrom === 'datetime');
+      (isc.SimpleType.getType(field.type).inheritsFrom === 'date' ||
+      isc.SimpleType.getType(field.type).inheritsFrom === 'datetime');
       if (isDate) {
         this.setValue(field.name, isc.Date.parseSchemaDate(columnValue.value));
       } else {
@@ -163,9 +178,11 @@
     } else {
       this.clearValue(field.name);
     }
+    
+    field.redraw();
   },
   
-  handleItemChange: function(item) {
+  handleItemChange: function(item){
     if (item._doFICCall) {
       var i;
       for (i = 0; i < this.dynamicCols.length; i++) {
@@ -179,23 +196,27 @@
     item._doFICCall = false;
   },
   
-  doChangeFICCall: function(item) {
-    var parentId = null, me = this;
+  doChangeFICCall: function(item){
+    var parentId = null, me = this, requestParams;
+    var allProperties = {}, sessionProperties = {};
+    
     if (this.view.parentProperty) {
       parentId = this.getValue(this.view.parentProperty);
     }
     
-    var allProperties = {}, sessionProperties = {};
+    // fills the allProperties    
     this.view.getContextInfo(allProperties, sessionProperties);
     
-    // collect the context information    
-    OB.RemoteCallManager.call('org.openbravo.client.application.window.FormInitializationComponent', allProperties, {
+    requestParams = isc.addProperties({
       MODE: 'CHANGE',
       PARENT_ID: parentId,
       TAB_ID: this.view.tabId,
       ROW_ID: this.getValue(OB.Constants.ID),
       CHANGED_COLUMN: item.inpColumnName
-    }, function(response, data, request){
+    }, allProperties);
+    
+    // collect the context information    
+    OB.RemoteCallManager.call('org.openbravo.client.application.window.FormInitializationComponent', null, requestParams, function(response, data, request){
       me.processFICReturn(response, data, request);
     });
   }
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-grid.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/ob-view-grid.js	Mon Jan 03 21:44:36 2011 +0100
@@ -1,895 +1,909 @@
-/*
- *************************************************************************
- * 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) 2010 Openbravo SLU
- * All Rights Reserved.
- * Contributor(s):  ______________________________________.
- ************************************************************************
- */
-isc.ClassFactory.defineClass('OBViewGrid', isc.OBGrid);
-
-isc.OBViewGrid.addClassProperties({
-  EDIT_LINK_FIELD_NAME: '_editLink',
-  NO_COUNT_PARAMETER: '_noCount', // prevent the count operation on the server
-  // note following 2 values should be the same
-  // ListGrid._$ArrowUp and ListGrid._$ArrowDown
-  ARROW_UP_KEY_NAME: 'Arrow_Up',
-  ARROW_DOWN_KEY_NAME: 'Arrow_Down'
-});
-
-/*
- * Todos: - edit button klik selects one record, deselects others, opens edit
- * view and refreshes child windows. - a grid which gets opened always selects
- * the first record - double click on a record does the same as the edit button -
- * single click opens bubble: edit in grid, use as filter, open on tab
- */
-// = OBViewGrid =
-// The OBViewGrid is the Openbravo specific subclass of the Smartclient
-// ListGrid.
-isc.OBViewGrid.addProperties({
-
-  // ** {{{ view }}} **
-  // The view member contains the pointer to the composite canvas which
-  // handles this form
-  // and the grid and other related components.
-  view: null,
-  
-  // ** {{{ foreignKeyFieldNames }}} **
-  // The list of fields which are foreign keys, these require custom
-  // filtering.
-  foreignKeyFieldNames: [],
-  
-  // ** {{{ editGrid }}} **
-  // Controls if an edit link column is created in the grid, set to false to
-  // prevent this.
-  editGrid: true,
-  
-  // ** {{{ editLinkFieldProperties }}} **
-  // The properties of the ListGridField created for the edit links.
-  editLinkFieldProperties: {
-    type: 'text',
-    canSort: false,
-    canFreeze: false,
-    canEdit: false,
-    canGroupBy: false,
-    canHide: false,
-    showTitle: true,
-    title: '&nbsp;',
-    autoFitWidth: true,
-    canFilter: true,
-    autoExpand: false,
-    filterEditorType: 'StaticTextItem',
-    filterEditorProperties: {
-      textAlign: 'center'
-    },
-    name: isc.OBViewGrid.EDIT_LINK_FIELD_NAME
-  },
-  
-  // ** {{{ dataPageSize }}} **
-  // The data page size used for loading paged data from the server.
-  dataPageSize: 100,
-    
-  autoFitFieldWidths: true,
-  autoFitWidthApproach: 'title',
-  canAutoFitFields: false,
-  width: '100%',
-
-  autoFetchTextMatchStyle: 'substring',
-  showFilterEditor: true,
-  canEdit: true,
-  alternateRecordStyles: true,
-  canReorderFields: true,
-  canFreezeFields: true,
-  canAddFormulaFields: true,
-  canAddSummaryFields: true,
-  canGroupBy: false,
-  selectionAppearance: 'checkbox',
-  useAllDataSourceFields: false,
-  editEvent: 'none',
-  showCellContextMenus: true,
-  canOpenRecordEditor: true,
-  showDetailFields: true,
-  
-  // internal sc grid property, see the ListGrid source code
-  preserveEditsOnSetData: false,
-  
-  waitForSave: true,
-  stopOnErrors: true,
-  confirmDiscardEdits: true,
-  
-  canMultiSort: false,
-  
-  emptyMessage: OB.I18N.getLabel('OBUIAPP_NoDataInGrid'),
-  discardEditsSaveButtonTitle: OB.I18N.getLabel('UINAVBA_Save'),
-  
-  // keeps track if we are in objectSelectionMode or in toggleSelectionMode
-  // objectSelectionMode = singleRecordSelection === true  
-  singleRecordSelection: false,
-  
-  dataProperties: {
-    useClientFiltering: false,
-    useClientSorting: false,
-    
-    transformData: function(newData, dsResponse){
-      // correct the length if there is already data in the localData array
-      if (this.localData) {
-        for (var i = dsResponse.endRow + 1; i < this.localData.length; i++) {
-          if (!Array.isLoading(this.localData[i]) && this.localData[i]) {
-            dsResponse.totalRows = i + 1;
-          } else {
-            break;
-          }
-        }
-      }
-      if (this.localData && this.localData[dsResponse.totalRows]) {
-        this.localData[dsResponse.totalRows] = null;
-      }
-      return this.Super('transformData', arguments);
-    }
-  },
-  
-  currentEditColumnLayout: null,
-  
-  refreshFields: function(){
-    this.setFields(this.completeFields.duplicate());
-  },
-  
-  createRecordComponent: function(record, colNum){
-    var layout = this.Super('createRecordComponent',arguments), rowNum;
-    if (layout) {
-      return layout;
-    }
-    if (this.isEditLinkColumn(colNum)) {
-      rowNum = this.getRecordIndex(record);
-      layout = isc.OBGridButtonsComponent.create({
-        record: record,
-        grid: this,
-        rowNum: rowNum
-      });
-      record.editColumnLayout = layout;
-    }
-    return layout;
-  },
-  
-  isEditLinkColumn: function(colNum){
-    var fieldName = this.getFieldName(colNum);
-    return (fieldName === isc.OBViewGrid.EDIT_LINK_FIELD_NAME);
-  },
-  
-  updateRecordComponent: function(record, colNum, component, recordChanged){
-    var superComponent = this.Super('updateRecordComponent', arguments);
-    if (superComponent) {
-      return superComponent;
-    }
-    if (this.isEditLinkColumn(colNum)) {
-      // clear the previous record pointer
-      if (recordChanged && component.record.editColumnLayout === component) {
-        component.record.editColumnLayout = null;
-      }
-      component.record = record;
-      record.editColumnLayout = component;
-      component.rowNum = this.getRecordIndex(record);
-      return component;
-    }
-    return null;
-  },
-  
-  initWidget: function(){
-    var thisGrid = this, localEditLinkField;
-    if (this.editGrid) {
-      // add the edit pencil in the beginning
-      localEditLinkField = isc.addProperties({}, this.editLinkFieldProperties);
-      localEditLinkField.width = this.editLinkColumnWidth;
-      this.fields.unshift(localEditLinkField);
-    }
-    
-    // added for showing counts in the filtereditor row
-    this.checkboxFieldDefaults = isc.addProperties(this.checkboxFieldDefaults, {
-      canFilter: true,
-      filterEditorProperties: {
-        textAlign: 'center'
-      },
-      filterEditorType: 'StaticTextItem'
-    });
-    
-    this.filterEditorProperties = {
-      isCheckboxField: function(){
-        return false;
-      },
-      actionButtonProperties: {
-        visibility: 'hidden'
-      }
-    };
-    
-    this.Super('initWidget', arguments);
-  },
-  
-  headerClick: function(fieldNum, header){
-    var field = this.fields[fieldNum];
-    if (this.isCheckboxField(field) && this.singleRecordSelection) {
-      this.deselectAllRecords();
-      this.singleRecordSelection = false;
-    }
-    return this.Super('headerClick', arguments);
-  },
-  
-  deselectAllRecords: function(){
-    this.allSelected = false;
-    return this.Super('deselectAllRecords', arguments);
-  },
-  
-  selectAllRecords: function(){
-    this.allSelected = true;
-    return this.Super('selectAllRecords', arguments);
-  },
-  
-  updateRowCountDisplay: function(){
-    var newValue = '';
-    if (this.data.getLength() > this.dataPageSize) {
-      newValue = '>' + this.dataPageSize;
-    } else if (this.data.getLength() === 0) {
-      newValue = '&nbsp;';
-    } else {
-      newValue = '' + this.data.getLength();
-    }
-    if (this.filterEditor) {
-      this.filterEditor.getEditForm().setValue(isc.OBViewGrid.EDIT_LINK_FIELD_NAME, newValue);
-    }
-  },
-  
-  refreshContents: function(callback){
-    var context = {
-      showPrompt: false,
-      textMatchStyle: this.autoFetchTextMatchStyle
-    };
-    this.filterData(this.getCriteria(), callback, context);
-  },
-  
-  dataArrived: function(startRow, endRow){
-    var record, ret = this.Super('dataArrived', arguments);
-    this.updateRowCountDisplay();
-    this.updateSelectedCountDisplay();
-    
-    if (this.targetRecordId) {
-      this.delayedHandleTargetRecord(startRow, endRow);
-    } else if (this.view.shouldOpenDefaultEditMode()) {
-      this.view.openDefaultEditView(this.getRecord(startRow));   
-    }
-    
-    return ret;
-  },
-  
-  // handle the target record when the body has been drawn
-  delayedHandleTargetRecord: function(startRow, endRow){
-    var rowTop, recordIndex, i, data = this.data;
-    if (!this.targetRecordId) {
-      return;
-    }
-    if (this.body) {
-      var gridRecord = data.find('id', this.targetRecordId);
-      
-      // no grid record found, stop here
-      if (!gridRecord) {
-        return;
-      }
-      recordIndex = this.getRecordIndex(gridRecord);
-      
-      this.targetRecordId = null;
-      if (data.criteria) {
-        data.criteria._targetRecordId = null;
-      }
-      
-      for (i = 0; i < startRow; i++) {
-        if (Array.isLoading(data.localData[i])) {
-          data.localData[i] = null;
-        }
-      }
-      
-      this.scrollRecordIntoView(recordIndex, false);
-      if (this.view.defaultEditMode) {
-        this.view.editRecord(gridRecord);   
-      } else {
-        this.doSelectSingleRecord(gridRecord);
-      }
-      
-      isc.Page.waitFor(this, "delayedHandleTargetRecord", {
-        method: this.view.openDirectChildTab(),
-        args: [],
-        target: this.view
-      });
-    } else {
-      // wait a bit longer
-      this.delayCall('delayedHandleTargetRecord', [startRow, endRow], 500, this);
-    }
-  },
-  
-  filterData: function(criteria, callback, requestProperties){
-    if (!requestProperties) {
-      requestProperties = {};
-    }
-    requestProperties.showPrompt = false;
-    
-    var theView = this.view;
-    var newCallBack = function(){
-      theView.recordSelected();
-      if (callback) {
-        callback();
-      }
-    };
-    
-    return this.Super('filterData', [criteria, newCallBack, requestProperties]);
-  },
-  
-  fetchData: function(criteria, callback, requestProperties){
-    if (!requestProperties) {
-      requestProperties = {};
-    }
-    requestProperties.showPrompt = false;
-    
-    var theView = this.view;    
-    
-    var newCallBack = function(){
-      theView.recordSelected();
-      if (callback) {
-        callback();
-      }
-    };
-    
-    return this.Super('fetchData', [criteria, newCallBack, requestProperties]);
-  },
-  
-  getCriteria: function() {
-    var criteria = this.Super("getCriteria", arguments);
-    if (!criteria) {
-      criteria = {};
-    }
-    criteria = this.convertCriteria(criteria);
-    criteria = OB.Utilities._getTabInfoRequestProperties(this.view, criteria);    
-    return criteria;
-  },
-  
-  // determine which field can be autoexpanded to use extra space  
-  getAutoFitExpandField: function(){
-    for (var i = 0; i < this.fields.length; i++) {
-      var field = this.fields[i];
-      if (field.autoExpand) {
-        return field;
-      }
-    }
-    return this.Super('getAutoFitExpandField', arguments);
-  },
-  
-  recordClick: function(viewer, record, recordNum, field, fieldNum, value, rawValue){
-    var me = this, EH = isc.EventHandler;
-    if (EH.isMouseEvent(EH.getEventType())) {
-      record._dblClickWaiting = true;
-      isc.Timer.setTimeout(function(){
-        // if no double click happened then do the single click
-        if (record._dblClickWaiting) {
-          record._dblClickWaiting = false;
-          me.handleRecordSelection(viewer, record, recordNum, field, fieldNum, value, rawValue, false);
-        }
-      }, OB.Constants.DBL_CLICK_DELAY);
-    } else {
-      me.handleRecordSelection(viewer, record, recordNum, field, fieldNum, value, rawValue, false);
-    }
-  },
-  
-  recordDoubleClick: function(viewer, record, recordNum, field, fieldNum, value, rawValue){
-    record._dblClickWaiting = false;
-    this.view.editRecord(record);
-  },
-  
-  convertCriteria: function(criteria){
-    if (!criteria) {
-      criteria = {};
-    }
-    
-    var isFiltering = criteria.length > 0;
-    var filterValues = [];
-    var index = 0, selectedValues;
-    var fkFieldsLength = this.foreignKeyFieldNames.getLength(), filterValue = null;
-    
-    if (this.targetRecordId) {
-      criteria._targetRecordId = this.targetRecordId;
-    }
-    
-    if (this.view.parentProperty) {
-      if (!this.view.parentView) {
-        criteria[this.view.parentProperty] = '-1';
-      } else {
-        selectedValues = this.view.parentView.viewGrid.getSelectedRecords();
-      }
-      if (selectedValues.length === 0) {
-        criteria[this.view.parentProperty] = '-1';
-        this.emptyMessage = OB.I18N.getLabel('OBUIAPP_NoParentSelected');
-      } else if (selectedValues.length > 1) {
-        criteria[this.view.parentProperty] = '-1';
-        this.emptyMessage = OB.I18N.getLabel('OBUIAPP_MultipleParentsSelected');
-      } else {
-        this.emptyMessage = OB.I18N.getLabel('OBUIAPP_NoDataInGrid');
-        criteria[this.view.parentProperty] = selectedValues[0][OB.Constants.ID];
-      }
-    }
-    
-    // now repair the filtering on foreign keys to use the identifier
-    //    for (index = 0; index < fkFieldsLength; index++) {
-    //      if (criteria[this.foreignKeyFieldNames[index]]) {
-    //        filterValue = criteria[this.foreignKeyFieldNames[index]];
-    //        delete criteria[this.foreignKeyFieldNames[index]];
-    //        criteria[this.foreignKeyFieldNames[index] + '.' +
-    //        OB.Constants.IDENTIFIER] = filterValue;
-    //      }
-    //    }
-    
-    // prevent the count operation
-    criteria[isc.OBViewGrid.NO_COUNT_PARAMETER] = 'true';
-    
-    if (this.orderByClause) {
-      criteria[OB.Constants.ORDERBY_PARAMETER] = this.orderByClause;
-    }
-    
-    if (this.whereClause) {
-      criteria[OB.Constants.WHERE_PARAMETER] = this.whereClause;
-    }
-    
-    return criteria;
-  },
-  
-  //+++++++++++++++++++++++++++++ Context menu on record click +++++++++++++++++++++++
-  
-  makeCellContextItems: function(record, rowNum, colNum){
-    var sourceWindow = this.view.standardWindow.windowId;
-    var menuItems = [];
-    var field = this.getField(colNum);
-    var grid = this;
-    if (this.canEdit) {
-      menuItems.add({
-        title: OB.I18N.getLabel('OBUIAPP_EditInGrid'),
-        click: function(){
-          grid.endEditing();
-          grid.startEditing(rowNum, colNum);
-        }
-      });
-    }
-    if (field.canFilter) {
-      menuItems.add({
-        title: OB.I18N.getLabel('OBUIAPP_UseAsFilter'),
-        click: function(){
-          var value;
-          var filterCriteria = grid.getCriteria();
-          // a foreign key field, use the displayfield/identifier
-          if (field.foreignKeyField && field.displayField) {
-            value = record[field.displayField];
-            filterCriteria[field.displayField] = value;
-          } else {
-            value = grid.getEditDisplayValue(rowNum, colNum, record);
-            filterCriteria[field.name] = value;
-          }
-          grid.setCriteria(filterCriteria);
-          grid.filterData(grid.getCriteria());
-        }
-      });
-    }
-    if (field.foreignKeyField) {
-      menuItems.add({
-        title: OB.I18N.getLabel('OBUIAPP_OpenOnTab'),
-        click: function(){
-          var fldName = field.name;
-          var dotIndex = fldName.indexOf('.');
-          if (dotIndex !== -1) {
-            fldName = fldName.substring(0, dotIndex);
-          }
-          OB.Utilities.openDirectView(sourceWindow, field.referencedKeyColumnName, field.targetEntity, record[fldName]);
-        }
-      });
-    }
-    
-    return menuItems;
-  },
-  
-  //+++++++++++++++++++++++++++++ Record Selection Handling +++++++++++++++++++++++
-  
-  updateSelectedCountDisplay: function(){
-    var selection = this.getSelection();
-    var selectionLength = selection.getLength();
-    var newValue = '&nbsp;';
-    if (!this.singleRecordSelection && selectionLength > 0) {
-      newValue = selectionLength + '';
-    }
-    if (this.filterEditor) {
-      this.filterEditor.getEditForm().setValue(this.getCheckboxField().name, newValue);
-    }
-  },
-  
-  // selectionChanged is called when the user makes changes
-  selectionChanged: function(record, state){
-    this.stopHover();
-    
-    // stop editing if the selection is changing  
-    var rowNum = this.getRecordIndex(record);
-    
-    if (this.getEditRow()) {
-      if (this.getEditRow() !== rowNum) {
-        this.endEditing();
-      } else {
-        // don't do any updates
-        this.updateSelectedCountDisplay();
-        return;
-      }
-    }
-    
-    isc.Log.logDebug('Selection changed ' + state, 'OB');
-    this.updateSelectedCountDisplay();
-    this.view.recordSelected();
-  },
-  
-  // selectionUpdated is called when the grid selection is changed
-  // programmatically
-  selectionUpdated: function(record, recordList){
-    isc.Log.logDebug('Selection updated ' + record, 'OB');
-    this.updateSelectedCountDisplay();
-    this.view.recordSelected();
-  },
-  
-  selectOnMouseDown: function(record, recordNum, fieldNum){
-  
-    // don't change selection on right mouse down
-    var EH = isc.EventHandler, eventType;
-    if (EH.rightButtonDown()) {
-      return;
-    }
-    
-    var previousSingleRecordSelection = this.singleRecordSelection;
-    var currentSelectedRecordSelected = (this.getSelectedRecord() === record);
-    if (this.getCheckboxFieldPosition() === fieldNum) {
-      if (this.singleRecordSelection) {
-        this.deselectAllRecords();
-      }
-      this.singleRecordSelection = false;
-      this.Super('selectOnMouseDown', arguments);
-      
-      // handle a special case:
-      // - singlerecordmode: checkbox is not checked
-      // - user clicks on checkbox
-      // in this case move to multi select mode and keep the record selected 
-      if (previousSingleRecordSelection && currentSelectedRecordSelected) {
-        this.selectSingleRecord(record);
-      }
-      
-      this.markForRedraw('Selection checkboxes need to be redrawn');
-    } else {
-      // do some checking, the handleRecordSelection should only be called
-      // in case of keyboard navigation and not for real mouse clicks,
-      // these are handled by the recordClick and recordDoubleClick methods
-      // if this method here would also handle mouseclicks then the doubleClick
-      // event is not captured anymore
-      eventType = EH.getEventType();
-      if (!EH.isMouseEvent(eventType)) {
-        this.handleRecordSelection(null, record, recordNum, null, fieldNum, null, null, true);
-      }
-    }
-  },
-  
-  handleRecordSelection: function(viewer, record, recordNum, field, fieldNum, value, rawValue, fromSelectOnMouseDown){
-    var EH = isc.EventHandler;
-    var keyName = EH.getKey();
-    
-    // don't change selection on right mouse down
-    if (EH.rightButtonDown()) {
-      return;
-    }
-    
-    // stop editing if the user clicks out of the row  
-    if (this.getEditRow() && this.getEditRow() !== recordNum) {
-      this.endEditing();
-    }
-    // do nothing, click in the editrow itself
-    if (this.getEditRow() && this.getEditRow() === recordNum) {
-      return;
-    }
-    
-    // if the arrow key was pressed and no ctrl/shift pressed then 
-    // go to single select mode
-    var arrowKeyPressed = keyName && (keyName === isc.OBViewGrid.ARROW_UP_KEY_NAME || keyName === isc.OBViewGrid.ARROW_DOWN_KEY_NAME);
-    
-    var previousSingleRecordSelection = this.singleRecordSelection;
-    if (arrowKeyPressed) {
-      if (EH.ctrlKeyDown() || EH.shiftKeyDown()) {
-        // move to multi-select mode, let the standard do it for us
-        this.singleRecordSelection = false;
-      } else {
-        this.doSelectSingleRecord(record);
-      }
-    } else if (this.getCheckboxFieldPosition() === fieldNum) {
-      if (this.singleRecordSelection) {
-        this.deselectAllRecords();
-      }
-      // click in checkbox field is done by standard logic
-      this.singleRecordSelection = false;
-    } else if (isc.EventHandler.ctrlKeyDown()) {
-      // only do something if record clicked and not from selectOnMouseDown
-      // this method got called twice from one clicK: through recordClick and
-      // to selectOnMouseDown. Only handle one.
-      if (!fromSelectOnMouseDown) {
-        this.singleRecordSelection = false;
-        // let ctrl-click also deselect records
-        if (this.isSelected(record)) {
-          this.deselectRecord(record);
-        } else {
-          this.selectRecord(record);
-        }
-      }
-    } else if (isc.EventHandler.shiftKeyDown()) {
-      this.singleRecordSelection = false;
-      this.selection.selectOnMouseDown(this, recordNum, fieldNum);
-    } else {
-      // click on the record which was already selected
-      this.doSelectSingleRecord(record);
-    }
-    
-    // mark some redraws if there are lines which don't 
-    // have a checkbox flagged, so if we move from single record selection 
-    // to multi record selection
-    if (!this.singleRecordSelection && previousSingleRecordSelection) {
-      this.markForRedraw('Selection checkboxes need to be redrawn');
-    }
-  },
-  
-  selectRecordForEdit: function(record){
-    this.Super('selectRecordForEdit', arguments);
-    this.doSelectSingleRecord(record);
-  },
-  
-  doSelectSingleRecord: function(record){
-    // if this record is already selected and the only one then do nothing
-    // note that when navigating with the arrow key that at a certain 2 are selected
-    // when going into this method therefore the extra check on length === 1
-    if (this.singleRecordSelection && this.isSelected(record) && this.getSelection().length === 1) {
-      return;
-    }
-    this.singleRecordSelection = true;
-    this.selectSingleRecord(record);
-    
-    // deselect the checkbox in the top
-    var fieldNum = this.getCheckboxFieldPosition(), field = this.fields[fieldNum];
-    var icon = this.checkboxFieldFalseImage || this.booleanFalseImage;
-    var title = this.getValueIconHTML(icon, field);
-    
-    this.setFieldTitle(fieldNum, title);
-  },
-  
-  // overridden to prevent the checkbox to be shown when only one 
-  // record is selected.
-  getCellValue: function(record, recordNum, fieldNum, gridBody){
-    var field = this.fields[fieldNum];
-    if (!field || this.allSelected) {
-      return this.Super('getCellValue', arguments);
-    }
-    // do all the cases which are handled in the super directly
-    if (this.isCheckboxField(field)) {
-      // NOTE: code copied from super class
-      var icon;
-      if (!this.body.canSelectRecord(record)) {
-        // record cannot be selected but we want the space allocated for the checkbox anyway.
-        icon = '[SKINIMG]/blank.gif';
-      } else if (this.singleRecordSelection && !this.allSelected) {
-        // always show the false image
-        icon = (this.checkboxFieldFalseImage || this.booleanFalseImage);
-      } else {
-        // checked if selected, otherwise unchecked
-        var isSel = this.selection.isSelected(record) ? true : false;
-        icon = isSel ? (this.checkboxFieldTrueImage || this.booleanTrueImage) : (this.checkboxFieldFalseImage || this.booleanFalseImage);
-      }
-      // if the record is disabled, make the checkbox image disabled as well
-      if (record[this.recordEnabledProperty] === false) {
-        icon = icon.replace('.', '_Disabled.');
-      }
-      
-      var html = this.getValueIconHTML(icon, field);
-      
-      return html;
-    } else {
-      return this.Super('getCellValue', arguments);
-    }
-  },
-  
-  getSelectedRecords: function(){
-    return this.getSelection();
-  },
-  
-  //+++++++++++++++++ functions for the edit-open column handling +++++++++++++++++
-  
-  editComplete: function(rowNum, colNum, newValues, oldValues, editCompletionEvent, dsResponse){
-    // during save the record looses the link to the editColumnLayout, restore it
-    var record = this.getRecord(rowNum);
-    if (oldValues.editColumnLayout && !record.editColumnLayout) {
-      record.editColumnLayout = oldValues.editColumnLayout;
-    }
-    if (record.editColumnLayout) {
-      record.editColumnLayout.showEditOpen();
-    }
-    return this.Super('editComplete', arguments);
-  },
-  
-  discardEdits: function(rowNum, colNum, dontHideEditor, editCompletionEvent){
-    var localArguments = arguments;
-    var me = this;
-    if (this.getEditForm().valuesHaveChanged()) {
-      isc.ask(OB.I18N.getLabel('OBUIAPP_ConfirmCancelEdit'), function(value){
-        if (value) {
-          me.Super('discardEdits', localArguments);
-        }
-      });
-    } else {
-      me.Super('discardEdits', localArguments);
-    }
-  },
-  
-  showInlineEditor: function(rowNum, colNum, newCell, newRow, suppressFocus){
-    if (this.baseStyleEdit) {
-      this.baseStyle = this.baseStyleEdit;
-    }
-    var result = this.Super('showInlineEditor', arguments);
-    
-    var record = this.getRecord(rowNum);
-    if (record && record.editColumnLayout) {
-      record.editColumnLayout.showSaveCancel();
-    }
-    
-    return result;
-  },
-  
-  hideInlineEditor: function(){
-    isc.Log.logDebug('hideInlineEditor ' + this.getEditRow(), 'OB');
-    if (this.baseStyleView) {
-      this.baseStyle = this.baseStyleView;
-    }
-    var rowNum = this.getEditRow();
-    var record = this.getRecord(rowNum);
-    var editColumnLayout = record.editColumnLayout;
-    if (record && record.editColumnLayout) {
-      isc.Log.logDebug('hideInlineEditor has record and editColumnLayout', 'OB');
-      record.editColumnLayout.showEditOpen();
-    } else if (this.currentEditColumnLayout) {
-      this.currentEditColumnLayout.showEditOpen();
-    } else {
-      isc.Log.logDebug('hideInlineEditor has NO record and editColumnLayout', 'OB');
-    }
-    return this.Super('hideInlineEditor', arguments);
-  }
-  
-});
-
-// = OBGridToolStrip =
-// The component which is inside of OBGridButtonsComponent
-isc.ClassFactory.defineClass('OBGridToolStrip', isc.ToolStrip);
-
-isc.OBGridToolStrip.addProperties({});
-
-// = OBGridToolStripIcon =
-// The icons which are inside of OBGridToolStrip
-isc.ClassFactory.defineClass('OBGridToolStripIcon', isc.ImgButton);
-
-isc.OBGridToolStripIcon.addProperties({
-  buttonType: null /* This could be: edit - form - cancel - save */
-});
-
-// = OBGridToolStripSeparator =
-// The separator between icons of OBGridToolStrip
-isc.ClassFactory.defineClass('OBGridToolStripSeparator', isc.Img);
-
-isc.OBGridToolStripSeparator.addProperties({});
-
-// = OBGridButtonsComponent =
-// The component which is used to create the contents of the 
-// edit open column in the grid
-isc.ClassFactory.defineClass('OBGridButtonsComponent', isc.HLayout);
-
-isc.OBGridButtonsComponent.addProperties({
-  OBGridToolStrip: null,
-  saveCancelLayout: null,
-  
-  // the grid to which this component belongs
-  grid: null,
-  
-  rowNum: null,
-  
-  // the record to which this component belongs
-  record: null,
-  
-  initWidget: function(){
-    var me = this;
-    editIcon = isc.OBGridToolStripIcon.create({
-      buttonType: 'edit',
-      action: function(){
-        me.doEdit();
-      }
-    });
-    
-    formIcon = isc.OBGridToolStripIcon.create({
-      buttonType: 'form',
-      action: function(){
-        me.doOpen();
-      }
-    });
-    
-    cancelIcon = isc.OBGridToolStripIcon.create({
-      buttonType: 'cancel',
-      action: function(){
-        me.doCancel();
-      }
-    });
-    
-    saveIcon = isc.OBGridToolStripIcon.create({
-      buttonType: 'save',
-      action: function(){
-        me.doSave();
-      }
-    });
-    
-    buttonSeparator1 = isc.OBGridToolStripSeparator.create({});
-    
-    buttonSeparator2 = isc.OBGridToolStripSeparator.create({});
-    
-    this.OBGridToolStrip = isc.OBGridToolStrip.create({
-      members: [formIcon, buttonSeparator1, editIcon, cancelIcon, buttonSeparator2, saveIcon]
-    });
-    
-    this.addMember(this.OBGridToolStrip);
-    this.OBGridToolStrip.hideMember(5);
-    this.OBGridToolStrip.hideMember(4);
-    this.OBGridToolStrip.hideMember(3);
-  },
-  
-  showEditOpen: function(){
-    this.OBGridToolStrip.hideMember(5);
-    this.OBGridToolStrip.hideMember(4);
-    this.OBGridToolStrip.hideMember(3);
-    this.OBGridToolStrip.showMember(2);
-    this.OBGridToolStrip.showMember(1);
-    this.OBGridToolStrip.showMember(0);
-    this.grid.currentEditColumnLayout = null;
-  },
-  
-  showSaveCancel: function(){
-    this.OBGridToolStrip.hideMember(2);
-    this.OBGridToolStrip.hideMember(1);
-    this.OBGridToolStrip.hideMember(0);
-    this.OBGridToolStrip.showMember(3);
-    this.OBGridToolStrip.showMember(4);
-    this.OBGridToolStrip.showMember(5);
-    this.grid.currentEditColumnLayout = this;
-  },
-  
-  doEdit: function(){
-    this.showSaveCancel();
-    this.grid.selectSingleRecord(this.record);
-    this.grid.startEditing(this.rowNum);
-  },
-  
-  doOpen: function(){
-    this.grid.view.editRecord(this.record);
-  },
-  
-  doSave: function(){
-    // note change back to editOpen is done in the editComplete event of the grid
-    // itself
-    this.grid.saveEdits();
-  },
-  
-  doCancel: function(){
-    this.grid.cancelEditing();
-  }
-  
-});
+/*
+ *************************************************************************
+ * 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) 2010 Openbravo SLU
+ * All Rights Reserved.
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+isc.ClassFactory.defineClass('OBViewGrid', isc.OBGrid);
+
+isc.OBViewGrid.addClassProperties({
+  EDIT_LINK_FIELD_NAME: '_editLink',
+  NO_COUNT_PARAMETER: '_noCount', // prevent the count operation on the server
+  // note following 2 values should be the same
+  // ListGrid._$ArrowUp and ListGrid._$ArrowDown
+  ARROW_UP_KEY_NAME: 'Arrow_Up',
+  ARROW_DOWN_KEY_NAME: 'Arrow_Down'
+});
+
+/*
+ * Todos: - edit button klik selects one record, deselects others, opens edit
+ * view and refreshes child windows. - a grid which gets opened always selects
+ * the first record - double click on a record does the same as the edit button -
+ * single click opens bubble: edit in grid, use as filter, open on tab
+ */
+// = OBViewGrid =
+// The OBViewGrid is the Openbravo specific subclass of the Smartclient
+// ListGrid.
+isc.OBViewGrid.addProperties({
+
+  // ** {{{ view }}} **
+  // The view member contains the pointer to the composite canvas which
+  // handles this form
+  // and the grid and other related components.
+  view: null,
+  
+  // ** {{{ foreignKeyFieldNames }}} **
+  // The list of fields which are foreign keys, these require custom
+  // filtering.
+  foreignKeyFieldNames: [],
+  
+  // ** {{{ editGrid }}} **
+  // Controls if an edit link column is created in the grid, set to false to
+  // prevent this.
+  editGrid: true,
+  
+  // ** {{{ editLinkFieldProperties }}} **
+  // The properties of the ListGridField created for the edit links.
+  editLinkFieldProperties: {
+    type: 'text',
+    canSort: false,
+    canFreeze: false,
+    canEdit: false,
+    canGroupBy: false,
+    canHide: false,
+    showTitle: true,
+    title: '&nbsp;',
+    autoFitWidth: true,
+    canDragResize: false,
+    canFilter: true,
+    autoExpand: false,
+    filterEditorType: 'StaticTextItem',
+    filterEditorProperties: {
+      textAlign: 'center'
+    },
+    name: isc.OBViewGrid.EDIT_LINK_FIELD_NAME
+  },
+  
+  // ** {{{ dataPageSize }}} **
+  // The data page size used for loading paged data from the server.
+  dataPageSize: 100,
+    
+  autoFitFieldWidths: true,
+  autoFitWidthApproach: 'title',
+  canAutoFitFields: false,
+  width: '100%',
+
+  autoFetchTextMatchStyle: 'substring',
+  showFilterEditor: true,
+  canEdit: true,
+  alternateRecordStyles: true,
+  canReorderFields: true,
+  canFreezeFields: true,
+  canAddFormulaFields: true,
+  canAddSummaryFields: true,
+  canGroupBy: false,
+  selectionAppearance: 'checkbox',
+  useAllDataSourceFields: false,
+  editEvent: 'none',
+  showCellContextMenus: true,
+  canOpenRecordEditor: true,
+  showDetailFields: true,
+  
+  // internal sc grid property, see the ListGrid source code
+  preserveEditsOnSetData: false,
+  
+  waitForSave: true,
+  stopOnErrors: true,
+  confirmDiscardEdits: true,
+  
+  canMultiSort: false,
+  
+  emptyMessage: OB.I18N.getLabel('OBUIAPP_NoDataInGrid'),
+  discardEditsSaveButtonTitle: OB.I18N.getLabel('UINAVBA_Save'),
+  
+  // keeps track if we are in objectSelectionMode or in toggleSelectionMode
+  // objectSelectionMode = singleRecordSelection === true  
+  singleRecordSelection: false,
+  
+  dataProperties: {
+    useClientFiltering: false,
+    useClientSorting: false,
+    
+    transformData: function(newData, dsResponse){
+      // correct the length if there is already data in the localData array
+      if (this.localData) {
+        for (var i = dsResponse.endRow + 1; i < this.localData.length; i++) {
+          if (!Array.isLoading(this.localData[i]) && this.localData[i]) {
+            dsResponse.totalRows = i + 1;
+          } else {
+            break;
+          }
+        }
+      }
+      if (this.localData && this.localData[dsResponse.totalRows]) {
+        this.localData[dsResponse.totalRows] = null;
+      }
+      return this.Super('transformData', arguments);
+    }
+  },
+  
+  currentEditColumnLayout: null,
+  
+  refreshFields: function(){
+    this.setFields(this.completeFields.duplicate());
+  },
+  
+  createRecordComponent: function(record, colNum){
+    var layout = this.Super('createRecordComponent',arguments), rowNum;
+    if (layout) {
+      return layout;
+    }
+    if (this.isEditLinkColumn(colNum)) {
+      rowNum = this.getRecordIndex(record);
+      layout = isc.OBGridButtonsComponent.create({
+        record: record,
+        grid: this,
+        rowNum: rowNum
+      });
+      record.editColumnLayout = layout;
+    }
+    return layout;
+  },
+  
+  isEditLinkColumn: function(colNum){
+    var fieldName = this.getFieldName(colNum);
+    return (fieldName === isc.OBViewGrid.EDIT_LINK_FIELD_NAME);
+  },
+  
+  updateRecordComponent: function(record, colNum, component, recordChanged){
+    var superComponent = this.Super('updateRecordComponent', arguments);
+    if (superComponent) {
+      return superComponent;
+    }
+    if (this.isEditLinkColumn(colNum)) {
+      // clear the previous record pointer
+      if (recordChanged && component.record.editColumnLayout === component) {
+        component.record.editColumnLayout = null;
+      }
+      component.record = record;
+      record.editColumnLayout = component;
+      component.rowNum = this.getRecordIndex(record);
+      return component;
+    }
+    return null;
+  },
+  
+  initWidget: function(){
+    var thisGrid = this, localEditLinkField;
+    if (this.editGrid) {
+      // add the edit pencil in the beginning
+      localEditLinkField = isc.addProperties({}, this.editLinkFieldProperties);
+      localEditLinkField.width = this.editLinkColumnWidth;
+      this.fields.unshift(localEditLinkField);
+    }
+    
+    // added for showing counts in the filtereditor row
+    this.checkboxFieldDefaults = isc.addProperties(this.checkboxFieldDefaults, {
+      canFilter: true,
+      filterEditorProperties: {
+        textAlign: 'center'
+      },
+      filterEditorType: 'StaticTextItem'
+    });
+    
+    this.filterEditorProperties = {
+      isCheckboxField: function(){
+        return false;
+      },
+      actionButtonProperties: {
+        visibility: 'hidden'
+      }
+    };
+    
+    this.Super('initWidget', arguments);
+  },
+  
+  headerClick: function(fieldNum, header){
+    var field = this.fields[fieldNum];
+    if (this.isCheckboxField(field) && this.singleRecordSelection) {
+      this.deselectAllRecords();
+      this.singleRecordSelection = false;
+    }
+    return this.Super('headerClick', arguments);
+  },
+  
+  deselectAllRecords: function(){
+    this.allSelected = false;
+    return this.Super('deselectAllRecords', arguments);
+  },
+  
+  selectAllRecords: function(){
+    this.allSelected = true;
+    return this.Super('selectAllRecords', arguments);
+  },
+  
+  updateRowCountDisplay: function(){
+    var newValue = '';
+    if (this.data.getLength() > this.dataPageSize) {
+      newValue = '>' + this.dataPageSize;
+    } else if (this.data.getLength() === 0) {
+      newValue = '&nbsp;';
+    } else {
+      newValue = '' + this.data.getLength();
+    }
+    if (this.filterEditor) {
+      this.filterEditor.getEditForm().setValue(isc.OBViewGrid.EDIT_LINK_FIELD_NAME, newValue);
+    }
+  },
+  
+  refreshContents: function(callback){
+    var context = {
+      showPrompt: false,
+      textMatchStyle: this.autoFetchTextMatchStyle
+    };
+    this.filterData(this.getCriteria(), callback, context);
+  },
+  
+  dataArrived: function(startRow, endRow){
+    var record, ret = this.Super('dataArrived', arguments);
+    this.updateRowCountDisplay();
+    this.updateSelectedCountDisplay();
+    
+    if (this.targetRecordId) {
+      this.delayedHandleTargetRecord(startRow, endRow);
+    } else if (this.view.shouldOpenDefaultEditMode()) {
+      this.view.openDefaultEditView(this.getRecord(startRow));   
+    }
+    
+    return ret;
+  },
+  
+  // handle the target record when the body has been drawn
+  delayedHandleTargetRecord: function(startRow, endRow){
+    var rowTop, recordIndex, i, data = this.data;
+    if (!this.targetRecordId) {
+      return;
+    }
+    if (this.body) {
+      var gridRecord = data.find('id', this.targetRecordId);
+      
+      // no grid record found, stop here
+      if (!gridRecord) {
+        return;
+      }
+      recordIndex = this.getRecordIndex(gridRecord);
+      
+      this.targetRecordId = null;
+      if (data.criteria) {
+        data.criteria._targetRecordId = null;
+      }
+      
+      for (i = 0; i < startRow; i++) {
+        if (Array.isLoading(data.localData[i])) {
+          data.localData[i] = null;
+        }
+      }
+      
+      this.scrollRecordIntoView(recordIndex, false);
+      if (this.view.defaultEditMode) {
+        this.view.editRecord(gridRecord);   
+      } else {
+        this.doSelectSingleRecord(gridRecord);
+      }
+      
+      isc.Page.waitFor(this, 'delayedHandleTargetRecord', {
+        method: this.view.openDirectChildTab(),
+        args: [],
+        target: this.view
+      });
+    } else {
+      // wait a bit longer
+      this.delayCall('delayedHandleTargetRecord', [startRow, endRow], 500, this);
+    }
+  },
+  
+  filterData: function(criteria, callback, requestProperties){
+    if (!requestProperties) {
+      requestProperties = {};
+    }
+    requestProperties.showPrompt = false;
+    
+    var theView = this.view;
+    var newCallBack = function(){
+      theView.recordSelected();
+      if (callback) {
+        callback();
+      }
+    };
+    
+    return this.Super('filterData', [this.convertCriteria(criteria), newCallBack, requestProperties]);
+  },
+  
+  fetchData: function(criteria, callback, requestProperties){
+    if (!requestProperties) {
+      requestProperties = {};
+    }
+    requestProperties.showPrompt = false;
+    
+    var theView = this.view;    
+    
+    var newCallBack = function(){
+      theView.recordSelected();
+      if (callback) {
+        callback();
+      }
+    };
+    
+    return this.Super('fetchData', [this.convertCriteria(criteria), newCallBack, requestProperties]);
+  },
+  
+  getInitialCriteria: function() {
+    var criteria = this.Super('getInitialCriteria', arguments);
+    
+    return this.convertCriteria(criteria);
+  },
+  
+  getCriteria: function() {
+    var criteria = this.Super('getCriteria', arguments);
+    if (!criteria) {
+      criteria = {};
+    }
+    criteria = this.convertCriteria(criteria);
+    return criteria;
+  },
+  
+  // determine which field can be autoexpanded to use extra space  
+  getAutoFitExpandField: function(){
+    for (var i = 0; i < this.fields.length; i++) {
+      var field = this.fields[i];
+      if (field.autoExpand) {
+        return field;
+      }
+    }
+    return this.Super('getAutoFitExpandField', arguments);
+  },
+  
+  recordClick: function(viewer, record, recordNum, field, fieldNum, value, rawValue){
+    var me = this, EH = isc.EventHandler;
+    if (EH.isMouseEvent(EH.getEventType())) {
+      record._dblClickWaiting = true;
+      isc.Timer.setTimeout(function(){
+        // if no double click happened then do the single click
+        if (record._dblClickWaiting) {
+          record._dblClickWaiting = false;
+          me.handleRecordSelection(viewer, record, recordNum, field, fieldNum, value, rawValue, false);
+        }
+      }, OB.Constants.DBL_CLICK_DELAY);
+    } else {
+      me.handleRecordSelection(viewer, record, recordNum, field, fieldNum, value, rawValue, false);
+    }
+  },
+  
+  recordDoubleClick: function(viewer, record, recordNum, field, fieldNum, value, rawValue){
+    record._dblClickWaiting = false;
+    this.view.editRecord(record);
+  },
+  
+  convertCriteria: function(criteria){
+    if (!criteria) {
+      criteria = {};
+    }
+    
+    if (criteria.conversionDone) {
+      return criteria;
+    }
+    
+    criteria.conversionDone = true;
+    
+    criteria = OB.Utilities._getTabInfoRequestProperties(this.view, criteria);    
+
+    var isFiltering = criteria.length > 0;
+    var filterValues = [];
+    var index = 0, selectedValues;
+    var fkFieldsLength = this.foreignKeyFieldNames.getLength(), filterValue = null;
+    
+    if (this.targetRecordId) {
+      criteria._targetRecordId = this.targetRecordId;
+    }
+    
+    if (this.view.parentProperty) {
+      if (!this.view.parentView) {
+        criteria[this.view.parentProperty] = '-1';
+      } else {
+        selectedValues = this.view.parentView.viewGrid.getSelectedRecords();
+      }
+      if (selectedValues.length === 0) {
+        criteria[this.view.parentProperty] = '-1';
+        this.emptyMessage = OB.I18N.getLabel('OBUIAPP_NoParentSelected');
+      } else if (selectedValues.length > 1) {
+        criteria[this.view.parentProperty] = '-1';
+        this.emptyMessage = OB.I18N.getLabel('OBUIAPP_MultipleParentsSelected');
+      } else {
+        this.emptyMessage = OB.I18N.getLabel('OBUIAPP_NoDataInGrid');
+        criteria[this.view.parentProperty] = selectedValues[0][OB.Constants.ID];
+      }
+    }
+    
+    // now repair the filtering on foreign keys to use the identifier
+    //    for (index = 0; index < fkFieldsLength; index++) {
+    //      if (criteria[this.foreignKeyFieldNames[index]]) {
+    //        filterValue = criteria[this.foreignKeyFieldNames[index]];
+    //        delete criteria[this.foreignKeyFieldNames[index]];
+    //        criteria[this.foreignKeyFieldNames[index] + '.' +
+    //        OB.Constants.IDENTIFIER] = filterValue;
+    //      }
+    //    }
+    
+    // prevent the count operation
+    criteria[isc.OBViewGrid.NO_COUNT_PARAMETER] = 'true';
+    
+    if (this.orderByClause) {
+      criteria[OB.Constants.ORDERBY_PARAMETER] = this.orderByClause;
+    }
+    
+    if (this.whereClause) {
+      criteria[OB.Constants.WHERE_PARAMETER] = this.whereClause;
+    }
+    
+    return criteria;
+  },
+  
+  //+++++++++++++++++++++++++++++ Context menu on record click +++++++++++++++++++++++
+  
+  makeCellContextItems: function(record, rowNum, colNum){
+    var sourceWindow = this.view.standardWindow.windowId;
+    var menuItems = [];
+    var field = this.getField(colNum);
+    var grid = this;
+    if (this.canEdit) {
+      menuItems.add({
+        title: OB.I18N.getLabel('OBUIAPP_EditInGrid'),
+        click: function(){
+          grid.endEditing();
+          grid.startEditing(rowNum, colNum);
+        }
+      });
+    }
+    if (field.canFilter) {
+      menuItems.add({
+        title: OB.I18N.getLabel('OBUIAPP_UseAsFilter'),
+        click: function(){
+          var value;
+          var filterCriteria = grid.getCriteria();
+          // a foreign key field, use the displayfield/identifier
+          if (field.foreignKeyField && field.displayField) {
+            value = record[field.displayField];
+            filterCriteria[field.displayField] = value;
+          } else {
+            value = grid.getEditDisplayValue(rowNum, colNum, record);
+            filterCriteria[field.name] = value;
+          }
+          grid.setCriteria(filterCriteria);
+          grid.filterData(grid.getCriteria());
+        }
+      });
+    }
+    if (field.foreignKeyField) {
+      menuItems.add({
+        title: OB.I18N.getLabel('OBUIAPP_OpenOnTab'),
+        click: function(){
+          var fldName = field.name;
+          var dotIndex = fldName.indexOf('.');
+          if (dotIndex !== -1) {
+            fldName = fldName.substring(0, dotIndex);
+          }
+          OB.Utilities.openDirectView(sourceWindow, field.referencedKeyColumnName, field.targetEntity, record[fldName]);
+        }
+      });
+    }
+    
+    return menuItems;
+  },
+  
+  //+++++++++++++++++++++++++++++ Record Selection Handling +++++++++++++++++++++++
+  
+  updateSelectedCountDisplay: function(){
+    var selection = this.getSelection();
+    var selectionLength = selection.getLength();
+    var newValue = '&nbsp;';
+    if (!this.singleRecordSelection && selectionLength > 0) {
+      newValue = selectionLength + '';
+    }
+    if (this.filterEditor) {
+      this.filterEditor.getEditForm().setValue(this.getCheckboxField().name, newValue);
+    }
+  },
+  
+  // selectionChanged is called when the user makes changes
+  selectionChanged: function(record, state){
+    this.stopHover();
+    
+    // stop editing if the selection is changing  
+    var rowNum = this.getRecordIndex(record);
+    
+    if (this.getEditRow()) {
+      if (this.getEditRow() !== rowNum) {
+        this.endEditing();
+      } else {
+        // don't do any updates
+        this.updateSelectedCountDisplay();
+        return;
+      }
+    }
+    
+    isc.Log.logDebug('Selection changed ' + state, 'OB');
+    this.updateSelectedCountDisplay();
+    this.view.recordSelected();
+  },
+  
+  // selectionUpdated is called when the grid selection is changed
+  // programmatically
+  selectionUpdated: function(record, recordList){
+    isc.Log.logDebug('Selection updated ' + record, 'OB');
+    this.updateSelectedCountDisplay();
+    this.view.recordSelected();
+  },
+  
+  selectOnMouseDown: function(record, recordNum, fieldNum){
+  
+    // don't change selection on right mouse down
+    var EH = isc.EventHandler, eventType;
+    if (EH.rightButtonDown()) {
+      return;
+    }
+    
+    var previousSingleRecordSelection = this.singleRecordSelection;
+    var currentSelectedRecordSelected = (this.getSelectedRecord() === record);
+    if (this.getCheckboxFieldPosition() === fieldNum) {
+      if (this.singleRecordSelection) {
+        this.deselectAllRecords();
+      }
+      this.singleRecordSelection = false;
+      this.Super('selectOnMouseDown', arguments);
+      
+      // handle a special case:
+      // - singlerecordmode: checkbox is not checked
+      // - user clicks on checkbox
+      // in this case move to multi select mode and keep the record selected 
+      if (previousSingleRecordSelection && currentSelectedRecordSelected) {
+        this.selectSingleRecord(record);
+      }
+      
+      this.markForRedraw('Selection checkboxes need to be redrawn');
+    } else {
+      // do some checking, the handleRecordSelection should only be called
+      // in case of keyboard navigation and not for real mouse clicks,
+      // these are handled by the recordClick and recordDoubleClick methods
+      // if this method here would also handle mouseclicks then the doubleClick
+      // event is not captured anymore
+      eventType = EH.getEventType();
+      if (!EH.isMouseEvent(eventType)) {
+        this.handleRecordSelection(null, record, recordNum, null, fieldNum, null, null, true);
+      }
+    }
+  },
+  
+  handleRecordSelection: function(viewer, record, recordNum, field, fieldNum, value, rawValue, fromSelectOnMouseDown){
+    var EH = isc.EventHandler;
+    var keyName = EH.getKey();
+    
+    // don't change selection on right mouse down
+    if (EH.rightButtonDown()) {
+      return;
+    }
+    
+    // stop editing if the user clicks out of the row  
+    if (this.getEditRow() && this.getEditRow() !== recordNum) {
+      this.endEditing();
+    }
+    // do nothing, click in the editrow itself
+    if (this.getEditRow() && this.getEditRow() === recordNum) {
+      return;
+    }
+    
+    // if the arrow key was pressed and no ctrl/shift pressed then 
+    // go to single select mode
+    var arrowKeyPressed = keyName && (keyName === isc.OBViewGrid.ARROW_UP_KEY_NAME || keyName === isc.OBViewGrid.ARROW_DOWN_KEY_NAME);
+    
+    var previousSingleRecordSelection = this.singleRecordSelection;
+    if (arrowKeyPressed) {
+      if (EH.ctrlKeyDown() || EH.shiftKeyDown()) {
+        // move to multi-select mode, let the standard do it for us
+        this.singleRecordSelection = false;
+      } else {
+        this.doSelectSingleRecord(record);
+      }
+    } else if (this.getCheckboxFieldPosition() === fieldNum) {
+      if (this.singleRecordSelection) {
+        this.deselectAllRecords();
+      }
+      // click in checkbox field is done by standard logic
+      this.singleRecordSelection = false;
+    } else if (isc.EventHandler.ctrlKeyDown()) {
+      // only do something if record clicked and not from selectOnMouseDown
+      // this method got called twice from one clicK: through recordClick and
+      // to selectOnMouseDown. Only handle one.
+      if (!fromSelectOnMouseDown) {
+        this.singleRecordSelection = false;
+        // let ctrl-click also deselect records
+        if (this.isSelected(record)) {
+          this.deselectRecord(record);
+        } else {
+          this.selectRecord(record);
+        }
+      }
+    } else if (isc.EventHandler.shiftKeyDown()) {
+      this.singleRecordSelection = false;
+      this.selection.selectOnMouseDown(this, recordNum, fieldNum);
+    } else {
+      // click on the record which was already selected
+      this.doSelectSingleRecord(record);
+    }
+    
+    // mark some redraws if there are lines which don't 
+    // have a checkbox flagged, so if we move from single record selection 
+    // to multi record selection
+    if (!this.singleRecordSelection && previousSingleRecordSelection) {
+      this.markForRedraw('Selection checkboxes need to be redrawn');
+    }
+  },
+  
+  selectRecordForEdit: function(record){
+    this.Super('selectRecordForEdit', arguments);
+    this.doSelectSingleRecord(record);
+  },
+  
+  doSelectSingleRecord: function(record){
+    // if this record is already selected and the only one then do nothing
+    // note that when navigating with the arrow key that at a certain 2 are selected
+    // when going into this method therefore the extra check on length === 1
+    if (this.singleRecordSelection && this.isSelected(record) && this.getSelection().length === 1) {
+      return;
+    }
+    this.singleRecordSelection = true;
+    this.selectSingleRecord(record);
+    
+    // deselect the checkbox in the top
+    var fieldNum = this.getCheckboxFieldPosition(), field = this.fields[fieldNum];
+    var icon = this.checkboxFieldFalseImage || this.booleanFalseImage;
+    var title = this.getValueIconHTML(icon, field);
+    
+    this.setFieldTitle(fieldNum, title);
+  },
+  
+  // overridden to prevent the checkbox to be shown when only one 
+  // record is selected.
+  getCellValue: function(record, recordNum, fieldNum, gridBody){
+    var field = this.fields[fieldNum];
+    if (!field || this.allSelected) {
+      return this.Super('getCellValue', arguments);
+    }
+    // do all the cases which are handled in the super directly
+    if (this.isCheckboxField(field)) {
+      // NOTE: code copied from super class
+      var icon;
+      if (!this.body.canSelectRecord(record)) {
+        // record cannot be selected but we want the space allocated for the checkbox anyway.
+        icon = '[SKINIMG]/blank.gif';
+      } else if (this.singleRecordSelection && !this.allSelected) {
+        // always show the false image
+        icon = (this.checkboxFieldFalseImage || this.booleanFalseImage);
+      } else {
+        // checked if selected, otherwise unchecked
+        var isSel = this.selection.isSelected(record) ? true : false;
+        icon = isSel ? (this.checkboxFieldTrueImage || this.booleanTrueImage) : (this.checkboxFieldFalseImage || this.booleanFalseImage);
+      }
+      // if the record is disabled, make the checkbox image disabled as well
+      if (record[this.recordEnabledProperty] === false) {
+        icon = icon.replace('.', '_Disabled.');
+      }
+      
+      var html = this.getValueIconHTML(icon, field);
+      
+      return html;
+    } else {
+      return this.Super('getCellValue', arguments);
+    }
+  },
+  
+  getSelectedRecords: function(){
+    return this.getSelection();
+  },
+  
+  //+++++++++++++++++ functions for the edit-open column handling +++++++++++++++++
+  
+  editComplete: function(rowNum, colNum, newValues, oldValues, editCompletionEvent, dsResponse){
+    // during save the record looses the link to the editColumnLayout, restore it
+    var record = this.getRecord(rowNum);
+    if (oldValues.editColumnLayout && !record.editColumnLayout) {
+      record.editColumnLayout = oldValues.editColumnLayout;
+    }
+    if (record.editColumnLayout) {
+      record.editColumnLayout.showEditOpen();
+    }
+    return this.Super('editComplete', arguments);
+  },
+  
+  discardEdits: function(rowNum, colNum, dontHideEditor, editCompletionEvent){
+    var localArguments = arguments;
+    var me = this;
+    if (this.getEditForm().valuesHaveChanged()) {
+      isc.ask(OB.I18N.getLabel('OBUIAPP_ConfirmCancelEdit'), function(value){
+        if (value) {
+          me.Super('discardEdits', localArguments);
+        }
+      });
+    } else {
+      me.Super('discardEdits', localArguments);
+    }
+  },
+  
+  showInlineEditor: function(rowNum, colNum, newCell, newRow, suppressFocus){
+    if (this.baseStyleEdit) {
+      this.baseStyle = this.baseStyleEdit;
+    }
+    var result = this.Super('showInlineEditor', arguments);
+    
+    var record = this.getRecord(rowNum);
+    if (record && record.editColumnLayout) {
+      record.editColumnLayout.showSaveCancel();
+    }
+    
+    return result;
+  },
+  
+  hideInlineEditor: function(){
+    isc.Log.logDebug('hideInlineEditor ' + this.getEditRow(), 'OB');
+    if (this.baseStyleView) {
+      this.baseStyle = this.baseStyleView;
+    }
+    var rowNum = this.getEditRow();
+    var record = this.getRecord(rowNum);
+    var editColumnLayout = record.editColumnLayout;
+    if (record && record.editColumnLayout) {
+      isc.Log.logDebug('hideInlineEditor has record and editColumnLayout', 'OB');
+      record.editColumnLayout.showEditOpen();
+    } else if (this.currentEditColumnLayout) {
+      this.currentEditColumnLayout.showEditOpen();
+    } else {
+      isc.Log.logDebug('hideInlineEditor has NO record and editColumnLayout', 'OB');
+    }
+    return this.Super('hideInlineEditor', arguments);
+  }
+  
+});
+
+// = OBGridToolStrip =
+// The component which is inside of OBGridButtonsComponent
+isc.ClassFactory.defineClass('OBGridToolStrip', isc.ToolStrip);
+
+isc.OBGridToolStrip.addProperties({});
+
+// = OBGridToolStripIcon =
+// The icons which are inside of OBGridToolStrip
+isc.ClassFactory.defineClass('OBGridToolStripIcon', isc.ImgButton);
+
+isc.OBGridToolStripIcon.addProperties({
+  buttonType: null /* This could be: edit - form - cancel - save */
+});
+
+// = OBGridToolStripSeparator =
+// The separator between icons of OBGridToolStrip
+isc.ClassFactory.defineClass('OBGridToolStripSeparator', isc.Img);
+
+isc.OBGridToolStripSeparator.addProperties({});
+
+// = OBGridButtonsComponent =
+// The component which is used to create the contents of the 
+// edit open column in the grid
+isc.ClassFactory.defineClass('OBGridButtonsComponent', isc.HLayout);
+
+isc.OBGridButtonsComponent.addProperties({
+  OBGridToolStrip: null,
+  saveCancelLayout: null,
+  
+  // the grid to which this component belongs
+  grid: null,
+  
+  rowNum: null,
+  
+  // the record to which this component belongs
+  record: null,
+  
+  initWidget: function(){
+    var me = this;
+    editIcon = isc.OBGridToolStripIcon.create({
+      buttonType: 'edit',
+      action: function(){
+        me.doEdit();
+      }
+    });
+    
+    formIcon = isc.OBGridToolStripIcon.create({
+      buttonType: 'form',
+      action: function(){
+        me.doOpen();
+      }
+    });
+    
+    cancelIcon = isc.OBGridToolStripIcon.create({
+      buttonType: 'cancel',
+      action: function(){
+        me.doCancel();
+      }
+    });
+    
+    saveIcon = isc.OBGridToolStripIcon.create({
+      buttonType: 'save',
+      action: function(){
+        me.doSave();
+      }
+    });
+    
+    buttonSeparator1 = isc.OBGridToolStripSeparator.create({});
+    
+    buttonSeparator2 = isc.OBGridToolStripSeparator.create({});
+    
+    this.OBGridToolStrip = isc.OBGridToolStrip.create({
+      members: [formIcon, buttonSeparator1, editIcon, cancelIcon, buttonSeparator2, saveIcon]
+    });
+    
+    this.addMember(this.OBGridToolStrip);
+    this.OBGridToolStrip.hideMember(5);
+    this.OBGridToolStrip.hideMember(4);
+    this.OBGridToolStrip.hideMember(3);
+  },
+  
+  showEditOpen: function(){
+    this.OBGridToolStrip.hideMember(5);
+    this.OBGridToolStrip.hideMember(4);
+    this.OBGridToolStrip.hideMember(3);
+    this.OBGridToolStrip.showMember(2);
+    this.OBGridToolStrip.showMember(1);
+    this.OBGridToolStrip.showMember(0);
+    this.grid.currentEditColumnLayout = null;
+  },
+  
+  showSaveCancel: function(){
+    this.OBGridToolStrip.hideMember(2);
+    this.OBGridToolStrip.hideMember(1);
+    this.OBGridToolStrip.hideMember(0);
+    this.OBGridToolStrip.showMember(3);
+    this.OBGridToolStrip.showMember(4);
+    this.OBGridToolStrip.showMember(5);
+    this.grid.currentEditColumnLayout = this;
+  },
+  
+  doEdit: function(){
+    this.showSaveCancel();
+    this.grid.selectSingleRecord(this.record);
+    this.grid.startEditing(this.rowNum);
+  },
+  
+  doOpen: function(){
+    this.grid.view.editRecord(this.record);
+  },
+  
+  doSave: function(){
+    // note change back to editOpen is done in the editComplete event of the grid
+    // itself
+    this.grid.saveEdits();
+  },
+  
+  doCancel: function(){
+    this.grid.cancelEditing();
+  }
+  
+});
--- a/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-application-styles.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-application-styles.js	Mon Jan 03 21:44:36 2011 +0100
@@ -250,11 +250,11 @@
   baseStyle: 'OBNavBarButton',
   height: 14,
   width: 14,
-  src: "[SKINIMG]../../org.openbravo.client.application/images/navbar/iconClose.png",
+  src: '[SKINIMG]../../org.openbravo.client.application/images/navbar/iconClose.png',
   showTitle: false,
-  imageType: "normal",
-  layoutAlign: "center",
-  overflow: "visible",
+  imageType: 'normal',
+  layoutAlign: 'center',
+  overflow: 'visible',
   showRollOver: false,
   showFocused: false,
   showDown: false
--- a/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-form-styles.css	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-form-styles.css	Mon Jan 03 21:44:36 2011 +0100
@@ -269,4 +269,8 @@
   font-family: 'lucida sans', sans-serif;
   font-size: 12px;
   font-weight: bold;
-}
\ No newline at end of file
+}
+
+.OBFormFieldLinkButton {
+  cursor: pointer;
+}
--- a/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-form-styles.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-form-styles.js	Mon Jan 03 21:44:36 2011 +0100
@@ -19,27 +19,40 @@
 
 
 isc.OBViewForm.addProperties({
-  styleName: "OBViewForm",
+  styleName: 'OBViewForm',
   //cellBorder: 1, // debug layout
   cellPadding: 8
 });
 
 
 isc.OBSectionItem.addProperties({
-  sectionHeaderClass: "OBSectionItemButton",
+  sectionHeaderClass: 'OBSectionItemButton',
   height: 24
 });
 
 isc.ClassFactory.defineClass('OBSectionItemButton', ImgSectionHeader);
-isc.OBSectionItemButton.changeDefaults("backgroundDefaults", {
+isc.OBSectionItemButton.changeDefaults('backgroundDefaults', {
   showRollOver: true,
   showDown: false,
   showDisabledIcon: false,
   showRollOverIcon: false,
-  src: "[SKIN]/../../org.openbravo.client.application/images/form/sectionItem-bg.png",
-  icon: "[SKIN]/../../org.openbravo.client.application/images/form/sectionItem-ico.png",
+  src: '[SKIN]/../../org.openbravo.client.application/images/form/sectionItem-bg.png',
+  icon: '[SKIN]/../../org.openbravo.client.application/images/form/sectionItem-ico.png',
   iconSize: 12,
   capSize: 12,
-  titleStyle: "OBSectionItemButton_Title_",
-  backgroundColor: "transparent"
-})
\ No newline at end of file
+  titleStyle: 'OBSectionItemButton_Title_',
+  backgroundColor: 'transparent'
+});
+
+isc.OBSearchItem.addProperties({
+  pickerIconHeight: 21,
+  pickerIconWidth: 21,
+  pickerIconSrc: '[SKINIMG]../../org.openbravo.client.application/images/form/search_picker.png',
+  newTabIconSrc: '[SKINIMG]../../org.openbravo.client.application/images/form/ico-to-new-tab.png',
+  newTabIconSize: 8
+});
+
+isc.OBFKItem.addProperties({
+  newTabIconSrc: '[SKINIMG]../../org.openbravo.client.application/images/form/ico-to-new-tab.png',
+  newTabIconSize: 8
+});
--- a/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-grid-styles.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-grid-styles.js	Mon Jan 03 21:44:36 2011 +0100
@@ -35,14 +35,14 @@
   hoverWidth: 200,
   editLinkColumnWidth: 58,
 
-  summaryRowConstructor: "OBGridSummary",
+  summaryRowConstructor: 'OBGridSummary',
   summaryRowDefaults:{
     showRollOver:false
   },
   summaryRowHeight: 22,
-  summaryRowStyle: "OBGridSummaryCell",
-  summaryRowStyle_sum: "OBGridSummaryCell_sum",
-  summaryRowStyle_avg: "OBGridSummaryCell_avg"
+  summaryRowStyle: 'OBGridSummaryCell',
+  summaryRowStyle_sum: 'OBGridSummaryCell_sum',
+  summaryRowStyle_avg: 'OBGridSummaryCell_avg'
 });
 
 isc.OBGrid.changeDefaults('filterEditorDefaults', {
--- a/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-tab-styles.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-tab-styles.js	Mon Jan 03 21:44:36 2011 +0100
@@ -29,5 +29,5 @@
   tabBarThickness: 38,
   styleName: 'OBTabSetChild',
   simpleTabBaseStyle: 'OBTabBarChildButton',
-  paneContainerClassName: "OBTabSetChildContainer"
+  paneContainerClassName: 'OBTabSetChildContainer'
 });
--- a/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-toolbar-styles.js	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.application/web/org.openbravo.userinterface.smartclient/openbravo/skins/3.00/org.openbravo.client.application/ob-toolbar-styles.js	Mon Jan 03 21:44:36 2011 +0100
@@ -19,7 +19,7 @@
 
 
 isc.OBToolbar.addProperties({
-  width: "100%",
+  width: '100%',
   height: 45,
   leftMargin: 30,
   rightMargin: 4,
@@ -31,7 +31,7 @@
 isc.OBToolbarIconButton.addProperties({
   width: 30,
   height: 28,
-  menuButtonImage: "[SKIN]/../../org.openbravo.client.application/images/toolbar/iconButton-menu-unfold.png"  /** There is a CSS hack to avoid showing it when no menu available. this.menuButtonImage inside initWidget doesn't run **/
+  menuButtonImage: '[SKIN]/../../org.openbravo.client.application/images/toolbar/iconButton-menu-unfold.png'  /** There is a CSS hack to avoid showing it when no menu available. this.menuButtonImage inside initWidget doesn't run **/
 });
 
 
--- a/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/reference/FKSearchUIDefinition.java	Mon Jan 03 17:31:58 2011 +0100
+++ b/modules/org.openbravo.client.kernel/src/org/openbravo/client/kernel/reference/FKSearchUIDefinition.java	Mon Jan 03 21:44:36 2011 +0100
@@ -18,6 +18,15 @@
  */
 package org.openbravo.client.kernel.reference;
 
+import org.openbravo.base.model.Property;
+import org.openbravo.client.kernel.KernelUtils;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.data.Sqlc;
+import org.openbravo.model.ad.domain.ModelImplementation;
+import org.openbravo.model.ad.domain.ModelImplementationMapping;
+import org.openbravo.model.ad.domain.Reference;
+import org.openbravo.model.ad.domain.Selector;
+import org.openbravo.model.ad.domain.SelectorColumn;
 import org.openbravo.model.ad.ui.Field;
 
 /**
@@ -32,8 +41,82 @@
     return "OBSearchItem";
   }
 
+  @Override
   public String getFieldProperties(Field field) {
-    return getGridFieldProperties(field);
+    if (field == null) {
+      return "";
+    }
+    final StringBuilder props = new StringBuilder();
+    final Property prop = KernelUtils.getInstance().getPropertyFromColumn(field.getColumn());
+    final Reference reference = OBDal.getInstance().get(Reference.class,
+        prop.getDomainType().getReference().getId());
+    ModelImplementation modelImplementation = null;
+    for (ModelImplementation localModelImplementation : reference.getADModelImplementationList()) {
+      if (localModelImplementation.isActive()) {
+        modelImplementation = localModelImplementation;
+        break;
+      }
+    }
+    if (modelImplementation == null) {
+      // TODO: warn
+      return props.toString();
+    }
+    ModelImplementationMapping modelImplementationMapping = null;
+    for (ModelImplementationMapping localModelImplementationMapping : modelImplementation
+        .getADModelImplementationMappingList()) {
+      if (localModelImplementationMapping.isActive()) {
+        if (modelImplementationMapping == null) {
+          modelImplementationMapping = localModelImplementationMapping;
+        } else if (localModelImplementationMapping.isDefault()) {
+          modelImplementationMapping = localModelImplementationMapping;
+          break;
+        }
+      }
+    }
+    if (modelImplementationMapping == null) {
+      // TODO: warn
+      return getJsonObjectString(props.toString());
+    }
+    props.append("searchUrl: '" + modelImplementationMapping.getMappingName() + "'");
+
+    Selector selector = null;
+    for (Selector localSelector : reference.getADSelectorList()) {
+      if (localSelector.isActive()) {
+        selector = localSelector;
+        break;
+      }
+    }
+    if (selector == null) {
+      // TODO: warn
+      return getJsonObjectString(props.toString());
+    }
+    final StringBuilder inFields = new StringBuilder();
+    final StringBuilder outFields = new StringBuilder();
+    for (SelectorColumn selectorColumn : selector.getADSelectorColumnList()) {
+      if (selectorColumn.isActive()) {
+        String columnName = selectorColumn.getDBColumnName()
+            + (selectorColumn.getSuffix() != null ? selectorColumn.getSuffix() : "");
+        columnName = "inp" + Sqlc.TransformaNombreColumna(columnName);
+        if (selectorColumn.getColumnType().equals("I")) {
+          if (inFields.length() > 0) {
+            inFields.append(",");
+          }
+          inFields.append("'" + columnName + "'");
+        } else {
+          if (outFields.length() > 0) {
+            outFields.append(",");
+          }
+          outFields.append("'" + columnName + "'");
+        }
+      }
+    }
+    props.append(", inFields: [" + inFields.toString() + "]");
+    props.append(", outFields: [" + outFields.toString() + "]");
+
+    return getJsonObjectString(props.toString());
   }
 
+  private String getJsonObjectString(String value) {
+    return "{" + value.trim() + "}";
+  }
 }