{-----------------------------------------------------------------------------
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/MPL-1.1.html

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is: JvBaseDBThreadedDataset.PAS, released on 2002-05-26.

The Initial Developer of the Original Code is Jens Fudickar
All Rights Reserved.

Contributor(s):

You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net

Description:
  Oracle Dataset with Threaded Functions

Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvBaseDBThreadedDataset.pas 11205 2007-03-11 18:15:58Z jfudickar $

unit JvBaseDBThreadedDataset;

{$I jvcl.inc}

interface

uses
  {$IFDEF UNITVERSIONING}
  JclUnitVersioning,
  {$ENDIF UNITVERSIONING}
  SysUtils, Classes, StdCtrls, ExtCtrls, Forms, Controls,
  DB,
  JvThread, JvThreadDialog, JvDynControlEngine;

type
  TJvThreadedDatasetOperation = (tdoOpen, tdoFetch, tdoLast, tdoRefresh, tdoNothing);
  TJvThreadedDatasetAction = (tdaOpen, tdaFetch, tdaNothing, tdaCancel);

  TJvThreadedDatasetFetchMode = (tdfmFetch, tdfmBreak, tdfmStop, tdfmNothing);

  TJvThreadedDatasetContinueCheckResult = (tdccrContinue, tdccrPause, tdccrStop, tdccrAll, tdccrCancel);

  TJvThreadedDatasetContinueAllowButton = (tdcaPause, tdcaStop, tdcaAll);
  TJvThreadedDatasetContinueAllowButtons = set of TJvThreadedDatasetContinueAllowButton;

  TJvBaseDatasetThreadHandler = class;

  TJvThreadedDatasetThreadEvent = procedure(DataSet: TDataSet;
    Operation: TJvThreadedDatasetOperation) of object;

  IJvThreadedDatasetInterface = interface
    ['{220CC94D-AA41-4195-B90C-ECA24BAD3CDB}']
    procedure BreakExecution;
    function CurrentFetchDuration: TDateTime;
    function CurrentOpenDuration: TDateTime;
    procedure DoInheritedInternalLast;
    procedure DoInheritedInternalRefresh;
    procedure DoInheritedSetActive(Active: Boolean);
    procedure DoInternalOpen;
    function IsThreadAllowed: Boolean;
    function ThreadIsActive: Boolean;
    procedure DoInheritedBeforeOpen;
    procedure DoInheritedAfterOpen;
    procedure DoInheritedBeforeRefresh;
    procedure DoInheritedAfterRefresh;
    function ErrorMessage: string;
    function GetDatasetFetchAllRecords: Boolean;
    procedure SetDatasetFetchAllRecords(const Value: Boolean);
    property DatasetFetchAllRecords: Boolean read GetDatasetFetchAllRecords write SetDatasetFetchAllRecords;
  end;

  TJvThreadedDatasetDialogOptions = class(TJvCustomThreadDialogOptions)
  private
    FCaption: string;
    FDynControlEngine: TJvDynControlEngine;
    FEnableCancelButton: Boolean;
    FFormStyle: TFormStyle;
    FShowCancelButton: Boolean;
    FShowRowsLabel: Boolean;
    FShowTimeLabel: Boolean;
    procedure SetCaption(const Value: string);
    procedure SetDynControlEngine(const Value: TJvDynControlEngine);
    procedure SetEnableCancelButton(const Value: Boolean);
    procedure SetFormStyle(const Value: TFormStyle);
    procedure SetShowCancelButton(const Value: Boolean);
    procedure SetShowRowsLabel(const Value: Boolean);
    procedure SetShowTimeLabel(const Value: Boolean);
  public
    constructor Create(AOwner: TJvCustomThreadDialog); override;
    destructor Destroy; override;
  published
    property Caption: string read FCaption write SetCaption;
    property DynControlEngine: TJvDynControlEngine read FDynControlEngine write SetDynControlEngine;
    property EnableCancelButton: Boolean read FEnableCancelButton write SetEnableCancelButton default True;
    property FormStyle: TFormStyle read FFormStyle write SetFormStyle;
    property ShowCancelButton: Boolean read FShowCancelButton write SetShowCancelButton default True;
    property ShowRowsLabel: Boolean read FShowRowsLabel write SetShowRowsLabel default True;
    property ShowTimeLabel: Boolean read FShowTimeLabel write SetShowTimeLabel default True;
  end;

  TJvThreadedDatasetThreadOptions = class(TPersistent)
  private
    FLastInThread: Boolean;
    FOpenInThread: Boolean;
    FPriority: TThreadPriority;
    FRefreshInThread: Boolean;
    FShowExceptionMessage: Boolean;
  public
    constructor Create;
  published
    property LastInThread: Boolean read FLastInThread write FLastInThread default False;
    property OpenInThread: Boolean read FOpenInThread write FOpenInThread default False;
    property Priority: TThreadPriority read FPriority write FPriority default tpIdle;
    property RefreshInThread: Boolean read FRefreshInThread write FRefreshInThread default False;
    property ShowExceptionMessage: Boolean read FShowExceptionMessage write FShowExceptionMessage default True;
  end;

  TJvThreadedDatasetCapitalizeLabelOptions = class(TPersistent)
  private
    FAutoExecuteAfterOpen: Boolean;
    FTrimToFirstBlank: Boolean;
  public
    constructor Create; virtual;
  published
    property AutoExecuteAfterOpen: Boolean read FAutoExecuteAfterOpen write FAutoExecuteAfterOpen default False;
    property TrimToFirstBlank: Boolean read FTrimToFirstBlank write FTrimToFirstBlank default False;
  end;

  TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions = class(TPersistent)
  private
    FAll: Boolean;
    FPause: Boolean;
    FCancel: Boolean;
  protected
    property Pause: Boolean read FPause write FPause default False;
    property Cancel: Boolean read FCancel write FCancel default False;
  public
    constructor Create; virtual;
  published
    property All: Boolean read FAll write FAll default False;
  end;

  TJvBaseThreadedDatasetEnhancedOptions = class(TPersistent)
  private
    FAllowedContinueRecordFetchOptions: TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions;
    FCapitalizeLabelOptions: TJvThreadedDatasetCapitalizeLabelOptions;
    FFetchRowsCheck: Integer;
    FFetchRowsFirst: Integer;
    FRefreshAsOpenClose: Boolean;
    FRefreshLastPosition: Boolean;
    procedure SetCapitalizeLabelOptions(const Value: TJvThreadedDatasetCapitalizeLabelOptions);
    procedure SetFetchRowsCheck(const Value: Integer);
    procedure SetFetchRowsFirst(const Value: Integer);
    procedure SetRefreshAsOpenClose(Value: Boolean);
    procedure SetRefreshLastPosition(const Value: Boolean);
  protected
    function CreateAllowedContinueRecordFetchOptions: TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions;
      virtual;
  public
    constructor Create; virtual;
    destructor Destroy; override;
  published
    property AllowedContinueRecordFetchOptions: TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions read
      FAllowedContinueRecordFetchOptions write FAllowedContinueRecordFetchOptions;
    property CapitalizeLabelOptions: TJvThreadedDatasetCapitalizeLabelOptions read
      FCapitalizeLabelOptions write SetCapitalizeLabelOptions;
    property FetchRowsCheck: Integer read FFetchRowsCheck write SetFetchRowsCheck default 2000;
    property FetchRowsFirst: Integer read FFetchRowsFirst write SetFetchRowsFirst default 1000;
    property RefreshAsOpenClose: Boolean read FRefreshAsOpenClose
      write SetRefreshAsOpenClose default False;
    property RefreshLastPosition: Boolean read FRefreshLastPosition
      write SetRefreshLastPosition default False;
  end;

  TJvDatasetThreadDialogForm = class(TJvCustomThreadDialogForm)
  private
    FRowsLabel: TControl;
    FTimeLabel: TControl;
    FRowsStaticText: TWinControl;
    FTimeStaticText: TWinControl;
    FCancelBtn: TButton;
    FCancelButtonPanel: TWinControl;
    FRowsPanel: TWinControl;
    FTimePanel: TWinControl;
    FDialogOptions: TJvThreadedDatasetDialogOptions;
    FDynControlEngine: TJvDynControlEngine;
    procedure CreateTextPanel(AOwner: TComponent; AParent: TWinControl;
      var Panel: TWinControl; var LabelCtrl: TControl; var StaticText: TWinControl;
      const BaseName: string);
    function GetConnectedDataset: TDataSet;
    function GetConnectedDatasetHandler: TJvBaseDatasetThreadHandler;
    function GetDialogOptions: TJvThreadedDatasetDialogOptions;
    procedure SetDialogOptions(const Value: TJvThreadedDatasetDialogOptions);
    procedure SetDynControlEngine(const Value: TJvDynControlEngine);
  protected
    procedure FillDialogData;
    procedure InitializeFormContents; override;
    procedure UpdateFormContents; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure CreateFormControls;
    procedure TransferDialogOptions; override;
    property ConnectedDataset: TDataSet read GetConnectedDataset;
    property ConnectedDatasetHandler: TJvBaseDatasetThreadHandler read GetConnectedDatasetHandler;
    property DynControlEngine: TJvDynControlEngine read FDynControlEngine write SetDynControlEngine;
  published
    property DialogOptions: TJvThreadedDatasetDialogOptions read GetDialogOptions write SetDialogOptions;
  end;

  TJvDatasetThreadDialog = class(TJvCustomThreadDialog)
  private
    function GetDialogOptions: TJvThreadedDatasetDialogOptions;
    procedure SetDialogOptions(const Value: TJvThreadedDatasetDialogOptions);
  protected
    function CreateDialogOptions: TJvCustomThreadDialogOptions; override;
  public
    function CreateThreadDialogForm(ConnectedThread: TJvThread): TJvCustomThreadDialogForm; override;
  published
    property DialogOptions: TJvThreadedDatasetDialogOptions read GetDialogOptions write SetDialogOptions;
  end;

  TJvBaseDatasetThread = class(TJvThread)
  private
    FConnectedDataset: TDataSet;
    FConnectedDatasetInterface: IJvThreadedDatasetInterface;
    FConnectedDatasetThreadHandler: TJvBaseDatasetThreadHandler;
    procedure SetConnectedDataset(const Value: TDataSet);
    procedure SetConnectedDatasetThreadHandler(const Value: TJvBaseDatasetThreadHandler);
  protected
    procedure intAfterCreateDialogForm(DialogForm: TJvCustomThreadDialogForm); override;
    property ConnectedDatasetInterface: IJvThreadedDatasetInterface read FConnectedDatasetInterface;
    property ConnectedDataset: TDataSet read FConnectedDataset;
  public
    procedure CancelExecute; override;
    property ConnectedDatasetThreadHandler: TJvBaseDatasetThreadHandler read
      FConnectedDatasetThreadHandler write SetConnectedDatasetThreadHandler;
  end;

  TJvBaseDatasetThreadHandler = class(TComponent)
  private
    FAfterThreadExecution: TJvThreadedDatasetThreadEvent;
    FBeforeThreadExecution: TJvThreadedDatasetThreadEvent;
    FCurrentAction: TJvThreadedDatasetAction;
    FCurrentFetchDuration: TDateTime;
    FCurrentOpenDuration: TDateTime;
    FCurrentOperation: TJvThreadedDatasetOperation;
    FCurrentOperationStart: TDateTime;
    FCurrentRow: Integer;
    FDataset: TDataSet;
    FEnhancedOptions: TJvBaseThreadedDatasetEnhancedOptions;
    FErrorMessage: string;
    FExecuteThread: TJvBaseDatasetThread;
    FFetchMode: TJvThreadedDatasetFetchMode;
    FIntDatasetWasFiltered: Boolean;
    FIntDatasetFetchAllRecords: Boolean;
    FIntRowCheckEnabled: Boolean;
    FIThreadedDatasetInterface: IJvThreadedDatasetInterface;
    FLastRowChecked: Integer;
    FMoveToRecordAfterOpen: Longint;
    FOperationWasHandledInThread: Boolean;
    FSynchMessageDlgBtn: Word;
    FSynchMessageDlgMsg: string;
    FThreadDialog: TJvDatasetThreadDialog;
    FThreadOptions: TJvThreadedDatasetThreadOptions;
    function GetCurrentAction: TJvThreadedDatasetAction;
    function GetCurrentFetchDuration: TDateTime;
    function GetCurrentOpenDuration: TDateTime;
    function GetCurrentOperation: TJvThreadedDatasetOperation;
    function GetCurrentOperationAction: string;
    function GetDatasetFetchAllRecords: Boolean;
    function GetDialogOptions: TJvThreadedDatasetDialogOptions;
    function GetFetchMode: TJvThreadedDatasetFetchMode;
    procedure HandleAfterOpenRefresh;
    procedure SetCurrentAction(const Value: TJvThreadedDatasetAction);
    procedure SetCurrentFetchDuration(const Value: TDateTime);
    procedure SetCurrentOpenDuration(const Value: TDateTime);
    procedure SetDatasetFetchAllRecords(const Value: Boolean);
    procedure SetDialogOptions(Value: TJvThreadedDatasetDialogOptions);
    procedure SetEnhancedOptions(Value: TJvBaseThreadedDatasetEnhancedOptions);
    procedure SetFetchMode(const Value: TJvThreadedDatasetFetchMode);
    procedure SetThreadOptions(const Value: TJvThreadedDatasetThreadOptions);
    procedure SynchAfterThreadExecution;
    procedure SynchBeforeThreadExecution;
    procedure SynchContinueFetchMessageDlg;
    procedure SynchErrorMessageDlg;
    property DatasetFetchAllRecords: Boolean read GetDatasetFetchAllRecords write SetDatasetFetchAllRecords;
    property OperationWasHandledInThread: Boolean read FOperationWasHandledInThread
      write FOperationWasHandledInThread;
  protected
    procedure BreakExecution;
    function CreateEnhancedOptions: TJvBaseThreadedDatasetEnhancedOptions; virtual;
    procedure DoThreadLast;
    procedure DoThreadOpen;
    procedure DoThreadRefresh;
    function ExecuteThreadIsActive: Boolean;
    procedure ExecuteThreadSynchronize(Method: TThreadMethod);
    procedure HandleAfterOpenRefreshThread;
    procedure HandleBeforeOpenRefresh;
    procedure InitOperation;
    procedure IntAfterThreadExecution(DataSet: TDataSet; Operation: TJvThreadedDatasetOperation);
    procedure IntBeforeThreadExecution(DataSet: TDataSet; Operation: TJvThreadedDatasetOperation);
    procedure IntSynchAfterOpen;
    procedure IntSynchAfterRefresh;
    procedure IntSynchBeforeOpen;
    procedure IntSynchBeforeRefresh;
    procedure SetErrorMessage(const Value: string);
    function SupportsBreakExecution: Boolean; virtual;
    procedure ThreadExecute(Sender: TObject; Params: Pointer);
    property CurrentOperation: TJvThreadedDatasetOperation read GetCurrentOperation;
    property ExecuteThread: TJvBaseDatasetThread read FExecuteThread;
    property FetchMode: TJvThreadedDatasetFetchMode read GetFetchMode write SetFetchMode;
    property IntRowCheckEnabled: Boolean read FIntRowCheckEnabled write FIntRowCheckEnabled;
    property IThreadedDatasetInterface: IJvThreadedDatasetInterface read FIThreadedDatasetInterface;
    property ThreadDialog: TJvDatasetThreadDialog read FThreadDialog;
  public
    constructor Create(AOwner: TComponent; ADataset: TDataSet); reintroduce;
        virtual;
    destructor Destroy; override;
    procedure AfterOpen;
    procedure AfterRefresh;
    procedure BeforeOpen;
    procedure BeforeRefresh;
    procedure CapitalizeDatasetLabels;
    function CheckContinueRecordFetch: TJvThreadedDatasetContinueCheckResult;
    procedure InternalLast; virtual;
    procedure InternalRefresh; virtual;
    procedure MoveTo(Position: Integer);
    procedure SetActive(Value: Boolean); virtual;
    function ThreadIsActive: Boolean;
    property CurrentAction: TJvThreadedDatasetAction read GetCurrentAction write SetCurrentAction;
    property CurrentFetchDuration: TDateTime read GetCurrentFetchDuration write SetCurrentFetchDuration;
    property CurrentOpenDuration: TDateTime read GetCurrentOpenDuration write SetCurrentOpenDuration;
    property CurrentOperationAction: string read GetCurrentOperationAction;
    property CurrentRow: Integer read FCurrentRow;
    property Dataset: TDataSet read FDataset;
    property ErrorMessage: string read FErrorMessage write SetErrorMessage;
  published
    property DialogOptions: TJvThreadedDatasetDialogOptions read GetDialogOptions write SetDialogOptions;
    property EnhancedOptions: TJvBaseThreadedDatasetEnhancedOptions read
      FEnhancedOptions write SetEnhancedOptions;
    property ThreadOptions: TJvThreadedDatasetThreadOptions read FThreadOptions write SetThreadOptions;
    property AfterThreadExecution: TJvThreadedDatasetThreadEvent read
      FAfterThreadExecution write FAfterThreadExecution;
    property BeforeThreadExecution: TJvThreadedDatasetThreadEvent read
      FBeforeThreadExecution write FBeforeThreadExecution;
  end;


{$IFDEF UNITVERSIONING}
const
  UnitVersioning: TUnitVersionInfo = (
    RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvBaseDBThreadedDataset.pas $';
    Revision: '$Revision: 11205 $';
    Date: '$Date: 2007-03-11 19:15:58 +0100 (dim., 11 mars 2007) $';
    LogPath: 'JVCL\run'
    );
{$ENDIF UNITVERSIONING}

implementation

uses
  Dialogs,
  JvDynControlEngineIntf, JvDSADialogs, JvResources;

//=== { TJvDatasetThreadDialog } =============================================

function TJvDatasetThreadDialog.CreateDialogOptions: TJvCustomThreadDialogOptions;
begin
  Result := TJvThreadedDatasetDialogOptions.Create(Self);
end;

function TJvDatasetThreadDialog.CreateThreadDialogForm(ConnectedThread: TJvThread): TJvCustomThreadDialogForm;
var
  ThreadDialogForm: TJvDatasetThreadDialogForm;
begin
  if DialogOptions.ShowDialog then
  begin
    if Assigned(ConnectedThread.Owner) and (ConnectedThread.Owner is TWinControl) then
      ThreadDialogForm := TJvDatasetThreadDialogForm.CreateNewFormStyle(ConnectedThread,
        DialogOptions.FormStyle, TWinControl(ConnectedThread.Owner))
    else
    if Assigned(ConnectedThread.Owner) and Assigned(ConnectedThread.Owner.Owner) and
      (ConnectedThread.Owner.Owner is TWinControl) then
      ThreadDialogForm := TJvDatasetThreadDialogForm.CreateNewFormStyle(ConnectedThread,
        DialogOptions.FormStyle, TWinControl(ConnectedThread.Owner.Owner))
    else
      ThreadDialogForm := TJvDatasetThreadDialogForm.CreateNewFormStyle(ConnectedThread,
        DialogOptions.FormStyle);
    ThreadDialogForm.DialogOptions := DialogOptions;
    ThreadDialogForm.CreateFormControls;
    Result := ThreadDialogForm;
  end
  else
    Result := nil;
end;

function TJvDatasetThreadDialog.GetDialogOptions: TJvThreadedDatasetDialogOptions;
begin
  Result := TJvThreadedDatasetDialogOptions(inherited DialogOptions);
end;

procedure TJvDatasetThreadDialog.SetDialogOptions(const Value: TJvThreadedDatasetDialogOptions);
begin
  inherited DialogOptions.Assign(Value);
end;

//=== { TJvDatasetThreadDialogForm } =========================================

constructor TJvDatasetThreadDialogForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  DynControlEngine := nil;
  InternalTimerInterval := 100;
end;

procedure TJvDatasetThreadDialogForm.CreateFormControls;
var
  MainPanel: TWinControl;
  ITmpPanel: IJvDynControlPanel;
  ITmpControl: IJvDynControl;
begin
  MainPanel := DynControlEngine.CreatePanelControl(Self, Self, 'MainPanel', '', alClient);
  if not Supports(MainPanel, IJvDynControlPanel, ITmpPanel) then
    raise EIntfCastError.CreateRes(@RsEIntfCastError);
  with ITmpPanel do
    ControlSetBorder(bvNone, bvNone, 0, bsNone, 5);

  CreateTextPanel(Self, MainPanel, FTimePanel, FTimeLabel, FTimeStaticText, 'Time');
  if Supports(FTimeLabel, IJvDynControl, ITmpControl) then
    ITmpControl.ControlSetCaption(RsODSOpenFetch);
  CreateTextPanel(Self, MainPanel, FRowsPanel, FRowsLabel, FRowsStaticText, 'Rows');
  if Supports(FRowsLabel, IJvDynControl, ITmpControl) then
    ITmpControl.ControlSetCaption(RsODSCurrentRecord);
  FCancelButtonPanel := DynControlEngine.CreatePanelControl(Self, MainPanel, 'ButtonPanel', '', alTop);
  FCancelBtn := DynControlEngine.CreateButton(Self, FCancelButtonPanel,
    'CancelBtn', RsButtonCancelCaption, '', DefaultCancelBtnClick, True, True);
  with FCancelBtn do
  begin
    Anchors := [akTop];
    Top := 2;
    FCancelButtonPanel.Height := FCancelBtn.Height + 3;
  end;

  BorderIcons := [];
  BorderStyle := bsDialog;
  if DialogOptions.Caption <> '' then
    Caption := DialogOptions.Caption
  else
    Caption := ' ';
  FormStyle := DialogOptions.FormStyle;
  OldCreateOrder := False;
  {$IFDEF COMPILER7_UP}
  Position := poOwnerFormCenter;
  {$ELSE}
  Position := poScreenCenter;
  {$ENDIF COMPILER7_UP}
  PixelsPerInch := 96;
end;

procedure TJvDatasetThreadDialogForm.CreateTextPanel(AOwner: TComponent;
  AParent: TWinControl; var Panel: TWinControl; var LabelCtrl: TControl;
  var StaticText: TWinControl; const BaseName: string);
var
  ITmpPanel: IJvDynControlPanel;
  ITmpAutoSize: IJvDynControlAutoSize;
  ITmpAlignment: IJvDynControlAlignment;
begin
  Panel := DynControlEngine.CreatePanelControl(AOwner, AParent, BaseName + 'Panel', '', alTop);
  if not Supports(Panel, IJvDynControlPanel, ITmpPanel) then
    raise EIntfCastError.CreateRes(@RsEIntfCastError);
  with ITmpPanel do
    ControlSetBorder(bvNone, bvNone, 0, bsNone, 3);
  LabelCtrl := DynControlEngine.CreateLabelControl(AOwner, Panel, BaseName + 'Label', '', nil);
  with LabelCtrl do
  begin
    Top := 1;
    Left := 1;
    Width := 90;
  end;
  StaticText := DynControlEngine.CreateStaticTextControl(AOwner, Panel, BaseName + 'StaticText', '');
  if Supports(StaticText, IJvDynControlAutoSize, ITmpAutoSize) then
    ITmpAutoSize.ControlSetAutoSize(False);
  if Supports(StaticText, IJvDynControlAlignment, ITmpAlignment) then
    ITmpAlignment.ControlSetAlignment(taCenter);
  with StaticText do
  begin
    Top := 1;
    Left := 95;
    Height := 18;
    Panel.Height := Height + 6;
  end;
end;

procedure TJvDatasetThreadDialogForm.FillDialogData;
var
  ITmpControl: IJvDynControl;
begin
  if Assigned(ConnectedDatasetHandler)
     and (ConnectedDatasetHandler.CurrentOpenDuration > 0) then
  with ConnectedDatasetHandler do
    begin
      if DialogOptions.Caption <> '' then
        Caption := DialogOptions.Caption +' - '+CurrentOperationAction
      else
        Caption := CurrentOperationAction;
      if Supports(FRowsStaticText, IJvDynControl, ITmpControl) then
        ITmpControl.ControlSetCaption(IntToStr(CurrentRow));
      if Supports(FTimeStaticText, IJvDynControl, ITmpControl) then
        ITmpControl.ControlSetCaption(
          FormatDateTime('hh:nn:ss', CurrentOpenDuration) + ' / ' +
            FormatDateTime('hh:nn:ss', CurrentFetchDuration));
    end
  else
  begin
    if DialogOptions.Caption <> '' then
      Caption := DialogOptions.Caption +' - '
    else
      Caption := '';
    if Supports(FRowsStaticText, IJvDynControl, ITmpControl) then
      ITmpControl.ControlSetCaption(IntToStr(0));
    if Supports(FTimeStaticText, IJvDynControl, ITmpControl) then
      ITmpControl.ControlSetCaption(
        FormatDateTime('hh:nn:ss', 0) + ' / ' +
        FormatDateTime('hh:nn:ss', 0));
  end;
  FRowsStaticText.Width:= FRowsPanel.Width - FRowsLabel.Width;
  FTimeStaticText.Width:= FTimePanel.Width - FTimeLabel.Width;
end;

function TJvDatasetThreadDialogForm.GetConnectedDataset: TDataSet;
begin
  if Assigned(ConnectedDatasetHandler) then
    Result := ConnectedDatasetHandler.Dataset
  else
    Result := nil;
end;

function TJvDatasetThreadDialogForm.GetConnectedDatasetHandler: TJvBaseDatasetThreadHandler;
begin
  if Assigned(ConnectedDataComponent) and (ConnectedDataComponent is TJvBaseDatasetThreadHandler) then
    Result := TJvBaseDatasetThreadHandler(ConnectedDataComponent)
  else
    Result := nil;
end;

function TJvDatasetThreadDialogForm.GetDialogOptions: TJvThreadedDatasetDialogOptions;
begin
  Result := FDialogOptions;
end;

procedure TJvDatasetThreadDialogForm.InitializeFormContents;
begin
  if Assigned(ConnectedDatasetHandler) then
    ConnectedDatasetHandler.InitOperation;
end;

procedure TJvDatasetThreadDialogForm.SetDialogOptions(const Value: TJvThreadedDatasetDialogOptions);
begin
  FDialogOptions := Value;
  DynControlEngine := DialogOptions.DynControlEngine;
end;

procedure TJvDatasetThreadDialogForm.SetDynControlEngine(const Value: TJvDynControlEngine);
begin
  if not Assigned(Value) then
    FDynControlEngine := DefaultDynControlEngine
  else
    FDynControlEngine := Value;
end;

procedure TJvDatasetThreadDialogForm.TransferDialogOptions;
var
  H: Integer;
begin
  ClientWidth := 220;
  FCancelButtonPanel.Visible := DialogOptions.ShowCancelButton;
  FCancelBtn.Enabled := DialogOptions.EnableCancelButton;
  FCancelBtn.Left := Round((FCancelButtonPanel.Width - FCancelBtn.Width) / 2);
  FRowsPanel.Visible := DialogOptions.ShowRowsLabel;
  FTimePanel.Visible := DialogOptions.ShowTimeLabel;
  H := 10;
  if FRowsPanel.Visible then
    H := H + FRowsPanel.Height;
  if FTimePanel.Visible then
    H := H + FTimePanel.Height;
  if FCancelButtonPanel.Visible then
    H := H + FCancelButtonPanel.Height;
  ClientHeight := H;
end;

procedure TJvDatasetThreadDialogForm.UpdateFormContents;
begin
  inherited UpdateFormContents;
  FillDialogData;
end;

//=== { TJvThreadedDatasetDialogOptions } ====================================

constructor TJvThreadedDatasetDialogOptions.Create(AOwner: TJvCustomThreadDialog);
begin
  inherited Create(AOwner);
  FEnableCancelButton := True;
  FShowCancelButton := True;
  FShowRowsLabel := True;
  FShowTimeLabel := True;
end;

destructor TJvThreadedDatasetDialogOptions.Destroy;
begin
  inherited Destroy;
end;

procedure TJvThreadedDatasetDialogOptions.SetCaption(const Value: string);
begin
  FCaption := Value;
end;

procedure TJvThreadedDatasetDialogOptions.SetDynControlEngine(const Value: TJvDynControlEngine);
begin
  FDynControlEngine := Value;
end;

procedure TJvThreadedDatasetDialogOptions.SetEnableCancelButton(const Value: Boolean);
begin
  FEnableCancelButton := Value;
end;

procedure TJvThreadedDatasetDialogOptions.SetFormStyle(const Value: TFormStyle);
begin
  FFormStyle := Value;
end;

procedure TJvThreadedDatasetDialogOptions.SetShowCancelButton(const Value: Boolean);
begin
  FShowCancelButton := Value;
end;

procedure TJvThreadedDatasetDialogOptions.SetShowRowsLabel(const Value: Boolean);
begin
  FShowRowsLabel := Value;
end;

procedure TJvThreadedDatasetDialogOptions.SetShowTimeLabel(const Value: Boolean);
begin
  FShowTimeLabel := Value;
end;

//=== { TJvBaseDatasetThread } ===============================================

procedure TJvBaseDatasetThread.intAfterCreateDialogForm(DialogForm: TJvCustomThreadDialogForm);
begin
  DialogForm.ConnectedDataComponent := ConnectedDatasetThreadHandler;
end;

procedure TJvBaseDatasetThread.CancelExecute;
begin
  if ConnectedDatasetThreadHandler.SupportsBreakExecution then
    ConnectedDatasetThreadHandler.BreakExecution
  else
    inherited CancelExecute;
end;

procedure TJvBaseDatasetThread.SetConnectedDataset(const Value: TDataSet);
begin
  FConnectedDataset := Value;
  if Assigned(Value) then
    if not Supports(Value, IJvThreadedDatasetInterface, FConnectedDatasetInterface) then
      raise EIntfCastError.CreateRes(@RsEIntfCastError)
    else
  else
    FConnectedDatasetInterface := nil;

end;

procedure TJvBaseDatasetThread.SetConnectedDatasetThreadHandler(const Value: TJvBaseDatasetThreadHandler);
begin
  FConnectedDatasetThreadHandler := Value;
  if Assigned(Value) then
    SetConnectedDataset (ConnectedDatasetThreadHandler.Dataset)
  else
    SetConnectedDataset (nil);
end;

//=== { TJvThreadedDatasetThreadOptions } ====================================

constructor TJvThreadedDatasetThreadOptions.Create;
begin
  inherited Create;
  FLastInThread := False;
  FOpenInThread := False;
  FPriority := tpIdle;
  FRefreshInThread := False;
  FShowExceptionMessage := True;
end;

//=== { TJvThreadedDatasetEnhancedOptions } ==================================

constructor TJvBaseThreadedDatasetEnhancedOptions.Create;
begin
  inherited Create;
  FRefreshAsOpenClose := False;
  FRefreshLastPosition := False;
  FCapitalizeLabelOptions := TJvThreadedDatasetCapitalizeLabelOptions.Create;
  FAllowedContinueRecordFetchOptions := CreateAllowedContinueRecordFetchOptions;
  FFetchRowsCheck := 2000;
  FFetchRowsFirst := 1000;
end;

destructor TJvBaseThreadedDatasetEnhancedOptions.Destroy;
begin
  FreeAndNil(FAllowedContinueRecordFetchOptions);
  FreeAndNil(FCapitalizeLabelOptions);
  inherited Destroy;
end;

function
  TJvBaseThreadedDatasetEnhancedOptions.CreateAllowedContinueRecordFetchOptions:
    TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions;
begin
  Result := TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions.Create;
end;

procedure TJvBaseThreadedDatasetEnhancedOptions.SetCapitalizeLabelOptions(
  const Value: TJvThreadedDatasetCapitalizeLabelOptions);
begin
  FCapitalizeLabelOptions.Assign(Value);
end;

procedure TJvBaseThreadedDatasetEnhancedOptions.SetFetchRowsCheck(const Value: Integer);
begin
  FFetchRowsCheck := Value;
end;

procedure TJvBaseThreadedDatasetEnhancedOptions.SetFetchRowsFirst(const Value: Integer);
begin
  FFetchRowsFirst := Value;
end;

procedure TJvBaseThreadedDatasetEnhancedOptions.SetRefreshAsOpenClose(Value: Boolean);
begin
  FRefreshAsOpenClose := Value;
end;

procedure TJvBaseThreadedDatasetEnhancedOptions.SetRefreshLastPosition(const Value: Boolean);
begin
  FRefreshLastPosition := Value;
end;

//=== { TJvThreadedDatasetCapitalizeLabelOptions } ===========================

constructor TJvThreadedDatasetCapitalizeLabelOptions.Create;
begin
  inherited Create;
  FAutoExecuteAfterOpen := False;
  FTrimToFirstBlank := False;
end;

//=== { TJvBaseDatasetThreadHandler } ========================================

constructor TJvBaseDatasetThreadHandler.Create(AOwner: TComponent; ADataset:
    TDataSet);
begin
  inherited Create (AOwner);
  FDataset := ADataset;
  if not Supports(ADataset, IJvThreadedDatasetInterface, FIThreadedDatasetInterface) then
    raise EIntfCastError.CreateRes(@RsEIntfCastError);

  FThreadOptions := TJvThreadedDatasetThreadOptions.Create;
  FExecuteThread := TJvBaseDatasetThread.Create(Self);
  FThreadDialog := TJvDatasetThreadDialog.Create(Self);
  FExecuteThread.Exclusive := True;
  FExecuteThread.OnExecute := ThreadExecute;
  FExecuteThread.ConnectedDatasetThreadHandler := Self;
  FExecuteThread.ThreadDialog := ThreadDialog;
  FEnhancedOptions := CreateEnhancedOptions;
  FCurrentOperation := tdoNothing;
end;

destructor TJvBaseDatasetThreadHandler.Destroy;
begin
  FreeAndNil(FEnhancedOptions);
  FreeAndNil(FThreadDialog);
  FreeAndNil(FExecuteThread);
  FreeAndNil(FThreadOptions);
  inherited Destroy;
end;

procedure TJvBaseDatasetThreadHandler.AfterOpen;
begin
  if not ExecuteThreadIsActive and not OperationWasHandledInThread and (CurrentOperation <> tdoRefresh) then
    HandleAfterOpenRefresh;
  ExecuteThreadSynchronize(IntSynchAfterOpen);
end;

procedure TJvBaseDatasetThreadHandler.AfterRefresh;
begin
  if not ExecuteThreadIsActive and not OperationWasHandledInThread then
    HandleAfterOpenRefresh;
  ExecuteThreadSynchronize(IntSynchAfterRefresh);
end;

procedure TJvBaseDatasetThreadHandler.BeforeOpen;
begin
  if (CurrentOperation <> tdoRefresh) then
  begin
    FMoveToRecordAfterOpen := -1;
    HandleBeforeOpenRefresh;
  end;
  ExecuteThreadSynchronize(IntSynchBeforeOpen);
end;

procedure TJvBaseDatasetThreadHandler.BeforeRefresh;
begin
  if EnhancedOptions.RefreshLastPosition then
    FMoveToRecordAfterOpen := Dataset.RecNo
  else
    FMoveToRecordAfterOpen := -1;
  HandleBeforeOpenRefresh;
  ExecuteThreadSynchronize(IntSynchBeforeRefresh);
end;

procedure TJvBaseDatasetThreadHandler.BreakExecution;
begin
  CurrentAction := tdaCancel;
  if (FetchMode = tdfmFetch) and (EnhancedOptions.AllowedContinueRecordFetchOptions.Pause or
    EnhancedOptions.AllowedContinueRecordFetchOptions.Cancel) then
    if EnhancedOptions.AllowedContinueRecordFetchOptions.Pause then
      FetchMode := tdfmBreak
    else
      FetchMode := tdfmStop
  else
    IThreadedDatasetInterface.BreakExecution;
  IntRowCheckEnabled := False;
end;

procedure TJvBaseDatasetThreadHandler.CapitalizeDatasetLabels;
var
  I, J: Integer;
  S: string;
  Upper: Boolean;
begin
  With Dataset do
    if Active then
      for I := 0 to FieldCount - 1 do
      begin
        S := LowerCase(Fields[I].DisplayLabel);
        Upper := True;
        for J := 1 to Length(S) do
          if S[J] in ['_', '$', ' '] then
          begin
            Upper := True;
            S[J] := ' ';
          end
          else
          if Upper then
          begin
            S[J] := UpCase(S[J]);
            Upper := False;
          end;
        if EnhancedOptions.CapitalizeLabelOptions.TrimToFirstBlank then
        begin
          J := Pos(' ', S);
          if J > 0 then
            S := Copy(S, J + 1, Length(S) - J);
        end;
        Fields[I].DisplayLabel := S;
      end;
end;

function TJvBaseDatasetThreadHandler.CheckContinueRecordFetch: TJvThreadedDatasetContinueCheckResult;
begin
  Result := tdccrContinue;
  FCurrentRow := Dataset.RecordCount;
  case FetchMode of
    tdfmBreak:
      begin
        Result := tdccrPause;
        FetchMode := tdfmFetch;
        Exit;
      end;
    tdfmStop:
      begin
        Result := tdccrStop;
        Exit;
      end;
  end;
  if (EnhancedOptions.FetchRowsCheck > 0) and IntRowCheckEnabled then
    if CurrentRow >= FLastRowChecked + EnhancedOptions.FetchRowsCheck then
    begin
      fCurrentFetchDuration := fCurrentFetchDuration + Now - FCurrentOperationStart;
      CurrentAction := tdaNothing;
      FLastRowChecked := CurrentRow;
      FSynchMessageDlgMsg := Format(RsODSRowsFetchedContinue, [CurrentRow]);
      ExecuteThreadSynchronize(SynchContinueFetchMessageDlg);
      case FSynchMessageDlgBtn of
        mrYes:
          Result := tdccrContinue;
        mrAll:
          begin
            Result := tdccrContinue;
            IntRowCheckEnabled := False;
          end;
        mrAbort:
          Result := tdccrCancel;
        mrCancel:
          Result := tdccrPause;
        mrNo:
          Result := tdccrStop;
      else
        Result := tdccrStop;
      end;
      CurrentAction := tdaFetch;
      FetchMode := tdfmFetch;
      FCurrentOperationStart := Now;
    end;
end;

function TJvBaseDatasetThreadHandler.CreateEnhancedOptions: TJvBaseThreadedDatasetEnhancedOptions;
begin
  Result := TJvBaseThreadedDatasetEnhancedOptions.Create;
end;

procedure TJvBaseDatasetThreadHandler.DoThreadLast;
begin
  IThreadedDatasetInterface.DoInheritedInternalLast;
end;

procedure TJvBaseDatasetThreadHandler.DoThreadOpen;
begin
  try
    IThreadedDatasetInterface.DoInheritedSetActive(True);
  finally
    HandleAfterOpenRefreshThread;
  end;
end;

procedure TJvBaseDatasetThreadHandler.DoThreadRefresh;
begin
  try
    if not EnhancedOptions.RefreshAsOpenClose then
    begin
      IThreadedDatasetInterface.DoInheritedInternalRefresh;
    end
    else
    begin
      Dataset.Close;
      IThreadedDatasetInterface.DoInternalOpen;
    end;
  finally
    HandleAfterOpenRefreshThread;
  end;
end;

function TJvBaseDatasetThreadHandler.ExecuteThreadIsActive: Boolean;
begin
  Result := Not ExecuteThread.Terminated;
end;

procedure TJvBaseDatasetThreadHandler.ExecuteThreadSynchronize(Method: TThreadMethod);
begin
  if ExecuteThreadIsActive then
    ExecuteThread.Synchronize(Method)
  else
    Method;
end;

function TJvBaseDatasetThreadHandler.GetCurrentAction: TJvThreadedDatasetAction;
begin
  Result := FCurrentAction;
end;

function TJvBaseDatasetThreadHandler.GetCurrentFetchDuration: TDateTime;
begin
  case CurrentAction of
    tdaOpen:
      Result := 0;
    tdaNothing, tdaCancel:
      Result := FCurrentFetchDuration;
    tdaFetch:
      Result := FCurrentFetchDuration + (Now - FCurrentOperationStart);
  else
    Result := 0;
  end;
end;

function TJvBaseDatasetThreadHandler.GetCurrentOpenDuration: TDateTime;
begin
  if CurrentAction = tdaOpen then
    Result := Now - FCurrentOperationStart
  else
    Result := FCurrentOpenDuration;
end;

function TJvBaseDatasetThreadHandler.GetCurrentOperation: TJvThreadedDatasetOperation;
begin
  Result := FCurrentOperation;
end;

function TJvBaseDatasetThreadHandler.GetCurrentOperationAction: string;
begin
  case CurrentOperation of
    tdoOpen:
      case CurrentAction of
        tdaOpen:
          Result := RsODSOpenQuery;
        tdaFetch:
          Result := RsODSOpenQueryFetchRecords;
        tdaCancel :
          Result := RsODSOpenQueryCancel;
      end;
    tdoRefresh:
      case CurrentAction of
        tdaOpen:
          Result := RsODSRefreshQuery;
        tdaFetch:
          Result := RsODSRefreshQueryFetchRecords;
        tdaCancel :
          Result := RsODSRefreshQueryCancel;
      end;
    tdoFetch:
      case CurrentAction of
        tdaFetch:
          Result := RsODSFetchRecords;
        tdaCancel :
          Result := RsODSFetchRecordsCancel;
      end;
    tdoLast:
      Result := RsODSGotoLastFetchRecords;
  end;
end;

function TJvBaseDatasetThreadHandler.GetDatasetFetchAllRecords: Boolean;
begin
  if Assigned(IThreadedDatasetInterface) then
    Result := IThreadedDatasetInterface.DatasetFetchAllRecords
  else
    Result := False;
end;

function TJvBaseDatasetThreadHandler.GetDialogOptions:
    TJvThreadedDatasetDialogOptions;
begin
  Result := ThreadDialog.DialogOptions;
end;

function TJvBaseDatasetThreadHandler.GetFetchMode: TJvThreadedDatasetFetchMode;
begin
  Result := FFetchMode;
end;

procedure TJvBaseDatasetThreadHandler.HandleAfterOpenRefresh;
begin
  try
    CurrentOpenDuration := Now - FCurrentOperationStart;
    FCurrentOperationStart := Now;
    DatasetFetchAllRecords := FIntDatasetFetchAllRecords;
    CurrentFetchDuration := 0;
    if CurrentAction <> tdaCancel then
    begin
      CurrentAction := tdaFetch;
      FetchMode := tdfmFetch;
      if Dataset.Active then
      begin
        Dataset.First;
        if DatasetFetchAllRecords then
          IThreadedDatasetInterface.DoInheritedInternalLast
        else
          if (EnhancedOptions.FetchRowsFirst > Dataset.RecordCount) or
            (FMoveToRecordAfterOpen > Dataset.RecordCount) then
            if FMoveToRecordAfterOpen > EnhancedOptions.FetchRowsFirst then
              Dataset.MoveBy(FMoveToRecordAfterOpen - 1)
            else
              Dataset.MoveBy(EnhancedOptions.FetchRowsFirst - 1);
      end;
    end;
    Dataset.Filtered := FIntDatasetWasFiltered;
    if Dataset.Active and (CurrentAction <> tdaCancel) then
      if FMoveToRecordAfterOpen > 0 then
        MoveTo(FMoveToRecordAfterOpen)
      else
        Dataset.First;
  finally
    CurrentAction := tdaNothing;
    ExecuteThreadSynchronize(Dataset.EnableControls);
  end;
end;

procedure TJvBaseDatasetThreadHandler.HandleAfterOpenRefreshThread;
begin
  HandleAfterOpenRefresh;
end;

procedure TJvBaseDatasetThreadHandler.HandleBeforeOpenRefresh;
begin
  OperationWasHandledInThread := False;
  ExecuteThreadSynchronize(Dataset.DisableControls);
  CurrentOpenDuration := 0;
  CurrentFetchDuration := 0;
  IntRowCheckEnabled := True;
  FCurrentRow := 0;
  FCurrentOperationStart := Now;
  CurrentAction := tdaOpen;
  FetchMode := tdfmNothing;
  FIntDatasetFetchAllRecords := DatasetFetchAllRecords;
  FLastRowChecked := 0;
  FIntDatasetWasFiltered := Dataset.Filtered;
  Dataset.Filtered := False;
  DatasetFetchAllRecords := False;
end;

procedure TJvBaseDatasetThreadHandler.InitOperation;
begin
  FCurrentOperationStart := 2*Now;
end;

procedure TJvBaseDatasetThreadHandler.IntAfterThreadExecution(DataSet: TDataSet;
  Operation: TJvThreadedDatasetOperation);
begin
  if Assigned(FAfterThreadExecution) then
    FAfterThreadExecution(DataSet, Operation);
end;

procedure TJvBaseDatasetThreadHandler.IntBeforeThreadExecution(DataSet: TDataSet;
  Operation: TJvThreadedDatasetOperation);
begin
  if Assigned(FBeforeThreadExecution) then
    FBeforeThreadExecution(DataSet, Operation);
end;

procedure TJvBaseDatasetThreadHandler.InternalLast;
var
  ShowModal: Boolean;
begin
  if FCurrentOperation <> tdoNothing then
    Exit;
  FCurrentOperation := tdoLast;
  if not ThreadOptions.LastInThread or ThreadIsActive or (csDesigning in ComponentState) then
  begin
    IThreadedDatasetInterface.DoInheritedInternalLast;
    FCurrentOperation := tdoNothing;
  end
  else
  begin
    if Assigned(ExecuteThread.ThreadDialog) then
    begin
      showModal := ExecuteThread.ThreadDialog.DialogOptions.ShowModal;
      ExecuteThread.ThreadDialog.DialogOptions.ShowModal := True;
    end
    else
      ShowModal := False;
    ExecuteThread.ExecuteWithDialog(nil);
    if Assigned(ExecuteThread.ThreadDialog) then
      ExecuteThread.ThreadDialog.DialogOptions.ShowModal := showModal;
  end;
end;

procedure TJvBaseDatasetThreadHandler.InternalRefresh;
begin
  if FCurrentOperation <> tdoNothing then
    Exit;
  FCurrentOperation := tdoRefresh;
  if not ThreadOptions.RefreshInThread or not IThreadedDatasetInterface.IsThreadAllowed or
    ThreadIsActive or (csDesigning in ComponentState) then
  begin
    IThreadedDatasetInterface.DoInheritedInternalRefresh;
    FCurrentOperation := tdoNothing;
  end
  else
    ExecuteThread.ExecuteWithDialog(nil);
end;

procedure TJvBaseDatasetThreadHandler.IntSynchAfterOpen;
begin
  if EnhancedOptions.CapitalizeLabelOptions.AutoExecuteAfterOpen then
    CapitalizeDatasetLabels;
  IThreadedDatasetInterface.DoInheritedAfterOpen;
  // Added because in the afteropen event the filtered could be activated, and it should be deactivated for the dialog
  FIntDatasetWasFiltered := Dataset.Filtered or FIntDatasetWasFiltered;
  Dataset.Filtered := False;
end;

procedure TJvBaseDatasetThreadHandler.IntSynchAfterRefresh;
begin
  IThreadedDatasetInterface.DoInheritedAfterRefresh;
end;

procedure TJvBaseDatasetThreadHandler.IntSynchBeforeOpen;
begin
  IThreadedDatasetInterface.DoInheritedBeforeOpen;
end;

procedure TJvBaseDatasetThreadHandler.IntSynchBeforeRefresh;
begin
  IThreadedDatasetInterface.DoInheritedBeforeRefresh;
end;

procedure TJvBaseDatasetThreadHandler.MoveTo(Position: Integer);
begin
  Dataset.MoveBy(Position - Dataset.RecNo);
end;

procedure TJvBaseDatasetThreadHandler.SetActive(Value: Boolean);
begin
  if not Value then
  begin
    CurrentOpenDuration := 0;
    CurrentFetchDuration := 0;
    IThreadedDatasetInterface.DoInheritedSetActive(Value);
  end
  else
  begin
    if (FCurrentOperation <> tdoNothing) and
       (CurrentOperation <> tdoRefresh) then
      Exit;
    if CurrentOperation <> tdoRefresh then
      FCurrentOperation := tdoOpen;
    if not ThreadOptions.OpenInThread or ThreadIsActive or (csDesigning in ComponentState) then
    begin
      IThreadedDatasetInterface.DoInheritedSetActive(Value);
      if CurrentOperation <> tdoRefresh then
        FCurrentOperation := tdoNothing;
    end
    else
      ExecuteThread.ExecuteWithDialog(nil);
  end;
end;

procedure TJvBaseDatasetThreadHandler.SetCurrentAction(const Value: TJvThreadedDatasetAction);
begin
  FCurrentAction := Value;
end;

procedure TJvBaseDatasetThreadHandler.SetCurrentFetchDuration(const Value: TDateTime);
begin
  FCurrentFetchDuration := Value;
end;

procedure TJvBaseDatasetThreadHandler.SetCurrentOpenDuration(const Value: TDateTime);
begin
  FCurrentOpenDuration := Value;
end;

procedure TJvBaseDatasetThreadHandler.SetDatasetFetchAllRecords(const Value: Boolean);
begin
   if Assigned(IThreadedDatasetInterface) then
    IThreadedDatasetInterface.DatasetFetchAllRecords := Value;
end;

procedure TJvBaseDatasetThreadHandler.SetDialogOptions(Value: TJvThreadedDatasetDialogOptions);
begin
  ThreadDialog.DialogOptions.Assign(Value);
end;

procedure TJvBaseDatasetThreadHandler.SetEnhancedOptions(Value: TJvBaseThreadedDatasetEnhancedOptions);
begin
  FEnhancedOptions.Assign(Value);
end;

procedure TJvBaseDatasetThreadHandler.SetErrorMessage(const Value: string);
begin
  FErrorMessage := Value;
end;

procedure TJvBaseDatasetThreadHandler.SetFetchMode(const Value: TJvThreadedDatasetFetchMode);
begin
  FFetchMode := Value;
end;

procedure TJvBaseDatasetThreadHandler.SetThreadOptions(const Value: TJvThreadedDatasetThreadOptions);
begin
  FThreadOptions.Assign(Value);
end;

function TJvBaseDatasetThreadHandler.SupportsBreakExecution: Boolean;
begin
  Result := True;
end;

procedure TJvBaseDatasetThreadHandler.SynchAfterThreadExecution;
begin
  IntAfterThreadExecution(Dataset, CurrentOperation);
end;

procedure TJvBaseDatasetThreadHandler.SynchBeforeThreadExecution;
begin
  IntBeforeThreadExecution(Dataset, CurrentOperation);
end;

procedure TJvBaseDatasetThreadHandler.SynchContinueFetchMessageDlg;
var
  Buttons: array of string;
  Results: array of Integer;
  L: Integer;

  procedure AddButton(Caption: string; ResultValue: Integer);
  begin
    Inc(L);
    SetLength (Buttons, L);
    SetLength (Results, L);
    Buttons[L-1] := Caption;
    Results[L-1] := ResultValue;
  end;

begin
  L := 0;
  AddButton(RsODSContinueYes, Integer(mrYes));
  if EnhancedOptions.AllowedContinueRecordFetchOptions.Pause then
    AddButton(RsODSContinuePause, Integer(mrCancel));
  AddButton(RsODSContinueNo, Integer(mrNo));
  if EnhancedOptions.AllowedContinueRecordFetchOptions.All then
    AddButton(RsODSContinueAll, Integer(mrAll));
  if EnhancedOptions.AllowedContinueRecordFetchOptions.Cancel then
    AddButton(RsODSContinueClose, Integer(mrAbort));
  FSynchMessageDlgBtn := JvDSADialogs.MessageDlgEx(FSynchMessageDlgMsg,
      mtConfirmation, Buttons, Results, 0, dckActiveForm, 0,
      0, 1, -1, DialogOptions.DynControlEngine);
end;

procedure TJvBaseDatasetThreadHandler.SynchErrorMessageDlg;
begin
  FSynchMessageDlgBtn := JvDSADialogs.MessageDlg(FSynchMessageDlgMsg,
    mtError, [mbOK], 0, dckScreen, 0,
    mbDefault, mbDefault, mbHelp, DialogOptions.DynControlEngine);
end;

procedure TJvBaseDatasetThreadHandler.ThreadExecute(Sender: TObject; Params: Pointer);
begin
  OperationWasHandledInThread := True;
  try
    SetErrorMessage('');
    ExecuteThreadSynchronize(SynchBeforeThreadExecution);
    try
      case FCurrentOperation of
        tdoOpen:
          DoThreadOpen;
        tdoRefresh:
          DoThreadRefresh;
        tdoLast:
          DoThreadLast;
      end;
    except
      on E: Exception do
      begin
        SetErrorMessage(E.Message);
        if ThreadOptions.ShowExceptionMessage then
        begin
          FSynchMessageDlgMsg := E.Message;
          ExecuteThreadSynchronize(SynchErrorMessageDlg);
        end;
      end;
    end;
    ExecuteThreadSynchronize(SynchAfterThreadExecution);
  finally
    FCurrentOperation := tdoNothing;
  end;
end;

function TJvBaseDatasetThreadHandler.ThreadIsActive: Boolean;
begin
  Result := not ExecuteThread.Terminated;
end;

//=== { TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions } ============

constructor TJvBaseThreadedDatasetAllowedContinueRecordFetchOptions.Create;
begin
  inherited Create;
  FAll := False;
  FCancel := False;
  FPause := False;
end;

{$IFDEF UNITVERSIONING}
initialization
  RegisterUnitVersion(HInstance, UnitVersioning);

finalization
  UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.

