Inheriting class properties has consequences: the inability to edit inherited properties. And this is correct: editing should only be done where this property was declared. But in the Data Keeper designer, some class property parameters may differ between classes, for example, the visibility and order of the property in the table view of the list of objects. Or the presence of detail. Therefore, a class property must have independent parameters for each class.

This can be achieved by adding another vproperty table and transferring to it parameters such as ordering, visibility and others that we will need soon to improve the editing form generation algorithm.

Changing the data structure required not only rewriting the script code and SQL queries, but also resolving the issue with the form for editing class properties. Typically, MVDB uses a separate editing form for each table. But in our case it would not be convenient for the user. Therefore, I decided to “paste” one editing form into another using the Form_ShowOnWinControl() procedure from the VClass\Forms.pas module.

On the main efmCProperty editing form (1), add a panVProperty panel (2), the size of which should be such that it can accommodate the additional efmVProperty editing form. More precisely, that part of the form on which the grbView element is located, containing components for editing the vproperty table.

On the efmVProperty form, in addition to the group with components for editing property parameters (1), there are invisible fields (2) that connect the form with a property (edtIDCProperty) and a class (edtIDClass). The btnSave button (3) is hidden behind the grbView group – if you make it invisible, then it cannot be “clicked” using the script. Its Action property (4) is configured to save data (5) to the vproperty table (6). Be sure to clear the “Close current form after saving” checkbox to ensure that the efmVProperty form remains visible within the efmCProperty form.

We perform the binding in the UserApp_InitForm procedure:

...
Form_ShowOnWinControl( efmVProperty, efmCProperty.panVProperty ); // second half of the editing form
...Code language: Delphi (delphi)

The onShow handler for the efmCProperty form needs some modification. In order for the data on the additional form to be loaded from the database, you need to find the ID of the record, which is calculated using the query. Or initialize the form to add a new entry. To do this I added a helper procedure NewRecord.

There is also a blocking for editing the main data in case we have opened a form for editing an inherited class property.

procedure efmCProperty_OnShow (Sender: TObject; Action: string);
// displaying the form for editing class properties
var
   tmpID: integer;
   tmpSQL: string;

   procedure NewRecord;
   // new entry
   begin
     efmVProperty.NewRecord('vproperty');
     efmVProperty.edtIDClass.Text := frmCProperty.edtIDClass.Text;
     efmVProperty.edtCaption.Text := efmCProperty.edtName.Text;
     // add parameter number
     efmVProperty.edtGridOrderNum.Value := frmCProperty.tgrMain.RowCount + 1;
     efmVProperty.edtFieldOrderNum.Value := frmCProperty.tgrMain.RowCount + 1;
   end;

begin
   if Action = 'NewRecord' then
   begin // new entry
     // basic properties
     efmCProperty.edtClassID.Value := frmCProperty.edtIDClass.Value;
     if frmCProperty.tgrMain.RowCount = 0 then // not a very obvious case - the first property is the name to display...
       efmCProperty.chbIsName.Checked := True;
     efmCProperty.cmbPType.dbItemID := 1;
     // auxiliary
     NewRecord;
   end
   else
   begin // existing record - load additional. data
     tmpSQL := 'SELECT id FROM vproperty WHERE id_class = '+frmCProperty.edtIDClass.Text+' AND id_cproperty = '+IntToStr(efmCProperty.btnSave.dbGeneralTableId);
     tmpID := SQLExecute( tmpSQL ) ;
     if tmpID = 0 then
       NewRecord
     else
       efmVProperty.ShowRecord('vproperty',tmpID);
   end;
   // you can edit structure elements only when editing the class where they are declared
   if frmCProperty.edtIDClass.Text = efmCProperty.edtClassID.Text then
   begin
     efmCProperty.grbStructure.Caption := 'Structure';
     efmCProperty.grbStructure.Enabled := True;
     efmCProperty.edtName.SetFocus;
   end
   else
   begin
     efmCProperty.grbStructure.Caption := 'Structure (view)';
     efmCProperty.grbStructure.Enabled := False;
     efmVProperty.edtCaption.SetFocus;
   end;
end;Code language: Delphi (delphi)

The second improvement concerns the button for saving data in the main editing form. It is necessary to add an onAfterClick event handler in which to cause data to be saved on an additional form.

procedure efmCProperty_btnSave_OnAfterClick(Sender: TObject);
begin
   efmVProperty.edtIDCProperty.Value := efmCProperty.btnSave.dbGeneralTableId; // connect
   efmVProperty.btnSave.Click; // save
   efmCProperty.Close; // the previous command confuses MVDB, so we need to close the form
end;Code language: JavaScript (javascript)

Results

This solution may seem complicated to some: instead of combining forms, it was possible to add or edit data in the vproperty table using SQL queries and scripts, but I tried to minimize the code that would have to be changed in case of any modifications, and to the maximum use the capabilities of MVDB itself.

Added blocking of structure editing if a class property is inherited (1). Display parameters (2) are bound to the class. Added separate controls for the order, visibility and width for the table view (3) and for components on the editing form (4).

Leave a Reply

Your email address will not be published. Required fields are marked *