www.pudn.com > TeeChart_Pro_v7_0_VCL_CLX_for_Delphi_BCB_Kylix_Ful > DBChart.pas


{******************************************} 
{ TDBChart Component                       } 
{ Copyright (c) 1995-2004 by David Berneda } 
{ All rights Reserved                      } 
{******************************************} 
unit DBChart; 
{$I TeeDefs.inc} 
 
interface 
 
uses 
  {$IFNDEF LINUX} 
  Windows, Messages, 
  {$ENDIF} 
  SysUtils, Classes, 
  {$IFDEF CLX} 
  QGraphics, QControls, QMenus, QForms, QDialogs, QExtCtrls, QStdCtrls, 
  {$ELSE} 
  Graphics, Controls, Menus, Forms, Dialogs, ExtCtrls, StdCtrls, 
  {$ENDIF} 
  Chart, DB, TeeProcs, TeCanvas, TeEngine; 
 
type 
  DBChartException=class(Exception); 
 
  TTeeDBGroup=(dgHour,dgDay,dgWeek,dgWeekDay,dgMonth,dgQuarter,dgYear,dgNone); 
 
  TListOfDataSources=class(TList) 
  private 
    procedure Put(Index:Integer; Value:TDataSource); 
    function Get(Index:Integer):TDataSource; 
  public 
    Procedure Clear; override; 
    property DataSource[Index:Integer]:TDataSource read Get write Put; default; 
  end; 
 
  TCustomDBChart=class; 
 
  TProcessRecordEvent=Procedure(Sender:TCustomDBChart; DataSet:TDataSet) of object; 
 
  TCustomDBChart = class(TCustomChart) 
  private 
    FAutoRefresh     : Boolean; 
    FRefreshInterval : Integer; 
    FShowGlassCursor : Boolean; 
    FOnProcessRecord : TProcessRecordEvent; 
    { internal } 
    IUpdating        : Boolean; 
    ITimer           : TTimer; 
    IDataSources     : TListOfDataSources; 
    Procedure DataSourceCheckDataSet(ADataSet:TDataSet); 
    Procedure DataSourceCloseDataSet(ADataSet:TDataSet); 
    Procedure CheckDataSet(ADataSet:TDataSet; ASeries:TChartSeries=nil); 
    Procedure CheckNewDataSource(ADataSet:TDataSet; SingleRow:Boolean); 
    Procedure SetRefreshInterval(Value:Integer); 
    Procedure CheckTimer; 
    Procedure OnRefreshTimer(Sender:TObject); 
  protected 
    procedure RemovedDataSource( ASeries: TChartSeries; 
                                 AComponent: TComponent ); override; 
  public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    Procedure Assign(Source:TPersistent); override; 
    Procedure CheckDatasource(ASeries:TChartSeries); override; 
    Function IsValidDataSource(ASeries:TChartSeries; AComponent:TComponent):Boolean; override; 
 
    Procedure FillValueSourceItems( AValueList:TChartValueList; Proc:TGetStrProc); override; 
    Procedure FillSeriesSourceItems( ASeries:TChartSeries; Proc:TGetStrProc); override; 
 
    Procedure RefreshDataSet(ADataSet:TDataSet; ASeries:TChartSeries); 
    Procedure RefreshData; 
    { properties } 
    property AutoRefresh:Boolean read FAutoRefresh write FAutoRefresh default True; 
    property RefreshInterval:Integer read FRefreshInterval write SetRefreshInterval default 0; 
    property ShowGlassCursor:Boolean read FShowGlassCursor write FShowGlassCursor default True; 
    { events } 
    property OnProcessRecord:TProcessRecordEvent read FOnProcessRecord 
                                                 write FOnProcessRecord; 
  published 
  end; 
 
  TDBChart=class(TCustomDBChart) 
  published 
    { TCustomDBChart properties } 
    property AutoRefresh; 
    property RefreshInterval; 
    property ShowGlassCursor; 
    { TCustomDBChart events } 
    property OnProcessRecord; 
 
    { TCustomChart Properties } 
    property AllowPanning; 
    property BackImage; 
    property BackImageInside; 
    property BackImageMode; 
    property BackImageTransp; 
    property BackWall; 
    property Border; 
    property BorderRound; 
    property BottomWall; 
    property Foot; 
    property Gradient; 
    property LeftWall; 
    property MarginBottom; 
    property MarginLeft; 
    property MarginRight; 
    property MarginTop; 
    property MarginUnits; 
    property PrintProportional; 
    property RightWall; 
    property SubFoot; 
    property SubTitle; 
    property Title; 
 
    { TCustomChart Events } 
    property OnAllowScroll; 
    property OnClickAxis; 
    property OnClickBackground; 
    property OnClickLegend; 
    property OnClickSeries; 
    property OnClickTitle; 
    property OnGetLegendPos; 
    property OnGetLegendRect; 
    property OnScroll; 
    property OnUndoZoom; 
    property OnZoom; 
 
    { TCustomAxisPanel properties } 
    property AxisBehind; 
    property AxisVisible; 
    property BottomAxis; 
    property Chart3DPercent; 
    property ClipPoints; 
    property CustomAxes; 
    property DepthAxis; 
    property DepthTopAxis; 
    property Frame; 
    property LeftAxis; 
    property Legend; 
    property MaxPointsPerPage; 
    property Monochrome; 
    property Page; 
    property RightAxis; 
    property ScaleLastPage; 
    property SeriesList; 
    property Shadow; 
    property TopAxis; 
    property View3D; 
    property View3DOptions; 
    property View3DWalls; 
    property Zoom; 
 
    { TCustomAxisPanel events } 
    property OnAfterDraw; 
    property OnBeforeDrawAxes; 
    property OnBeforeDrawChart; 
    property OnBeforeDrawSeries; 
    property OnGetAxisLabel; 
    property OnGetLegendText; 
    property OnGetNextAxisLabel; 
    property OnPageChange; 
 
    { TPanel properties } 
    property Align; 
    property BevelInner; 
    property BevelOuter; 
    property BevelWidth; 
 
    {$IFDEF CLX} 
    property Bitmap; 
    {$ENDIF} 
 
    property BorderWidth; 
    property Color; 
    {$IFNDEF CLX} 
    property DragCursor; 
    {$ENDIF} 
    property DragMode; 
    property Enabled; 
    property ParentColor; 
    property ParentShowHint; 
    property PopupMenu; 
    property ShowHint; 
    property TabOrder; 
    property TabStop; 
    property Visible; 
    property Anchors; 
    {$IFNDEF CLX} 
    property AutoSize; 
    {$ENDIF} 
    property Constraints; 
    {$IFNDEF CLX} 
    property DragKind; 
    property Locked; 
    {$ENDIF} 
 
    { TPanel events } 
    property OnClick; 
    {$IFDEF D5} 
    property OnContextPopup; 
    {$ENDIF} 
    property OnDblClick; 
    property OnDragDrop; 
    property OnDragOver; 
    property OnEndDrag; 
    property OnStartDrag; 
    property OnEnter; 
    property OnExit; 
    property OnKeyDown; 
    property OnKeyPress; 
    property OnKeyUp; 
    property OnMouseDown; 
    property OnMouseMove; 
    property OnMouseUp; 
    property OnMouseWheel; 
    property OnMouseWheelDown; 
    property OnMouseWheelUp; 
    property OnResize; 
    {$IFNDEF CLX} 
    property OnCanResize; 
    {$ENDIF} 
    property OnConstrainedResize; 
    {$IFNDEF CLX} 
    property OnDockDrop; 
    property OnDockOver; 
    property OnEndDock; 
    property OnGetSiteInfo; 
    property OnStartDock; 
    property OnUnDock; 
    {$ENDIF} 
 
    {$IFDEF K3} 
    property OnMouseEnter; 
    property OnMouseLeave; 
    {$ENDIF} 
  end; 
 
  TTeeFieldType=(tftNumber,tftDateTime,tftText,tftNone); 
 
{ given a VCL "database field type", this function returns 
  a more simplified "type": (number, date, text) } 
Function TeeFieldType(AType:TFieldType):TTeeFieldType; 
 
{ Returns the ISO- Week number (from 1 to 52) of a given "ADate" parameter, 
  and decrements "Year" if it's the first week of the year. } 
Function DateToWeek(ADate:TDateTime; Var Year:Word):Integer; 
 
{ same as DateToWeek, using a different algorithm 
  (compatible with TeeChart version 4 } 
Function DateToWeekOld(Const ADate:TDateTime; Var Year:Word):Integer; 
 
{ internal, used by DBChart Summary feature } 
Function TeeGetDBPart(Num:Integer; St:String):String; 
Function StrToDBGroup(St:String):TTeeDBGroup; 
Function StrToDBOrder(St:String):TChartListOrder; 
 
type 
  TCheckDataSetEvent=procedure(DataSet:TDataSet) of object; 
 
  TDBChartDataSource=class(TDataSource) 
  private 
    FDBChart   : TCustomDBChart; 
    FWasActive : Boolean; 
    Procedure DataSourceRowChange(Sender:TObject; Field:TField); 
    Procedure DataSourceStateChange(Sender:TObject); 
    Procedure DataSourceUpdateData(Sender:TObject); 
  protected 
    OnCheckDataSet : TCheckDataSetEvent; 
    OnCloseDataSet : TCheckDataSetEvent; 
    Procedure SetDataSet(Value:TDataSet; SingleRow:Boolean=False); 
  end; 
 
Procedure FillDataSetFields(DataSet:TDataSet; Proc:TGetStrProc); 
 
implementation 
 
Uses TeeConst, TypInfo; 
 
{$IFDEF CLR} 
type 
  TBookMark=IntPtr;  // Pending fix in Borland.VclDBRtl.dll 
{$ENDIF} 
 
{ TDBChartDataSource } 
Procedure TDBChartDataSource.SetDataSet(Value:TDataSet; SingleRow:Boolean=False); 
Begin 
  DataSet:=Value; 
  FWasActive:=DataSet.Active; 
 
  {$IFDEF CLR} 
  Include(OnStateChange,DataSourceStateChange); 
  Include(OnUpdateData,DataSourceUpdateData); 
  if SingleRow then Include(OnDataChange,DataSourceRowChange); 
 
  {$ELSE} 
 
  OnStateChange:=DataSourceStateChange; 
  OnUpdateData:=DataSourceUpdateData; 
  if SingleRow then OnDataChange:=DataSourceRowChange; 
  {$ENDIF} 
end; 
 
Procedure TDBChartDataSource.DataSourceRowChange(Sender:TObject; Field:TField); 
begin 
  if Assigned(FDBChart) then 
     if not FDBChart.IUpdating then 
        With TDBChartDataSource(Sender) do OnCheckDataSet(DataSet); 
end; 
 
Procedure TDBChartDataSource.DataSourceUpdateData(Sender:TObject); 
Begin 
  With TDBChartDataSource(Sender) do 
  if State= {$IFDEF CLR}TDataSetState.{$ENDIF}dsBrowse then OnCheckDataSet(DataSet) 
                    else FWasActive:=False; 
End; 
 
Procedure TDBChartDataSource.DataSourceStateChange(Sender:TObject); 
Begin 
  With TDBChartDataSource(Sender) do 
  if State={$IFDEF CLR}TDataSetState.{$ENDIF}dsInactive then 
  Begin 
    FWasActive:=False; 
    if Assigned(OnCloseDataSet) then OnCloseDataSet(DataSet); 
  end 
  else 
  if (State={$IFDEF CLR}TDataSetState.{$ENDIF}dsBrowse) and (not FWasActive) then 
  Begin 
    OnCheckDataSet(DataSet); 
    FWasActive:=True; 
  end; 
end; 
 
{ TListOfDataSources } 
Procedure TListOfDataSources.Clear; 
var t : Integer; 
begin 
  for t:=0 to Count-1 do DataSource[t].Free; 
  inherited; 
end; 
 
procedure TListOfDataSources.Put(Index:Integer; Value:TDataSource); 
begin 
  inherited Items[Index]:=Value; 
end; 
 
function TListOfDataSources.Get(Index:Integer):TDataSource; 
begin 
  result:=TDataSource(inherited Items[Index]); 
end; 
 
{ TDBChart } 
Constructor TCustomDBChart.Create(AOwner: TComponent); 
begin 
  inherited; 
  IDataSources:=TListOfDataSources.Create; 
  FAutoRefresh:=True; 
  FShowGlassCursor:=True; 
  ITimer:=nil; 
  IUpdating:=False; 
end; 
 
Destructor TCustomDBChart.Destroy; 
begin 
  ITimer.Free; 
  IDataSources.Free; 
  inherited; 
end; 
 
// When "AComponent" source is removed from ASeries DataSourceList, 
// this method also removes AComponent from internal IDataSources list. 
procedure TCustomDBChart.RemovedDataSource( ASeries: TChartSeries; 
                                            AComponent: TComponent ); 
var t   : Integer; 
    tmp : TDataSet; 
begin 
  inherited; 
 
  if AComponent is TDataSet then 
  for t:=0 to IDataSources.Count-1 do 
  begin 
    tmp:=IDataSources[t].DataSet; 
    if (not Assigned(tmp)) or (tmp=AComponent) then 
    begin 
      IDataSources[t].Free; 
      IDataSources.Delete(t); 
      break; 
    end; 
  end; 
end; 
 
Procedure TCustomDBChart.CheckTimer; 
Begin 
  if Assigned(ITimer) then ITimer.Enabled:=False; 
  if (FRefreshInterval>0) and (not (csDesigning in ComponentState) ) then 
  Begin 
    if not Assigned(ITimer) then 
    Begin 
      ITimer:=TTimer.Create(Self); 
      ITimer.Enabled:=False; 
      ITimer.OnTimer:=OnRefreshTimer; 
    end; 
    ITimer.Interval:=FRefreshInterval*1000; 
    ITimer.Enabled:=True; 
  end; 
End; 
 
Procedure TCustomDBChart.OnRefreshTimer(Sender:TObject); 
var t : Integer; 
Begin 
  ITimer.Enabled:=False;  { no try..finally here ! } 
  for t:=0 to IDataSources.Count-1 do 
  With IDataSources[t] do 
  if DataSet.Active then 
  Begin 
    DataSet.Refresh; 
    CheckDataSet(DataSet); 
  end; 
  ITimer.Enabled:=True; 
end; 
 
Procedure TCustomDBChart.SetRefreshInterval(Value:Integer); 
Begin 
  if (Value<0) or (Value>60) then 
     Raise DBChartException.Create(TeeMsg_RefreshInterval); 
  FRefreshInterval:=Value; 
  CheckTimer; 
End; 
 
Function TCustomDBChart.IsValidDataSource(ASeries:TChartSeries; AComponent:TComponent):Boolean; 
Begin 
  result:=inherited IsValidDataSource(ASeries,AComponent); 
  if not Result then result:=(AComponent is TDataSet) or (AComponent is TDataSource); 
end; 
 
Procedure TCustomDBChart.CheckNewDataSource(ADataSet:TDataSet; SingleRow:Boolean); 
Var tmpDataSource : TDBChartDataSource; 
Begin 
  if IDataSources.IndexOf(ADataSet)=-1 then 
  begin 
    tmpDataSource:=TDBChartDataSource.Create(nil); { 5.02 } 
    With tmpDataSource do 
    begin 
      SetDataSet(ADataSet,SingleRow); 
      OnCheckDataSet:=DataSourceCheckDataSet; 
      OnCloseDataSet:=DataSourceCloseDataSet; 
    end; 
    IDataSources.Add(tmpDataSource); 
  end; 
end; 
 
Procedure TCustomDBChart.CheckDatasource(ASeries:TChartSeries); 
Begin 
  if Assigned(ASeries) then 
  With ASeries do 
    if ParentChart=Self then 
    Begin 
      if Assigned(DataSource) then 
      Begin 
        ASeries.Clear; 
        if DataSource is TDataSet then 
        Begin 
          CheckNewDataSource(TDataSet(DataSource),False); 
          CheckDataSet(TDataSet(DataSource),ASeries); 
        end 
        else 
        if (DataSource is TDataSource) and Assigned(TDataSource(DataSource).DataSet) then 
        begin 
          CheckNewDataSource(TDataSource(DataSource).DataSet,True); 
          CheckDataSet(TDataSource(DataSource).DataSet,ASeries); 
        end 
        else inherited; 
      end 
      else inherited; 
    end 
    else Raise ChartException.Create(TeeMsg_SeriesParentNoSelf); 
end; 
 
Procedure TCustomDBChart.CheckDataSet(ADataSet:TDataSet; ASeries:TChartSeries=nil); 
Begin 
  if FAutoRefresh then RefreshDataSet(ADataSet,ASeries); 
end; 
 
Procedure TCustomDBChart.DataSourceCheckDataSet(ADataSet:TDataSet); 
begin 
  CheckDataSet(ADataSet); 
end; 
 
Procedure TCustomDBChart.DataSourceCloseDataSet(ADataSet:TDataSet); 
var t : Integer; 
begin 
  if FAutoRefresh then 
     for t:=0 to SeriesCount-1 do 
         if Series[t].DataSource=ADataSet then Series[t].Clear; 
end; 
 
type TValueListAccess=class(TChartValueList); 
 
     TDBChartAgg=(dcaNone, dcaSum, dcaCount, dcaHigh, dcaLow, dcaAverage); 
     TDBChartSeries=packed record 
        ASeries     : TChartSeries; 
        YManda      : Boolean; 
        MandaList   : TChartValueList; 
        LabelSort   : TChartListOrder; 
        LabelField  : TField; 
        ColorField  : TField; 
        MandaField  : TField; 
        NumFields   : Integer; 
        GroupPrefix : TTeeDBGroup; 
        AggPrefix   : TDBChartAgg; 
     end; 
 
     TDBChartSeriesList=Array of TDBChartSeries; 
 
Procedure TCustomDBChart.RefreshDataSet(ADataSet:TDataSet; ASeries:TChartSeries); 
Var HasAnyDataSet : Boolean; 
 
  Procedure ProcessRecord(const tmpSeries:TDBChartSeries); 
  var tmpxLabel : String; 
      tmpColor  : TColor; 
      tmpNotMand: Double; 
      tmpMand   : Double; 
 
    Procedure AddToSeries(const DestSeries:TDBChartSeries); 
    Var t        : Integer; 
        tmpIndex : Integer; 
    begin 
      With DestSeries do 
      if AggPrefix<>dcaNone then 
      begin 
        tmpIndex:=ASeries.Labels.IndexOfLabel(tmpXLabel); 
 
        if tmpIndex=-1 then { new point } 
        begin 
          if AggPrefix=dcaCount then tmpMand:=1 
          else 
          if AggPrefix=dcaAverage then tmpColor:=1; 
 
          ASeries.Add(tmpMand,tmpXLabel,tmpColor); 
        end 
        else { existing point, do aggregation } 
        With MandaList do 
        Case AggPrefix of 
          dcaSum:   Value[tmpIndex]:=Value[tmpIndex]+tmpMand; 
          dcaCount: Value[tmpIndex]:=Value[tmpIndex]+1; 
          dcaHigh:  if tmpMand>Value[tmpIndex] then Value[tmpIndex]:=tmpMand; 
          dcaLow:   if tmpManddcaNone then tmpColor:=clTeeColor 
      else 
      if Assigned(ColorField) then 
         tmpColor:=ColorField.AsInteger 
      else 
      {$IFNDEF CLX} // CLX limitation 
      if Assigned(MandaField) and MandaField.IsNull then 
         tmpColor:=clNone 
      else 
      {$ENDIF} 
         tmpColor:=clTeeColor; 
 
      if NumFields=1 then 
      begin 
        if (not HasAnyDataSet) and (not Assigned(LabelField)) then 
           tmpXLabel:=MandaList.ValueSource; 
 
        tmpData:=TValueListAccess(ASeries.NotMandatoryValueList).IData; 
 
        if Assigned(tmpData) then 
           tmpNotMand:=TField(tmpData).AsFloat 
//           ADataSet.GetFieldData(TField(tmpData), @tmpNotMand)  // v7 speed opt. 
        else 
           tmpNotMand:=0; 
 
        if Assigned(MandaField) then tmpMand:=GetFieldValue(MandaField) 
                                else tmpMand:=0; 
 
        // add summary point 
        AddToSeries(tmpSeries); 
      end 
      else AddSingleRecord 
    end; 
  end; 
 
Var FListSeries : TDBChartSeriesList; 
 
  Procedure FillTempSeriesList; 
 
   Function GetDataSet(ASeries:TChartSeries):TDataSet; 
   begin 
     With ASeries do 
     if DataSource is TDataSet then result:=TDataSet(DataSource) 
     else 
     if DataSource is TDataSource then 
        result:=TDataSource(DataSource).DataSet 
     else 
        result:=nil; 
   end; 
 
   Function IsDataSet(ASeries:TChartSeries):Boolean; 
   var tmp : TDataSet; 
   begin 
     tmp:=GetDataSet(ASeries); 
     if Assigned(tmp) then 
     begin 
       result:=tmp=ADataSet; 
       HasAnyDataSet:=ASeries.DataSource is TDataSet; 
     end 
     else result:=False; 
   end; 
 
   Procedure AddList(tmpSeries:TChartSeries); 
   var tmp : TDataSet; 
 
      Function GetAField(Const FieldName:String):TField; 
      begin 
        if FieldName='' then result:=nil 
                        else result:=tmp.FieldByName(FieldName); 
      end; 
 
      Function GetAFieldPrefix(St:String; Var Prefix:String):TField; 
      begin 
        Prefix:=TeeGetDBPart(1,St); 
        if Prefix<>'' then St:=TeeGetDBPart(2,St); 
        result:=GetAField(St); 
      end; 
 
   var t        : Integer; 
       tmpAgg   : String; 
       tmpGroup : String; 
       {$IFNDEF CLR} 
       tmpV     : TValueListAccess; 
       {$ENDIF} 
   begin 
     SetLength(FListSeries,Length(FListSeries)+1); 
     With FListSeries[Length(FListSeries)-1] do 
     begin 
       ASeries   :=tmpSeries; 
       YManda    :=ASeries.YMandatory; 
       MandaList :=ASeries.MandatoryValueList; 
       NumFields :=TeeNumFields(MandaList.ValueSource); 
 
       tmp:=GetDataSet(ASeries); 
 
       if Assigned(tmp) then 
       With ASeries do 
       begin 
         LabelField:=GetAFieldPrefix(XLabelsSource,tmpGroup); 
 
         // try to find #SORTASC# or #SORTDESC# in label grouping 
         LabelSort:=StrToDBOrder(tmpGroup); 
         if LabelSort=loNone then 
            GroupPrefix:=StrToDBGroup(tmpGroup) // find #HOUR# etc 
         else 
            GroupPrefix:=dgNone; 
 
         ColorField:=GetAField(ColorSource); 
         MandaField:=GetAFieldPrefix(TeeExtractField(MandaList.ValueSource,1),tmpAgg); 
 
         if tmpAgg<>'' then 
         begin 
           tmpAgg:=UpperCase(tmpAgg); 
           if tmpAgg='SUM'   then AggPrefix:=dcaSum else 
           if tmpAgg='COUNT' then AggPrefix:=dcaCount else 
           if tmpAgg='HIGH'  then AggPrefix:=dcaHigh else 
           if tmpAgg='LOW'   then AggPrefix:=dcaLow else 
           if tmpAgg='AVG'   then AggPrefix:=dcaAverage else 
                                  AggPrefix:=dcaNone; 
         end 
         else 
         begin 
           AggPrefix:=dcaNone; 
           for t:=0 to ValuesList.Count-1 do 
           begin 
             {$IFDEF CLR} 
             if ValuesList[t]<>MandaList then 
                TValueListAccess(ValuesList[t]).IData:=GetAField(ValuesList[t].ValueSource); 
             {$ELSE} 
             tmpV:=TValueListAccess(ValuesList[t]); 
             if tmpV<>MandaList then tmpV.IData:=GetAField(tmpV.ValueSource); 
             {$ENDIF} 
           end; 
         end; 
       end; 
     end; 
   end; 
 
  var t         : Integer; 
      tmpSeries : TChartSeries; 
  begin 
    FListSeries:=nil; 
    if Assigned(ASeries) then 
    begin 
      AddList(ASeries); 
      HasAnyDataSet:=ASeries.DataSource=ADataSet; 
    end 
    else 
    for t:=0 to SeriesCount-1 do 
    Begin 
      tmpSeries:=Series[t]; 
      if IsDataSet(tmpSeries) and 
         (tmpSeries.MandatoryValueList.ValueSource<>'') then 
            AddList(tmpSeries); 
    end; 
  end; 
 
  Procedure TraverseDataSet; 
  Var b : TBookMark; 
      t : Integer; 
      tt: Integer; 
  begin 
    With ADataSet do 
    begin 
      DisableControls; 
      try 
        b:=GetBookMark; 
        try 
          First; 
          While not EOF do 
          try 
            if Assigned(FOnProcessRecord) then FOnProcessRecord(Self,ADataSet); 
            for t:=0 to Length(FListSeries)-1 do 
                if FListSeries[t].ASeries.DataSource=ADataSet then 
                   ProcessRecord(FListSeries[t]); 
            Next; 
          except 
            on EAbort do break; { <-- exit while loop !!! } 
          end; 
 
          for t:=0 to Length(FListSeries)-1 do 
          With FListSeries[t] do 
          begin 
            if AggPrefix=dcaAverage then 
            begin 
              for tt:=0 to ASeries.Count-1 do 
              begin 
                MandaList.Value[tt]:=MandaList.Value[tt]/ASeries.ValueColor[tt]; 
                ASeries.ValueColor[tt]:=clTeeColor; 
              end; 
            end; 
 
            if (AggPrefix<>dcaNone) and (LabelSort<>loNone) then 
               ASeries.SortByLabels(LabelSort); 
          end; 
        finally 
          try 
            GotoBookMark(b); 
          finally 
            FreeBookMark(b); 
          end; 
        end; 
      finally 
        EnableControls; 
      end; 
    end; 
  end; 
 
Var OldCursor : TCursor; 
    t         : Integer; 
    OldPaint  : Boolean; 
Begin 
  if not IUpdating then 
  With ADataSet do 
  if Active then 
  Begin 
    IUpdating:=True; 
    FListSeries:=nil; 
    HasAnyDataSet:=False; 
    try 
      FillTempSeriesList; 
      if Length(FListSeries)>0 then 
      Begin 
        OldCursor:=Screen.Cursor; 
        if FShowGlassCursor then Screen.Cursor:=crHourGlass; 
 
        OldPaint:=AutoRepaint; 
        AutoRepaint:=False; 
        try 
          for t:=0 to Length(FListSeries)-1 do 
              FListSeries[t].ASeries.Clear; 
          if HasAnyDataSet then TraverseDataSet 
          else 
          begin 
            {$IFDEF TEEOCX} 
            ADataSet.Resync([]); 
            {$ENDIF} 
            if Assigned(FOnProcessRecord) then FOnProcessRecord(Self,ADataSet); 
            for t:=0 to Length(FListSeries)-1 do 
                if TDataSource(FListSeries[t].ASeries.DataSource).DataSet=ADataSet then 
                begin 
                  ProcessRecord(FListSeries[t]); 
                end; 
          end; 
 
          for t:=0 to Length(FListSeries)-1 do 
          begin 
            FListSeries[t].ASeries.CheckOrder; 
            FListSeries[t].ASeries.RefreshSeries; 
          end; 
        finally 
          AutoRepaint:=OldPaint; 
          Invalidate; 
          if FShowGlassCursor then Screen.Cursor:=OldCursor; 
        end; 
      end; 
    finally 
      FListSeries:=nil; 
      IUpdating:=False; 
    end; 
  end; 
end; 
 
Procedure TCustomDBChart.RefreshData; 
var t : Integer; 
Begin 
  for t:=0 to IDataSources.Count-1 do 
      RefreshDataSet(IDataSources[t].DataSet,nil); 
End; 
 
Procedure FillDataSetFields(DataSet:TDataSet; Proc:TGetStrProc); 
var t : Integer; 
begin 
  with DataSet do 
  begin 
    if FieldCount > 0 then 
       for t:=0 to FieldCount-1 do Proc(Fields[t].FieldName) 
    else 
    Begin 
      FieldDefs.Update; 
      for t:=0 to FieldDefs.Count-1 do Proc(FieldDefs[t].Name); 
    end; 
  end; 
end; 
 
Procedure TCustomDBChart.FillSeriesSourceItems(ASeries:TChartSeries; Proc:TGetStrProc); 
Begin 
  With ASeries do 
  if Assigned(DataSource) then 
  begin 
    if DataSource is TDataSource then 
       FillDataSetFields(TDataSource(DataSource).DataSet,Proc) 
    else 
    if DataSource is TDataSet then 
       FillDataSetFields(TDataSet(DataSource),Proc); 
  end; 
end; 
 
Procedure TCustomDBChart.FillValueSourceItems(AValueList:TChartValueList; Proc:TGetStrProc); 
Begin 
  With AValueList.Owner do 
  if Assigned(DataSource) then 
  Begin 
    if (DataSource is TDataSet) or (DataSource is TDataSource) then 
       FillSeriesSourceItems(AValueList.Owner,Proc) 
    else 
       inherited; 
  end; 
end; 
 
Procedure TCustomDBChart.Assign(Source:TPersistent); 
begin 
  if Source is TCustomDBChart then 
  With TCustomDBChart(Source) do 
  begin 
    Self.AutoRefresh    :=AutoRefresh; 
    Self.RefreshInterval:=RefreshInterval; 
    Self.ShowGlassCursor:=ShowGlassCursor; 
  end; 
  inherited; 
end; 
 
{ 5.01 Reported by : Timo Goebel  } 
Function DateToWeek(ADate:TDateTime; Var Year:Word):Integer; 
const FirstWeekDay  = 2;  // 2: Monday (ISO-8601) 
      FirstWeekDate = 4; // 4: First four day-week (ISO-8601) 
var Month : Word; 
    Day   : Word; 
begin 
  ADate:=ADate-((DayOfWeek(ADate)-FirstWeekDay+7) mod 7)+ 7-FirstWeekDate; 
  DecodeDate(ADate,Year,Month,Day); 
  Result:=(Trunc(ADate-EncodeDate(Year,1,1)) div 7)+1; 
end; 
 
Function DateToWeekOld(Const ADate:TDateTime; Var Year:Word):Integer; 
Const FirstDay=0; { Monday } 
Var d,m,y,j,j0,j1,Week : Word; 
begin 
  DecodeDate(ADate,y,m,d); 
  if (m < 3) then 
    j := 1461*(y-1) div 4 + (153*(m+9)+2) div 5 + d 
  else 
    j := 1461*y div 4 + (153*(m-3)+2) div 5 + d; 
 
  j0:=1461*(y-1) DIV 4 + 310; 
  j0:=j0-(j0-FirstDay) MOD 7; 
 
  If (j0 then 
       if Num=1 then result:=Copy(St,1,i-1) 
       else 
       if Num=2 then result:=Copy(St,i+1,Length(St)-i); 
  end; 
end; 
 
Function StrToDBGroup(St:String):TTeeDBGroup; 
begin 
  St:=UpperCase(St); 
  if St='HOUR' then result:=dgHour else 
  if St='DAY' then result:=dgDay else 
  if St='WEEK' then result:=dgWeek else 
  if St='WEEKDAY' then result:=dgWeekDay else 
  if St='MONTH' then result:=dgMonth else 
  if St='QUARTER' then result:=dgQuarter else 
  if St='YEAR' then result:=dgYear else 
     result:=dgNone; 
end; 
 
Function StrToDBOrder(St:String):TChartListOrder; 
begin 
  St:=UpperCase(St); 
  if St='SORTASC' then result:=loAscending 
  else 
  if St='SORTDES' then result:=loDescending 
  else 
     result:=loNone; 
end; 
 
end.