Home > JavaScript, Object Pascal, OP4JS, Smart Mobile Studio > Object models, a Smart Pascal example

Object models, a Smart Pascal example

Most information developers work with is hierarchal and organized in a classical parent and child manner. Parent-child relationships is so universal that they are everywhere, from how visual controls are organized to how elements in a document is stored. No matter if it’s a visual treeview in Delphi, an html element in a document or entries in a pdf-file; it’s pretty much all organized in a series of inter-linked, parent-child relationships.

Since parent-child trees is so universal, developers usually end up with a unit that contains a couple of simple base-classes. Typically these classes are used to create a model of things. The tree can contain the actual data itself – or more commonly, it’s used to represent a model that is later processed or realized visually.

synchro

Most frameworks are essentially parent-child hierarchies

Here is an example of such a unit. It compiles under Smart Pascal and should work fine for most versions. It has virtually no dependencies.

Populate the data property with whatever data you want to represent, then you can enumerate and work with the model. What you use it for is eventually up to you. I use it a lot when dealing with menus; it makes it easier to define menus and sub-menus and then simply feed the model to a construction routine.

unit DataNodes;

interface

uses
  System.Types;

type

  // for older SMS versions that lack "system.types", un-remark this:
  // TEnumResult = (erContinue = $A0, erBreak = $10);

  TCustomDataNode = class;
  TCustomDataNodeList = array of TCustomDataNode;

  TDataNodeEnumEnterProc = function (const Root: TCustomDataNode): TEnumResult;
  TDataNodeEnumExitProc = function (const Root: TCustomDataNode): TEnumResult;
  TDataNodeEnumProc = function  (const Child: TCustomDataNode): TEnumResult;
  TDataNodeCompareProc = function (const Value: variant): boolean;

  TCustomDataNode = class
  protected
    property  Parent: TCustomDataNode;
    property  Caption: string;
  public
    property  Data: variant;
    property  Children: TCustomDataNodeList;

    procedure Clear;

    function  Search(const Compare: TDataNodeCompareProc): TCustomDataNode;

    procedure ForEach(const Before: TDataNodeEnumEnterProc;
              const Process: TDataNodeEnumProc;
              const After: TDataNodeEnumExitProc); overload;

    procedure ForEach(const Process: TDataNodeEnumProc); overload;

    function  Serialize: string;
    class function  Parse(const JSonData: string): TCustomDataNode;

    constructor Create(const NodeOwner: TCustomDataNode;
                NodeText: string; const NodeData: variant); overload;

    constructor Create(const NodeOwner: TCustomDataNode;
                const NodeData: variant); overload;
  end;

  TDataNode = class(TCustomDataNode)
  public
    property  Parent;
    property  Caption;
  end;

  TDataNodeTree = class(TCustomDataNode)
  public
    property  Caption;
  end;

implementation

//#############################################################################
// TCustomDataNode
//#############################################################################

constructor TCustomDataNode.Create(const NodeOwner: TCustomDataNode;
            NodeText: string; const NodeData: variant);
begin
  Parent := NodeOwner;
  Caption := NodeText;
  Data := NodeData;
end;

constructor TCustomDataNode.Create(const NodeOwner: TCustomDataNode;
         const NodeData: variant);
begin
  Parent := NodeOwner;
  Data := NodeData;
end;

function TCustomDataNode.Serialize: string;
begin
  asm
    @result = JSON.stringify(@self);
  end;
end;

class function TCustomDataNode.Parse(const JSonData: string): TCustomDataNode;
begin
  asm
    @result = JSON.parse(@JSONData);
  end;
end;

procedure TCustomDataNode.Clear;
begin
  try
    for var x := 0 to Children.length-1 do
    begin
      if Children[x] <> nil then
        Children[x].free;
    end;
  finally
    Children.Clear();
  end;
end;

function TCustomDataNode.Search(const Compare: TDataNodeCompareProc): TCustomDataNode;
var
  LResult: TCustomDataNode;
begin
  ForEach( function (const Child: TCustomDataNode): TEnumResult
    begin
      if Compare(Child.Data) then
      begin
        LResult := Child;
        result := TEnumResult.erBreak;
      end;
    end);
  result := LResult;
end;

procedure TCustomDataNode.ForEach(const Before: TDataNodeEnumEnterProc;
          const Process: TDataNodeEnumProc;
          const After: TDataNodeEnumExitProc);
begin
  if assigned(Before) then
  Before(self);
  try
    if assigned(Process) then
    begin
      for var LChild in Children do
      begin
        if Process(LChild) = erBreak then
        break;
      end;
    end;
  finally
    if assigned(After) then
    After(self);
  end;
end;

procedure TCustomDataNode.ForEach(const Process: TDataNodeEnumProc);
begin
  if assigned(Process) then
  begin
    for var LChild in Children do
    begin
      if Process(LChild) = erBreak then
      break;
    end;
  end;
end;

end.
Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: