From 76a6c670222166baf4a216668a7e6dad7e036ed4 Mon Sep 17 00:00:00 2001
From: michael <michael@freepascal.org>
Date: Sat, 30 Sep 2017 11:58:05 +0000
Subject: [PATCH] * Patch from Pascal Riekenberg to fix multi-column layout

git-svn-id: trunk@37363 -
---
 packages/fcl-report/demos/rptcolumns.pp |  37 +-
 packages/fcl-report/src/fpreport.pp     | 675 ++++++++++--------------
 2 files changed, 309 insertions(+), 403 deletions(-)

diff --git a/packages/fcl-report/demos/rptcolumns.pp b/packages/fcl-report/demos/rptcolumns.pp
index 3f25b653f8..f1975ed273 100644
--- a/packages/fcl-report/demos/rptcolumns.pp
+++ b/packages/fcl-report/demos/rptcolumns.pp
@@ -263,13 +263,33 @@ begin
   Memo.TextAlignment.Horizontal := taLeftJustified;
   Memo.TextAlignment.Vertical := tlCenter;
 
+  DataFooter := TFPReportDataFooterBand.Create(p);
+  DataFooter.Layout.Height := 10;
+  DataFooter.Frame.Shape := fsRectangle;
+  DataFooter.Frame.BackgroundColor := TFPReportColor($ffa500);
+  DataFooter.UseParentFont := False;
+  DataFooter.Font.Name := 'LiberationSans-Bold';
+  DataFooter.Font.Color := clWhite;
+
+  Memo := TFPReportMemo.Create(DataFooter);
+  Memo.Layout.Left := 5;
+  Memo.Layout.Top := 1.5;
+  Memo.Layout.Width := 50;
+  Memo.Layout.Height := 8;
+  Memo.Text := 'DataFooter Band';
+  Memo.TextAlignment.Horizontal := taLeftJustified;
+  Memo.TextAlignment.Vertical := tlCenter;
+
   DataBand := TFPReportDataBand.Create(p);
   DataBand.Layout.Height := 10;
   DataBand.Data := FDataPage2;
+  DataBand.KeepTogetherWithChildren := False;
   DataBand.Frame.Shape := fsRectangle;
   DataBand.Frame.BackgroundColor := clDataBand;
   { associated DataHeader band }
   DataBand.HeaderBand := DataHeader;
+  { associated DataFooter band }
+  DataBand.FooterBand := DataFooter;
 
   Memo := TFPReportMemo.Create(DataBand);
   Memo.Layout.Left := 5;
@@ -292,23 +312,6 @@ begin
 
   DataBand.ChildBand := ChildBand;
 
-  DataFooter := TFPReportDataFooterBand.Create(p);
-  DataFooter.Layout.Height := 10;
-  DataFooter.Frame.Shape := fsRectangle;
-  DataFooter.Frame.BackgroundColor := TFPReportColor($ffa500);
-  DataFooter.UseParentFont := False;
-  DataFooter.Font.Name := 'LiberationSans-Bold';
-  DataFooter.Font.Color := clWhite;
-
-  Memo := TFPReportMemo.Create(DataFooter);
-  Memo.Layout.Left := 5;
-  Memo.Layout.Top := 1.5;
-  Memo.Layout.Width := 50;
-  Memo.Layout.Height := 8;
-  Memo.Text := 'DataFooter Band';
-  Memo.TextAlignment.Horizontal := taLeftJustified;
-  Memo.TextAlignment.Vertical := tlCenter;
-
   ColumnFooter := TFPReportColumnFooterBand.Create(p);
   ColumnFooter.Layout.Height := 15;
   ColumnFooter.Frame.Shape := fsRectangle;
diff --git a/packages/fcl-report/src/fpreport.pp b/packages/fcl-report/src/fpreport.pp
index 20a57499c7..f2bc0bab0d 100644
--- a/packages/fcl-report/src/fpreport.pp
+++ b/packages/fcl-report/src/fpreport.pp
@@ -664,7 +664,7 @@ type
     procedure Assign(Source: TPersistent); override;
     procedure BeginUpdate;
     procedure EndUpdate;
-    function EvaluateVisibility : boolean;
+    function EvaluateVisibility : boolean; virtual;
     property Parent: TFPReportElement read FParent write SetParent;
     Property Report : TFPCustomReport read GetReport;
     { Runtime Layout - populated when layouting of report is calculated. }
@@ -886,6 +886,7 @@ type
     Class Function ReportBandType : TFPReportBandType; virtual;
     procedure   WriteElement(AWriter: TFPReportStreamer; AOriginal: TFPReportElement = nil); override;
     procedure   ReadElement(AReader: TFPReportStreamer); override;
+    function EvaluateVisibility: boolean; override;
     property Page : TFPReportCustomPage read GetReportPage;
   end;
   TFPReportCustomBandClass = Class of TFPReportCustomBand;
@@ -1089,8 +1090,6 @@ type
     procedure   StoreRTBands(pBands: TBandList);
     { This property defines the hierarchy of nested groups. For the top most group, this property will be nil. }
     property    ParentGroupHeader: TFPReportCustomGroupHeaderBand read FParentGroupHeader write SetGroupHeader;
-    { This property defines the hierarchy of nested groups. For the bottom most group, this property will be nil. }
-    property    ChildGroupHeader: TFPReportCustomGroupHeaderBand read FChildGroupHeader;
     { Indicates related GroupFooter band. This will automatically be set by the GroupFooter. }
     property    GroupFooter: TFPReportCustomGroupFooterBand read FGroupFooter;
     { can be a field name or an expression }
@@ -1121,6 +1120,8 @@ type
     function    IsInitialGroupChange: Boolean;
     procedure   ResetGroupConditionValues;
     Class Function ReportBandType : TFPReportBandType; override;
+    { This property defines the hierarchy of nested groups. For the bottom most group, this property will be nil. }
+    property    ChildGroupHeader: TFPReportCustomGroupHeaderBand read FChildGroupHeader;
   end;
 
 
@@ -1390,6 +1391,7 @@ type
   TFPCustomReport = class(TFPReportComponent)
   private
     FPages: TFPList;
+    FRTCurDsgnPageIdx: integer;
     FOnBeginReport: TFPReportBeginReportEvent;
     FOnEndReport: TFPReportEndReportEvent;
     FReportData: TFPReportDataCollection;
@@ -1524,11 +1526,11 @@ type
   TFPReportLayouter = Class(TComponent)
   Private
     FMyReport: TFPCustomReport;
-    FPageIdx: integer;
     FNewPage: boolean;  // indicates if a new ReportPage needs to be created - used if DataBand spans multiple pages for example
     FNewColumn: boolean;
     FLastDsgnDataBand: TFPReportCustomDataBand;
     FSpaceLeft: TFPReportUnits;
+    FColumnYStartPos: TFPReportUnits;
     FLastYPos: TFPReportUnits;
     FLastXPos: TFPReportUnits;
     FPageFooterYPos: TFPReportUnits;
@@ -1542,26 +1544,30 @@ type
     FPageDetailsPrinted: Boolean;
     FCurrentColumn: UInt8;
     FMultiColumn: boolean;
-    FHeaderList: TBandList;
+    FPageHeader: TFPReportCustomPageHeaderBand;
+    FTitle: TFPReportCustomTitleBand;
+    FColumnHeader: TFPReportCustomColumnHeaderBand;
     FFooterList: TBandList;
-    FGroupList: TBandList;
+    FColumnFooter: TFPReportCustomColumnFooterBand;
+    FRTColumnFooterList: TBandList;
+    FGroupHeaderList: TBandList;
     FBottomStackedFooterList: TBandList;
     FRTPage: TFPReportCustomPage;
     FCurrentRTColumnFooterBand: TFPReportCustomColumnFooterBand;
     FDataLevelStack: UInt8;
     procedure ClearBandList;
     function GetPage(AIndex: integer): TFPReportCustomPage;
+    function GetRTCurDsgnPageIdx: Integer;
     function GetPerDesignerPageCount(Index : Cardinal): Cardinal;
     function GetRTCurPageIdx: Integer;
     function GetRTObjects: TFPList;
     procedure SetGetPerDesignerPageCount(Index : Cardinal; AValue: Cardinal);
     Function GetPageNumberPerDesignerPage : Integer;
+    procedure SetRTCurDsgnPageIdx(pPageIdx: Integer);
     Procedure SetPageNumberPerDesignerPage(aValue : Integer);
     function FooterSpaceNeeded: TFPReportUnits;
   protected
-    function HandleBandVisibility(aBand: TFPReportCustomBand; doRecalcLayout : Boolean): Boolean;
     procedure CheckNewOrOverFlow(CheckMulticolumn: Boolean = True);
-    procedure CheckRemaining(CheckMulticolumn: Boolean = True);
     procedure SetPageCount(aCount : Integer);
     procedure IncPageNumberPerDesignerPage;
     procedure InitRTCurPageIdx;
@@ -1574,25 +1580,18 @@ type
     procedure InitDesignPage(aPageIdx: integer); virtual;
     procedure RunDataLoop(aPageIdx: Integer; aPageData: TFPReportData); virtual;
     procedure PrepareRecord;
-    procedure RecalcBandLayout(ABand: TFPReportCustomBand); virtual;
-    procedure PopulateFooterList(APage: TFPReportCustomPage); virtual;
-    procedure PopulateHeaderList(APage: TFPReportCustomPage);virtual;
-    procedure PopulateGroupList(APage: TFPReportCustomPage);virtual;
-    procedure RemoveTitleBandFromHeaderList;virtual;
-    procedure RemoveColumnFooterFromFooterList;virtual;
+    procedure PrepareFooter(APage: TFPReportCustomPage); virtual;
+    procedure PrepareHeader(APage: TFPReportCustomPage);virtual;
+    procedure PrepareGroupHeader(APage: TFPReportCustomPage);virtual;
     procedure UpdateSpaceRemaining(const ABand: TFPReportCustomBand; const AUpdateYPos: boolean = True);virtual;
     function CommonRuntimeBandProcessing(const aBand: TFPReportCustomBand): TFPReportCustomBand; virtual;
-    function MaybeSkipBand(const ADsgnBand: TFPReportCustomBand): boolean; virtual;
     procedure ShowDataBand(const aBand: TFPReportCustomDataBand);virtual;
-    procedure ShowDataFooterBand(const aBand: TFPReportCustomDataFooterBand); virtual;
     procedure ShowDataHeaderBand(const aBand: TFPReportCustomDataHeaderBand); virtual;
     procedure ShowDetailBand(const AMasterBand: TFPReportCustomDataBand);virtual;
-    function ShowPageHeaderBand(const aBand: TFPReportCustomBand): boolean; virtual;
-    function ShowColumnHeaderBand(const aBand: TFPReportCustomBand): boolean; virtual;
-    procedure ShowFooterBand(aBand: TFPReportCustomPageFooterBand); virtual;
-    procedure ShowColumnFooterBand(APage: TFPReportCustomPage; ABand: TFPReportCustomColumnFooterBand); virtual;
-    Procedure HandleHeaderBands; virtual;
+    procedure ShowColumnFooterBand(aBand: TFPReportCustomColumnFooterBand); virtual;
+    function HandleHeaderBands: Boolean; virtual;
     Procedure HandleFooterBands; virtual;
+    Procedure HandleRTColumnFooterBands; virtual;
     procedure HandleRepeatedGroupHeaderBands; virtual;
     procedure HandleDataBands; virtual;
     procedure HandleGroupBands; virtual;
@@ -1602,9 +1601,10 @@ type
     procedure ShowGroupFooterBand(aBand: TFPReportCustomGroupFooterBand); virtual;
     function ShowBandWithChilds(aBand: TFPReportCustomBand): Boolean; virtual;
     function NoSpaceRemaining: boolean;virtual;
-    procedure EndPage; virtual;
     procedure StartNewPage; virtual;
     procedure StartNewColumn;virtual;
+    procedure EndColumn; virtual;
+    procedure EndPage; virtual;
     procedure HandleOverflowed;virtual;
     Procedure DoExecute; virtual;
     // In case descendents need these, make them available
@@ -1615,7 +1615,7 @@ type
     Property RTCurColumn : UInt8 Read FCurrentColumn;
     Property RTCurPage : TFPReportCustomPage Read FRTPage;
     Property RTCurColumnFooterBand : TFPReportCustomColumnFooterBand Read FCurrentRTColumnFooterBand;
-    Property PageIdx : Integer Read FPageIdx;
+    Property RTCurDsgnPageIdx : Integer Read GetRTCurDsgnPageIdx write SetRTCurDsgnPageIdx;
     Property PageNumberPerDesignerPage : Integer Read GetPageNumberPerDesignerPage Write SetPageNumberPerDesignerPage;
   Public
     Procedure Execute(aReport : TFPCustomReport);
@@ -2041,7 +2041,6 @@ type
     Property OnConfigCallBack : TFPReportExporterConfigHandler Read FOnConfigCallBack Write FOnConfigCallBack;
   end;
 
-
 procedure ReportError(Msg: string); inline;
 procedure ReportError(Fmt: string; Args: array of const);
 function  HorzTextAlignmentToString(AEnum: TFPReportHorzTextAlignment): string; inline;
@@ -2460,7 +2459,6 @@ begin
     Result := EncodeDate(lY, lM, lD) + EncodeTime(lH, lMi, lS, 0);
 end;
 
-
 { TFPReportElementEditor }
 
 procedure TFPReportElementEditor.SetElement(AValue: TFPReportElement);
@@ -7991,6 +7989,45 @@ begin
   end;
 end;
 
+function TFPReportCustomBand.EvaluateVisibility: boolean;
+
+begin
+  Result := inherited EvaluateVisibility;
+  if not Result then
+    exit;
+  Result := False;
+  if FVisibleOnPage = vpAll then
+  begin
+    // do nothing special
+  end
+  else if (Report.FPageNumberPerDesignerPage = 1) then
+  begin // first page rules
+    if (FVisibleOnPage in [vpFirstOnly, vpFirstAndLastOnly]) then
+    begin
+      // do nothing special
+    end
+    else if (FVisibleOnPage in [vpNotOnFirst, vpLastOnly, vpNotOnFirstAndLast]) then
+      Exit; // user asked to skip this band
+  end
+  else if (Report.FPageNumberPerDesignerPage > 1) then
+  begin  // multi-page rules
+    if FVisibleOnPage in [vpFirstOnly] then
+      Exit  // user asked to skip this band
+    else if FVisibleOnPage in [vpNotOnFirst] then
+    begin
+      // do nothing special
+    end
+    else if (not Report.IsFirstPass) then
+    begin // last page rules
+      if (FVisibleOnPage in [vpLastOnly, vpFirstAndLastOnly]) and (Report.FPageNumberPerDesignerPage < Report.FPerDesignerPageCount[Report.FRTCurDsgnPageIdx]) then
+        Exit
+      else if (FVisibleOnPage in [vpNotOnLast, vpFirstOnly, vpNotOnFirstAndLast]) and (Report.FPageNumberPerDesignerPage = Report.FPerDesignerPageCount[Report.FRTCurDsgnPageIdx]) then
+        Exit; // user asked to skip this band
+    end;
+  end;
+  Result := True;
+end;
+
 { TFPReportCustomBandWithData }
 
 procedure TFPReportCustomBandWithData.SetData(const AValue: TFPReportData);
@@ -9452,26 +9489,6 @@ end;
   TFPReportLayouter
   ---------------------------------------------------------------------}
 
-procedure TFPReportLayouter.RemoveTitleBandFromHeaderList;
-var
-  idx: integer;
-  lBand: TFPReportCustomBand;
-begin
-  idx := FHeaderList.Find(TFPReportCustomTitleBand, lBand);
-  if idx > -1 then
-    FHeaderList.Delete(idx);
-end;
-
-procedure TFPReportLayouter.RemoveColumnFooterFromFooterList;
-var
-  idx: integer;
-  lBand: TFPReportCustomBand;
-begin
-  idx := FFooterList.Find(TFPReportCustomColumnFooterBand, lBand);
-  if idx > -1 then
-    FFooterList.Delete(idx);
-end;
-
 procedure TFPReportLayouter.UpdateSpaceRemaining(const ABand: TFPReportCustomBand; const AUpdateYPos: boolean = True);
 begin
   FSpaceLeft := FSpaceLeft - ABand.RTLayout.Height;
@@ -9488,98 +9505,23 @@ begin
   Result.RTLayout.Left := FLastXPos;
 end;
 
-{ Result of True means ADsgnBand must be skipped. Result of False means ADsgnBand
-  must be rendered (ie: not skipped).  }
-
-function TFPReportLayouter.MaybeSkipBand(const ADsgnBand: TFPReportCustomBand): boolean;
-
-begin
-  Result := True;
-  if ADsgnBand.VisibleOnPage = vpAll then
-  begin
-    // do nothing special
-  end
-  else if (PageNumberPerDesignerPage = 1) then
-  begin // first page rules
-    if (ADsgnBand.VisibleOnPage in [vpFirstOnly, vpFirstAndLastOnly]) then
-    begin
-      // do nothing special
-    end
-    else if (ADsgnBand.VisibleOnPage in [vpNotOnFirst, vpLastOnly, vpNotOnFirstAndLast]) then
-      Exit; // user asked to skip this band
-  end
-  else if (PageNumberPerDesignerPage > 1) then
-  begin  // multi-page rules
-    if ADsgnBand.VisibleOnPage in [vpFirstOnly] then
-      Exit  // user asked to skip this band
-    else if ADsgnBand.VisibleOnPage in [vpNotOnFirst] then
-    begin
-      // do nothing special
-    end
-    else if (not IsFirstPass) then
-    begin // last page rules
-      if (ADsgnBand.VisibleOnPage in [vpLastOnly, vpFirstAndLastOnly]) and (PageNumberPerDesignerPage < PerDesignerPageCount[PageIdx]) then
-        Exit
-      else if (ADsgnBand.VisibleOnPage in [vpNotOnLast, vpFirstOnly, vpNotOnFirstAndLast]) and (PageNumberPerDesignerPage = PerDesignerPageCount[PageIdx]) then
-        Exit; // user asked to skip this band
-    end;
-  end;
-  Result := False;
-end;
-
-{ Result of True means ADsgnBand must be skipped. Result of False means aBand
-  must be rendered (ie: not skipped).  }
-function TFPReportLayouter.ShowPageHeaderBand(const aBand: TFPReportCustomBand) : boolean;
-begin
-  Result := True;
-  if not (aBand is TFPReportCustomPageHeaderBand) then
-    Exit;
-  if MaybeSkipBand(aBand as TFPReportCustomPageHeaderBand) then
-    Exit;
-  CommonRuntimeBandProcessing(aBand);
-  Result := False;
-end;
-
-function TFPReportLayouter.ShowColumnHeaderBand(const aBand: TFPReportCustomBand): boolean;
-
-var
-  lBand: TFPReportCustomBand;
-  lRTBand: TFPReportCustomBand;
-
+function TFPReportLayouter.HandleHeaderBands: Boolean;
 begin
   Result := False;
-  lRTBand := CommonRuntimeBandProcessing(aBand);
-  { Only once we show the first column header do we take into account
-    the column footer. }
-  lBand := Pages[PageIdx].FindBand(TFPReportCustomColumnFooterBand);
-  FFooterList.Add(lBand);
-  UpdateSpaceRemaining(lRTBand,false);
-end;
-
-procedure TFPReportLayouter.HandleHeaderBands;
-
-Var
-  I : Integer;
-  lBand: TFPReportCustomBand;
-
-begin
   { Show all header bands }
-  for I := 0 to FHeaderList.Count - 1 do
-    begin
-    lBand := FHeaderList[I];
-    if lBand is TFPReportCustomPageHeaderBand then
-      begin
-      if ShowPageHeaderBand(lBand) then
-        Continue;
-      end
-    else if lBand is TFPReportCustomColumnHeaderBand then
-      begin
-      if ShowColumnHeaderBand(lBand) then
-        Continue;
-      end
-    else
-      UpdateSpaceRemaining(CommonRuntimeBandProcessing(lBand));
-    end;
+  if Assigned(FPageHeader) then
+    //ShowPageHeaderBand(FPageHeader);
+    ShowBandWithChilds(FPageHeader);
+  if Assigned(FTitle) then
+    UpdateSpaceRemaining(CommonRuntimeBandProcessing(FTitle));
+  if NoSpaceRemaining then
+  begin
+    // ToDo: This shouldn't happen at all. Maybe we should throw an exception
+    StartNewPage;
+    { set result to True to not continue StartNewPage
+      as we are on an other page already              }
+    Result := True;
+  end;
 end;
 
 procedure TFPReportLayouter.HandleFooterBands;
@@ -9624,8 +9566,7 @@ begin
           lRTBand := TFPReportCustomBand(lFooter.PrepareObject(FRTPage));
           lRTBand.RecalcLayout;
           lRTBand.BeforePrint;
-          if MaybeSkipBand(lRTBand) or
-          not lRTBand.EvaluateVisibility then
+          if not lRTBand.EvaluateVisibility then
           begin
             //WriteLn('      discarded');
             lRTBand.Page.RemoveChild(lRTBand);
@@ -9663,8 +9604,7 @@ begin
           lRTBand := TFPReportCustomBand(lFooter.PrepareObject(FRTPage));
           lRTBand.RecalcLayout;
           lRTBand.BeforePrint;
-          if MaybeSkipBand(lRTBand) or
-          not lRTBand.EvaluateVisibility then
+          if not lRTBand.EvaluateVisibility then
           begin
             //WriteLn('      discarded');
             lRTBand.Page.RemoveChild(lRTBand);
@@ -9687,6 +9627,25 @@ begin
   end;
 end;
 
+procedure TFPReportLayouter.HandleRTColumnFooterBands;
+
+var
+  lOffset: TFPReportUnits;
+  i: Integer;
+  lBand: TFPReportCustomBand;
+
+begin
+  { move all allready layouted column footers (only fpStackAtBottom)
+    up by offset of page footer                                      }
+  lOffset := FRTPage.RTLayout.Top + FRTPage.RTLayout.Height - FPageFooterYPos;
+  for i:=0 to FRTColumnFooterList.Count-1 do
+  begin
+    lBand := FRTColumnFooterList[i];
+    lBand.RTLayout.Top := lBand.RTLayout.Top - lOffset;
+  end;
+  FRTColumnFooterList.Clear;
+end;
+
 procedure TFPReportLayouter.HandleRepeatedGroupHeaderBands;
 
 var
@@ -9694,9 +9653,9 @@ var
   lGrp: TFPReportCustomGroupHeaderBand;
 
 begin
-  for I:=FGroupList.Count-1 downto 0 do
+  for I:=FGroupHeaderList.Count-1 downto 0 do
   begin
-    lGrp := TFPReportCustomGroupHeaderBand(FGroupList[I]);
+    lGrp := TFPReportCustomGroupHeaderBand(FGroupHeaderList[I]);
     if lGrp.ReprintedHeader and
     ( not lGrp.GroupChanged or
     lGrp.FNeedsReprintedHeader) and
@@ -9717,53 +9676,70 @@ begin
   end;
 end;
 
-procedure TFPReportLayouter.ShowColumnFooterBand(APage: TFPReportCustomPage;
-  ABand: TFPReportCustomColumnFooterBand);
+procedure TFPReportLayouter.ShowColumnFooterBand(aBand: TFPReportCustomColumnFooterBand);
 
 var
-  lBandCount: integer;
-  lOverflowBand: TFPReportCustomBand;
-  lFooterBand : TFPReportCustomColumnFooterBand;
+  lPageFooterYPos: TFPreportUnits;
+  lBand, lRTBand : TFPReportCustomBand;
 
 begin
-  lBandCount := FRTPage.BandCount - 1;
-  lOverflowBand := FRTPage.Bands[lBandCount]; { store reference to band that caused the new column }
-  lFooterBand := TFPReportCustomColumnFooterBand(CommonRuntimeBandProcessing(ABand));
-  if FPageFooterYPos = -1 then
-    lFooterBand.RTLayout.Top := (APage.RTLayout.Top + APage.RTLayout.Height) - lFooterBand.RTLayout.Height
-  else
-    lFooterBand.RTLayout.Top := FPageFooterYPos - lFooterBand.RTLayout.Height;
-  if lFooterBand.FooterPosition = fpNormal then
-    begin
-    if FNewColumn or FOverflowed then
-      { take height of overflowed band into account }
-      lFooterBand.RTLayout.Top := FLastYPos - lOverflowBand.RTLayout.Height
-    else
-      lFooterBand.RTLayout.Top := FLastYPos;
+  lPageFooterYPos := -1;
+  lBand := aBand;
+  while Assigned(lBand) do
+  begin
+    try
+      lRTBand := CommonRuntimeBandProcessing(aBand);
+      if not lRTBand.EvaluateVisibility then
+      begin
+        lRTBand.Page.RemoveChild(lRTBand);
+        lRTBand.Free;
+        Continue;
+      end;
+      if aBand.FooterPosition = fpNormal then
+      begin
+        lRTBand.RTLayout.Top := FLastYPos;
+      end
+      else if aBand.FooterPosition = fpStackAtBottom then
+      begin
+        if lPageFooterYPos = -1 then
+          lPageFooterYPos := (FRTPage.RTLayout.Top + FRTPage.RTLayout.Height);
+        lRTBand.RTLayout.Top := lPageFooterYPos - lRTBand.RTLayout.Height;
+        FRTColumnFooterList.Add(lRTBand);
+      end;
+    finally
+      lBand := lBand.ChildBand;
     end;
+  end;
 end;
 
 function TFPReportLayouter.NoSpaceRemaining: boolean;
 
 var
-  lSpaceNeede: TFPReportUnits;
+  lSpaceNeeded: TFPReportUnits;
 
 begin
-  lSpaceNeede := FooterSpaceNeeded;
-  Result:=(FSpaceLeft-lSpaceNeede)<= 0;
-  //writeln(' -> ',FormatFloat('#,##0.0', FSpaceLeft-lSpaceNeede));
+  lSpaceNeeded := FooterSpaceNeeded;
+  Result:=(FSpaceLeft-lSpaceNeeded)< 0;
+  //writeln(' -> ',FormatFloat('#,##0.0', FSpaceLeft-lSpaceNeeded));
   if Result then
+  begin
+    if FMultiColumn and
+    (FCurrentColumn < Pages[RTCurDsgnPageIdx].ColumnCount) then
     begin
-    if FMultiColumn and (FCurrentColumn < Pages[PageIdx].ColumnCount) then
-      begin
       FNewColumn := True;
-      end
+    end
     else
-      begin
+    begin
       FOverflowed := True;
       FNewPage := True;
-      end;
-    end
+    end;
+  end
+end;
+
+procedure TFPReportLayouter.EndColumn;
+begin
+  if Assigned(FColumnFooter) then
+    ShowColumnFooterBand(FColumnFooter);
 end;
 
 procedure TFPReportLayouter.EndPage;
@@ -9773,11 +9749,16 @@ var
   i: Integer;
 
 begin
+  if Assigned(FRTPage) then
+    EndColumn;
   { handle footers }
   FPageFooterYPos := FRTPage.RTLayout.Top + FRTPage.RTLayout.Height;
   { page footer }
   HandleFooterBands;
+  { column footers }
+  HandleRTColumnFooterBands;
   { bottom stacked footers }
+  // ToDo: make them work in Multicolumn mode
   for i:=FBottomStackedFooterList.Count-1 downto 0 do
   begin
     lFooter := TFPReportCustomGroupFooterBand(FBottomStackedFooterList[i]);
@@ -9787,56 +9768,17 @@ begin
   FBottomStackedFooterList.Clear;
 end;
 
-
 procedure TFPReportLayouter.StartNewColumn;
-
-var
-  lIdx: integer;
-  lBandCount: integer;
-  lBand: TFPReportCustomBand;
-  lOverflowBand: TFPReportCustomBand;
-
 begin
+  { prepare next column/page }
   if Assigned(FLastDsgnDataBand) then
     report.ClearDataBandLastTextValues(FLastDsgnDataBand);
-  if FMultiColumn and (FFooterList.Find(TFPReportCustomColumnFooterBand) <> nil) then
-    lBandCount := FRTPage.BandCount - 2  // skip over the ColumnFooter band
-  else
-    lBandCount := FRTPage.BandCount - 1;
-  lOverflowBand := FRTPage.Bands[lBandCount]; { store reference to band that caused the new column }
-  FSpaceLeft := Pages[PageIdx].Layout.Height; // original designer page
-  FRTPage := TFPReportCustomPage(RTObjects[RTCurPageIdx]);
-  FLastYPos := FRTPage.RTLayout.Top;
-  FLastXPos := FLastXPos + lOverflowBand.RTLayout.Width + Pages[PageIdx].ColumnGap;
-  { Adjust starting Y-Pos based on bands in lHeaderList. }
-  for lIdx := 0 to FHeaderList.Count-1 do
-    begin
-    lBand := FHeaderList[lIdx];
-    if lBand is TFPReportCustomPageHeaderBand then
-      begin
-      if MaybeSkipBand(lBand) then
-        Continue;
-      end
-    else if lBand is TFPReportCustomColumnHeaderBand then
-      begin
-      if ShowColumnHeaderBand(lBand) then
-        Continue;
-      end;
-    UpdateSpaceRemaining(lBand,True);
-    end;
+  FLastYPos := FColumnYStartPos;
+  FSpaceLeft := Pages[RTCurDsgnPageIdx].Layout.Height - (FColumnYStartPos - Pages[RTCurDsgnPageIdx].Layout.Top);
   inc(FCurrentColumn);
-  { If footer band exists, reduce available space }
-  lBand := FRTPage.FindBand(TFPReportCustomPageFooterBand);
-  if Assigned(lBand) then
-    UpdateSpaceRemaining(lBand, False);
-
-  if NoSpaceRemaining then
-    Exit;
-  { Fix position of last band that caused the new column }
-  lOverflowBand.RTLayout.Left := FLastXPos;
-  lOverflowBand.RTLayout.Top := FLastYPos;
-  { Adjust the next starting point of the next data band. }
-  UpdateSpaceRemaining(lOverflowBand);
+  { print column header }
+  if Assigned(FColumnHeader) then
+    ShowBandWithChilds(FColumnHeader);
   FNewColumn := False;
 end;
 
@@ -9864,42 +9806,22 @@ begin
   UpdateSpaceRemaining(lOverflowBand);
 end;
 
-procedure TFPReportLayouter.ShowFooterBand(aBand: TFPReportCustomPageFooterBand);
-
-var
-  lRTBand: TFPReportCustomBand;
-
+procedure TFPReportLayouter.PrepareHeader(APage: TFPReportCustomPage);
 begin
-  FPageFooterYPos := -1;
-  if MaybeSkipBand(aBand) then
-    Exit;
-  lRTBand := TFPReportCustomBand(aBand.PrepareObject(FRTPage));
-  lRTBand.RecalcLayout;
-  lRTBand.BeforePrint;
-  lRTBand.RTLayout.Top := (FRTPage.RTLayout.Top + FRTPage.RTLayout.Height) - lRTBand.RTLayout.Height;
-  FPageFooterYPos := lRTBand.RTLayout.Top;
-  // We don't adjust lLastYPos because this is a page footer
-  UpdateSpaceRemaining(lRTBand, False);
-end;
-
-procedure TFPReportLayouter.PopulateHeaderList(APage: TFPReportCustomPage);
-
-begin
-  FHeaderList.Clear;
-  FHeaderList.Add(APage.FindBand(TFPReportCustomPageHeaderBand));
-  FHeaderList.Add(APage.FindBand(TFPReportCustomTitleBand));
+  FTitle := TFPReportCustomTitleBand(APage.FindBand(TFPReportCustomTitleBand));
+  FPageHeader := TFPReportCustomPageHeaderBand(APage.FindBand(TFPReportCustomPageHeaderBand));
   if FMultiColumn then
-    FHeaderList.Add(Pages[PageIdx].FindBand(TFPReportColumnHeaderBand));
+    FColumnHeader := TFPReportColumnHeaderBand(Pages[RTCurDsgnPageIdx].FindBand(TFPReportColumnHeaderBand));
 end;
 
-procedure TFPReportLayouter.PopulateGroupList(APage: TFPReportCustomPage);
+procedure TFPReportLayouter.PrepareGroupHeader(APage: TFPReportCustomPage);
 
 var
   I: Integer;
   lGroup: TFPReportCustomGroupHeaderBand;
 
 begin
-  FGroupList.Clear;
+  FGroupHeaderList.Clear;
   lGroup := nil;
   // search for lowest group (without child group)
   for I:=0 to APage.BandCount-1 do
@@ -9916,7 +9838,7 @@ begin
   while Assigned(lGroup) do
   begin
     lGroup.ResetGroupConditionValues;
-    FGroupList.Add(lGroup);
+    FGroupHeaderList.Add(lGroup);
     if Assigned(lGroup.GroupFooter) then
       FHasGroupFooter := true;
     lGroup := lGroup.ParentGroupHeader;
@@ -9980,8 +9902,7 @@ begin
         lBand:=TFPReportCustomBand(lFooter.PrepareObject(FRTPage));
         try
           lBand.BeforePrint;
-          if not MaybeSkipBand(lBand) and
-          lBand.EvaluateVisibility then begin
+          if lBand.EvaluateVisibility then begin
             lValue := lValue + lBand.RTLayout.Height;
             Result := Result + lBand.RTLayout.Height;
           end;
@@ -9993,9 +9914,31 @@ begin
       end;
       Report.FRTInIntermediateGroupFooter := False;
     finally
-      //write(FormatFloat('#,##0.0', lValue),' ');
+      //write('GF:',FormatFloat('#,##0.0', lValue),' ');
     end;
   end;
+  if Assigned(FColumnFooter) then
+  begin
+    lValue := 0;
+    lFooter := FColumnFooter;
+    while Assigned(lFooter) do
+    begin
+      lBand:=TFPReportCustomBand(lFooter.PrepareObject(FRTPage));
+      try
+        lBand.BeforePrint;
+        if lBand.EvaluateVisibility then begin
+          lValue := lValue + lBand.RTLayout.Height;
+          Result := Result + lBand.RTLayout.Height;
+        end;
+        lFooter := lFooter.ChildBand;
+      finally
+        lBand.Page.RemoveChild(lBand);
+        lBand.Free;
+      end;
+    end;
+    //write('CF:',FormatFloat('#,##0.0', lValue),' ');
+  end;
+
   //Write(' = ',FormatFloat('#,##0.0', Result));
 end;
 
@@ -10009,11 +9952,21 @@ begin
   Result:=Report.Pages[AIndex];
 end;
 
+function TFPReportLayouter.GetRTCurDsgnPageIdx: Integer;
+begin
+  Result := Report.FRTCurDsgnPageIdx;
+end;
+
 function TFPReportLayouter.GetPageNumberPerDesignerPage: Integer;
 begin
   Result:=Report.FPageNumberPerDesignerPage;
 end;
 
+procedure TFPReportLayouter.SetRTCurDsgnPageIdx(pPageIdx: Integer);
+begin
+  Report.FRTCurDsgnPageIdx := pPageIdx;
+end;
+
 function TFPReportLayouter.IsFirstPass: Boolean;
 begin
   Result:=Report.IsFirstPass;
@@ -10024,7 +9977,7 @@ begin
   Result:=Report.TwoPass;
 end;
 
-procedure TFPReportLayouter.PopulateFooterList(APage: TFPReportCustomPage);
+procedure TFPReportLayouter.PrepareFooter(APage: TFPReportCustomPage);
 
 var
   i: Integer;
@@ -10034,13 +9987,15 @@ begin
   FFooterList.Clear;
   FFooterList.Add(APage.FindBand(TFPReportCustomPageFooterBand));
   { add group footers that have to be printed on every page }
-  for i:=FGroupList.Count-1 downto 0 do
+  for i:=FGroupHeaderList.Count-1 downto 0 do
   begin
-    lGrp:=TFPReportCustomGroupHeaderBand(FGroupList[i]);
+    lGrp:=TFPReportCustomGroupHeaderBand(FGroupHeaderList[i]);
     if Assigned(lGrp.GroupFooter) and
     lGrp.FIntermediateFooter then
       FFooterList.Add(lGrp.GroupFooter);
   end;
+  if FMultiColumn then
+    FColumnFooter := TFPReportColumnFooterBand(Pages[RTCurDsgnPageIdx].FindBand(TFPReportColumnFooterBand));
 end;
 
 procedure TFPReportLayouter.IncPageNumber;
@@ -10066,42 +10021,30 @@ begin
   { new page }
   if Assigned(FLastDsgnDataBand) then
     report.ClearDataBandLastTextValues(FLastDsgnDataBand);
-  FSpaceLeft := Pages[PageIdx].Layout.Height; // original designer page
+  FSpaceLeft := Pages[RTCurDsgnPageIdx].Layout.Height; // original designer page
 
-  FRTPage := TFPReportCustomPage(Pages[PageIdx].PrepareObject(nil));
+  FRTPage := TFPReportCustomPage(Pages[RTCurDsgnPageIdx].PrepareObject(nil));
   Report.FRTCurPageIdx := Report.RTObjects.Add(FRTPage);
 
   FLastYPos := FRTPage.RTLayout.Top;
   FLastXPos := FRTPage.RTLayout.Left;
+  FCurrentColumn := 0;
   IncPageNumber;
-  FCurrentColumn := 1;
-  FNewColumn := False;
   if IsFirstPass then
-    PerDesignerPageCount[PageIdx] := PerDesignerPageCount[PageIdx] + 1;
+    PerDesignerPageCount[RTCurDsgnPageIdx] := PerDesignerPageCount[RTCurDsgnPageIdx] + 1;
   if (PageNumberPerDesignerPage = 1) then
-    RemoveTitleBandFromHeaderList;
+    { remove title band }
+    FTitle := nil;
   IncPageNumberPerDesignerPage;
-  HandleHeaderBands;
+  if HandleHeaderBands then
+    exit;
+  FColumnYStartPos := FLastYPos;
+  StartNewColumn;
   HandleRepeatedGroupHeaderBands;
   FNewPage := False;
   FPageDetailsPrinted := False;
 end;
 
-procedure TFPReportLayouter.CheckRemaining(CheckMulticolumn: Boolean);
-
-begin
-  if NoSpaceRemaining then
-    begin
-    if CheckMulticolumn and FMultiColumn then
-      begin
-      FCurrentRTColumnFooterBand := TFPReportCustomColumnFooterBand(FFooterList.Find(TFPReportCustomColumnFooterBand));
-      if Assigned(FCurrentRTColumnFooterBand) then
-        ShowColumnFooterBand(FRTPage, FCurrentRTColumnFooterBand);
-      end;
-    CheckNewOrOverFlow(CheckMulticolumn);
-    end;
-end;
-
 procedure TFPReportLayouter.ShowDataBand(const aBand: TFPReportCustomDataBand);
 begin
   FLastDsgnDataBand := aBand;
@@ -10109,38 +10052,14 @@ begin
     FPageDetailsPrinted := True;
 end;
 
-function TFPReportLayouter.HandleBandVisibility(aBand: TFPReportCustomBand; doRecalcLayout: Boolean): Boolean;
-
-begin
-  Result:=aBand.EvaluateVisibility;
-  if Result then
-    begin
-    if DoRecalcLayout then
-      RecalcBandLayout(aBand);
-    UpdateSpaceRemaining(aBand);
-    CheckRemaining(True);
-    end
-  else
-    begin
-    // remove invisible band
-    FRTPage.RemoveChild(aBand);
-    FreeAndNil(aBand);
-    end;
-end;
-
 procedure TFPReportLayouter.ShowDataHeaderBand(const aBand: TFPReportCustomDataHeaderBand);
 begin
   if FDataHeaderPrinted then
     Exit; // nothing further to do
-  if HandleBandVisibility(CommonRuntimeBandProcessing(aBand),False) then
+  if ShowBandWithChilds(aBand) then
     FDataHeaderPrinted := True;
 end;
 
-procedure TFPReportLayouter.ShowDataFooterBand(const aBand: TFPReportCustomDataFooterBand);
-begin
-  HandleBandVisibility(CommonRuntimeBandProcessing(aBand),False);
-end;
-
 procedure TFPReportLayouter.ShowDetailBand(const AMasterBand: TFPReportCustomDataBand);
 
 var
@@ -10157,9 +10076,9 @@ begin
   lDetailBandList := TBandList.Create;
   try
     { collect bands of interest }
-    for i := 0 to Pages[PageIdx].BandCount-1 do
+    for i := 0 to Pages[RTCurDsgnPageIdx].BandCount-1 do
       begin
-      lDetailBand := Pages[PageIdx].Bands[i];
+      lDetailBand := Pages[RTCurDsgnPageIdx].Bands[i];
       if (lDetailBand is TFPReportCustomDataBand)
         and (TFPReportCustomDataBand(lDetailBand).MasterBand = AMasterBand)
         and (TFPReportCustomDataBand(lDetailBand).Data <> nil) then
@@ -10176,8 +10095,8 @@ begin
       if not lData.IsOpened then
         begin
         lData.Open;
-        Report.InitializeExpressionVariables(Pages[PageIdx], lData);
-        Report.CacheMemoExpressions(PageIdx, lData);
+        Report.InitializeExpressionVariables(Pages[RTCurDsgnPageIdx], lData);
+        Report.CacheMemoExpressions(RTCurDsgnPageIdx, lData);
         end;
       lData.First;
       if (not lData.EOF) and (lDsgnDetailBand.HeaderBand <> nil) then
@@ -10196,7 +10115,7 @@ begin
       CheckNewOrOverFlow;
       // only print if we actually had data
       if (lData.RecNo > 1) and (lDsgnDetailBand.FooterBand <> nil) then
-        ShowDataFooterBand(lDsgnDetailBand.FooterBand);
+        ShowBandWithChilds(lDsgnDetailBand.FooterBand);
       lDsgnDetailBand := nil;
       end;
   finally
@@ -10215,9 +10134,9 @@ begin
   lGroupChanged := false;
   lHighestGroupWithChange := 0;
   // process footers
-  For I := 0 to FGroupList.Count - 1 do
+  For I := 0 to FGroupHeaderList.Count - 1 do
   begin
-    lGroup := TFPReportCustomGroupHeaderBand(FGroupList[I]);
+    lGroup := TFPReportCustomGroupHeaderBand(FGroupHeaderList[I]);
     if lGroup.GroupChanged then
     begin
       lGroupChanged := true;
@@ -10239,7 +10158,7 @@ begin
   // process headers
   For I := lHighestGroupWithChange downto 0 do
   begin
-    lGroup := TFPReportCustomGroupHeaderBand(FGroupList[I]);
+    lGroup := TFPReportCustomGroupHeaderBand(FGroupHeaderList[I]);
     ShowGroupHeaderBand(lGroup, True);
   end;
 end;
@@ -10263,9 +10182,9 @@ begin
         ShowDataHeaderBand(D.HeaderBand);
       ShowDataBand(D);
       { set DetailsPrinted in all groups }
-      for j := 0 to FGroupList.Count-1 do
+      for j := 0 to FGroupHeaderList.Count-1 do
       begin
-        TFPReportCustomGroupHeaderBand(FGroupList[j]).FDetailsPrinted := True;
+        TFPReportCustomGroupHeaderBand(FGroupHeaderList[j]).FDetailsPrinted := True;
       end;
       ShowDetailBand(D);
       dec(FDataLevelStack);
@@ -10280,9 +10199,9 @@ Var
   lBand: TFPReportCustomGroupFooterBand;
 
 begin
-  for I := 0 to FGroupList.Count-1 do
+  for I := 0 to FGroupHeaderList.Count-1 do
   begin
-    lBand := TFPReportCustomGroupHeaderBand(FGroupList[I]).GroupFooter;
+    lBand := TFPReportCustomGroupHeaderBand(FGroupHeaderList[I]).GroupFooter;
     if Assigned(lBand) then
       ShowGroupFooterBand(lBand);
   end;
@@ -10303,11 +10222,11 @@ Var
 
 begin
   // Create a list of bands that need to be printed as page headers
-  PopulateHeaderList(aPage);
+  PrepareHeader(aPage);
   // Create a list of group headers
-  PopulateGroupList(aPage);
+  PrepareGroupHeader(aPage);
   // Create a list of bands that need to be printed as page footers
-  PopulateFooterList(aPage);
+  PrepareFooter(aPage);
   // find Bands of interest
   ClearBandList;
   for I := 0 to aPage.BandCount-1 do
@@ -10362,21 +10281,22 @@ begin
   if not aPageData.IsOpened then
     aPageData.Open;
   if IsFirstPass then
-    begin
+  begin
     Report.InitializeExpressionVariables(Pages[aPageIdx], aPageData);
     Report.CacheMemoExpressions(aPageIdx, aPageData);
-    end;
+  end;
   aPageData.First;
   InitBandList(Pages[aPageIdx],aPageData);
   while not aPageData.EOF do
-    begin
+  begin
     PrepareRecord;
-    CheckNewOrOverFlow(True);
+    if FNewPage then
+      StartNewPage;
     if FHasGroups then
       HandleGroupBands;
     HandleDataBands;
     aPageData.Next;
-    end;
+  end;
   PrepareRecord;
   CheckNewOrOverFlow(True);
   // only print if we actually had data
@@ -10387,18 +10307,9 @@ begin
       lBand := TFPReportCustomBand(Report.FBands[I]);
       if lBand is TFPReportCustomDataBand then
         if TFPReportCustomDataBand(lBand).FooterBand <> nil then
-          ShowDataFooterBand(TFPReportCustomDataBand(lBand).FooterBand);
+          ShowBandWithChilds(TFPReportCustomDataBand(lBand).FooterBand);
       end;
     end;
-  { Process ColumnFooterBand as needed }
-  if FMultiColumn then
-    begin
-    FCurrentRTColumnFooterBand:= TFPReportCustomColumnFooterBand(FFooterList.Find(TFPReportCustomColumnFooterBand));
-    if Assigned(FCurrentRTColumnFooterBand) then
-      ShowColumnFooterBand(FRTPage, FCurrentRTColumnFooterBand);
-    end;
-  { ColumnFooter could have caused a new column or page }
-  CheckNewOrOverFlow(True);
   if FHasGroupFooter then
     HandleLastGroupFooters;
   aPageData.Close;
@@ -10407,8 +10318,8 @@ end;
 procedure TFPReportLayouter.PrepareRecord;
 begin
   Report.Variables.PrepareExpressionValues;
-  if FGroupList.Count > 0 then
-    TFPReportCustomGroupHeaderBand(FGroupList[0]).EvaluateGroupCondition;
+  if FGroupHeaderList.Count > 0 then
+    TFPReportCustomGroupHeaderBand(FGroupHeaderList[0]).EvaluateGroupCondition;
 end;
 
 procedure TFPReportLayouter.InitPass(aPassIdx: Integer);
@@ -10416,9 +10327,8 @@ procedure TFPReportLayouter.InitPass(aPassIdx: Integer);
 begin
   Report.FIsFirstPass := (aPassIdx = 1);
   Report.EmptyRTObjects;
-  FHeaderList.Clear;
   FFooterList.Clear;
-  FGroupList.Clear;
+  FGroupHeaderList.Clear;
   ClearBandList;
   InitRTCurPageIdx;
   FOverflowed := False;
@@ -10435,7 +10345,7 @@ end;
 procedure TFPReportLayouter.InitDesignPage(aPageIdx: integer);
 
 begin
-  FPageIdx:=aPageIdx;
+  RTCurDsgnPageIdx:=aPageIdx;
   FMultiColumn := Pages[aPageIdx].ColumnCount > 1;
   PageNumberPerDesignerPage := 0;
   FFoundDataBand := False;
@@ -10443,8 +10353,9 @@ begin
   FNewPage := True;
   FCurrentColumn := 1;
   FNewColumn := False;
-  FPageFooterYPos := -1;
-
+  FRTPage := nil;
+  FColumnHeader := nil;
+  FColumnFooter := nil;
 end;
 
 procedure TFPReportLayouter.HandleReportSummaryBands;
@@ -10455,21 +10366,18 @@ Var
 
 begin
   for I:=0 to Report.FBands.Count-1 do
-    begin
+  begin
     lBand := TFPReportCustomBand(Report.FBands[I]);
     if lBand is TFPReportCustomSummaryBand then
-      begin
+    begin
       { We are allowed to use design Layout.Height instead of RTLayout.Height
         because this band appears outside the data loop, thus memos will not
         grow. Height of the band is as it was at design time. }
-      if (TFPReportCustomSummaryBand(lBand).StartNewPage) or (lBand.Layout.Height > FSpaceLeft) then
+      if (TFPReportCustomSummaryBand(lBand).StartNewPage) or (lBand.Layout.Height > (FSpaceLeft - FooterSpaceNeeded)) then
         StartNewPage;
-      { Restore reference to lDsgnBand and SummaryBand, because StartNewPage
-        could have changed the value of lDsgnBand. }
-      lBand := TFPReportCustomBand(Report.FBands[I]);
-      UpdateSpaceRemaining(CommonRuntimeBandProcessing(lBand));
-      end;
+      ShowBandWithChilds(lBand);
     end;
+  end;
 end;
 
 procedure TFPReportLayouter.ShowGroupHeaderBand(
@@ -10500,43 +10408,50 @@ var
   lStartAgain, lSameBandAgain: Boolean;
   j: Integer;
   lGrp, lToMoveGrp: TFPReportCustomGroupHeaderBand;
+  lColumnYStartPos: TFPReportUnits;
 
   procedure HandleOverflowedBands;
 
   var
     i: Integer;
+    lBand2: TFPReportCustomBand;
 
   begin
-    if FOverflowed then
+    if FNewColumn or
+    FOverflowed then
     begin
+      EndColumn;
       if aBand.KeepTogetherWithChildren then
       begin
-        { complete band with child bands move to next page}
+        { complete band with child bands move to next column/page }
         lStartAgain := True;
-        { remove all overflowed bands and start again on new page }
+        if FNewColumn then
+          { calc x pos of next column }
+          FLastXPos := FLastXPos + lHandledBands[0].RTLayout.Width + Pages[RTCurDsgnPageIdx].ColumnGap;
+        { remove all overflowed bands and start again on new column/page }
         for i := 0 to lHandledBands.Count-1 do
         begin
-          lBand := lHandledBands[i];
+          lBand2 := lHandledBands[i];
           { remove band from current page }
-          lBand.Page.RemoveChild(lBand);
+          lBand2.Page.RemoveChild(lBand2);
           { correct LastYPos }
-          FLastYPos := FLastYPos - lBand.RTLayout.Height;
+          FLastYPos := FLastYPos - lBand2.RTLayout.Height;
           { free mem }
-          lBand.Free;
+          lBand2.Free;
         end;
         lHandledBands.Clear;
-        //writeln('   complete move to next page');
+        //writeln('   complete move to next column/page');
         { notify band }
         aBand.MovedToNextPageWithChilds;
 
         { if OverflowWithFirstDataBand is set,
-          also move header to next page          }
-        if FGroupList.Count > 0 then
+          also move header to next column/page }
+        if FGroupHeaderList.Count > 0 then
         begin
           { when data band overflows use start with lowest gropup header }
           if aBand is TFPReportCustomDataBand and
           not Assigned(TFPReportCustomDataBand(aband).MasterBand) then
-            lToMoveGrp := TFPReportCustomGroupHeaderBand(FGroupList[0])
+            lToMoveGrp := TFPReportCustomGroupHeaderBand(FGroupHeaderList[0])
           { when group header overflows use start with parent group header }
           else if aBand is TFPReportCustomGroupHeaderBand then
             lToMoveGrp := TFPReportCustomGroupHeaderBand(aBand).ParentGroupHeader;
@@ -10551,18 +10466,18 @@ var
               { remove RT bands of group from current page }
               for i := 0 to lGrp.FRTBands.Count - 1 do
               begin
-                lBand := lGrp.FRTBands[i];
+                lBand2 := lGrp.FRTBands[i];
                 { remove band from current page }
-                lBand.Page.RemoveChild(lBand);
+                lBand2.Page.RemoveChild(lBand2);
                 { correct LastYPos }
-                FLastYPos := FLastYPos - lBand.RTLayout.Height;
+                FLastYPos := FLastYPos - lBand2.RTLayout.Height;
                 { free mem }
-                lBand.Free;
+                lBand2.Free;
               end;
               lGrp.FRTBands.Clear;
               { mark group as completed -> no intermediate footer needed on
-                current page and no reprinted header needed
-                as following group header will start on new page             }
+                current column/page and no reprinted header needed
+                as following group header will start on new column/page     }
               lGrp.FNeedsIntermediateFooter := False;
               lGrp.FNeedsReprintedHeader := False;
             end;
@@ -10573,8 +10488,11 @@ var
       end
       else
       begin
-        { only current band moves to next page}
+        { only current band moves to next column/page }
         lSameBandAgain := True;
+        If FNewColumn then
+          { calc x pos of next column }
+          FLastXPos := FLastXPos + lRTBand.RTLayout.Width + Pages[RTCurDsgnPageIdx].ColumnGap;
         { remove band from current page }
         lRTBand.Page.RemoveChild(lRTBand);
         { correct LastYPos }
@@ -10585,7 +10503,10 @@ var
       end;
       { set state variable }
       aBand.FIsOverflowed := True;
-      { do not handle overflowe in CheckNewOrOverFlow }
+      { handle new column }
+      if FNewColumn then
+        StartNewColumn;
+      { do not handle overflow in CheckNewOrOverFlow }
       FOverflowed := False;
     end;
   end;
@@ -10598,9 +10519,9 @@ var
     { reprint moved headers only (not overflowed ones) }
     if Assigned(lToMoveGrp) then
     begin
-      for i := FGroupList.Count-1 downto 0 do
+      for i := FGroupHeaderList.Count-1 downto 0 do
       begin
-        lGrp := TFPReportCustomGroupHeaderBand(FGroupList[i]);
+        lGrp := TFPReportCustomGroupHeaderBand(FGroupHeaderList[i]);
         if lGrp.OverflowWithFirstDataBand and
         not lGrp.FDetailsPrinted then
         begin
@@ -10656,7 +10577,8 @@ begin
           if NoSpaceRemaining then
           begin
             HandleOverflowedBands;
-            CheckNewOrOverFlow;
+            if FNewPage then
+              StartNewPage;
             HandleMovedGroupHeaders;
           end;
           if lStartAgain then
@@ -10685,24 +10607,6 @@ begin
   end;
 end;
 
-procedure TFPReportLayouter.RecalcBandLayout(ABand: TFPReportCustomBand);
-
-var
-  i: integer;
-  e: TFPReportElement;
-
-begin
-  for i := ABand.ChildCount-1 downto 0 do
-  begin
-    e := ABand.Child[i];
-    if not e.EvaluateVisibility then
-    begin
-      ABand.RemoveChild(e);
-      FreeAndNil(e);
-    end;
-  end;
-end;
-
 procedure TFPReportLayouter.DoExecute;
 
 Var
@@ -10741,24 +10645,23 @@ begin
 end;
 
 procedure TFPReportLayouter.Execute(aReport: TFPCustomReport);
-
 begin
-  FHeaderList := Nil;
   FFooterList := Nil;
-  FGroupList := Nil;
+  FGroupHeaderList := Nil;
   FBottomStackedFooterList := nil;
+  FRTColumnFooterList := nil;
   FmyReport:=AReport;
   try
-    FHeaderList := TBandList.Create;
     FFooterList := TBandList.Create;
-    FGroupList := TBandList.Create;
+    FGroupHeaderList := TBandList.Create;
     FBottomStackedFooterList := TBandList.Create;
+    FRTColumnFooterList := TBandList.Create;
     DoExecute;
   finally
-    FreeAndNil(FGroupList);
-    FreeAndNil(FHeaderList);
+    FreeAndNil(FGroupHeaderList);
     FreeAndNil(FFooterList);
     FreeAndNil(FBottomStackedFooterList);
+    FreeAndNil(FRTColumnFooterList);
     FMyReport:=Nil; // Don't free :)
   end;
 end;