Difference between revisions of "Implementation"

From ADempiere
Jump to: navigation, search
This Wiki is read-only for reference purposes to avoid broken links.
(Adempiere Included "Form")
 
(6 intermediate revisions by the same user not shown)
Line 11: Line 11:
 
For example we can include Form by which show graph or picture or specific form which could interact with the current selected record.
 
For example we can include Form by which show graph or picture or specific form which could interact with the current selected record.
  
'''AD Tab Configuration'''
 
  
[[File:Esempio.jpg]]
+
'''AD Tab Configuration'''<br>
 +
Into the Tab window I added the new Field in which we can indicate the reference to the AD_Form
  
----
+
[[File:ADTabConf.jpg]]
  
Java user interface<br>
 
List of modified class:<br>
 
Vpanel.java org.compiere.grid.VPanel
 
  
 +
'''SQL Scripts'''<br>
 +
Here is the sql scripts for the Postgres database
  
Web user interface<br>
+
SET search_path TO adempiere;
List of modified class:<br>
+
AdTabPanel.java org.adempiere.webui.panel
+
  
Web and java user interface<br>
+
ALTER TABLE ad_field ADD COLUMN included_form_id numeric(10);
List of modified classes:<br>
+
GridField.java
+
GridTabVo.java org.compiere.GridTabVo
+
  
 +
ALTER TABLE ad_field ALTER COLUMN included_form_id SET STORAGE MAIN;
  
SQL Scripts<br>
+
ALTER TABLE ad_column ADD COLUMN included_form_id numeric(10);
  
 +
ALTER TABLE ad_column ALTER COLUMN included_form_id SET STORAGE MAIN;
  
 +
ALTER TABLE ad_column ALTER COLUMN included_form_id SET DEFAULT NULL::numeric;
 +
 +
INSERT INTO ad_element(
 +
  ad_element_id, ad_client_id, ad_org_id, isactive, created, createdby,
 +
  updated, updatedby, columnname, entitytype, "name", printname,
 +
  description, help, po_name, po_printname, po_description, po_help)
 +
  VALUES (1000003,0,0,'Y','2010-11-05 17:52:09',0,'2010-11-05
 +
  17:52:09',0,'Included_Form_ID','U','Included_Form_ID','Included_Form_ID','','','','','','');
 +
 +
INSERT INTO ad_column(
 +
  ad_column_id, ad_client_id, ad_org_id, isactive, created, updated,
 +
  createdby, updatedby, name, description, help, version, entitytype,
 +
  columnname, ad_table_id, ad_reference_id, ad_reference_value_id,
 +
  ad_val_rule_id, fieldlength, defaultvalue, iskey, isparent, ismandatory,
 +
  isupdateable, readonlylogic, isidentifier, seqno, istranslated,
 +
  isencrypted, callout, vformat, valuemin, valuemax, isselectioncolumn,
 +
  ad_element_id, ad_process_id, issyncdatabase, isalwaysupdateable,
 +
  columnsql, mandatorylogic, infofactoryclass, isautocomplete,
 +
  isallowlogging, formatpattern, included_form_id)
 +
VALUES (1000010,0,0,'Y','2010-11-05 18:24:53','2010-11-05
 +
          18:24:53',0,0,'Included_Form_ID','','',0,'U','Included_Form_ID',107,18,284,NULL,10,'','N','N','N','Y','','N',NULL,
 +
          'N','N','','','','','N',1000003,NULL,'N','N','','','','N','Y','',NULL);
 +
 +
INSERT INTO ad_field(
 +
    ad_field_id, ad_client_id, ad_org_id, isactive, created, createdby,
 +
    updated, updatedby, name, description, help, iscentrallymaintained,
 +
    ad_tab_id, ad_column_id, ad_fieldgroup_id, isdisplayed, displaylogic,
 +
    displaylength, isreadonly, seqno, sortno, issameline, isheading,
 +
    isfieldonly, isencrypted, entitytype, obscuretype, ad_reference_id,
 +
    ismandatory, included_tab_id, defaultvalue, ad_reference_value_id,
 +
    ad_val_rule_id, infofactoryclass, included_form_id)
 +
VALUES (1000008,0,0,'Y','2010-11-05 18:27:35',0,'2010-11-05 18:27:35',0,'Included_Form_ID','','','Y',107,1000010,NULL,'Y','',10,'N',NULL,NULL,
 +
        'N','N','N','N','U','',NULL,'',NULL,'',NULL,NULL,'',NULL);
 +
 +
CREATE OR REPLACE VIEW ad_field_v AS
 +
  SELECT t.ad_window_id, f.ad_tab_id, f.ad_field_id, tbl.ad_table_id, f.ad_column_id, f.name, f.description,
 +
    f.help, f.isdisplayed, f.displaylogic, f.displaylength, f.seqno, f.sortno, f.issameline, f.isheading, f.isfieldonly,
 +
    f.isreadonly, f.isencrypted AS isencryptedfield, f.obscuretype, c.columnname, c.columnsql, c.fieldlength,
 +
    c.vformat, COALESCE(f.defaultvalue, c.defaultvalue) AS defaultvalue, c.iskey, c.isparent,
 +
    COALESCE(f.ismandatory, c.ismandatory) AS ismandatory, c.isidentifier, c.istranslated,
 +
    COALESCE(f.ad_reference_value_id, c.ad_reference_value_id) AS ad_reference_value_id, c.callout,
 +
    COALESCE(f.ad_reference_id, c.ad_reference_id) AS ad_reference_id, COALESCE(f.ad_val_rule_id,
 +
    c.ad_val_rule_id) AS ad_val_rule_id, c.ad_process_id, c.isalwaysupdateable, c.readonlylogic,
 +
    c.mandatorylogic, c.isupdateable, c.isencrypted AS isencryptedcolumn, c.isselectioncolumn, tbl.tablename,
 +
    c.valuemin, c.valuemax, fg.name AS fieldgroup, vr.code AS validationcode, f.included_tab_id,
 +
    fg.fieldgrouptype, fg.iscollapsedbydefault, COALESCE(f.infofactoryclass, c.infofactoryclass) AS
 +
    infofactoryclass, c.isautocomplete, f.included_form_id
 +
  FROM ad_field f
 +
    JOIN ad_tab t ON f.ad_tab_id = t.ad_tab_id
 +
    LEFT JOIN ad_fieldgroup fg ON f.ad_fieldgroup_id = fg.ad_fieldgroup_id
 +
    LEFT JOIN ad_column c ON f.ad_column_id = c.ad_column_id
 +
    JOIN ad_table tbl ON c.ad_table_id = tbl.ad_table_id
 +
    JOIN ad_reference r ON c.ad_reference_id = r.ad_reference_id
 +
    LEFT JOIN ad_val_rule vr ON vr.ad_val_rule_id = COALESCE(f.ad_val_rule_id, c.ad_val_rule_id)
 +
  WHERE f.isactive = 'Y'::bpchar AND c.isactive = 'Y'::bpchar;
 +
 +
CREATE OR REPLACE VIEW ad_field_vt AS
 +
  SELECT trl.ad_language, t.ad_window_id, f.ad_tab_id, f.ad_field_id, tbl.ad_table_id, f.ad_column_id,
 +
    trl.name, trl.description, trl.help, f.isdisplayed, f.displaylogic, f.displaylength, f.seqno, f.sortno, f.issameline,
 +
    f.isheading, f.isfieldonly, f.isreadonly, f.isencrypted AS isencryptedfield, f.obscuretype, c.columnname,
 +
    c.columnsql, c.fieldlength, c.vformat, COALESCE(f.defaultvalue, c.defaultvalue) AS defaultvalue, c.iskey,
 +
    c.isparent, COALESCE(f.ismandatory, c.ismandatory) AS ismandatory, c.isidentifier, c.istranslated,
 +
    COALESCE(f.ad_reference_value_id, c.ad_reference_value_id) AS ad_reference_value_id, c.callout,
 +
    COALESCE(f.ad_reference_id, c.ad_reference_id) AS ad_reference_id, COALESCE(f.ad_val_rule_id,
 +
    c.ad_val_rule_id) AS ad_val_rule_id, c.ad_process_id, c.isalwaysupdateable, c.readonlylogic,
 +
    c.mandatorylogic, c.isupdateable, c.isencrypted AS isencryptedcolumn, c.isselectioncolumn, tbl.tablename,
 +
    c.valuemin, c.valuemax, fgt.name AS fieldgroup, vr.code AS validationcode, f.included_tab_id,
 +
    fg.fieldgrouptype, fg.iscollapsedbydefault, COALESCE(f.infofactoryclass, c.infofactoryclass) AS
 +
    infofactoryclass, c.isautocomplete, f.included_form_id
 +
  FROM ad_field f
 +
    JOIN ad_field_trl trl ON f.ad_field_id = trl.ad_field_id
 +
    JOIN ad_tab t ON f.ad_tab_id = t.ad_tab_id
 +
    LEFT JOIN ad_fieldgroup fg ON f.ad_fieldgroup_id = fg.ad_fieldgroup_id
 +
    LEFT JOIN ad_fieldgroup_trl fgt ON f.ad_fieldgroup_id = fgt.ad_fieldgroup_id AND trl.ad_language::text =
 +
              fgt.ad_language::text
 +
    LEFT JOIN ad_column c ON f.ad_column_id = c.ad_column_id
 +
    JOIN ad_table tbl ON c.ad_table_id = tbl.ad_table_id
 +
    JOIN ad_reference r ON c.ad_reference_id = r.ad_reference_id
 +
    LEFT JOIN ad_val_rule vr ON vr.ad_val_rule_id = COALESCE(f.ad_val_rule_id, c.ad_val_rule_id)
 +
  WHERE f.isactive = 'Y'::bpchar AND c.isactive = 'Y'::bpchar;
 +
 +
 +
'''Program source modifications'''<br>
 +
In this paragraph I explain the modifications at the program source for the Java user interface and Web user
 +
interface and at the based object GridField and GridTabVo.
 +
 +
''List of modified classes of the dictionary objects:''<br>
 +
GridField.java<br>
 +
GridTabVo.java          org.compiere.GridTabVo
 +
 +
''List of modified classes of the Java User Interface:''<br>
 +
Vpanel.java              org.compiere.grid.VPanel<br>
 +
GridController.java      org.compiere.grid.GridController
 +
 +
''List of modified classes of the Web User Interface:''<br>
 +
AdTabPanel.java          org.adempiere.webui.panel
 +
 +
''List of new class:''<br>
 +
IncludedForm.java<br>
 +
IincludedForm.java
 +
 +
 +
'''''GridField.java'''''<br>
 +
New public get method for the field IncludedFormID
 +
        //Matteo::START
 +
        public int getIncluded_Form_ID ()
 +
        {
 +
        return m_vo.Included_Form_ID;
 +
        }
 +
        //Matteo::END
 +
 +
'''''GridTabVo.java'''''<br>
 +
At the end of create method, I insert this new else if statement for the new field IncludedFormID
 +
        //Matteo::START
 +
        else if (columnName.equalsIgnoreCase("Included_Form_ID"))
 +
                vo.Included_Form_ID = rs.getInt(i);
 +
        //Matteo::END
 +
 +
 +
'''''Vpanel.Java'''''<br>
 +
New List in which save the included forms
 +
        //Matteo::start
 +
        private List<IncludedForm> includedForm = new ArrayList<IncludedForm>();
 +
        //Matteo::End
 +
       
 +
        Public method which returns the list of included forms
 +
        //Matteo::START
 +
        /**
 +
        * Used by GridController object to fire the onDataStatusChanged event for each included form
 +
        */
 +
        public List<IncludedForm> getIncludedForms()
 +
        {
 +
                return includedForm;
 +
        }
 +
        //Matteo::END
 +
 +
 +
In the public method addField I add this code which dipslay the form into the tab and add his reference to the list.
 +
        //Matteo::start
 +
        int AD_Form_ID = mField.getIncluded_Form_ID();
 +
        if (AD_Form_ID !=0){
 +
                IncludedForm form = new IncludedForm(m_WindowNo);
 +
                form.openForm(AD_Form_ID);
 +
                if (!mField.isSameLine()){
 +
                        m_main.add(form.getContentPane(),"newLine, spanx, growx");
 +
                }else{
 +
                        m_main.add(form.getContentPane(),"spanx, growx");
 +
                }
 +
                includedForm.add(form);
 +
                return;
 +
        }
 +
        //Matteo::end
 +
 +
'''''GridController.Java'''''<br>
 +
At the end of public method dataStatusChanged, I add this piece of code where I execute the method
 +
ondataStatusChanged for each included form of the current vPanel.
 +
        //Matteo::START
 +
        if (!vPanel.getIncludedForms().isEmpty())
 +
        {
 +
                for(IncludedForm form : vPanel.getIncludedForms() )
 +
                {
 +
                        form.onDataStatusChanged(Env.getCtx(), m_WindowNo, e);
 +
                }
 +
        }
 +
        //Matteo::END
 +
 +
'''''AdTabPanel.java'''''<br>
 +
As in the Vpanel classe, I added a new List in which save the included forms
 +
        //Matteo::START
 +
        private List<ADForm> includedForm = new ArrayList<ADForm>();
 +
        //Matteo::END
 +
In the createUI method, in the loop of fields I added:
 +
                //Matteo::START
 +
                //included Form
 +
                if (field.getIncluded_Form_ID()>0){
 +
                                if (!field.isSameLine()){
 +
                                          rows.appendChild(row);
 +
                                          row = new Row();
 +
                                          row.setSpans("5");
 +
                                }else{
 +
                                          row.setSpans("1,1,2");
 +
                                }
 +
                                ADForm form = ADForm.openForm(field.getIncluded_Form_ID());
 +
                                form.setTitle(null);
 +
                                form.setAttribute("columnName", field.getColumnName());
 +
                                String formStyle = "position: relative;";
 +
                                form.setStyle(formStyle);
 +
                                row.appendChild(form);
 +
                                rows.appendChild(row);
 +
                                includedForm.add(form);
 +
                                continue;
 +
                }
 +
                //Matteo::END
 +
 +
And inside the dataStatusChanged I raise the event to each Form included in the Tab
 +
        //Matteo::START
 +
        if (!includedForm.isEmpty()){
 +
                for (ADForm form : includedForm){
 +
                        IincludedForm myForm = (IincludedForm)form;
 +
                        myForm.onDataStatusChanged(Env.getCtx(),windowNo,e);
 +
                }
 +
        }
 +
        //Matteo::END
 +
 +
'''''IncludedForm.java'''''<br>
 +
package org.matica;
 +
import java.awt.BorderLayout;
 +
import java.util.Properties;
 +
import java.util.logging.Level;
 +
import org.compiere.apps.form.FormFrame;
 +
import org.compiere.apps.form.FormPanel;
 +
import org.compiere.model.DataStatusEvent;
 +
import org.compiere.swing.CPanel;
 +
import org.compiere.util.CLogger;
 +
import org.compiere.util.Env;
 +
public  class IncludedForm extends FormFrame implements IincludedForm {
 +
      private static CLogger log = CLogger.getCLogger(IncludedForm.class);
 +
      /**    WindowNo                                    */
 +
      private int                    m_WindowNo;
 +
      /**    The Panel to be displayed    */
 +
      private FormPanel      m_panel = null;
 +
      /** Form ID                    */
 +
      private int            p_AD_Form_ID = 0;
 +
      private CPanel m_container = null;
 +
      public IncludedForm(int WindowNo)
 +
      {
 +
              m_WindowNo = WindowNo;
 +
      }
 +
      /* (non-Javadoc)
 +
        * @see org.compiere.apps.form.FormFrame#openForm(int)
 +
        */
 +
      @Override
 +
      public boolean openForm(int AD_Form_ID) {
 +
              // TODO Auto-generated method stub
 +
              return super.openForm(AD_Form_ID);
 +
      }
 +
      /* (non-Javadoc)
 +
        * @see org.compiere.apps.form.FormFrame#openForm(int, java.lang.String, java.lang.String)
 +
        */
 +
  @Override
 +
  protected boolean openForm(int AD_Form_ID, String className, String name) {
 +
        // TODO Auto-generated method stub
 +
        log.info("AD_Form_ID=" + AD_Form_ID + " - Class=" + className);
 +
        Properties ctx = Env.getCtx();
 +
        Env.setContext(ctx, m_WindowNo, "WindowName", name);
 +
        setTitle(Env.getHeader(ctx, m_WindowNo));
 +
        try
 +
        {
 +
                //    Create instance w/o parameters
 +
                m_panel = (FormPanel)Class.forName(className).newInstance();
 +
        }
 +
        catch (Exception e)
 +
        {
 +
                log.log(Level.SEVERE, "Class=" + className + ", AD_Form_ID=" + AD_Form_ID,e);
 +
                return false;
 +
        }
 +
        //
 +
        m_container = new CPanel();
 +
        m_container.setLayout(new BorderLayout());
 +
        m_panel.init(m_WindowNo, this);
 +
        p_AD_Form_ID = AD_Form_ID;
 +
        return true;
 +
  }
 +
  public CPanel getContentPane(){
 +
        return m_container;
 +
  }
 +
  @Override
 +
  public void onDataStatusChanged(Properties ctx, int parentWindowNo,      DataStatusEvent e)
 +
  {
 +
        ((IincludedForm)m_panel).onDataStatusChanged(ctx, parentWindowNo, e);
 +
  }
 +
}
 +
 +
 +
'''''IincludedForm.java'''''<br>
 +
package org.matica;
 +
import java.util.Properties;
 +
import org.compiere.model.DataStatusEvent;
 +
public interface IincludedForm {
 +
      public void onDataStatusChanged(Properties ctx, int parentWindowNo,DataStatusEvent e);
 +
}
  
 
--[[User:Mcarminati|Mcarminati]] 14:07, 5 September 2011 (UTC)
 
--[[User:Mcarminati|Mcarminati]] 14:07, 5 September 2011 (UTC)

Latest revision as of 07:57, 5 September 2011

Adempiere Included "Form"

I'd like to submit to the Adempiere community a simple and pratical extention by witch include into a tab of window's Adempiere a Form (AD_Form object)


BOM.jpg

In the previous picture is shown a Window with a single Tab in wich is included the standard Form named BOM Drop. This is only an example, but by this ploy developers could include into a Tab many different objects and extend the Adempiere user interface.

For example we can include Form by which show graph or picture or specific form which could interact with the current selected record.


AD Tab Configuration
Into the Tab window I added the new Field in which we can indicate the reference to the AD_Form

ADTabConf.jpg


SQL Scripts
Here is the sql scripts for the Postgres database

SET search_path TO adempiere;
ALTER TABLE ad_field ADD COLUMN included_form_id numeric(10);
ALTER TABLE ad_field ALTER COLUMN included_form_id SET STORAGE MAIN;
ALTER TABLE ad_column ADD COLUMN included_form_id numeric(10);
ALTER TABLE ad_column ALTER COLUMN included_form_id SET STORAGE MAIN;
ALTER TABLE ad_column ALTER COLUMN included_form_id SET DEFAULT NULL::numeric;
INSERT INTO ad_element(
 ad_element_id, ad_client_id, ad_org_id, isactive, created, createdby,
 updated, updatedby, columnname, entitytype, "name", printname,
 description, help, po_name, po_printname, po_description, po_help)
 VALUES (1000003,0,0,'Y','2010-11-05 17:52:09',0,'2010-11-05
 17:52:09',0,'Included_Form_ID','U','Included_Form_ID','Included_Form_ID',,,,,,);
INSERT INTO ad_column(
  ad_column_id, ad_client_id, ad_org_id, isactive, created, updated,
  createdby, updatedby, name, description, help, version, entitytype,
  columnname, ad_table_id, ad_reference_id, ad_reference_value_id,
  ad_val_rule_id, fieldlength, defaultvalue, iskey, isparent, ismandatory,
  isupdateable, readonlylogic, isidentifier, seqno, istranslated,
  isencrypted, callout, vformat, valuemin, valuemax, isselectioncolumn,
  ad_element_id, ad_process_id, issyncdatabase, isalwaysupdateable,
  columnsql, mandatorylogic, infofactoryclass, isautocomplete,
  isallowlogging, formatpattern, included_form_id)
VALUES (1000010,0,0,'Y','2010-11-05 18:24:53','2010-11-05
          18:24:53',0,0,'Included_Form_ID',,,0,'U','Included_Form_ID',107,18,284,NULL,10,,'N','N','N','Y',,'N',NULL,
          'N','N',,,,,'N',1000003,NULL,'N','N',,,,'N','Y',,NULL);
INSERT INTO ad_field(
    ad_field_id, ad_client_id, ad_org_id, isactive, created, createdby,
    updated, updatedby, name, description, help, iscentrallymaintained,
    ad_tab_id, ad_column_id, ad_fieldgroup_id, isdisplayed, displaylogic,
    displaylength, isreadonly, seqno, sortno, issameline, isheading,
    isfieldonly, isencrypted, entitytype, obscuretype, ad_reference_id,
    ismandatory, included_tab_id, defaultvalue, ad_reference_value_id,
    ad_val_rule_id, infofactoryclass, included_form_id)
VALUES (1000008,0,0,'Y','2010-11-05 18:27:35',0,'2010-11-05 18:27:35',0,'Included_Form_ID',,,'Y',107,1000010,NULL,'Y',,10,'N',NULL,NULL,
        'N','N','N','N','U',,NULL,,NULL,,NULL,NULL,,NULL);
CREATE OR REPLACE VIEW ad_field_v AS
 SELECT t.ad_window_id, f.ad_tab_id, f.ad_field_id, tbl.ad_table_id, f.ad_column_id, f.name, f.description,
   f.help, f.isdisplayed, f.displaylogic, f.displaylength, f.seqno, f.sortno, f.issameline, f.isheading, f.isfieldonly,
   f.isreadonly, f.isencrypted AS isencryptedfield, f.obscuretype, c.columnname, c.columnsql, c.fieldlength,
   c.vformat, COALESCE(f.defaultvalue, c.defaultvalue) AS defaultvalue, c.iskey, c.isparent,
   COALESCE(f.ismandatory, c.ismandatory) AS ismandatory, c.isidentifier, c.istranslated,
   COALESCE(f.ad_reference_value_id, c.ad_reference_value_id) AS ad_reference_value_id, c.callout,
   COALESCE(f.ad_reference_id, c.ad_reference_id) AS ad_reference_id, COALESCE(f.ad_val_rule_id,
   c.ad_val_rule_id) AS ad_val_rule_id, c.ad_process_id, c.isalwaysupdateable, c.readonlylogic,
   c.mandatorylogic, c.isupdateable, c.isencrypted AS isencryptedcolumn, c.isselectioncolumn, tbl.tablename,
   c.valuemin, c.valuemax, fg.name AS fieldgroup, vr.code AS validationcode, f.included_tab_id,
   fg.fieldgrouptype, fg.iscollapsedbydefault, COALESCE(f.infofactoryclass, c.infofactoryclass) AS
   infofactoryclass, c.isautocomplete, f.included_form_id
 FROM ad_field f
   JOIN ad_tab t ON f.ad_tab_id = t.ad_tab_id
   LEFT JOIN ad_fieldgroup fg ON f.ad_fieldgroup_id = fg.ad_fieldgroup_id
   LEFT JOIN ad_column c ON f.ad_column_id = c.ad_column_id
   JOIN ad_table tbl ON c.ad_table_id = tbl.ad_table_id
   JOIN ad_reference r ON c.ad_reference_id = r.ad_reference_id
   LEFT JOIN ad_val_rule vr ON vr.ad_val_rule_id = COALESCE(f.ad_val_rule_id, c.ad_val_rule_id)
 WHERE f.isactive = 'Y'::bpchar AND c.isactive = 'Y'::bpchar;
CREATE OR REPLACE VIEW ad_field_vt AS
 SELECT trl.ad_language, t.ad_window_id, f.ad_tab_id, f.ad_field_id, tbl.ad_table_id, f.ad_column_id,
   trl.name, trl.description, trl.help, f.isdisplayed, f.displaylogic, f.displaylength, f.seqno, f.sortno, f.issameline,
   f.isheading, f.isfieldonly, f.isreadonly, f.isencrypted AS isencryptedfield, f.obscuretype, c.columnname,
   c.columnsql, c.fieldlength, c.vformat, COALESCE(f.defaultvalue, c.defaultvalue) AS defaultvalue, c.iskey,
   c.isparent, COALESCE(f.ismandatory, c.ismandatory) AS ismandatory, c.isidentifier, c.istranslated,
   COALESCE(f.ad_reference_value_id, c.ad_reference_value_id) AS ad_reference_value_id, c.callout,
   COALESCE(f.ad_reference_id, c.ad_reference_id) AS ad_reference_id, COALESCE(f.ad_val_rule_id,
   c.ad_val_rule_id) AS ad_val_rule_id, c.ad_process_id, c.isalwaysupdateable, c.readonlylogic,
   c.mandatorylogic, c.isupdateable, c.isencrypted AS isencryptedcolumn, c.isselectioncolumn, tbl.tablename,
   c.valuemin, c.valuemax, fgt.name AS fieldgroup, vr.code AS validationcode, f.included_tab_id,
   fg.fieldgrouptype, fg.iscollapsedbydefault, COALESCE(f.infofactoryclass, c.infofactoryclass) AS
   infofactoryclass, c.isautocomplete, f.included_form_id
 FROM ad_field f
   JOIN ad_field_trl trl ON f.ad_field_id = trl.ad_field_id
   JOIN ad_tab t ON f.ad_tab_id = t.ad_tab_id
   LEFT JOIN ad_fieldgroup fg ON f.ad_fieldgroup_id = fg.ad_fieldgroup_id
   LEFT JOIN ad_fieldgroup_trl fgt ON f.ad_fieldgroup_id = fgt.ad_fieldgroup_id AND trl.ad_language::text =
             fgt.ad_language::text
   LEFT JOIN ad_column c ON f.ad_column_id = c.ad_column_id
   JOIN ad_table tbl ON c.ad_table_id = tbl.ad_table_id
   JOIN ad_reference r ON c.ad_reference_id = r.ad_reference_id
   LEFT JOIN ad_val_rule vr ON vr.ad_val_rule_id = COALESCE(f.ad_val_rule_id, c.ad_val_rule_id)
 WHERE f.isactive = 'Y'::bpchar AND c.isactive = 'Y'::bpchar;


Program source modifications
In this paragraph I explain the modifications at the program source for the Java user interface and Web user interface and at the based object GridField and GridTabVo.

List of modified classes of the dictionary objects:
GridField.java
GridTabVo.java org.compiere.GridTabVo

List of modified classes of the Java User Interface:
Vpanel.java org.compiere.grid.VPanel
GridController.java org.compiere.grid.GridController

List of modified classes of the Web User Interface:
AdTabPanel.java org.adempiere.webui.panel

List of new class:
IncludedForm.java
IincludedForm.java


GridField.java
New public get method for the field IncludedFormID

       //Matteo::START
       public int getIncluded_Form_ID ()
       {
        return m_vo.Included_Form_ID;
       }
       //Matteo::END

GridTabVo.java
At the end of create method, I insert this new else if statement for the new field IncludedFormID

       //Matteo::START
       else if (columnName.equalsIgnoreCase("Included_Form_ID"))
                vo.Included_Form_ID = rs.getInt(i);
       //Matteo::END


Vpanel.Java
New List in which save the included forms

       //Matteo::start
       private List<IncludedForm> includedForm = new ArrayList<IncludedForm>();
       //Matteo::End
       
       Public method which returns the list of included forms
       //Matteo::START
       /**
        * Used by GridController object to fire the onDataStatusChanged event for each included form
        */
       public List<IncludedForm> getIncludedForms()
       {
               return includedForm;
       }
       //Matteo::END


In the public method addField I add this code which dipslay the form into the tab and add his reference to the list.

       //Matteo::start
       int AD_Form_ID = mField.getIncluded_Form_ID();
       if (AD_Form_ID !=0){
               IncludedForm form = new IncludedForm(m_WindowNo);
               form.openForm(AD_Form_ID);
               if (!mField.isSameLine()){
                       m_main.add(form.getContentPane(),"newLine, spanx, growx");
               }else{
                       m_main.add(form.getContentPane(),"spanx, growx");
               }
               includedForm.add(form);
               return;
       }
       //Matteo::end

GridController.Java
At the end of public method dataStatusChanged, I add this piece of code where I execute the method ondataStatusChanged for each included form of the current vPanel.

       //Matteo::START
       if (!vPanel.getIncludedForms().isEmpty())
       {
               for(IncludedForm form : vPanel.getIncludedForms() )
               {
                       form.onDataStatusChanged(Env.getCtx(), m_WindowNo, e);
               }
       }
       //Matteo::END

AdTabPanel.java
As in the Vpanel classe, I added a new List in which save the included forms

        //Matteo::START
        private List<ADForm> includedForm = new ArrayList<ADForm>();
        //Matteo::END

In the createUI method, in the loop of fields I added:

               //Matteo::START
               //included Form
               if (field.getIncluded_Form_ID()>0){
                                if (!field.isSameLine()){
                                         rows.appendChild(row);
                                         row = new Row();
                                         row.setSpans("5");
                                }else{
                                         row.setSpans("1,1,2");
                                }
                                ADForm form = ADForm.openForm(field.getIncluded_Form_ID());
                                form.setTitle(null);
                                form.setAttribute("columnName", field.getColumnName());
                                String formStyle = "position: relative;";
                                form.setStyle(formStyle);
                                row.appendChild(form);
                                rows.appendChild(row);
                                includedForm.add(form);
                                continue;
               }
               //Matteo::END

And inside the dataStatusChanged I raise the event to each Form included in the Tab

        //Matteo::START
        if (!includedForm.isEmpty()){
               for (ADForm form : includedForm){
                       IincludedForm myForm = (IincludedForm)form;
                       myForm.onDataStatusChanged(Env.getCtx(),windowNo,e);
               }
        }
        //Matteo::END

IncludedForm.java

package org.matica;
import java.awt.BorderLayout;
import java.util.Properties;
import java.util.logging.Level;
import org.compiere.apps.form.FormFrame;
import org.compiere.apps.form.FormPanel;
import org.compiere.model.DataStatusEvent;
import org.compiere.swing.CPanel;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
public  class IncludedForm extends FormFrame implements IincludedForm {
      private static CLogger log = CLogger.getCLogger(IncludedForm.class);
      /**     WindowNo                                    */
      private int                    m_WindowNo;
      /**     The Panel to be displayed     */
      private FormPanel      m_panel = null;
      /** Form ID                    */
      private int            p_AD_Form_ID = 0;
      private CPanel m_container = null;
      public IncludedForm(int WindowNo)
      {
              m_WindowNo = WindowNo;
      }
      /* (non-Javadoc)
       * @see org.compiere.apps.form.FormFrame#openForm(int)
       */
      @Override
      public boolean openForm(int AD_Form_ID) {
              // TODO Auto-generated method stub
              return super.openForm(AD_Form_ID);
      }
      /* (non-Javadoc)
       * @see org.compiere.apps.form.FormFrame#openForm(int, java.lang.String, java.lang.String)
       */
  @Override
  protected boolean openForm(int AD_Form_ID, String className, String name) {
        // TODO Auto-generated method stub
        log.info("AD_Form_ID=" + AD_Form_ID + " - Class=" + className);
        Properties ctx = Env.getCtx();
        Env.setContext(ctx, m_WindowNo, "WindowName", name);
        setTitle(Env.getHeader(ctx, m_WindowNo));
        try
        {
                //     Create instance w/o parameters
                m_panel = (FormPanel)Class.forName(className).newInstance();
        }
        catch (Exception e)
        {
                log.log(Level.SEVERE, "Class=" + className + ", AD_Form_ID=" + AD_Form_ID,e);
                return false;
        }
        //
        m_container = new CPanel();
        m_container.setLayout(new BorderLayout());
        m_panel.init(m_WindowNo, this);
        p_AD_Form_ID = AD_Form_ID;
        return true;
  }
  public CPanel getContentPane(){
        return m_container;
  }
  @Override
  public void onDataStatusChanged(Properties ctx, int parentWindowNo,       DataStatusEvent e)
  {
        ((IincludedForm)m_panel).onDataStatusChanged(ctx, parentWindowNo, e);
  }
}


IincludedForm.java

package org.matica;
import java.util.Properties;
import org.compiere.model.DataStatusEvent;
public interface IincludedForm {
      public void onDataStatusChanged(Properties ctx, int parentWindowNo,DataStatusEvent e);
}

--Mcarminati 14:07, 5 September 2011 (UTC)