{*********************************************************}
{*                  OVCTBCLS.PAS 4.06                    *}
{*********************************************************}

{* ***** BEGIN LICENSE BLOCK *****                                            *}
{* Version: MPL 1.1                                                           *}
{*                                                                            *}
{* The contents of this file are subject to the Mozilla Public License        *}
{* Version 1.1 (the "License"); you may not use this file except in           *}
{* compliance with the License. You may obtain a copy of the License at       *}
{* http://www.mozilla.org/MPL/                                                *}
{*                                                                            *}
{* 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 TurboPower Orpheus                                    *}
{*                                                                            *}
{* The Initial Developer of the Original Code is TurboPower Software          *}
{*                                                                            *}
{* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002    *}
{* TurboPower Software Inc. All Rights Reserved.                              *}
{*                                                                            *}
{* Contributor(s):                                                            *}
{*                                                                            *}
{* ***** END LICENSE BLOCK *****                                              *}

{$I OVC.INC}

{$B-} {Complete Boolean Evaluation}
{$I+} {Input/Output-Checking}
{$P+} {Open Parameters}
{$T-} {Typed @ Operator}
{W-} {Windows Stack Frame}
{$X+} {Extended Syntax}

unit ovctbcls;
  {-Table column, column array classes}

interface

uses
  {$IFNDEF LCL} Windows, {$ELSE} LclIntf, LclType, {$ENDIF} 
  SysUtils, Graphics, Classes, Controls, Forms,
  OvcConst, OvcTCmmn, OvcTCell;

type
  TOvcTableColumnClass = class of TOvcTableColumn;
  TOvcTableColumn = class(TPersistent)
    protected {private}
      {property fields-even size}
      FDefCell  : TOvcBaseTableCell;
      FNumber   : TColNum;
      FOnColumnChanged : TColChangeNotifyEvent;
      FTable    : TOvcTableAncestor;
      FWidth    : Integer;
      {property fields-odd size}
      FHidden   : boolean;
      Filler    : byte;

    protected
      {property access}
      procedure SetDefCell(BTC : TOvcBaseTableCell);
      procedure SetHidden(H : boolean);
      procedure SetWidth(W : Integer);

      {miscellaneous}
      procedure tcDoColumnChanged;
      procedure tcNotifyCellDeletion(Cell : TOvcBaseTableCell);

    public {protected}
      {internal only usage}
      property Number : TColNum
         read FNumber write FNumber;
      property OnColumnChanged : TColChangeNotifyEvent
         write FOnColumnChanged;

    public
      procedure Assign(Source : TPersistent); override;
      constructor Create(ATable : TOvcTableAncestor); virtual;
      destructor Destroy; override;

      {properties}
      property Table : TOvcTableAncestor
         read FTable;

    published
      {properties for streaming}
      property DefaultCell: TOvcBaseTableCell
         read FDefCell write SetDefCell;

      property Hidden : boolean
        read FHidden write SetHidden;

      property Width  : Integer
         read FWidth write SetWidth;
  end;

  TOvcTableColumns = class(TPersistent)
    protected {private}
      {property fields}
      FList   : TList;
      FOnColumnChanged: TColChangeNotifyEvent;
      FFixups : TStringList;
      FTable  : TOvcTableAncestor;

      {other fields}
      tcColumnClass : TOvcTableColumnClass;

    protected
      {property access}
      function GetCol(ColNum : TColNum) : TOvcTableColumn;
      function GetCount : Integer;
      function GetDefaultCell(ColNum : TColNum) : TOvcBaseTableCell;
      function GetHidden(ColNum : TColNum) : boolean;
      function GetWidth(ColNum : TColNum) : Integer;

      procedure SetCol(ColNum : TColNum; C : TOvcTableColumn);
      procedure SetCount(C : Integer);
      procedure SetDefaultCell(ColNum : TColNum; C : TOvcBaseTableCell);
      procedure SetHidden(ColNum : TColNum; H : boolean);
      procedure SetWidth(ColNum : TColNum; W : Integer);

      {event access}
      procedure SetOnColumnChanged(OC : TColChangeNotifyEvent);

      {other}
      procedure tcDoColumnChanged(ColNum1, ColNum2 : TColNum;
                                  Action : TOvcTblActions);

    public
      {internal only usage}
      procedure tcNotifyCellDeletion(Cell : TOvcBaseTableCell);
      function tcStartLoading : TStringList;
      procedure tcStopLoading;

      property OnColumnChanged : TColChangeNotifyEvent
         write SetOnColumnChanged;

    public
      constructor Create(ATable : TOvcTableAncestor; ANumber : Integer;
                         AColumnClass : TOvcTableColumnClass);
      destructor Destroy; override;

      procedure Append(C : TOvcTableColumn);
      procedure Clear;
      procedure Delete(ColNum : TColNum);
      procedure Exchange(ColNum1, ColNum2 : TColNum);
      procedure Insert(const ColNum : TColNum; C : TOvcTableColumn);

      property Count : Integer
         read GetCount write SetCount;

      property DefaultCell [ColNum : TColNum] : TOvcBaseTableCell
         read GetDefaultCell write SetDefaultCell;

      property Hidden [ColNum : TColNum] : boolean
         read GetHidden write SetHidden;

      property List [ColNum : TColNum] : TOvcTableColumn
         read GetCol write SetCol;
         default;

      property Table : TOvcTableAncestor
         read FTable write FTable;

      property Width [ColNum : TColNum] : Integer
         read GetWidth write SetWidth;
  end;

implementation


{===TOvcTableColumn=====================================================}
constructor TOvcTableColumn.Create(ATable : TOvcTableAncestor);
  begin
    inherited Create;
    FWidth := tbDefColWidth;
    FDefCell := nil;
    FTable := ATable;
  end;
{--------}
destructor TOvcTableColumn.Destroy;
  begin
    DefaultCell := nil;
    inherited Destroy;
  end;
{--------}
procedure TOvcTableColumn.Assign(Source : TPersistent);
  var
    Src : TOvcTableColumn absolute Source;
  begin
    if not (Source is TOvcTableColumn) then
      Exit;
    FWidth := Src.Width;
    FHidden := Src.Hidden;
    DefaultCell := Src.DefaultCell;
  end;
{--------}
procedure TOvcTableColumn.tcDoColumnChanged;
  begin
    if Assigned(FOnColumnChanged) then
      FOnColumnChanged(Self, FNumber, 0, taSingle);
  end;
{--------}
procedure TOvcTableColumn.tcNotifyCellDeletion(Cell : TOvcBaseTableCell);
  begin
    if (Cell = FDefCell) then
      DefaultCell := nil;
  end;
{--------}
procedure TOvcTableColumn.SetDefCell(BTC : TOvcBaseTableCell);
  var
    DoIt : boolean;
  begin
    DoIt := false;
    if (BTC <> FDefCell) then
      if Assigned(BTC) then
        begin
          if (BTC.References = 0) or
             ((BTC.References > 0) and (BTC.Table = FTable)) then
            DoIt := true;
        end
      else
        DoIt := true;

    if DoIt then
      begin
        if Assigned(FDefCell) then
          FDefCell.DecRefs;
        FDefCell := BTC;
        if Assigned(FDefCell) then
          begin
            if (FDefCell.References = 0) then
              FDefCell.Table := FTable;
            FDefCell.IncRefs;
          end;
        tcDoColumnChanged;
      end;
  end;
{--------}
procedure TOvcTableColumn.SetHidden(H : boolean);
  begin
    if (H <> FHidden) then
      begin
        FHidden := H;
        tcDoColumnChanged;
      end;
  end;
{--------}
procedure TOvcTableColumn.SetWidth(W : Integer);
  begin
    if (W <> FWidth) then
      begin
        FWidth := W;
        tcDoColumnChanged;
      end;
  end;
{====================================================================}



{===TOvcTableColumns=======================================================}
constructor TOvcTableColumns.Create(ATable : TOvcTableAncestor;
                                    ANumber : Integer;
                                    AColumnClass : TOvcTableColumnClass);
  var
    i : Integer;
    Col : TOvcTableColumn;
  begin
    inherited Create;
    FTable := ATable;
    FList := TList.Create;
    tcColumnClass := AColumnClass;
    for i := 0 to pred(ANumber) do
      begin
        Col := AColumnClass.Create(FTable);
        Col.Number := i;
        Append(Col);
      end;
  end;
{--------}
destructor TOvcTableColumns.Destroy;
  begin
    if Assigned(FList) then
      begin
        OnColumnChanged := nil;
        Clear;
        FList.Free;
      end;
    FFixups.Free;
  end;
{--------}
procedure TOvcTableColumns.Append(C : TOvcTableColumn);
  begin
    if (FList.Count = Classes.MaxListSize) then
      TableErrorRes(SCTableMaxColumns);
    if (C.Table <> FTable) or (not (C is tcColumnClass)) then
      Exit;
    C.Number := FList.Count;
    FList.Add(C);
    C.OnColumnChanged := FOnColumnChanged;
    tcDoColumnChanged(C.Number, 0, taInsert);
  end;
{--------}
procedure TOvcTableColumns.Clear;
  var
    i : Integer;
  begin
    for i := 0 to pred(FList.Count) do
      TOvcTableColumn(FList[i]).Free;
    FList.Clear;
    tcDoColumnChanged(0, 0, taAll);
  end;
{--------}
procedure TOvcTableColumns.Delete(ColNum : TColNum);
  var
    i : integer;
  begin
    if (0 <= ColNum) and (ColNum < FList.Count) then
      begin
        TOvcTableColumn(FList[ColNum]).Free;
        FList.Delete(ColNum);
        for i := 0 to pred(FList.Count) do
          TOvcTableColumn(FList[i]).Number := i;
        tcDoColumnChanged(ColNum, 0, taDelete);
        if Assigned(FFixups) then
          if (ColNum < FFixups.Count) then
            FFixups.Delete(ColNum);
      end;
  end;
{--------}
procedure TOvcTableColumns.Exchange(ColNum1, ColNum2 : TColNum);
  var
    Temp1, Temp2 : pointer;
  begin
    if (ColNum1 <> ColNum2) and
       (0 <= ColNum1) and (ColNum1 < FList.Count) and
       (0 <= ColNum2) and (ColNum2 < FList.Count) then
      begin
        Temp1 := FList[ColNum1];
        Temp2 := FList[ColNum2];
        TOvcTableColumn(Temp1).Number := ColNum2;
        TOvcTableColumn(Temp2).Number := ColNum1;
        FList[ColNum1] := Temp2;
        FList[ColNum2] := Temp1;
        tcDoColumnChanged(ColNum1, ColNum2, taExchange);
      end;
  end;
{--------}
function TOvcTableColumns.GetCol(ColNum : TColNum) : TOvcTableColumn;
  begin
    if (0 <= ColNum) and (ColNum < FList.Count) then
      Result := TOvcTableColumn(FList[ColNum])
    else
      Result := nil;
  end;
{--------}
function TOvcTableColumns.GetCount : Integer;
  begin
    Result := FList.Count;
  end;
{--------}
function TOvcTableColumns.GetDefaultCell(ColNum : TColNum) : TOvcBaseTableCell;
  begin
    Result := nil;
    if (0 <= ColNum) and (ColNum < FList.Count) then
      Result := TOvcTableColumn(FList[ColNum]).DefaultCell;
  end;
{--------}
function TOvcTableColumns.GetHidden(ColNum : TColNum) : boolean;
  begin
    Result := True;
    if (0 <= ColNum) and (ColNum < FList.Count) then
      Result := TOvcTableColumn(FList[ColNum]).Hidden;
  end;
{--------}
function TOvcTableColumns.GetWidth(ColNum : TColNum) : Integer;
  begin
    Result := 0;
    if (0 <= ColNum) and (ColNum < FList.Count) then
      Result := TOvcTableColumn(FList[ColNum]).Width;
  end;
{--------}
procedure TOvcTableColumns.Insert(const ColNum : TColNum;
                                  C : TOvcTableColumn);
  var
    i : integer;
  begin
    if (FList.Count = Classes.MaxListSize) then
      TableErrorRes(SCTableMaxColumns);
    if (C.Table <> FTable) or (not (C is tcColumnClass)) then
      Exit;
    if (0 <= ColNum) and (ColNum < FList.Count) then
      begin
        FList.Insert(ColNum, C);
        for i := 0 to pred(FList.Count) do
          TOvcTableColumn(FList[i]).Number := i;
        C.OnColumnChanged := FOnColumnChanged;
        tcDoColumnChanged(ColNum, 0, taInsert);
        if Assigned(FFixups) then begin
          FFixups.Insert(ColNum, 'unknown');
          FFixups.Objects[ColNum] := C;
        end;
      end;
  end;
{--------}
procedure TOvcTableColumns.tcDoColumnChanged(ColNum1, ColNum2 : TColNum;
                                             Action : TOvcTblActions);
  begin
    if Assigned(FOnColumnChanged) then
      FOnColumnChanged(Self, ColNum1, ColNum2, Action);
  end;
{--------}
procedure TOvcTableColumns.tcNotifyCellDeletion(Cell : TOvcBaseTableCell);
  var
    ColNum : TColNum;
  begin
    for ColNum := 0 to pred(FList.Count) do
      TOvcTableColumn(FList[ColNum]).tcNotifyCellDeletion(Cell);
  end;
{--------}
procedure TOvcTableColumns.SetCol(ColNum : TColNum; C : TOvcTableColumn);
  var
    PC : TOvcTableColumn;
  begin
    if (C.Table <> FTable) or (not (C is tcColumnClass)) then
      Exit;
    if (0 <= ColNum) and (ColNum < FList.Count) then
      begin
        PC := GetCol(ColNum);
        PC.Assign(C);
      end;
  end;
{--------}
procedure TOvcTableColumns.SetCount(C : Integer);
  var
    ColNum : TColNum;
    Col : TOvcTableColumn;
  begin
    if (C > 0) and (C <> Count) then
      if (C < Count) then
        begin
          {must destroy the end set of columns}
          for ColNum := pred(Count) downto C do
            Delete(ColNum);
        end
      else {C > Count}
        begin
          {must add some new columns on the end}
          for ColNum := Count to pred(C) do
            begin
              Col := tcColumnClass.Create(FTable);
              Col.Number := ColNum;
              Append(Col);
            end;
        end;
  end;
{--------}
procedure TOvcTableColumns.SetDefaultCell(ColNum : TColNum; C : TOvcBaseTableCell);
  begin
    if (0 <= ColNum) and (ColNum < FList.Count) then
      TOvcTableColumn(FList[ColNum]).DefaultCell := C;
  end;
{--------}
procedure TOvcTableColumns.SetHidden(ColNum : TColNum; H : boolean);
  begin
    if (0 <= ColNum) and (ColNum < FList.Count) then
      TOvcTableColumn(FList[ColNum]).Hidden := H;
  end;
{--------}
procedure TOvcTableColumns.SetOnColumnChanged(OC : TColChangeNotifyEvent);
  var
    i : Integer;
  begin
    FOnColumnChanged := OC;
    for i := 0 to pred(FList.Count) do
      TOvcTableColumn(FList[i]).OnColumnChanged := OC;
  end;
{--------}
procedure TOvcTableColumns.SetWidth(ColNum : TColNum; W : Integer);
  begin
    if (0 <= ColNum) and (ColNum < FList.Count) then
      TOvcTableColumn(FList[ColNum]).Width := W;
  end;
{--------}
function TOvcTableColumns.tcStartLoading : TStringList;
  begin
    if Assigned(FFixups) then
      FFixups.Clear
    else
      FFixups := TStringList.Create;
    Result := FFixups;
  end;
{--------}
procedure TOvcTableColumns.tcStopLoading;
  {------}
  function GetImmediateParentForm(Control : TControl) : TWinControl;
    var
      ParentCtrl : TControl;
    begin
      ParentCtrl := Control.Parent;
      while (Assigned(ParentCtrl)) and
            (not (ParentCtrl is TCustomForm))
            {$IFDEF VERSION5}
            and (not (ParentCtrl is TCustomFrame))
            {$ENDIF}
            do
        ParentCtrl := ParentCtrl.Parent;
      Result := TForm(ParentCtrl);
    end;
  {------}
  function GetFormName(const S, FormName : string) : string;
    var
      PosDot : integer;
    begin
      PosDot := Pos('.', S);
      if (PosDot <> 0) then
        Result := Copy(S, 1, pred(PosDot))
      else
        Result := FormName;
    end;
  {------}
  function FormNamesEqual(const CmptFormName, FormName : string) : boolean;
    var
      PosUL : integer;
    begin
      Result := true;
      if (FormName = '') or (CmptFormName = FormName) then
        Exit;
      PosUL := length(FormName);
      while (PosUL > 0) and (FormName[PosUL] <> '_') do
        dec(PosUL);
      if (PosUL > 0) then
        if (CmptFormName = Copy(FormName, 1, pred(PosUL))) then
          Exit;
      Result := false;
    end;
  {------}
  function GetComponentName(const S : string) : string;
    var
      PosDot : integer;
    begin
      PosDot := Pos('.', S);
      if (PosDot <> 0) then
        Result := Copy(S, succ(PosDot), length(S))
      else
        Result := S;
    end;
  {------}
  var
    i      : integer;
    Form   : TWinControl;
    Compnt : TComponent;
    DM     : integer;
    DataMod: TDataModule;
    DMCount: integer;
  begin
    {if there's nothing to fix up, exit now}
    if not Assigned(FFixups) then
      Exit;
    {fixup references to cell components on the table's form}
    try
      Form := GetImmediateParentForm(FTable);
      for i := pred(FFixups.Count) downto 0 do
        if FormNamesEqual(GetFormName(FFixups[i], Form.Name),
                          Form.Name) then
          begin
            Compnt := Form.FindComponent(GetComponentName(FFixups[i]));
            if Assigned(Compnt) and (Compnt is TOvcBaseTableCell) then
              begin
                TOvcTableColumn(FFixups.Objects[i]).DefaultCell := TOvcBaseTableCell(Compnt);
                FFixups.Delete(i);
              end;
          end;
    {fixup references to cell components on any data modules}
    if (FFixups.Count <> 0) then begin
      DM := 0;
{$IFNDEF LCL}
      DMCount := Screen.DataModuleCount;
{$ELSE}
      DMCount := 0;
{$ENDIF}
      while (FFixups.Count > 0) and (DM < DMCount) do begin
{$IFNDEF LCL}
        DataMod := Screen.DataModules[DM];
{$ENDIF}
        for i := pred(FFixups.Count) downto 0 do
          if (GetFormName(FFixups[i], Form.Name) = DataMod.Name) then begin
            Compnt := DataMod.FindComponent(GetComponentName(FFixups[i]));
            if Assigned(Compnt) and (Compnt is TOvcBaseTableCell) then begin
              TOvcTableColumn(FFixups.Objects[i]).DefaultCell
                := TOvcBaseTableCell(Compnt);
              FFixups.Delete(i);
            end;
          end;
        inc(DM);
      end;
    end;
    finally
      FFixups.Free;
      FFixups := nil;
    end;
  end;
{====================================================================}

end.
