Implementation

From ADempiere
Revision as of 07:50, 5 September 2011 by Mcarminati (Talk) (Adempiere Included "Form")

Jump to: navigation, search
This Wiki is read-only for reference purposes to avoid broken links.

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)