unit QExport4;

{$R QEResStr.res}
{$R QEEULA.res}

{$I QExport4VerCtrl.inc}

{$IFDEF VCL6}
  {$WARN UNIT_PLATFORM OFF}
{$ENDIF}

interface

uses
  {$IFDEF VCL16}
    System.Classes,
    Data.DB,
    Vcl.Graphics,
    Vcl.ExtCtrls,
    Winapi.Windows,
    {$IFDEF VCL10}
      System.WideStrings,
    {$ELSE}
      QExport4EmsWideStrings,
    {$ENDIF}
    {$IFNDEF NOGUI}
       Vcl.ComCtrls,
       Vcl.DbGrids,
       Vcl.Grids,
    {$ENDIF}
       Vcl.ClipBrd,
  {$ELSE}
    Classes,
    DB,
    Graphics,
    ExtCtrls,
    Windows,
    {$IFDEF VCL10}
      WideStrings,
    {$ELSE}
      QExport4EmsWideStrings,
    {$ENDIF}
    {$IFNDEF NOGUI}
       ComCtrls,
       DbGrids,
       Grids,
    {$ENDIF}
       ClipBrd,
  {$ENDIF}
  QExport4Types,
  QExport4CustomSource,
  QExport4EmsWideStrUtils,
  QExport4IniFiles;

type
  TQExportRow = class;
  TQExport4 = class;

  TNormalFunc = function(const Str: QEString): QEString of object;
  TSpecialCharacters = set of AnsiChar;
  TQExportSource = (esDataSet, esListView, esDBGrid, esStringGrid, esCustom);
  TQExportColAlign = (ecaLeft, ecaCenter, ecaRight);
  TQExportPageOrientation = (poPortrait, poLandscape);
  TQExportUnits = (unInch, unMillimeter, unDot);
  TQExportPageFormat = (pfLetter, pfLegal, pfA3, pfA4, pfA5, pfB5_JIS,
    pfUS_Std_Fanfold, pfFanfold, pfUser);

  {$IFDEF QE_UNICODE}
  TQExportCharsetType =
      (ectLocalANSI, ectLocalOEM, ectLocalMAC,
//      ectArmscii8, ectAscii, ectCp850, ectCp852, ectCp866, ectCp1250,     /// dee test
//      ectCp1251, ectCp1256, ectCp1257, ectDec8, ectGeostd8, ectGreek,
//      ectHebrew, ectHp8, ectKeybcs2, ectKoi8r, ectKoi8u, ectLatin1,
//      ectLatin2, ectLatin5, ectLatin7, ectMacce, ectMacroman, ectSwe7,
      ectUTF8, ectUTF16, ectUTF32);
  {$ELSE}
  TQExportCharsetType = (ectLocalANSI);
  {$ENDIF}

{  TQExportCodePage = (cpLocalANSI, cpLocalOEM, cpLocalMAC, cpUTF8, cpUTF16, cpUTF32,
    cpIBM037, cpIBM437, cpIBM500, cpASMO708, cpASMO449, cpTransparentArabic,
    cpDOS720, cpIBM737, cpIBM775, cpIBM850, cpIBM852, cpIBM855, cpIBM857,
    cpIBM00858, cpIBM860, cpIBM861, cpDOS862, cpIBM863, cpIBM864,
    cpIBM865, cp866, cpIBM869, cpIBM870, cpWindows874, cp875, cpShiftJIS,
    cpGB2312, cpKSc56011987, cpBig5, cpIBM1026, cpIBM01047, cpIBM01140,
    cpIBM01141, cpIBM01142, cpIBM01143, cpIBM01144, cpIBM01145, cpIBM01146,
    cpIBM01147, cpIBM01148, cpIBM01149, cpUnicodeFFFE, cpWindows1250,
    cpWindows1251, cpWindows1252, cpWindows1253, cpWindows1254, cpWindows1255,
    cpWindows1256, cpWindows1257, cpWindows1258, cpJohab, cpMacintosh,
    cpXMACJapanese, cpXMACChinesetrad, cpXMACKorean, cpXMACArabic, cpXMACHebrew,
    cpXMACGreek, cpXMACCyrillic, cpXMACChinesesimp, cpXMACRomanian,
    cpXMACUkrainian, cpXMACThai, cpXMACCe, cpXMACIcelandic, cpXMACTurkish,
    CPXMACCroatian, cpUTF32BE, cpXChineseCNS, cpXCP20001, cpXChineseEten,
    cpXCP20003, cpXCP20004, cpXCP20005, cpXIA5, cpXIA5German, cpXIA5Swedish,
    cpXIA5Norwegian, cpUSASCII, cpXCP20261, cpXCP20269, cpIBM273,
    cpIBM277, cpIBM278, cpIBM280, cpIBM284, cpIBM285, cpIBM290, cpIBM297,
    cpIBM420, cpIBM423, cpIBM424, cpXEBCDICKoreanExtended, cpIBMThai,
    cpKOI8R, cpIBM871, cpIBM880, cpIBM905, cpIBM00924, cpEUCJP02081990and01211990,
    cpXCP20936, cpXCP20949, cp1025, cpKOI8U, cpISO88591, cpISO88592, cpISO88593,
    cpISO88594, cpISO88595, cpISO88596, cpISO88597, cpISO88598, cpISO88599,
    cpISO885913, cpISO885915, cpXEuropa, cpISO88598I, cpISO2022JP, cpCSISO2022JP,
    cpISO2022JP1bytekana, cpISO2022KR, cpXCP50227, cpISO2022TraditionalChinese,
    cpEBCDICJapaneseKatakanaExtended, cpEBCDICUSCanadaandJapanese,
    cpEBCDICKoreanExtendedandKorean,
    cpEBCDICSimplifiedChineseExtendedandSimplifiedChinese,
    cpEBCDICSimplifiedChinese, cpEBCDICUSCanadaandTraditionalChinese,
    cpEBCDICJapaneseLatinExtendedandJapanese, cpEUCJP, cpEUCCN, cpEUCKR,
    cpEUCTraditionalChinese, cpHZGB2312, //UNDER WXP ONLY!!! cpGB18030,
    cpXISCIIDE, cpXISCIIBE, cpXISCIITA, cpXISCIITE, cpXISCIIAS, cpXISCIIOR,
    cpXISCIIKA, cpXISCIIMA, cpXISCIIGU, cpXISCIIPA, cpUTF7, cpNone);}

  TExportedRecordEvent = procedure(Sender: TObject; RecNo: integer) of object;
  TGetExportTextEvent = procedure(Sender: TObject; ColNo: integer;
    var Text: QEString) of object;
  TGetCellParamsEvent = procedure(Sender: TObject; RecNo, ColNo: integer;
    const Value: QEString; var Align: TQExportColAlign; AFont: TFont;
    var Background: TColor) of object;
  TQExportStopEvent = procedure(Sender: TObject;
    var CanContinue: boolean) of object;
  TBeforeExportRowEvent = procedure(Sender: TObject; Row: TQExportRow;
    var Accept: boolean) of object;
  TOnCustomFormat = procedure(Sender: TObject; Field: TField;
    var Value: QEString) of object;

  TLocalizeEvent = procedure(StringID: Integer; var ResultString: string) of object;

  TQExportLocale = class(TObject)
  private
    FDllHandle: Cardinal;
    FLoaded: Boolean;
    FOnLocalize: TLocalizeEvent;
    FIDEMode: Boolean;
  public
    constructor Create;
    function LoadStr(ID: Integer): string;
    procedure LoadDll(const Name: string);
    procedure UnloadDll;
    property OnLocalize: TLocalizeEvent read FOnLocalize write FOnLocalize;
  end;

  TQExportFormats = class(TPersistent)
  private
    FDecimalSeparator: char;
    FThousandSeparator: char;
    FDateSeparator: char;
    FTimeSeparator: char;
    FIntegerFormat: string;
    FFloatFormat : string;
    FDateFormat: string;
    FTimeFormat: string;
    FDateTimeFormat: string;
    FCurrencyFormat: string;
    FBooleanTrue: QEString;
    FBooleanFalse: QEString;
    FNullString: QEString;

    FOldDecimalSeparator: char;
    FOldThousandSeparator: char;
    FOldDateSeparator: char;
    FOldTimeSeparator: char;
    FKeepOriginalFormat: Boolean;

    procedure SetIntegerFormat(const Value: string);
    procedure SetFloatFormat(const Value: string);
    procedure SetDateFormat(const Value: string);
    procedure SetTimeFormat(const Value: string);
    procedure SetDateTimeFormat(const Value: string);
    procedure SetCurrencyFormat(const Value: string);
    procedure SetBooleanTrue(const Value: QEString);
    procedure SetBooleanFalse(const Value: QEString);

    procedure SetNullString(const Value: QEString);
    procedure SetDateSeparator(const Value: char);
    procedure SetDecimalSeparator(const Value: char);
    procedure SetThousandSeparator(const Value: char);
    procedure SetTimeSeparator(const Value: char);

  protected
    procedure DefineProperties(Filer: TFiler); override;

    procedure ReadIntegerFormat(Reader: TReader);
    procedure ReadFloatFormat(Reader: TReader);
    procedure ReadDateFormat(Reader: TReader);
    procedure ReadTimeFormat(Reader: TReader);
    procedure ReadDateTimeFormat(Reader: TReader);
    procedure ReadCurrencyFormat(Reader: TReader);

    procedure WriteIntegerFormat(Writer: TWriter);
    procedure WriteFloatFormat(Writer: TWriter);
    procedure WriteDateFormat(Writer: TWriter);
    procedure WriteTimeFormat(Writer: TWriter);
    procedure WriteDateTimeFormat(Writer: TWriter);
    procedure WriteCurrencyFormat(Writer: TWriter);
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
    procedure ResetFormats;
    procedure StoreSeparators;
    procedure RestoreSeparators;
    procedure ApplyParams;
    property KeepOriginalFormat: Boolean read FKeepOriginalFormat write
      FKeepOriginalFormat;
  published
    property DecimalSeparator: char read FDecimalSeparator
      write SetDecimalSeparator stored True;
    property ThousandSeparator: char read FThousandSeparator
      write SetThousandSeparator stored True;
    property DateSeparator: char read FDateSeparator write SetDateSeparator
      stored True;
    property TimeSeparator: char read FTimeSeparator write SetTimeSeparator
      stored True;
    property IntegerFormat: string read FIntegerFormat
      write SetIntegerFormat stored False;
    property FloatFormat: string read FFloatFormat
      write SetFloatFormat stored False;
    property DateFormat: string read FDateFormat
      write SetDateFormat stored False;
    property TimeFormat: string read FTimeFormat
      write SetTimeFormat stored False;
    property DateTimeFormat: string read FDateTimeFormat
      write SetDateTimeFormat stored False;
    property CurrencyFormat: string read FCurrencyFormat
      write SetCurrencyFormat stored False;
    property BooleanTrue: QEString read FBooleanTrue
      write SetBooleanTrue  stored True;
    property BooleanFalse: QEString read FBooleanFalse
      write SetBooleanFalse stored True;
    // dee
    property NULLString: QEString read FNullString write SetNullString;
  end;

  TQExportColumns = class;

  TQExportColumn = class(TCollectionItem)
  private
    FNumber: integer;
    FColType: TQExportColType;
    FFieldType: TFieldType;
    {mp - Here is non-Unicode caption}
    FName: string;
    FCaption: string;
    FWidth: integer;
    FColAlign: TQExportColAlign;
    FFormat: string;
    FSQLType: string;
    FLength: integer;
    FTag: integer;

    FAllowFormat: boolean;
    FIsNumeric: boolean;
    FIsString: boolean;
    FIsBlob: boolean;
    FIsMemo: boolean;
    FIsVisible: boolean;
    FIsExported: boolean;

    FNumPrecision: Integer;
    FNumSize: Integer;

    function GetColumns: TQExportColumns;
    function GetIsDefaultFormat: boolean;
  public
    constructor Create(Collection: TCollection); override;
    procedure SetDefaultFormat;
    function GetDefaultFormat: string;

    property Columns: TQExportColumns read GetColumns;

    property Number: integer read FNumber write FNumber;
    property Name: string read FName write FName;
    property Caption: string read FCaption write FCaption;
    property Width: integer read FWidth write FWidth;
    property ColType: TQExportColType read FColType write FColType;
    property FieldType: TFieldType read FFieldType write FFieldType;
    property ColAlign: TQExportColAlign read FColAlign write FColAlign;
    property Format: string read FFormat write FFormat;
    property SQLType: string read FSQLType write FSQLType;
    property Length: integer read FLength write FLength;
    property Tag: integer read FTag write FTag;

    property AllowFormat: boolean read FAllowFormat;
    property IsNumeric: boolean read FIsNumeric;
    property IsString: boolean read FIsString;
    property IsBlob: boolean read FIsBlob;
    property IsMemo: boolean read FIsMemo;
    property IsVisible: boolean read FIsVisible;
    property IsDefaultFormat: boolean read GetIsDefaultFormat;

    property IsExported: boolean read FIsExported write FIsExported;

    property NumPrecision: Integer read FNumPrecision write FNumPrecision default 15;
    property NumSize: Integer read FNumSize write FNumSize default 4;
  end;

  TQExportColumns = class(TCollection)
  private
    FHolder: TPersistent;
    FNormalFunc: TNormalFunc;
    FRecordCounter: integer;

    FOwnerExportedFields: TStrings;
    FOwnerExportSource: TQExportSource;
    FOwnerDataSet: TDataSet;
    FOwnerCustomSource: TqeCustomSource4;
    {$IFNDEF NOGUI}
    FOwnerListView: TListView;
    FOwnerDBGrid: TDBGrid;
    FOwnerStringGrid: TStringGrid;
    {$ENDIF}
    FOwnerOnlyVisibleFields: boolean;
    FOwnerFormats: TQExportFormats;
    FOwnerAutoCalcStrType: boolean;
    FOwnerUserFormats: TStrings;
    FOwnerColumnsWidth: TStrings;
    FOwnerCaptions: TStrings;
    FOwnerColumnsAlign: TStrings;
    FOwnerSkipRecCount: integer;
    FOwnerExportRecCount: integer;
    FOwnerColumnsLength: TStrings;
    FOwnerCaptionRow: integer;
    FOwnerAutoCalcColWidth: Boolean;

    FOwnerOnFetchedRecord: TExportedRecordEvent;

    function GetColumn(Index: integer): TQExportColumn;
    procedure SetColumn(Index: integer; Value: TQExportColumn);

    procedure LoadOwnerProperties;

    function SetColumnNumber(Index: integer; BLOB: boolean): integer;
    procedure SetColumnName(Index: integer);
    procedure SetColumnType(Index: integer);
    procedure SetColumnFormat(Index: integer);
    procedure SetColumnWidth(Index: integer);
    procedure SetColumnCaption(Index: integer);
    procedure SetColumnAlign(Index: integer);
    procedure SetColumnLength(Index: integer);
    procedure SetColumnSQLType(Index: integer);

    procedure SetColumnAllowFormat(Index: integer);
    procedure SetColumnIsNumeric(Index: integer);
    procedure SetColumnIsString(Index: integer);
    procedure SetColumnIsBlob(Index: integer);
    procedure SetColumnIsMemo(Index: integer);
    procedure SetColumnIsVisible(Index: integer);
  public
    constructor Create(Holder: TPersistent; NormalFunc: TNormalFunc);

    function Add: TQExportColumn;
    procedure Fill(BLOB: boolean);
    procedure AutoCalcColWidth(const AllowCaptions: Boolean);
    function IndexOfName(const AName: string): integer;
    procedure EmptyTags;
    function GetColumnIsNull(Index: integer): boolean;
    function GetColumnData(Index: integer): Variant;
    function ContainsBLOB: boolean;
    function ContainsMEMO: boolean;

    property Holder: TPersistent read FHolder;
    property Items[Index: integer]: TQExportColumn read GetColumn
      write SetColumn; default;
  end;

{$M+}
  TQExportWriter = class
  private
    FStream: TStream;
    FOwner: TComponent;
  {$IFDEF QE_UNICODE}
  protected
    procedure WriteToStreamUsingCharset(Stream: TStream; WS: WideString;
      CharsetType: TQExportCharsetType);
    procedure WriteUsingCharset(WS: WideString); virtual;
  {$ENDIF}
  protected
    property Owner: TComponent read FOwner;
  public
    constructor Create(AOwner: TQExport4; AStream: TStream); virtual;

    procedure Write(const S: QEString);
    procedure WriteLn(const S: QEString);
    {$IFDEF QE_UNICODE}
    procedure WriteSignature;
    {$ENDIF}
    procedure EmptyLine;
    procedure CharLine(Chr: QEChar; Count: integer);
    function PadL(const S: QEString;
      Chr: QEChar; Count: integer): QEString;
    function PadR(const S: QEString;
      Chr: QEChar; Count: integer): QEString;
    function PadC(const S: QEString;
      Chr: QEChar; Count: integer): QEString;
    function AlignToStr(Value: TQExportColAlign): QEString; virtual;

    property Stream: TStream read FStream write FStream;
  end;
{$M-}

  TQExportCol = class;

  TQExportWriterClass = class of TQExportWriter;

  TQExportCol = class
  private
    FName: string;
    FValue: QEString;
    FColumnIndex: integer;
    FRow: TQExportRow;
    FData: Variant;
  public
    constructor Create(Row: TQExportRow);
    property Row: TQExportRow read FRow;
    property ColumnIndex: integer read FColumnIndex;
    property Name: string read FName;
    property Value: QEString read FValue write FValue;
    property Data: Variant read FData write FData;
  end;

  TQExportRow = class(TList)
  private
    FIndex: TStringList;
    FColumns: TQExportColumns;
    FFormats: TQExportFormats;
    function Get(Index: Integer): TQExportCol;
    procedure Put(Index: Integer; const Value: TQExportCol);
  public
    constructor Create(Columns: TQExportColumns; Formats: TQExportFormats);
    destructor Destroy; override;
    function Add(const AName: string; AColumnIndex: integer): TQExportCol;
    procedure Clear; {$IFNDEF VCL3}override;{$ENDIF}
    procedure Delete(Index: integer);
    function First: TQExportCol;
    procedure Insert(Index: Integer; Item: TQExportCol);
    procedure SetValue(const AName, AValue: QEString; AData: Variant);
    procedure ClearValues;
    function Last: TQExportCol;
    function IndexOf(Item: TQExportCol): integer;
    function Remove(Item: TQExportCol): integer;
    function ColByName(const AName: string): TQExportCol;
    property Index: TStringList read FIndex;

    property Columns: TQExportColumns read FColumns;
    property Formats: TQExportFormats read FFormats;
    property Items[Index: Integer]: TQExportCol read Get write Put; default;
  end;

  TQExport4 = class(TComponent)
  private
    FRecordCounter: integer;
    FColumns: TQExportColumns;
    FExportRow: TQExportRow;

    FExportSource: TQExportSource;

    FDataSet: TDataSet;
    FCustomSource: TqeCustomSource4;
    {$IFNDEF NOGUI}
    FDBGrid: TDBGrid;
    FListView: TListView;
    FStringGrid: TStringGrid;
    {$ENDIF}
    FExportedFields: TStrings;

    FTitle: string;
    FHeader: TqeStrings;
    FCaptions: TStrings;
    FAllowCaptions: boolean;
    FFooter: TqeStrings;
    FFormats: TQExportFormats;
    FUserFormats: TStrings;
    FColumnsWidth: TStrings;
    FColumnsAlign: TStrings;
    FColumnsLength: TStrings;

    FCurrentRecordOnly: boolean;
    FGoToFirstRecord: boolean;
    FExportRecCount: integer;
    FSkipRecCount: integer;
    FOnlyVisibleFields: boolean;
    FAutoCalcStrType: boolean;
    FAutoCalcColWidth: boolean;
    FCaptionRow: integer;
    FExportEmpty: boolean;
    FAborted: boolean;

    F_Version: string;
    FAbout: string;

    FOnBeginExport: TNotifyEvent;
    FOnFetchedRecord: TExportedRecordEvent;
    FOnSkippedRecord: TExportedRecordEvent;
    FOnExportedRecord: TExportedRecordEvent;
    FOnStopExport: TQExportStopEvent;
    FOnGetExportText: TGetExportTextEvent;
    FOnGetCellParams: TGetCellParamsEvent;
    FOnEndExport: TNotifyEvent;
    FOnBeforeExportRow: TBeforeExportRowEvent;
    FOnCustomFormat: TOnCustomFormat;

    procedure SetExportedFields(const Value: TStrings);
    procedure SetCaptions(const Value: TStrings);
    procedure SetFooter(const Value: TqeStrings);
    procedure SetHeader(const Value: TqeStrings);
    procedure SetUserFormats(const Value: TStrings);
    procedure SetFormats(const Value: TQExportFormats);
    procedure SetColumnsWidth(const Value: TStrings);
    procedure SetColumnsAlign(const Value: TStrings);
    procedure SetColumnsLength(const Value: TStrings);

    procedure CheckExportSource;
  protected
    FWriter: TQExportWriter;
    {$IFDEF QE_UNICODE}
    FCharsetType: TQExportCharsetType;
    procedure SetCharsetType(const Value: TQExportCharsetType); virtual;
    {$ENDIF}

    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;

    function GetWriterClass: TQExportWriterClass; virtual;
    function GetWriter: TQExportWriter;

    procedure DisableControls;
    procedure CheckFormats; virtual;
    procedure BeginExport; virtual;
    procedure BeforeExport; virtual;
    procedure DoExport;
    procedure AfterExport; virtual;
    procedure EndExport; virtual;
    procedure EnableControls;

    procedure First;
    procedure Next;
    procedure Skip(Count: integer);
    function  EndOfFile: boolean; virtual;

    function GetBookmark: TBookmark;
    procedure GoToBookmark(Bookmark: TBookmark);
    procedure FreeBookmark(Bookmark: TBookmark);

    function IsEmpty: boolean;
    function IsActive: boolean;

    function GetCaptionRow: string; virtual;
    procedure WriteCaptionRow; virtual;
    procedure FillExportRow; virtual;
    function GetDataRow: QEString; virtual;
    procedure WriteDataRow; virtual;

    function GetColCaption(Index: integer): string; virtual;
    function GetColData(ColValue: QEString;
      Column: TQExportColumn): QEString; virtual;

    function GetSpecialCharacters: TSpecialCharacters; virtual;
    procedure SaveProperties(IniFile: TQIniFile); virtual;
    procedure LoadProperties(IniFile: TQIniFile); virtual;

    procedure GetCellParams(RecNo, ColNo: integer; const Value: string;
      var Align: TQExportColAlign; AFont: TFont;
      var Background: TColor); dynamic;
    function CanContinue: boolean;
    procedure CheckUserFomat(const AUserFormat: TStrings);
    procedure DoShowResult; virtual;
    procedure FillExportCol(Index: Integer); virtual;
    procedure ShowResult;
  protected
    property RecordCounter: integer read FRecordCounter write FRecordCounter;
    property Columns: TQExportColumns read FColumns write FColumns;
    property ExportRow: TQExportRow read FExportRow;
  protected
    property Title: string read FTitle write FTitle;
    property AllowCaptions: boolean read FAllowCaptions
      write FAllowCaptions default true;
    property AutoCalcColWidth: boolean read FAutoCalcColWidth
      write FAutoCalcColWidth default false;
    property ColumnsWidth: TStrings read FColumnsWidth write SetColumnsWidth;
    property ColumnsAlign: TStrings read FColumnsAlign write SetColumnsAlign;
    property ColumnsLength: TStrings read FColumnsLength write SetColumnsLength;

    property OnGetCellParams: TGetCellParamsEvent read FOnGetCellParams
      write FOnGetCellParams;
    property OnFetchedRecord: TExportedRecordEvent read FOnFetchedRecord
      write FOnFetchedRecord;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure Execute; virtual;
    procedure ExportToStream(AStream: TStream);
    procedure Abort; virtual;
    function NormalString(const S: QEString): QEString; virtual;

    procedure SavePropertiesToFile(const FileName: string);
    procedure LoadPropertiesFromFile(const FileName: string);

    procedure SavePropertiesToStream(AStream: TStream);
    procedure LoadPropertiesFromStream(AStream: TStream);

    function GetExportedValue(Col: TQExportCol): QEString; virtual;

    property Aborted: boolean read FAborted write FAborted;

    property Header: TqeStrings read FHeader write SetHeader;
    property Captions: TStrings read FCaptions write SetCaptions;
    property Footer: TqeStrings read FFooter write SetFooter;
    property Formats: TQExportFormats read FFormats write SetFormats;
    property UserFormats: TStrings read FUserFormats write SetUserFormats;
    {$IFDEF QE_UNICODE}
    property CharsetType: TQExportCharsetType read FCharsetType write SetCharsetType;
    {$ENDIF}
  published
    property ExportSource: TQExportSource read FExportSource
      write FExportSource default esDataSet;
    property DataSet: TDataSet read FDataSet write FDataSet;
    property CustomSource: TqeCustomSource4 read FCustomSource
      write FCustomSource;
    {$IFNDEF NOGUI}
    property ListView: TListView read FListView write FListView;
    property DBGrid: TDBGrid read FDBGrid write FDBGrid;
    property StringGrid: TStringGrid read FStringGrid write FStringGrid;
    {$ENDIF}
    property ExportedFields: TStrings read FExportedFields
      write SetExportedFields;

    property CurrentRecordOnly: boolean read FCurrentRecordOnly
      write FCurrentRecordOnly default false;
    property GoToFirstRecord: boolean read FGoToFirstRecord
      write FGoToFirstRecord default true;
    property ExportRecCount: integer read FExportRecCount
      write FExportRecCount default 0;
    property SkipRecCount: integer read FSkipRecCount
      write FSkipRecCount default 0;
    property OnlyVisibleFields: boolean read FOnlyVisibleFields
      write FOnlyVisibleFields default false;
    property AutoCalcStrType: boolean read FAutoCalcStrType
      write FAutoCalcStrType default false;
    property CaptionRow: integer read FCaptionRow write FCaptionRow default -1;
    property ExportEmpty: boolean read FExportEmpty
      write FExportEmpty default true;

    property About: string read FAbout write FAbout;
    property _Version: string read F_Version write F_Version;

    property OnBeginExport: TNotifyEvent read FOnBeginExport
      write FOnBeginExport;
    property OnEndExport: TNotifyEvent read FOnEndExport write FOnEndExport;
    property OnSkippedRecord: TExportedRecordEvent read FOnSkippedRecord
      write FOnSkippedRecord;
    property OnExportedRecord: TExportedRecordEvent read FOnExportedRecord
      write FOnExportedRecord;
    property OnStopExport: TQExportStopEvent read FOnStopExport
      write FOnStopExport;
    property OnGetExportText: TGetExportTextEvent read FOnGetExportText
      write FOnGetExportText;
    property OnBeforeExportRow: TBeforeExportRowEvent read FOnBeforeExportRow
      write FOnBeforeExportRow;
    property OnCustomFormat: TOnCustomFormat read FOnCustomFormat
      write FOnCustomFormat;
  end;

  TQExport4Text = class(TQExport4)
  private
    FFileName,
    FOldFileName,
    FExportedFileName: string;
    FShowFile: boolean;
    FPrintFile: boolean;
    FAppendDateTimeToFileName: Boolean;
  protected
    procedure AfterExecute; virtual;
    procedure BeforeExecute; virtual;
    procedure SaveProperties(IniFile: TQIniFile); override;
    procedure LoadProperties(IniFile: TQIniFile); override;
    function GetShowedFileName: string; virtual;
    function GetPrintedFileName: string; virtual;
    procedure DoShowResult; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Execute; override;
    property AppendDateTimeToFileName: Boolean read FAppendDateTimeToFileName
      write FAppendDateTimeToFileName;
    property ExportedFileName: String read FExportedFileName
      write FExportedFileName;
  published
    property FileName: string read FFileName write FFileName;
    property ShowFile: boolean read FShowFile write FShowFile default false;
    property PrintFile: boolean read FPrintFile write FPrintFile default false;
  end;

  TQExport4AdvancedText = class(TQExport4Text)
  protected
    procedure SaveProperties(IniFile: TQIniFile); override;
    procedure LoadProperties(IniFile: TQIniFile); override;
  published
    property Header;
    property Footer;
  end;

  TQExport4FormatTextSQL = class(TQExport4AdvancedText)
  protected
    procedure SaveProperties(IniFile: TQIniFile); override;
    procedure LoadProperties(IniFile: TQIniFile); override;
  published
    property Formats;
    property UserFormats;
  end;

  TQExport4FormatText = class(TQExport4AdvancedText)
  protected
    procedure SaveProperties(IniFile: TQIniFile); override;
    procedure LoadProperties(IniFile: TQIniFile); override;
  published
    property AllowCaptions;
    property Captions;
    property Formats;
    property UserFormats;
  end;

  TQExport4Memory = class(TQExport4)
  private
    FReplaceZeroChars: Boolean;
  protected
    function GetColData(ColValue: QEString;
      Column: TQExportColumn): QEString; override;
  public
//    {$IFNDEF NOGUI}
    procedure Execute; override;
//    {$ENDIF}
    property ReplaceZeroChars: Boolean read FReplaceZeroChars
      write FReplaceZeroChars;
  end;

//  {$IFNDEF NOGUI}
  {$IFDEF QE_UNICODE}
  TWideClipboard = class(TClipboard)
  private
    {$IFDEF VER130}
    FOpenRefCount: Integer;
    FClipboardWindow: HWND;
    FAllocated: Boolean;
    FEmptied: Boolean;
    procedure Adding;
    procedure SetVer130TextBuf(const Value: WideString);
    {$ENDIF}
    function GetAsWideText: WideString;
    procedure SetAsWideText(const Value: WideString);
  public
    property AsWideText: WideString read GetAsWideText write SetAsWideText;
  end;
  {$ENDIF}
//  {$ENDIF}

function DataType2QExportColType(Field: TField): TQExportColType;
function DataType2SQLType(Field: TField): string;
function QExportType2SQLType(Column: TQExportColumn): string;
function QExportColTypeAsString(ExportColType: TQExportColType): string;
function QExportSourceAsString(ExportSource: TQExportSource): string;

function QExportLocale: TQExportLocale;
function QExportLoadStr(ID: Integer): string;

implementation

uses
  {$IFDEF VCL16}
    System.StrUtils,
    System.SysUtils,
    System.TypInfo,
    Winapi.ShellAPI,
    QExport4StrIDs,
    {$IFDEF ADVANCED_DATA_EXPORT_TRIAL_VERSION}
      fuQExport4About,
    {$ENDIF}
    Vcl.FileCtrl,
  {$ELSE}
    {$IFDEF VCL6}
      StrUtils,
    {$ENDIF}
    SysUtils,
    TypInfo,
    ShellAPI,
    QExport4StrIDs,
    {$IFDEF ADVANCED_DATA_EXPORT_TRIAL_VERSION}
      fuQExport4About,
    {$ENDIF}
    FileCtrl,
  {$ENDIF}
  {$IFDEF VCL17}
    System.Types,
  {$ENDIF}
  QExport4Common;

type
  TShowResultThread = class(TThread)
  private
    FExport: TQExport4;
    procedure SyncShowResult;
  protected
    procedure Execute; override;
  public
    constructor Create(AExport: TQExport4);
  end;

var
  Locale: TQExportLocale = nil;

function QExportLocale: TQExportLocale;
begin
  if Locale = nil then
    Locale := TQExportLocale.Create;
  Result := Locale;
end;

function QExportLoadStr(ID: Integer): string;
begin
  Result := QExportLocale.LoadStr(ID);
end;

function DataType2QExportColType(Field: TField): TQExportColType;
begin
  Result := ectUnknown;
  if not Assigned(Field) then Exit;
  case Field.DataType of
    ftMemo,
    ftFmtMemo,
    {$IFNDEF VCL3}
    ftOraClob,
    ftWideString,
    {$ENDIF}
    {$IFDEF VCL10}
    ftWideMemo,
    ftFixedWideChar,
    {$ENDIF}
    ftFixedChar,
    ftString, ftGuid: Result := ectString;
    ftSmallint, ftInteger,
    {$IFDEF VCL12}
    ftByte, ftShortInt,
    {$ENDIF}
    ftWord, ftAutoInc: Result := ectInteger;
    {$IFNDEF VCL3}
    ftLargeInt: Result := ectBigint;
    {$ENDIF}
    {$IFDEF VCL12}
    ftLongWord: Result := ectBigInt;
    {$ENDIF}
    ftBoolean: Result := ectBoolean;
    ftFloat:  Result := ectFloat;
    {$IFDEF VCL6}
    ftFMTBcd:
      begin
        if TFMTBCDField(Field).currency then
          Result := ectCurrency
        else
          Result := ectNumeric;
      end;
    {$ENDIF}
    ftBCD:
      begin
        if TBCDField(Field).currency then
          Result := ectCurrency
        else
          Result := ectNumeric;
      end;
    ftCurrency: Result := ectCurrency;
    ftDate: Result := ectDate;
    ftTime: Result := ectTime;
    {$IFDEF VCL6}
    ftTimeStamp,
    {$ENDIF}
    ftDateTime: Result := ectDateTime;
  end;
end;

function DataType2SQLType(Field: TField): string;
begin
  Result := 'UNKNOWN';
  case Field.DataType of
    ftOraBlob, ftBlob, ftMemo, ftGraphic, ftFmtMemo: Result := 'BLOB';
    {$IFNDEF VCL3} ftWideString, {$ENDIF}
    ftString: Result := Format('CHAR(%d)', [Field.Size]);
    ftSmallint, ftInteger, {$IFNDEF VCL3} ftLargeInt, {$ENDIF}
    ftWord, ftBoolean: Result := 'INTEGER';
    ftFloat, ftBCD, {$IFDEF VCL6} ftFMTBcd, {$ENDIF} ftCurrency: Result := 'DOUBLE PRECISION';
    ftDate, ftTime, ftDateTime: Result := 'DATE';
    ftOraClob: Result := 'CLOB'
  end;
end;

function QExportType2SQLType(Column: TQExportColumn): string;
begin
  case Column.ColType of
    ectInteger, ectBigint, ectBoolean: Result := 'INTEGER';
    ectFloat, ectCurrency: Result := 'DOUBLE PRECISSION';
    ectDate, ectTime, ectDateTime: Result := 'DATE';
    ectNumeric: Result := Format('NUMERIC(%d,%d)', [Column.NumPrecision,
      Column.NumSize]);
    ectString: Result := Format('CHAR(%d)', [Column.Width]);
  end;
end;

function QExportColTypeAsString(ExportColType: TQExportColType): string;
begin
  case ExportColType of
    ectInteger, ectBigint: Result := 'Integer';
    ectFloat: Result := 'Float';
    ectNumeric: Result := 'Numeric';
    ectCurrency: Result := 'Currency';
    ectDate: Result := 'Date';
    ectTime: Result := 'Time';
    ectDateTime: Result := 'DateTime';
    ectString: Result := 'String';
    ectBoolean: Result := 'Boolean';
    else Result := 'Unknown';
  end;
end;

function QExportSourceAsString(ExportSource: TQExportSource): string;
begin
  case ExportSource of
    esDataSet: Result := 'DataSet';
    esCustom: Result := 'CustomSource';
    esDBGrid: Result := 'DBGrid';
    esListView: Result := 'ListView';
    esStringGrid: Result := 'StringGrid';
    else Result := EmptyStr;
  end;
end;

{$IFDEF ADVANCED_DATA_EXPORT_TRIAL_VERSION}
function IsIDERuning: Boolean;
begin
  Result := (FindWindow('TAppBuilder', nil) <> 0) or
            (FindWindow('TPropertyInspector', nil) <> 0) or
            (FindWindow('TAlignPalette', nil) <> 0);
end;
{$ENDIF}

procedure CheckTrial;
begin
{$IFDEF ADVANCED_DATA_EXPORT_TRIAL_VERSION}
  if not IsIDERuning then
    ShowAboutForm;
{$ENDIF}
end;

{ TQExportFormats }

constructor TQExportFormats.Create;
begin
  inherited;
  ResetFormats;
  FKeepOriginalFormat := False;
  StoreSeparators;
end;

procedure TQExportFormats.Assign(Source: TPersistent);
begin
  if Source is TQExportFormats then begin
    IntegerFormat := (Source as TQExportFormats).IntegerFormat;
    FloatFormat := (Source as TQExportFormats).FloatFormat;
    DateFormat := (Source as TQExportFormats).DateFormat;
    TimeFormat := (Source as TQExportFormats).TimeFormat;
    DateTimeFormat := (Source as TQExportFormats).DateTimeFormat;
    CurrencyFormat := (Source as TQExportFormats).CurrencyFormat;
    BooleanTrue := (Source as TQExportFormats).BooleanTrue;
    BooleanFalse := (Source as TQExportFormats).BooleanFalse;
    NullString := (Source as TQExportFormats).NullString;

    DecimalSeparator := (Source as TQExportFormats).DecimalSeparator;
    ThousandSeparator := (Source as TQExportFormats).ThousandSeparator;
    DateSeparator := (Source as TQExportFormats).DateSeparator;
    TimeSeparator := (Source as TQExportFormats).TimeSeparator;
    FKeepOriginalFormat := (Source as TQExportFormats).KeepOriginalFormat;
    Exit;
  end;
  inherited;
end;

procedure TQExportFormats.ResetFormats;
begin
  FIntegerFormat := DefaultIntegerFormat;
  FFloatFormat := DefaultFloatFormat;
  FDateFormat := DefaultDateFormat;
  FTimeFormat := DefaultTimeFormat;
  FDateTimeFormat := DefaultDateTimeFormat;
  FCurrencyFormat := DefaultCurrencyFormat;
  FBooleanTrue := S_BOOLEAN_TRUE;
  FBooleanFalse := S_BOOLEAN_FALSE;

  FDecimalSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DecimalSeparator;
  FThousandSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}ThousandSeparator;
  FDateSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DateSeparator;
  FTimeSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}TimeSeparator;
end;

procedure TQExportFormats.StoreSeparators;
begin
  FOldDecimalSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DecimalSeparator;
  FOldThousandSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}ThousandSeparator;
  FOldDateSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DateSeparator;
  FOldTimeSeparator :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}TimeSeparator;
end;

procedure TQExportFormats.RestoreSeparators;
begin
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DecimalSeparator :=
    FOldDecimalSeparator;
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}ThousandSeparator :=
    FOldThousandSeparator;
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DateSeparator :=
    FOldDateSeparator;
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}TimeSeparator :=
    FOldTimeSeparator;
end;

{Change Sysutils separators for export sequence}
procedure TQExportFormats.ApplyParams;
begin
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DecimalSeparator :=
    FDecimalSeparator;
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}ThousandSeparator :=
    FThousandSeparator;
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}DateSeparator :=
    FDateSeparator;
  {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.{$IFDEF VCL17}FormatSettings.{$ENDIF}TimeSeparator :=
    FTimeSeparator;
end;

procedure TQExportFormats.SetIntegerFormat(const Value: string);
begin
  if FIntegerFormat <> Value then
    if Value = EmptyStr
      then FIntegerFormat := DefaultIntegerFormat
      else FIntegerFormat := Value;
end;

procedure TQExportFormats.SetFloatFormat(const Value: string);
begin
  if FFloatFormat <> Value then
    if Value = EmptyStr then
      FFloatFormat := DefaultFloatFormat
    else
      FFloatFormat := Value;
end;

procedure TQExportFormats.SetDateFormat(const Value: string);
begin
  if FDateFormat <> Value then
    if Value = EmptyStr
      then FDateFormat := DefaultDateFormat
      else FdateFormat := Value;
end;

procedure TQExportFormats.SetDateSeparator(const Value: char);
begin
  if FDateSeparator <> Value then
    FDateSeparator := Value;
end;

procedure TQExportFormats.SetThousandSeparator(const Value: char);
var
  SysThoSep: Char;
begin
  inherited;
  SysThoSep := {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.
               {$IFDEF VCL17}FormatSettings.{$ENDIF}ThousandSeparator;
  if FThousandSeparator <> Value then
    if Value = '' then
      FThousandSeparator := SysThoSep
    else
      FThousandSeparator := Value;
end;

procedure TQExportFormats.SetTimeFormat(const Value: string);
begin
  if FTimeFormat <> Value then
    if Value = EmptyStr
      then FTimeFormat := DefaultTimeFormat
      else FTimeFormat := Value;
end;

procedure TQExportFormats.SetTimeSeparator(const Value: char);
begin
  if FTimeSeparator <> Value then
    FTimeSeparator := Value;
end;

procedure TQExportFormats.SetDateTimeFormat(const Value: string);
begin
  if FDateTimeFormat <> Value then
    if Value = EmptyStr
      then FDateTimeFormat := DefaultDateTimeFormat
      else FDateTimeFormat := Value;
end;

procedure TQExportFormats.SetDecimalSeparator(const Value: char);
var
  SysDecSep: Char;
begin
  inherited;
  SysDecSep := {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.
               {$IFDEF VCL17}FormatSettings.{$ENDIF}DecimalSeparator;
  if FDecimalSeparator <> Value then
    if Value = '' then
      FDecimalSeparator := SysDecSep
    else
      FDecimalSeparator := Value;
end;

procedure TQExportFormats.SetCurrencyFormat(const Value: string);
begin
  if FCurrencyFormat <> Value then
    if Value = EmptyStr
      then FCurrencyFormat := DefaultCurrencyFormat
      else FCurrencyFormat := Value;
end;

procedure TQExportFormats.SetBooleanTrue(const Value: QEString);
begin
  if FBooleanTrue <> Value then
    if Value = EmptyStr
      then FBooleanTrue := S_BOOLEAN_TRUE
      else FBooleanTrue := Value;
end;

procedure TQExportFormats.SetBooleanFalse(const Value: QEString);
begin
  if FBooleanFalse <> Value then
    if Value = EmptyStr
      then FBooleanFalse := S_BOOLEAN_FALSE
      else FBooleanFalse := Value;
end;

procedure TQExportFormats.SetNullString(const Value: QEString);
begin
  FNullString := Trim(Value);
end;

procedure TQExportFormats.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);

  Filer.DefineProperty('IntegerFormat', ReadIntegerFormat, WriteIntegerFormat,
    True);
  Filer.DefineProperty('FloatFormat', ReadFloatFormat, WriteFloatFormat,
    True);
  Filer.DefineProperty('DateFormat', ReadDateFormat, WriteDateFormat,
    True);
  Filer.DefineProperty('TimeFormat', ReadTimeFormat, WriteTimeFormat,
    True);
  Filer.DefineProperty('DateTimeFormat', ReadDateTimeFormat, WriteDateTimeFormat,
    True );
  Filer.DefineProperty('CurrencyFormat', ReadCurrencyFormat, WriteCurrencyFormat,
    True);
end;

procedure TQExportFormats.ReadIntegerFormat(Reader: TReader);
begin
  FIntegerFormat := Reader.ReadString;
end;

procedure TQExportFormats.ReadFloatFormat(Reader: TReader);
begin
  FFloatFormat := Reader.ReadString;
end;

procedure TQExportFormats.ReadDateFormat(Reader: TReader);
begin
  FDateFormat := Reader.ReadString;
end;

procedure TQExportFormats.ReadTimeFormat(Reader: TReader);
begin
  FTimeFormat := Reader.ReadString;
end;

procedure TQExportFormats.ReadDateTimeFormat(Reader: TReader);
begin
  FDateTimeFormat := Reader.ReadString;
end;

procedure TQExportFormats.ReadCurrencyFormat(Reader: TReader);
begin
  FCurrencyFormat := Reader.ReadString;
end;

procedure TQExportFormats.WriteIntegerFormat(Writer: TWriter);
begin
  Writer.WriteString(FIntegerFormat);
end;

procedure TQExportFormats.WriteFloatFormat(Writer: TWriter);
begin
  Writer.WriteString(FFloatFormat);
end;

procedure TQExportFormats.WriteDateFormat(Writer: TWriter);
begin
  Writer.WriteString(FDateFormat);
end;

procedure TQExportFormats.WriteTimeFormat(Writer: TWriter);
begin
  Writer.WriteString(FTimeFormat);
end;

procedure TQExportFormats.WriteDateTimeFormat(Writer: TWriter);
begin
  Writer.WriteString(FDateTimeFormat);
end;

procedure TQExportFormats.WriteCurrencyFormat(Writer: TWriter);
begin
  Writer.WriteString(FCurrencyFormat);
end;

{ TQExportColumn }

constructor TQExportColumn.Create(Collection: TCollection);
begin
  inherited;
  FTag := 0;
  FFieldType := ftUnknown;
end;

function TQExportColumn.GetColumns: TQExportColumns;
begin
  Result := Collection as TQExportColumns;
end;

function TQExportColumn.GetIsDefaultFormat: boolean;
begin
  Result := false;
  if FAllowFormat then
    case FColType of
      ectInteger, ectBigint: Result := FFormat = Columns.FOwnerFormats.IntegerFormat;
      ectFloat, ectNumeric: Result := FFormat = Columns.FOwnerFormats.FloatFormat;
      ectDate: Result := FFormat = Columns.FOwnerFormats.DateFormat;
      ectTime: Result := FFormat = Columns.FOwnerFormats.TimeFormat;
      ectDateTime: Result := FFormat = Columns.FOwnerFormats.DateTimeFormat;
      ectCurrency: Result := FFormat = Columns.FOwnerFormats.CurrencyFormat;
    end;
end;

function TQExportColumn.GetDefaultFormat: string;
begin
  Result := EmptyStr;
  if FAllowFormat then
    case FColType of
      ectInteger, ectBigint: Result := Columns.FOwnerFormats.IntegerFormat;
      ectFloat, ectNumeric: Result := Columns.FOwnerFormats.FloatFormat;
      ectDate: Result := Columns.FOwnerFormats.DateFormat;
      ectTime: Result := Columns.FOwnerFormats.TimeFormat;
      ectDateTime: Result := Columns.FOwnerFormats.DateTimeFormat;
      ectCurrency: Result := Columns.FOwnerFormats.CurrencyFormat;
    end;
end;

procedure TQExportColumn.SetDefaultFormat;
begin
  FFormat := GetDefaultFormat;
end;

{ TQExportColumns }

constructor TQExportColumns.Create(Holder: TPersistent; NormalFunc: TNormalFunc);
begin
  inherited Create(TQExportColumn);
  FHolder := Holder;
  FNormalFunc := NormalFunc;
end;

function TQExportColumns.Add: TQExportColumn;
begin
  Result := TQExportColumn(inherited Add);
end;

function TQExportColumns.GetColumn(Index: integer): TQExportColumn;
begin
  Result := TQExportColumn(inherited Items[Index]);
end;

procedure TQExportColumns.SetColumn(Index: integer; Value: TQExportColumn);
begin
  Items[Index].Assign(Value);
end;

procedure TQExportColumns.LoadOwnerProperties;
var
  PropInfo: PPropInfo;
begin
  PropInfo := GetPropInfo(FHolder.ClassInfo, 'ExportedFields');
  if Assigned(PropInfo) then
    FOwnerExportedFields := TStrings(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'ExportSource');
  if Assigned(PropInfo) then
    FOwnerExportSource := TQExportSource(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'DataSet');
  if Assigned(PropInfo) then
    FOwnerDataSet := TDataSet(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'CustomSource');
  if Assigned(PropInfo) then
    FOwnerCustomSource := TqeCustomSource4(GetOrdProp(FHolder, PropInfo));

  {$IFNDEF NOGUI}
  PropInfo := GetPropInfo(FHolder.ClassInfo, 'ListView');
  if Assigned(PropInfo) then
    FOwnerListView := TListView(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'DBGrid');
  if Assigned(PropInfo) then
    FOwnerDBGrid := TDBGrid(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'StringGrid');
  if Assigned(PropInfo) then
    FOwnerStringGrid := TStringGrid(GetOrdProp(FHolder, PropInfo));
  {$ENDIF}

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'OnlyVisibleFields');
  if Assigned(PropInfo) then
    FOwnerOnlyVisibleFields := Boolean(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'Formats');
  if Assigned(PropInfo) then
    FOwnerFormats := TQExportFormats(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'AutoCalcStrType');
  if Assigned(PropInfo) then
    FOwnerAutoCalcStrType := Boolean(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'CaptionRow');
  if Assigned(PropInfo) then
    FOwnerCaptionRow := Integer(GetOrdProp(FHolder, PropInfo))
  else FOwnerCaptionRow := -1;

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'UserFormats');
  if Assigned(PropInfo) then
    FOwnerUserFormats := TStrings(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'ColumnsWidth');
  if Assigned(PropInfo) then
    FOwnerColumnsWidth := TStrings(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'Captions');
  if Assigned(PropInfo) then
    FOwnerCaptions := TStrings(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'ColumnsAlign');
  if Assigned(PropInfo) then
    FOwnerColumnsAlign := TStrings(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'SkipRecCount');
  if Assigned(PropInfo) then
    FOwnerSkipRecCount := Integer(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'ExportRecCount');
  if Assigned(PropInfo) then
    FOwnerExportRecCount := Integer(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'ColumnsLength');
  if Assigned(PropInfo) then

    FOwnerColumnsLength := TStrings(GetOrdProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'OnFetchedRecord');
  if Assigned(PropInfo) then
    FOwnerOnFetchedRecord := TExportedRecordEvent(GetMethodProp(FHolder, PropInfo));

  PropInfo := GetPropInfo(FHolder.ClassInfo, 'AutoCalcColWidth');
  if Assigned(PropInfo) then
    FOwnerAutoCalcColWidth := Boolean(GetOrdProp(FHolder, PropInfo));
end;

procedure TQExportColumns.Fill(BLOB: boolean);
var
  i, j: integer;
  FColCount: integer;
  FColumn: TQExportColumn;
begin
  LoadOwnerProperties;
  FColCount := 0;
  if FOwnerExportedFields.Count = 0 then begin
    case FOwnerExportSource of
      esDataSet:
        if Assigned(FOwnerDataSet) then
          FColCount := FOwnerDataSet.FieldCount;
      esCustom:
        if Assigned(FOwnerCustomSource) then
          FColCount := FOwnerCustomSource.ColCount;
      {$IFNDEF NOGUI}
      esListView:
        if Assigned(FOwnerListView) then
          FColCount := FOwnerListView.Columns.Count;
      esDBGrid:
        if Assigned(FOwnerDBGrid) then
          FColCount := FOwnerDBGrid.Columns.Count;
      esStringGrid:
        if Assigned(FOwnerStringGrid) then
          FColCount := FOwnerStringGrid.ColCount;
      {$ENDIF}
    end
  end
  else FColCount := FOwnerExportedFields.Count;
  for i := 0 to FColCount - 1 do  begin
    j := SetColumnNumber(i, BLOB);
    if  j = -1 then Continue;
    FColumn := Add;
    FColumn.Number := j;
  end;
  for i := 0 to Count - 1 do begin
    SetColumnName(i);
    SetColumnType(i);
    SetColumnCaption(i);
    SetColumnWidth(i);
    SetColumnFormat(i);
    SetColumnAlign(i);
    SetColumnSQLType(i);
    SetColumnIsString(i);
    SetColumnLength(i);
    SetColumnAllowFormat(i);
    SetColumnIsNumeric(i);
    SetColumnIsBlob(i);
    SetColumnIsMemo(i);
    SetColumnIsVisible(i);
  end;
end;

function TQExportColumns.SetColumnNumber(Index: integer; BLOB: boolean): integer;
var
  Field: TField;
  Column: TqeCustomColumn;
  {$IFNDEF NOGUI}j: integer;{$ENDIF}
begin
  Result := -1;
  if FOwnerExportedFields.Count = 0 then begin
    case FOwnerExportSource of
      esDataSet: begin
        Field := FOwnerDataSet.Fields[Index];
        if Assigned(Field) and
           (((BLOB) or (not Field.IsBlob)) and
            ((not FOwnerOnlyVisibleFields) or Field.Visible)) then
          Result := Index;
      end;
      {$IFNDEF NOGUI}
      esDBGrid: begin
        Field := FOwnerDBGrid.Columns[Index].Field;
        if Assigned(Field)  and
           (((BLOB) or (not Field.IsBlob)) and
            ((not FOwnerOnlyVisibleFields) or Field.Visible)) then
          Result := Index
      end;
      else Result := Index;
      {$ENDIF}
    end;
    Exit;
  end;

  case FOwnerExportSource of
    esDataSet: begin
      if FOwnerExportedFields.Names[Index] <> '' then
        Field := FOwnerDataSet.FieldByName(FOwnerExportedFields.Names[Index])
      else
        Field := FOwnerDataSet.FieldByName(FOwnerExportedFields[Index]);
      if Assigned(Field) and
         ((not FOwnerOnlyVisibleFields) or Field.Visible) then
        Result := Field.Index;
    end;
    esCustom: begin
      Column := FOwnerCustomSource.ColumnByName(FOwnerExportedFields[Index]);
      if Assigned(Column) then
        Result := Column.Index;
    end;
    {$IFNDEF NOGUI}
    esDBGrid:
      for j := 0 to FOwnerDBGrid.Columns.Count - 1 do begin
        Field := FOwnerDBGrid.Columns[j].Field;
        if Assigned(Field) and
           (((AnsiCompareText(Field.FieldName, FOwnerExportedFields[Index]) = 0) or
           (AnsiCompareText(Field.FieldName, FOwnerExportedFields.Names[Index]) = 0)) and
            (not FOwnerOnlyVisibleFields or Field.Visible)) then
          Result := j;
      end;
    esListView:
      for j := 0 to FOwnerListView.Columns.Count - 1 do begin
        if AnsiCompareText(FOwnerListView.Columns[j].Caption,
                           FOwnerExportedFields[Index]) = 0 then
          Result := j;
      end;
    esStringGrid: begin
//dee
      if(Length(FOwnerExportedFields[Index])>Length(S_XML_StringGridFieldName))
      then begin
        Result := StrToIntDef(StringReplace(FOwnerExportedFields[Index],
          S_XML_StringGridFieldName,'',[]), -1);
      end else begin
            Result := StrToIntDef(FOwnerExportedFields[Index], -1);
      end;
//\
      if not ((Result >= 0) and (Result <= FOwnerStringGrid.ColCount)) then
        Result := -1;
    end;
    {$ENDIF}
  end;
end;

procedure TQExportColumns.SetColumnName(Index: integer);
  var
    NameOfValue: String;
begin
  // Items[Index].Number must be defined
  with Items[Index] do
    case FOwnerExportSource of
      esDataSet:
      begin
        if Index < FOwnerExportedFields.Count then
          NameOfValue:=FOwnerExportedFields.Names[Index]
        else
          NameOfValue := '';
        if (NameOfValue <> '') and (FOwnerExportedFields.Values[NameOfValue] <> '') then
          Name := FOwnerExportedFields.Values[NameOfValue]
        else
          Name := FOwnerDataSet.Fields[Number].FieldName;
      end;
      esCustom: Name := FOwnerCustomSource.Columns[Number].ColumnName;
      {$IFNDEF NOGUI}
      esDBGrid:
      begin
        if Index < FOwnerExportedFields.Count then
          NameOfValue:=FOwnerExportedFields.Names[Index]
        else
          NameOfValue := '';
        if (NameOfValue <> '') and (FOwnerExportedFields.Values[NameOfValue] <> '') then
          Name := FOwnerExportedFields.Values[NameOfValue]
        else
          Name := FOwnerDBGrid.Columns[Number].Field.FieldName;
      end;
      esListView: Name := FOwnerListView.Columns[Number].Caption;
      esStringGrid: Name := S_XML_StringGridFieldName+IntToStr(Number);
      {$ENDIF}
    end;
end;

procedure TQExportColumns.SetColumnType(Index: integer);
begin
  // Items[Index].Number must be defined
  with Items[Index] do
    case FOwnerExportSource of
      esDataSet:
      begin
        ColType := DataType2QExportColType(FOwnerDataSet.Fields[Items[Index].Number]);
        FieldType := FOwnerDataSet.Fields[Number].DataType;
        if (ColType in [ectNumeric]) then
        begin
          FNumPrecision := TBCDField(FOwnerDataSet.Fields[Items[Index].Number]).Precision;
          FNumSize := TBCDField(FOwnerDataSet.Fields[Items[Index].Number]).Size;
        end;
        {$IFDEF VCL6}
        if (FOwnerDataSet.Fields[Items[Index].Number] is TFmtBCDField) then
        begin
          FNumPrecision := TFmtBCDField(FOwnerDataSet.Fields[Items[Index].Number]).Precision;
          FNumSize := TFmtBCDField(FOwnerDataSet.Fields[Items[Index].Number]).Size;
        end;
        {$ENDIF}
      end;
      esCustom: ColType := FOwnerCustomSource.Columns[Number].ColumnType;
      {$IFNDEF NOGUI}
      esDBGrid:
      begin
        ColType := DataType2QExportColType(FOwnerDBGrid.Columns[Number].Field);
        FieldType := FOwnerDBGrid.Columns[Number].Field.DataType;
      end;
      esListView:
        if not FOwnerAutoCalcStrType
          then ColType := ectString
          else if FOwnerListView.Items.Count > 0 then begin
            if Number = 0
              then ColType := CalcStringType(FOwnerListView.Items[0].Caption,
                FOwnerFormats.BooleanTrue, FOwnerFormats.BooleanFalse)
              else ColType := CalcStringType(FOwnerListView.Items[0].SubItems[Number - 1],
                FOwnerFormats.BooleanTrue, FOwnerFormats.BooleanFalse);
          end;
      esStringGrid:
        if not FOwnerAutoCalcStrType
          then ColType := ectString
          else ColType := CalcStringType(FOwnerStringGrid.Cells[Number,
            FOwnerStringGrid.Row], FOwnerFormats.BooleanTrue,
            FOwnerFormats.BooleanFalse);
      {$ENDIF}
    end;
end;

procedure TQExportColumns.SetColumnFormat(Index: integer);
var
  i: integer;
begin
  // Items[Index].ColType must be defined
  if Assigned(FOwnerFormats) then
  case Items[Index].ColType of
    ectInteger, ectBigint:
      Items[Index].Format := FOwnerFormats.IntegerFormat;
    ectFloat, ectNumeric:
      Items[Index].Format := FOwnerFormats.FloatFormat;
    ectDate:
      Items[Index].Format := FOwnerFormats.DateFormat;
    ectTime:
      Items[Index].Format := FOwnerFormats.TimeFormat;
    ectDateTime:
      Items[Index].Format := FOwnerFormats.DateTimeFormat;
    ectCurrency:
      Items[Index].Format := FOwnerFormats.CurrencyFormat;
      end;

  if Assigned(FOwnerUserFormats) then
  begin
    i := FOwnerUserFormats.IndexOfName(Items[Index].Name);
    if i > -1 then
      Items[Index].Format :=
        FOwnerUserFormats.Values[FOwnerUserFormats.Names[i]];
    end;
end;

procedure TQExportColumns.SetColumnWidth(Index: integer);
var
  i: integer;
  DataField: TField;

  {//mp - get width for numeric formats}
  function GetWidth(DS: Integer; const CFormat: string): Integer;
  var
    MaxRes: Extended;
    j: Integer;
    TestFlag: Boolean;
  begin
    MaxRes := Exp(DS * 8 * Ln(2));
    Result := 0;
    while MaxRes > 1 do
    begin
      Result := Result + 1;
      MaxRes := MaxRes / 10;
    end;
    TestFlag := false;
    if Pos(',', CFormat) <> 0 then
      Result := Result + (Result div 3);
    for j := 1 to System.Length(CFormat) do
    begin
      if CFormat = '.' then
      begin
        Result := Result + 1;
        TestFlag := true;
      end;
      if (CFormat <> '.')
        and (CFormat <> ',') and TestFlag then
          Result := Result + 1;
    end;
  end;
  {//mp}

begin
  if Assigned(FOwnerColumnsWidth) then
    begin
    i := FOwnerColumnsWidth.IndexOfName(Items[Index].Name);
      if i > -1 then begin
        {Need to correct column width}
      Items[Index].Width := StrToIntDef(FOwnerColumnsWidth.Values[
        FOwnerColumnsWidth.Names[i]], 0);
        Exit;
      end;
    end;

  if FOwnerAutoCalcColWidth then
    Exit;
    
  // Items[Index].Number must be defined
    case FOwnerExportSource of
      esDataSet:
      begin
      DataField := FOwnerDataSet.Fields[Items[Index].Number];
      Items[Index].Width := DataField.DisplayWidth;
      if DataField.DataType in [ftSmallint, ftInteger, ftFloat, ftLargeint] then
        begin
          //if float/integer value is represented in epsilon form
          //then it can contain five symbols {E+-xxx}
          if assigned(FOwnerFormats) then
          if DataField.DataType in [ftSmallint, ftInteger, ftLargeint] then
            Items[Index].Width := GetWidth(DataField.DataSize, FOwnerFormats.FIntegerFormat)
            else
            Items[Index].Width := GetWidth(DataField.DataSize, FOwnerFormats.FFloatFormat);
        end;
      if Items[Index].Width > 100 then Items[Index].Width := 100;
      end;
    esCustom:
      Items[Index].Width := FOwnerCustomSource.Columns[Items[Index].Number].Width;
      {$IFNDEF NOGUI}
    esDBGrid:
      Items[Index].Width := FOwnerDBGrid.Columns[Items[Index].Number].Width div
        FOwnerDBGrid.Canvas.TextWidth('X');
      esListView: begin
      Items[Index].Width := FOwnerListView.Columns[Items[Index].Number].Width div
          GetTextWidth(FOwnerListView, 'X');
      end;
    esStringGrid: Items[Index].Width := FOwnerStringGrid.ColWidths[Items[Index].Number] div
        FOwnerStringGrid.Canvas.TextWidth('X');
      {$ENDIF}
    end;
end;

procedure TQExportColumns.SetColumnCaption(Index: integer);
var
  i: integer;
begin
  if Assigned(FOwnerCaptions) then
    with FOwnerCaptions, Items[Index] do begin
      i := IndexOfName(Name);
      if i > -1 then begin
        Caption := Values[Names[i]];
        Exit;
      end;
    end;
  // Items[Index].Number must be defined
  with Items[Index] do
    case FOwnerExportSource of
      esDataSet: Caption := FOwnerDataSet.Fields[Number].DisplayLabel;
      esCustom: Caption := FOwnerCustomSource.Columns[Number].Caption;
      {$IFNDEF NOGUI}
      esDBGrid: Caption := FOwnerDBGrid.Columns[Number].Title.Caption;
      esListView: Caption := FOwnerListView.Columns[Number].Caption;
      esStringGrid:
        if FOwnerCaptionRow > -1
          then Caption := FOwnerStringGrid.Cells[Number, FOwnerCaptionRow]
          else Caption := 'ColNo_' + IntToStr(Number);
      {$ENDIF}
    end;
end;

procedure TQExportColumns.SetColumnAlign(Index: integer);
var
  i: integer;
  s: String;
begin
  // Items[Index].ColType must be defined
  if Assigned(FOwnerColumnsAlign) then
    with FOwnerColumnsAlign, Items[Index] do begin
      i := IndexOfName(Name);
      if i > -1 then begin
        s := AnsiUpperCase(Values[Names[i]]);
        if s <> '' then
          case s[1] of
            'L': ColAlign := ecaLeft;
            'C': COlAlign := ecaCenter;
            'R': ColAlign := ecaRight;
            else ColAlign := ecaLeft;
          end
        else ColAlign := ecaLeft;
        Exit;
      end;
      case ColType of
        ectInteger,
        ectBigint,
        ectFloat,
        ectNumeric,
        ectCurrency: ColAlign := ecaRight;
        ectBoolean: ColAlign := ecaCenter;
        else ColAlign := ecaLeft;
      end;
    end;
end;

procedure TQExportColumns.AutoCalcColWidth(const AllowCaptions: Boolean);
var
  i, w: integer;
  Bookmark: TBookmark;
  Str: QEstring;
  Data: Variant;
begin
  if AllowCaptions then
    for i := 0 to Count - 1 do
      if not Assigned(FOwnerColumnsWidth) or
        (FOwnerColumnsWidth.IndexOfName(Items[I].Name) < 0) then
      if Length(Items[i].Caption) > Items[i].Width then
        Items[i].Width := Length(Items[i].Caption);

  Bookmark := QExportGetBookmark(FOwnerExportSource, FOwnerDataSet,
    FOwnerCustomSource{$IFNDEF NOGUI}, FOwnerDBGrid, FOwnerListView,
    FOwnerStringGrid{$ENDIF});
  try
    QExportFirst(FOwnerExportSource, FOwnerDataSet, FOwnerCustomSource
      {$IFNDEF NOGUI}, FOwnerDBGrid, FOwnerListView, FOwnerStringGrid{$ENDIF});

    if not QExportIsEmpty(FOwnerExportSource, FOwnerDataSet, FOwnerCustomSource
      {$IFNDEF NOGUI}, FOwnerDBGrid, FOwnerListView, FOwnerStringGrid{$ENDIF}) then
    begin
      for i := 0 to FOwnerSkipRecCount - 1 do
        QExportNext(FOwnerExportSource, FOwnerDataSet, FOwnerCustomSource,
          {$IFNDEF NOGUI}FOwnerDBGrid, FOwnerListView, FOwnerStringGrid,{$ENDIF} FRecordCounter);

      FRecordCounter := 0;
      while not QExportEOF(FOwnerExportSource, FOwnerDataSet, FOwnerCustomSource,
        {$IFNDEF NOGUI}FOwnerDBGrid, FOwnerListView, FOwnerStringGrid,{$ENDIF}
        FRecordCounter, FOwnerExportRecCount, FOwnerSkipRecCount) and
        ((FOwnerExportRecCount = 0) or
         (FRecordCounter < FOwnerExportRecCount)) do
      begin
        //if Aborted and not CanContinue then Break;
        for i := 0 to Count - 1 do
          if not Assigned(FOwnerColumnsWidth) or
            (FOwnerColumnsWidth.IndexOfName(Items[I].Name) < 0) then
        begin
          QExportGetColData(FOwnerExportSource, FOwnerDataSet,
            FOwnerCustomSource, {$IFNDEF NOGUI}FOwnerDBGrid, FOwnerListView,
            FOwnerStringGrid,{$ENDIF} Self, FOwnerFormats, i,
            FRecordCounter, FOwnerSkipRecCount, Str, Data);
          Str := FNormalFunc(Str);
          w := Length(Str);
          if w > Items[i].Width then
            Items[i].Width := w;
        end;
        QExportNext(FOwnerExportSource, FOwnerDataSet, FOwnerCustomSource,
        {$IFNDEF NOGUI}FOwnerDBGrid, FOwnerListView, FOwnerStringGrid,{$ENDIF}
        FRecordCounter);
        if Assigned(FOwnerOnFetchedRecord) then
          FOwnerOnFetchedRecord(Holder, FRecordCounter);
        Sleep(0);
      end;
      QExportGoToBookmark(FOwnerExportSource, FOwnerDataSet, FOwnerCustomSource,
        {$IFNDEF NOGUI}FOwnerDBGrid, FOwnerListView, FOwnerStringGrid,{$ENDIF}
        Bookmark);
    end;
  finally
    QExportFreeBookmark(FOwnerExportSource, FOwnerDataSet,
      {$IFNDEF NOGUI}FOwnerDBGrid, FOwnerListView, FOwnerStringGrid, {$ENDIF}
      Bookmark);
  end;
end;

procedure TQExportColumns.SetColumnSQLType(Index: integer);
begin
  with Items[Index] do begin
    case FOwnerExportSource of
      esDataSet: SQLType := DataType2SQLType(FOwnerDataSet.Fields[Number]);
      esCustom: SQLType := QExportType2SQLType(Items[Index]);
      {$IFNDEF NOGUI}
      esDBGrid: SQLType := DataType2SQLType(FOwnerDBGrid.Columns[Number].Field);
      esListView,
      esStringGrid: QExportType2SQLType(Items[Index]);
      {$ENDIF}
    end;
  end;
end;

procedure TQExportColumns.SetColumnLength(Index: integer);
var
  i: integer;
begin
  if not Items[Index].IsString then Exit;
  if Assigned(FOwnerColumnsLength) then
    if FOwnerExportSource in [esListView, esStringGrid] then
      with FOwnerColumnsLength, Items[Index] do begin
        i := IndexOfName(Name);
        if i > -1 then begin
          Length := StrToIntDef(Values[Names[i]], 255);
          Exit;
        end;
      end;
  /// Items[Index].Number must be defined
  with Items[Index] do
    case FOwnerExportSource of
      esDataSet: Length := FOwnerDataSet.Fields[Number].Size;
      esCustom: Length := MinimumInt(FOwnerCustomSource.Columns[Number].Size, 255);
      {$IFNDEF NOGUI}
      esDBGrid: Length := MinimumInt(FOwnerDBGrid.Columns[Number].Field.Size, 255);
      esListView: Length := 255;
      esStringGrid: Length := 255;
      {$ENDIF}
    end;
end;

procedure TQExportColumns.SetColumnAllowFormat(Index: integer);
begin
  Items[Index].FAllowFormat := Items[Index].ColType in [ectInteger, ectBigint,
    ectFloat, ectNumeric, ectDate, ectTime, ectDateTime, ectCurrency];
end;

procedure TQExportColumns.SetColumnIsNumeric(Index: integer);
begin
  Items[Index].FIsNumeric := Items[Index].ColType in [ectInteger, ectBigint,
    ectFloat, ectNumeric, ectCurrency];
end;

procedure TQExportColumns.SetColumnIsString(Index: integer);
begin
  Items[Index].FIsString := Items[Index].ColType in [ectString];
end;

function TQExportColumns.GetColumnIsNull(Index: integer): boolean;
begin
  case FOwnerExportSource of
    esDataSet: Result := FOwnerDataSet.Fields[Items[Index].Number].IsNull;
    {$IFNDEF NOGUI}
    esDBGrid: Result := FOwnerDBGrid.Columns[Items[Index].Number].Field.IsNull;
    {$ENDIF}
    else Result := false;
  end;
end;

function TQExportColumns.GetColumnData(Index: integer): Variant;
begin
  case FOwnerExportSource of
    esDataSet:
      Result := FOwnerDataSet.Fields[Items[Index].Number].Value;
    {$IFNDEF NOGUI}
    esDBGrid:
      Result := FOwnerDBGrid.Columns[Items[Index].Number].Field.Value;
    {$ENDIF}
  else
    Result := '';
  end;
end;

procedure TQExportColumns.SetColumnIsBlob(Index: integer);
begin
  case FOwnerExportSource of
    esDataSet: Items[Index].FIsBlob := FOwnerDataSet.Fields[Items[Index].Number].IsBlob;
    {$IFNDEF NOGUI}
    esDBGrid: Items[Index].FIsBlob := FOwnerDBGrid.Columns[Items[Index].Number].Field.IsBlob;
    {$ENDIF}
    else Items[Index].FIsBlob := false;
  end;
end;

procedure TQExportColumns.SetColumnIsMemo(Index: integer);
begin
  case FOwnerExportSource of
    esDataSet: Items[Index].FIsMemo :=
      FOwnerDataSet.Fields[Items[Index].Number].DataType in [ftMemo, ftFmtMemo
      {$IFNDEF VCL3}, ftOraClob{$ENDIF}{$IFDEF VCL10}, ftWideMemo{$ENDIF}];
    {$IFNDEF NOGUI}
    esDBGrid: Items[Index].FIsMemo :=
      FOwnerDBGrid.Columns[Items[Index].Number].Field.DataType in [ftMemo, ftFmtMemo
      {$IFNDEF VCL3}, ftOraClob{$ENDIF}{$IFDEF VCL10}, ftWideMemo{$ENDIF}];
    {$ENDIF}
    else Items[Index].FIsMemo := false;
  end;
end;

procedure TQExportColumns.SetColumnIsVisible(Index: integer);
begin
  case FOwnerExportSource of
    esDataSet: Items[Index].FIsVisible := FOwnerDataSet.Fields[Items[Index].Number].Visible;
    {$IFNDEF NOGUI}
    esDBGrid: Items[Index].FIsVisible := FOwnerDBGrid.Columns[Items[Index].Number].Field.Visible;
    {$ENDIF}
    else Items[Index].FIsVisible := true;
  end;
end;

function TQExportColumns.IndexOfName(const AName: string): integer;
var
  i: integer;
begin
  Result := -1;
  for i := 0 to Count - 1 do
    if AnsiCompareText(AName, Items[i].Name) = 0 then begin
      Result := i;
      Exit;
    end;
end;

procedure TQExportColumns.EmptyTags;
var
  i: integer;
begin
  for i := 0 to Count - 1 do
    Items[i].Tag := 0;
end;

function TQExportColumns.ContainsBLOB: boolean;
var
  i: integer;
begin
  Result := false;
  for i := 0 to Count - 1 do
    if Items[i].IsBlob then begin
      Result := true;
      Exit;
    end;
end;

function TQExportColumns.ContainsMEMO: boolean;
var
  i: integer;
begin
  Result := false;
  for i := 0 to Count - 1 do
    if Items[i].IsMemo then begin
      Result := true;
      Exit;
    end;
end;

{ TQExportWriter }

constructor TQExportWriter.Create(AOwner: TQExport4; AStream: TStream);
begin
  inherited Create;
  FStream := AStream;
  FOwner := AOwner;
end;

{$IFDEF QE_UNICODE}
procedure TQExportWriter.WriteToStreamUsingCharset(Stream: TStream; WS: WideString;
  CharsetType: TQExportCharsetType);
var
  s: AnsiString;
  {$IFNDEF VER130}
  UCS4: UCS4String;
  {$ENDIF}
begin
  if WS = EmptyStr then
    Exit;

  case CharsetType of
    ectLocalANSI, ectLocalOEM, ectLocalMAC:
      begin
        s := WideStringToString(WS, Integer(CharsetType));
        Stream.WriteBuffer(s[1], Length(s));
      end;
    ectUTF8:
      begin
        s := UTF8Encode(WS);
        Stream.WriteBuffer(s[1], Length(s));
      end;
    ectUTF16:
      begin
        Stream.WriteBuffer(WS[1], Length(WS) * SizeOf(WideChar));
      end;
    {$IFNDEF VER130}
    ectUTF32:
      begin
        UCS4 := WideStringToUCS4String(WS);
        Stream.WriteBuffer(UCS4[1], Length(UCS4) * SizeOf(LongWord));
      end;
    {$ENDIF}
  end;
end;

procedure TQExportWriter.WriteUsingCharset(WS: WideString);
begin
  if not Assigned(Owner) then Exit;
  WriteToStreamUsingCharset(FStream, WS, TQExport4(Owner).CharsetType);
end;
{$ENDIF}

procedure TQExportWriter.EmptyLine;
begin
  WriteLn(EmptyStr);
end;

procedure TQExportWriter.CharLine(Chr: QEChar; Count: integer);
var
  i: integer;
  str: string;
begin
  str := EmptyStr;
  for i := 0 to Count - 1 do str := str + Chr;
  WriteLn(str);
end;

function TQExportWriter.PadL(const S: QEString;
  Chr: QEChar; Count: integer): QEString;
var
  L, i: integer;
  PadStr: QEString;
begin
  Result := S;
  L := Length(S);
  if L > Count then
    Result := Copy(S, 1, Count)
  else
    if (Count - L) > 0 then
    begin
      SetLength(PadStr, Count - L);
      for i := 1 to Count - L do
        PadStr[i] := Chr;
      Result := PadStr + S;
    end;
end;

function TQExportWriter.PadR(const S: QEString;
  Chr: QEChar; Count: integer): QEString;
var
  L, i: integer;
  PadStr: QEString;
begin
  Result := S;
  L := Length(S);
  if L > Count then
    Result := Copy(S, 1, Count)
  else
    if (Count - L) > 0 then
    begin
      SetLength(PadStr, Count - L);
      for i := 1 to Count - L do
        PadStr[i] := Chr;
      Result := S + PadStr;
    end;
end;

function TQExportWriter.PadC(const S: QEString;
  Chr: QEChar; Count: integer): QEString;
var
  l, r: integer;
begin
  if Length(S) >= Count then
  begin
    Result := Copy(S, 1, Count);
    Exit;
  end;
  Result := S;
  l := (Count - Length(Result)) div 2;
  r := Count - Length(Result) - l;
  Result := PadL(Result, Chr, Length(Result) + l);
  Result := PadR(Result, Chr, Length(Result) + r);
end;

procedure TQExportWriter.Write(const S: QEString);
begin
{$IFDEF QE_UNICODE}
  WriteUsingCharset(S);
{$ELSE}
  if S <> '' then
    FStream.WriteBuffer(S[1], Length(S));
{$ENDIF}
end;

procedure TQExportWriter.WriteLn(const S: QEString);
begin
  Write(S + CRLF);
end;

{$IFDEF QE_UNICODE}
procedure TQExportWriter.WriteSignature;
{
UTF-8
  $EF $BB $BF
UTF-16BE
  $FE $FF
UTF-16LE
  $FF $FE
UTF-32BE
  $FF $FE $00 $00
UTF-32LE
  $00 $00 $FE $FF
}
const
  UTF8Sign: array [0..2] of Byte = ($EF, $BB, $BF);
  UTF16LESign: array [0..1] of Byte = ($FF, $FE);
  UTF32LESign: array [0..3] of Byte = ($00, $00, $FE, $FF);
begin
  if not Assigned(Owner) then Exit;
  case TQExport4(Owner).CharsetType of
    ectUTF8:
      FStream.WriteBuffer(UTF8Sign, Length(UTF8Sign));
    ectUTF16:
      FStream.WriteBuffer(UTF16LESign, Length(UTF16LESign));
    ectUTF32:
      FStream.WriteBuffer(UTF32LESign, Length(UTF32LESign));
  end;
end;
{$ENDIF}

function TQExportWriter.AlignToStr(Value: TQExportColAlign): QEString;
begin
  case Value of
    ecaLeft: Result := 'Left alignment';
    ecaCenter: Result := 'Center alignment';
    ecaRight: Result := 'Right alignment';
    else Result := 'Unknown alignment';
  end
end;

{ TQExportCol }

constructor TQExportCol.Create(Row: TQExportRow);
begin
  inherited Create;
  FColumnIndex := -1;
  FName := EmptyStr;
  FValue := EmptyStr;
  FRow := Row;
end;

{ TQExportRow }

constructor TQExportRow.Create(Columns: TQExportColumns;
  Formats: TQExportFormats);
begin
  inherited Create;
  FIndex := TStringList.Create;
  FColumns := Columns;
  FFormats := Formats;
end;

destructor TQExportRow.Destroy;
begin
  Clear;
  FIndex.Free;
  inherited;
end;

function TQExportRow.Add(const AName: string; AColumnIndex: integer): TQExportCol;
begin
  Result := TQExportCol.Create(Self);
  Result.FName := Trim(AName);
  Result.FColumnIndex := AColumnIndex;
  inherited Add(Result);
end;

procedure TQExportRow.Clear;
var
  i: integer;
begin
  for i := Count - 1 downto 0 do Delete(i);
  inherited;
end;

procedure TQExportRow.Delete(Index: integer);
begin
  TQExportCol(Items[Index]).Free;
  inherited Delete(Index);
end;

function TQExportRow.First: TQExportCol;
begin
  Result := TQExportCol(inherited First);
end;

procedure TQExportRow.Insert(Index: Integer; Item: TQExportCol);
begin
  inherited Insert(Index, Item);
end;

procedure TQExportRow.SetValue(const AName, AValue: QEString; AData: Variant);
var
  i: integer;
begin
  FIndex.Find(AName, i);
  if i > -1 then begin
    i := Integer(FIndex.Objects[i]);
    Items[i].Value := AValue;
    Items[i].Data := AData;
  end;
end;

procedure TQExportRow.ClearValues;
var
  i: integer;
begin
  for i := 0 to Count - 1 do
    Items[i].Value := EmptyStr
end;

function TQExportRow.Last: TQExportCol;
begin
  Result := TQExportCol(inherited Last);
end;

function TQExportRow.IndexOf(Item: TQExportCol): Integer;
begin
  Result := inherited IndexOf(Item);
end;

function TQExportRow.Remove(Item: TQExportCol): Integer;
begin
  Result := inherited Remove(Item);
end;

function TQExportRow.ColByName(const AName: string): TQExportCol;
var
  i: integer;
begin
  Result := nil;
  for i := 0 to Count - 1 do
    if AnsiCompareText(AName, Items[i].Name) = 0 then begin
      Result := Items[i];
      Exit;
    end;
end;

function TQExportRow.Get(Index: Integer): TQExportCol;
begin
  Result := TQExportCol(inherited Get(Index));
end;

procedure TQExportRow.Put(Index: Integer; const Value: TQExportCol);
begin
  inherited Put(Index, Value);
end;

{ TQExport4 }

constructor TQExport4.Create(AOwner: TComponent);
begin
  inherited;
  FRecordCounter := 0;
  FColumns := TQExportColumns.Create(Self, NormalString);

  FExportSource := esDataSet;
  FExportedFields := TStringList.Create;
  FHeader := TqeStringList.Create;
  FCaptions := TStringList.Create;
  FAllowCaptions := true;
  FFooter := TqeStringList.Create;
  FFormats := TQExportFormats.Create;
  FUserFormats := TStringList.Create;
  FColumnsWidth := TStringList.Create;
  FColumnsAlign := TStringList.Create;
  FColumnsLength := TStringList.Create;

  FExportRow := TQExportRow.Create(Columns, Formats);

  FCurrentRecordOnly := false;
  FGoToFirstRecord := true;
  FSkipRecCount := 0;
  FExportRecCount := 0;
  FOnlyVisibleFields := false;
  FAutoCalcStrType := false;
  FAutoCalcColWidth := false;
  FCaptionRow := -1;
  FExportEmpty := true;

  {$IFDEF QE_UNICODE}
  FCharSetType := ectUTF8;
  {$ENDIF}

  FAborted := false;

  F_Version := S_VERSION_NUMBER;
  FAbout := S_ABOUT;   
end;

destructor TQExport4.Destroy;
begin
  FExportRow.Free;
  FColumns.Free;

  FExportedFields.Free;
  FHeader.Free;
  FCaptions.Free;
  FFooter.Free;
  FFormats.Free;
  FUserFormats.Free;
  FColumnsWidth.Free;
  FColumnsAlign.Free;
  FColumnsLength.Free;
  inherited;
end;

procedure TQExport4.Execute;
begin
end;

procedure TQExport4.ExportToStream(AStream: TStream);
begin
  FWriter := GetWriterClass.Create(Self, AStream);
  try
    DoExport;
  finally
    FWriter.Free;
  end;
end;

procedure TQExport4.Abort;
begin
  FAborted := true;
end;


{$IFDEF QE_UNICODE}
procedure TQExport4.SetCharsetType(const Value: TQExportCharsetType);
begin
  if FCharsetType <> Value then
    FCharsetType := Value;
end;
{$ENDIF}

procedure TQExport4.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if Operation = opRemove then begin
    if AComponent = FDataSet then FDataSet := nil;
    if AComponent = FCustomSource then FCustomSource := nil;
    {$IFNDEF NOGUI}
    if AComponent = FListView then FListView := nil;
    if AComponent = FDBGrid then FDBGrid := nil;
    if AComponent = FStringGrid then FStringGrid := nil;
    {$ENDIF}
  end;
end;

procedure TQExport4.CheckUserFomat(const AUserFormat: TStrings);
const
  NameValueSeparator = '=';
  //For BCB5

var
  ItemText,
  SectionValue: String;
  I,
  PosSeparator: Integer;
begin
  if Assigned(AUserFormat) then
    for I := 0 to AUserFormat.Count - 1 do
    begin
      ItemText := AUserFormat[I];
      PosSeparator := Pos(NameValueSeparator, ItemText);

      if PosSeparator > 0 then
      begin
        SectionValue := Copy(ItemText, PosSeparator + 1,
          Length(ItemText) - PosSeparator);

        if Pos(NameValueSeparator, SectionValue) > 0 then
          //UserFormat was saved by TQExport
          AUserFormat[I] := SectionValue;
      end;
    end;
end;

procedure TQExport4.LoadPropertiesFromFile(const FileName: string);
var
  IniFile: TQIniFile;
begin
  IniFile := TQIniFile.Create(FileName);
  try
    IniFile.Version :=
      StrToIntDef(IniFile.ReadString('IniVersion', 'Number', '0'), 0);
    LoadProperties(IniFile);
  finally
    IniFile.Free;
  end;
end;

procedure TQExport4.LoadPropertiesFromStream(AStream: TStream);
var
  IniFile: TQIniFile;
begin
  IniFile := TQIniFile.Create(AStream);
  try
    IniFile.LoadFromStream;
    IniFile.Version :=
      StrToIntDef(IniFile.ReadString('IniVersion', 'Number', '0'), 0);
    LoadProperties(IniFile);
  finally
    IniFile.Free;
  end;
end;

procedure TQExport4.SavePropertiesToFile(const FileName: string);
var
  IniFile: TQIniFile;
begin
  IniFile := TQIniFile.CreateWritingVersion(FileName, 400);
  try
    SaveProperties(IniFile);
  finally
    IniFile.Free;
  end;
end;

procedure TQExport4.SavePropertiesToStream(AStream: TStream);
var
  IniFile: TQIniFile;
begin
  IniFile := TQIniFile.CreateWritingVersion(AStream, 400);
  try
    SaveProperties(IniFile);
    IniFile.SaveToStream;
  finally
    IniFile.Free;
  end;
end;

procedure TQExport4.DisableControls;
begin
  QExportDisableControls(FExportSource, FDataSet, FCustomSource
    {$IFNDEF NOGUI}, FDBGrid, FListView, FStringGrid{$ENDIF});
end;

procedure TQExport4.EnableControls;
begin
  QExportEnableControls(FExportSource, FDataSet, FCustomSource
    {$IFNDEF NOGUI}, FDBGrid, FListView, FStringGrid{$ENDIF});
end;

procedure TQExport4.First;
begin
  FRecordCounter := 0;
  QExportFirst(FExportSource, FDataSet, FCustomSource
    {$IFNDEF NOGUI}, FDBGrid, FListView, FStringGrid{$ENDIF});
end;

procedure TQExport4.Next;
begin
  QExportNext(FExportSource, FDataSet, FCustomSource,
    {$IFNDEF NOGUI}FDBGrid, FListView, FStringGrid,{$ENDIF}FRecordCounter);
end;

procedure TQExport4.Skip(Count: integer);
begin
  QExportSkip(FExportSource, FDataSet, FCustomSource,
    {$IFNDEF NOGUI}FDBGrid, FListView, FStringGrid,{$ENDIF}
    FSkipRecCount, FOnSkippedRecord, Self, FRecordCounter)
end;

function TQExport4.EndOfFile: boolean;
begin
  Result := QExportEof(ExportSource, DataSet, CustomSource,
    {$IFNDEF NOGUI}DBGrid, ListView, StringGrid,{$ENDIF} RecordCounter,
    ExportRecCount, SkipRecCount);
end;

function TQExport4.GetBookmark: TBookmark;
begin
  Result := QExportGetBookmark(FExportSource, FDataSet, FCustomSource
    {$IFNDEF NOGUI}, FDBGrid, FListView, FStringGrid{$ENDIF});
end;

procedure TQExport4.GoToBookmark(Bookmark: TBookmark);
begin
  FRecordCounter := 0;
  QExportGoToBookmark(FExportSource, FDataSet, FCustomSource,
  {$IFNDEF NOGUI}FDBGrid, FListView, FStringGrid,{$ENDIF} Bookmark);
end;

procedure TQExport4.FreeBookmark(Bookmark: TBookmark);
begin
  QExportFreeBookmark(FExportSource, FDataSet, {$IFNDEF NOGUI}FDBGrid,
    FListView, FStringGrid,{$ENDIF} Bookmark);
end;

function TQExport4.IsEmpty: boolean;
begin
  Result := QExportIsEmpty(FExportSource, FDataSet, FCustomSource
    {$IFNDEF NOGUI}, FDBGrid, FListView, FStringGrid{$ENDIF});
end;

function TQExport4.IsActive: boolean;
begin
  Result := QExportIsActive(FExportSource, FDataSet, FCustomSource
    {$IFNDEF NOGUI}, FDBGrid, FListView, FStringGrid{$ENDIF});
end;

function TQExport4.GetColCaption(Index: integer): string;
begin
  Result := NormalString(Columns[Index].Caption);
end;

function TQExport4.GetColData(ColValue: QEString;
  Column: TQExportColumn): QEString;
begin
  Result := ColValue;
end;

function TQExport4.NormalString(const S: QEString): QEString;
begin
  Result := S;
end;

procedure TQExport4.FillExportRow;
var
  i: integer;
begin
  for i := 0 to FColumns.Count - 1 do
    FillExportCol(i);
end;

function TQExport4.GetDataRow: QEString;
var
  i: integer;
begin
  Result := EmptyStr;
  for i := 0 to FExportRow.Count - 1 do
    Result := Result + GetExportedValue(FExportRow[i]);
end;

function TQExport4.GetCaptionRow: string;
var
  i: integer;
begin
  Result := EmptyStr;
  for i := 0 to Columns.Count - 1 do
    Result := Result + GetColCaption(i);
end;

procedure TQExport4.DoExport;
var
  AcceptRow: boolean;
begin
  FRecordCounter := 0;
  CheckExportSource;
  if not IsActive
    then raise Exception.CreateFmt(QExportLoadStr(QEM_ExportSourceNotActive),
                                   [QExportSourceAsString(FExportSource)]);
  if (not FExportEmpty) and IsEmpty
    then raise Exception.CreateFmt(QExportLoadStr(QEM_ExportSourceEmpty),
                                   [QExportSourceAsString(FExportSource)]);


  {$IFDEF ADVANCED_DATA_EXPORT_TRIAL_VERSION}
  if (FExportRecCount = 0) or
    (FExportRecCount > MaxRecordCountTrial) then
      FExportRecCount := MaxRecordCountTrial;
  {$ENDIF}

  DisableControls;
  try
    BeginExport;
    if Aborted then Exit;
    if AutoCalcColWidth then
      Columns.AutoCalcColWidth(FAllowCaptions);
    if Aborted then Exit;
    try
      if FAllowCaptions then WriteCaptionRow;
      if Aborted then Exit;
      if FGoToFirstRecord then First;
      BeforeExport;
      if Aborted then Exit;
      Skip(SkipRecCount);
      if Aborted then Exit;
      RecordCounter := 0;
      while not EndOfFile and
        ((FExportRecCount = 0) or
         (FRecordCounter < FExportRecCount)) do
      begin
        if FAborted and not CanContinue then Break;
        AcceptRow := true;
        FillExportRow;
        if Assigned(FOnBeforeExportRow) then
          FOnBeforeExportRow(Self, FExportRow, AcceptRow);
        if AcceptRow then begin
          WriteDataRow;
          if Assigned(FOnExportedRecord)
            then FOnExportedRecord(Self, FRecordCounter);
        end;
        if FCurrentRecordOnly
          then Break
          else Next;
        Sleep(0);
      end;
      AfterExport;
    finally
      EndExport;
    end;
  finally
    EnableControls;
  end;
end;

procedure TQExport4.SetExportedFields(const Value: TStrings);
begin
  FExportedFields.Assign(Value);
end;

procedure TQExport4.BeginExport;
var
  i: integer;
begin
  CheckTrial;
  Columns.Clear;
  Columns.Fill(True);

  CheckFormats;
  Formats.ApplyParams;
  FExportRow.Clear;
  FExportRow.FIndex.Clear;

  for i := 0 to Columns.Count - 1 do begin
    FExportRow.Add(Columns[i].Name, i);
    FExportRow.FIndex.AddObject(Columns[i].Name, TObject(i));
  end;
  FExportRow.FIndex.Sort;

  FAborted := False;

  {$IFNDEF NOGUI}
  case FExportSource of
    esListView: begin
      FSkipRecCount := MinimumInt(FSkipRecCount, FListView.Items.Count);
      if FExportRecCount > 0 then
        FExportRecCount := MinimumInt(FExportRecCount, FListView.Items.Count);
    end;
  end;
  {$ENDIF}
  if Assigned(FOnBeginExport) then FOnBeginExport(Self);
end;

procedure TQExport4.EndExport;
begin
  if Assigned(FOnEndExport) then FOnEndExport(Self);
end;

procedure TQExport4.SetCaptions(const Value: TStrings);
begin
  FCaptions.Assign(Value);
end;

procedure TQExport4.SetFooter(const Value: TqeStrings);
begin
  TqeStringList(FFooter).Text := TqeStringList(Value).Text;
end;

procedure TQExport4.SetHeader(const Value: TqeStrings);
begin
  TqeStringList(FHeader).Text := TqeStringList(Value).Text;
end;

procedure TQExport4.SetUserFormats(const Value: TStrings);
begin
  FUserFormats.Assign(Value);
end;

procedure TQExport4.SetFormats(const Value: TQExportFormats);
begin
  FFormats.Assign(Value);
end;

procedure TQExport4.AfterExport;
begin
  FFormats.RestoreSeparators;
end;

procedure TQExport4.BeforeExport;
begin

end;

function TQExport4.GetSpecialCharacters: TSpecialCharacters;
begin
  Result := [];
end;

procedure TQExport4.SetColumnsWidth(const Value: TStrings);
begin
  FColumnsWidth.Assign(Value);
end;

procedure TQExport4.SetColumnsAlign(const Value: TStrings);
begin
  FColumnsAlign.Assign(Value);
end;

procedure TQExport4.SetColumnsLength(const Value: TStrings);
begin
  FColumnsLength.Assign(Value);
end;

procedure TQExport4.CheckExportSource;
begin
  QExportCheckSource(ExportSource, FDataSet, FCustomSource
    {$IFNDEF NOGUI}, FDBGrid, FListView, FStringGrid{$ENDIF});
end;

procedure TQExport4.CheckFormats;
begin
end;

function TQExport4.GetWriterClass: TQExportWriterClass;
begin
  Result := TQExportWriter;
end;

function TQExport4.GetWriter: TQExportWriter;
begin
  Result := TQExportWriter(FWriter);
end;

procedure TQExport4.WriteCaptionRow;
begin

end;

procedure TQExport4.WriteDataRow;
begin
end;

function TQExport4.CanContinue: boolean;
begin
  Result := not FAborted;
  if Assigned(FOnStopExport) then FOnStopExport(Self, Result);
  FAborted := not Result;
end;

procedure TQExport4.DoShowResult;
begin
//
end;

procedure TQExport4.FillExportCol(Index: Integer);
var
{$IFNDEF QE_UNICODE}
  str: QEString;
{$ENDIF}
  wstr: QEString;
  Data: Variant;
begin
  {$IFDEF QE_UNICODE}
    QExportGetColData(FExportSource, FDataSet, FCustomSource,
    {$IFNDEF NOGUI}FDBGrid, FListView, FStringGrid,{$ENDIF}
    FColumns, FFormats, Index, FRecordCounter,
    FSkipRecCount, wstr, Data);
    if (FExportSource = esDataSet) then
      if Assigned(FOnCustomFormat) then
        FOnCustomFormat(Self, FDataSet.Fields[FColumns[Index].Number], wstr);

    if Assigned(FOnGetExportText) then
      FOnGetExportText(Self, Index, wstr);
    FExportRow.SetValue(Columns[Index].Name, wstr, Data);
  {$ELSE}
    QExportGetColData(FExportSource, FDataSet, FCustomSource,
      {$IFNDEF NOGUI}FDBGrid, FListView, FStringGrid,{$ENDIF}
      FColumns, FFormats, Index, FRecordCounter,
      FSkipRecCount, Str, Data);
    wstr := str;
    if Assigned(FOnGetExportText) then
      FOnGetExportText(Self, Index, wstr);
    FExportRow.SetValue(Columns[Index].Name, wstr, Data);
  {$ENDIF};
end;

procedure TQExport4.GetCellParams(RecNo, ColNo: integer; const Value: string;
  var Align: TQExportColAlign; AFont: TFont; var Background: TColor);
begin
  if Assigned(FOnGetCellParams) then
    FOnGetCellParams(Self, RecNo, ColNo, Value, Align, AFont, Background);
end;

procedure TQExport4.LoadProperties(IniFile: TQIniFile);
var i: Integer;
begin
  with IniFile do begin
    //--- General
    GoToFirstRecord := ReadBool(S_GENERAL, S_GoToFirstRecord, GoToFirstRecord);
    ExportEmpty := ReadBool(S_GENERAL, S_ExportEmpty, ExportEmpty);
    CurrentRecordOnly := ReadBool(S_GENERAL, S_CurrentRecordOnly, CurrentRecordOnly);
    ExportRecCount := ReadInteger(S_GENERAL, S_ExportRecCount, ExportRecCount);
    SkipRecCount := ReadInteger(S_GENERAL, S_SkipRecCount, SkipRecCount);
    OnlyVisibleFields := ReadBool(S_GENERAL, S_OnlyVisibleFields, OnlyVisibleFields);
    AutoCalcStrType := ReadBool(S_GENERAL, S_AutoCalcStrType, AutoCalcStrType);
    CaptionRow := ReadInteger(S_GENERAL, S_CaptionRow, CaptionRow);
    //--- ExportedFields
    ExportedFields.Clear;
    IniFile.ReadSectionValues(S_FIELDS, ExportedFields);
    for i:=0 to ExportedFields.Count-1 do
      ExportedFields[i]:=Copy(ExportedFields[i], Pos('=',ExportedFields[i])+1,
        Length(ExportedFields[i]));
  end;
end;

procedure TQExport4.SaveProperties(IniFile: TQIniFile);
var
  i: integer;
begin
  with IniFile do begin
    //--- General
    WriteBool(S_GENERAL, S_GoToFirstRecord, GoToFirstRecord);
    WriteBool(S_GENERAL, S_ExportEmpty, ExportEmpty);
    WriteBool(S_GENERAL, S_CurrentRecordOnly, CurrentRecordOnly);
    WriteInteger(S_GENERAL, S_ExportRecCount, ExportRecCount);
    WriteInteger(S_GENERAL, S_SkipRecCount, SkipRecCount);
    WriteBool(S_GENERAL, S_OnlyVisibleFields, OnlyVisibleFields);
    WriteBool(S_GENERAL, S_AutoCalcStrType, AutoCalcStrType);
    WriteInteger(S_GENERAL, S_CaptionRow, CaptionRow);
    //--- ExportedFields
    EraseSection(S_FIELDS);
    for i := 0 to ExportedFields.Count - 1 do
      WriteString(S_FIELDS, Format('%s%d', [S_Field,i]), ExportedFields[i]);
  end;
end;

function TQExport4.GetExportedValue(Col: TQExportCol): QEString;
begin
  Result := NormalString(Col.Value);
  Result := GetColData(Result, FColumns[Col.ColumnIndex]);
end;

procedure TQExport4.ShowResult;
begin
  TShowResultThread.Create(Self);
end;

{ TQExport4Text }

constructor TQExport4Text.Create(AOwner: TComponent);
begin
  inherited;
  FShowFile := false;
  FAppendDateTimeToFileName := False;
end;

procedure TQExport4Text.AfterExecute;
begin
  FExportedFileName := FFileName;
  if FAppendDateTimeToFileName then
    FFileName := FOldFileName;
end;

procedure TQExport4Text.BeforeExecute;
begin
  if FAppendDateTimeToFileName then
  begin
    FOldFileName := FFileName;
    FFileName := GetDateTimeFileName(FFileName);
  end;
end;

procedure TQExport4Text.SaveProperties(IniFile: TQIniFile);
begin
  inherited;
    //--- General
  IniFile.WriteString(S_GENERAL, S_FileName, Self.FileName);
  IniFile.WriteBool(S_GENERAL, S_ShowFile, ShowFile);
  IniFile.WriteBool(S_GENERAL, S_PrintFile, PrintFile);
  IniFile.WriteBool(S_GENERAL, S_AppendDateTimeToFileName,
    AppendDateTimeToFileName);
end;

procedure TQExport4Text.LoadProperties(IniFile: TQIniFile);
begin
  inherited;
  //--- General
  FileName := IniFile.ReadString(S_GENERAL, S_FileName, FileName);
  ShowFile := IniFile.ReadBool(S_GENERAL, S_ShowFile, ShowFile);
  PrintFile := IniFile.ReadBool(S_GENERAL, S_PrintFile, PrintFile);
  AppendDateTimeToFileName := IniFile.ReadBool(S_GENERAL,
    S_AppendDateTimeToFileName, AppendDateTimeToFileName);
end;

function TQExport4Text.GetShowedFileName: string; 
begin
  Result := FFileName;
end;

function TQExport4Text.GetPrintedFileName: string; 
begin
  Result := FFileName;
end;

procedure TQExport4Text.Execute;
var
  FS: TFileStream;
  Dir: string;
begin
  BeforeExecute;
  try
    Dir := ExtractFileDir(FFileName);
    if Dir = EmptyStr then Dir := ExtractFilePath(ParamStr(0));
    if not DirectoryExists(Dir) then begin
      ForceDirectories(Dir);
      if not DirectoryExists(Dir) then
        raise Exception.CreateFmt(QExportLoadStr(QEM_DirNotFound), [Dir]);
    end;
    FS := TFileStream.Create(FFileName, fmCreate);
    try
      ExportToStream(FS);
    finally
      FS.Free;
    end;
    ShowResult;
  finally
    AfterExecute;
  end;
end;

procedure TQExport4Text.DoShowResult;
begin
  if not Aborted then begin
    if FShowFile then
      ShellExecute(0, 'open', PChar(GetShowedFileName{FFileName}), '', '', SW_SHOWNORMAL);
    if FPrintFile then
      ShellExecute(0, 'print', PChar(GetPrintedFileName{FFileName}), '', '', SW_SHOWNORMAL);
  end;
end;

{ TQExport4AdvancedText }

procedure TQExport4AdvancedText.SaveProperties(IniFile: TQIniFile);
var
  i: integer;
begin
  inherited;
  with IniFile do begin
    EraseSection(S_HEADER);
    for i := 0 to Header.Count - 1 do
      WriteStringW(S_HEADER, QEFormat('%s%d', [S_Line, i]), Header[i]);
    EraseSection(S_FOOTER);
    for i := 0 to Footer.Count - 1 do
      WriteStringW(S_FOOTER, QEFormat('%s%d', [S_Line, i]), Footer[i]);
  end;
end;

procedure TQExport4AdvancedText.LoadProperties(IniFile: TQIniFile);
var
  i: Integer;
begin
  inherited;
  with IniFile do
  begin
    Header.Clear;
    ReadSectionValuesW(S_HEADER, Header);
    for i := 0 to Header.Count - 1 do
      Header[i] := Copy(Header[i], QEPos('=', Header[i]) + 1, Length(Header[i]));
    Footer.Clear;
    ReadSectionValuesW(S_FOOTER, Footer);
    for i := 0 to Footer.Count - 1 do
      Footer[i] := Copy(Footer[i], QEPos('=', Footer[i]) + 1, Length(Footer[i]));
  end;
end;

{ TQExport4FormatText }

procedure TQExport4FormatText.SaveProperties(IniFile: TQIniFile);
var
  i: integer;
begin
  inherited;
  with IniFile do begin
    WriteBool(S_GENERAL, S_AllowCaptions, AllowCaptions);
    //--- Captions
    EraseSection(S_CAPTIONS);
    for i := 0 to Captions.Count - 1 do
      WriteString(S_CAPTIONS, Format('%s%d', [S_Line, i]), Captions[i]);
    //--- Formats
    WriteString(S_FORMATS, S_Integer, Formats.IntegerFormat);
    WriteString(S_FORMATS, S_Float, Formats.FloatFormat);
    WriteString(S_FORMATS, S_Date, Formats.DateFormat);
    WriteString(S_FORMATS, S_Time, Formats.TimeFormat);
    WriteString(S_FORMATS, S_DateTime, Formats.DateTimeFormat);
    WriteString(S_FORMATS, S_Currency, Formats.CurrencyFormat);
    WriteString(S_FORMATS, S_BooleanTrue, Formats.BooleanTrue);
    WriteString(S_FORMATS, S_BooleanFalse, Formats.BooleanFalse);
    WriteString(S_FORMATS, S_NullString, Formats.NullString);
    WriteString(S_FORMATS, S_DecimalSeparator, Formats.DecimalSeparator);
    WriteString(S_FORMATS, S_ThousandSeparator, Formats.ThousandSeparator);
    WriteString(S_FORMATS, S_DateSeparator, Formats.DateSeparator);
    WriteString(S_FORMATS, S_TimeSeparator, Formats.TimeSeparator);
    WriteBool(S_FORMATS, S_KeepOriginalFormat, Formats.KeepOriginalFormat);
    //--- UserFormats
    EraseSection(S_USER_FORMATS);
    for i := 0 to UserFormats.Count - 1 do
      WriteString(S_USER_FORMATS, Format('%s%d', [S_Line, i]), UserFormats[i]);
  end;
end;

procedure TQExport4FormatText.LoadProperties(IniFile: TQIniFile);
begin
  inherited;
  with IniFile do begin
    AllowCaptions := ReadBool(S_GENERAL, S_AllowCaptions, AllowCaptions);
    //--- Captions
    Captions.Clear;
    ReadSectionValues(S_CAPTIONS, Captions);
    //--- Formats
    Formats.IntegerFormat := ReadString(S_FORMATS, S_Integer, Formats.IntegerFormat);
    Formats.FloatFormat := ReadString(S_FORMATS, S_Float, Formats.FloatFormat);
    Formats.DateFormat := ReadString(S_FORMATS, S_Date, Formats.DateFormat);
    Formats.TimeFormat := ReadString(S_FORMATS, S_Time, Formats.TimeFormat);
    Formats.DateTimeFormat := ReadString(S_FORMATS, S_DateTime, Formats.DateTimeFormat);
    Formats.CurrencyFormat := ReadString(S_FORMATS, S_Currency, Formats.CurrencyFormat);
    Formats.BooleanTrue := ReadString(S_FORMATS, S_BooleanTrue, Formats.BooleanTrue);
    Formats.BooleanFalse := ReadString(S_FORMATS, S_BooleanFalse, Formats.BooleanFalse);
    Formats.NullString := ReadString(S_FORMATS, S_NullString, Formats.NullString);
    Formats.DecimalSeparator := ReadString(S_FORMATS,
      S_DecimalSeparator, Formats.DecimalSeparator)[1];
    Formats.ThousandSeparator := ReadString(S_FORMATS,
      S_ThousandSeparator, Formats.ThousandSeparator)[1];
    Formats.DateSeparator := ReadString(S_FORMATS,
      S_DateSeparator, Formats.DateSeparator)[1];
    Formats.TimeSeparator := ReadString(S_FORMATS,
      S_TimeSeparator, Formats.TimeSeparator)[1];
    Formats.KeepOriginalFormat := ReadBool(S_FORMATS, S_KeepOriginalFormat,
      Formats.KeepOriginalFormat);
    //--- UserFormats
    UserFormats.Clear;
    ReadSectionValues(S_USER_FORMATS, UserFormats);

    CheckUserFomat(UserFormats);
  end;
end;

//{$IFNDEF NOGUI}
{ TQExport4Memory }

procedure TQExport4Memory.Execute;
var
  MS: TMemoryStream;
  s: QEString;
  Size: Integer;
begin
  MS := TMemoryStream.Create;
  try
    Clipboard.Clear;
    ExportToStream(MS);
    Size := MS.Size;
    if Size > 0 then
    begin
      MS.Position := 0;
      SetLength(s, Size div SizeOf(QEChar));
      MS.Read(s[1], Size);
      {$IFDEF QE_UNICODE}
      TWideClipboard(Clipboard).AsWideText := s;
      {$ELSE}
      Clipboard.AsText := s;
      {$ENDIF}
    end;
  finally
    MS.Free;
  end;
end;
//{$ENDIF}

{ TQExportLocale }

constructor TQExportLocale.Create;
begin
  FIDEMode := AnsiUpperCase(ExtractFileName(ParamStr(0))) = 'DELPHI32.EXE';
end;

procedure TQExportLocale.LoadDll(const Name: string);
begin
  if FLoaded then
    UnloadDll;

  FDllHandle := LoadLibrary(PChar(Name));
  FLoaded := FDllHandle <> HINSTANCE_ERROR;

  { TODO : Perhaps, any localization code will be needed here }
end;

function TQExportLocale.LoadStr(ID: Integer): string;
var
  Buffer: array[0..1023] of Char;
  Handle: THandle;
begin
  if Assigned(FOnLocalize) then
  begin
    Result := '';
    FOnLocalize(ID, Result);
    if Result <> '' then
      Exit;
  end;

  if FLoaded then
    Handle := FDllHandle
  else
    Handle := HInstance;

  if FIDEMode then
    Result :=
    {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.LoadStr(ID)
  else
    SetString(Result, Buffer, LoadString(Handle, ID, Buffer, SizeOf(Buffer)));
end;

procedure TQExportLocale.UnloadDll;
begin
  if FLoaded then
    FreeLibrary(FDllHandle);

  FLoaded := False;

  { TODO : Perhaps, any localization code will be needed here }
end;

function TQExport4Memory.GetColData(ColValue: QEString;
  Column: TQExportColumn): QEString;
var
  IndexChar0: Integer;  
begin
  Result := inherited GetColData(ColValue, Column);


  if FReplaceZeroChars then
  begin
    IndexChar0 := Pos(#0, Result);
    while IndexChar0 > 0 do
    begin
      Result[IndexChar0] := #32;
      IndexChar0 := PosEx(#0, Result, IndexChar0);
    end;
  end;
end;

{ TQExport4FormatTextSQL }

procedure TQExport4FormatTextSQL.LoadProperties(IniFile: TQIniFile);
begin
  inherited;
  with IniFile do
  begin
    //--- Formats
    Formats.IntegerFormat := ReadString(S_FORMATS, S_Integer, Formats.IntegerFormat);
    Formats.FloatFormat := ReadString(S_FORMATS, S_Float, Formats.FloatFormat);
    Formats.DateFormat := ReadString(S_FORMATS, S_Date, Formats.DateFormat);
    Formats.TimeFormat := ReadString(S_FORMATS, S_Time, Formats.TimeFormat);
    Formats.DateTimeFormat := ReadString(S_FORMATS, S_DateTime, Formats.DateTimeFormat);
    Formats.CurrencyFormat := ReadString(S_FORMATS, S_Currency, Formats.CurrencyFormat);
    Formats.BooleanTrue := ReadString(S_FORMATS, S_BooleanTrue, Formats.BooleanTrue);
    Formats.BooleanFalse := ReadString(S_FORMATS, S_BooleanFalse, Formats.BooleanFalse);
    Formats.NullString := ReadString(S_FORMATS, S_NullString, Formats.NullString);
    //--- UserFormats
    UserFormats.Clear;
    ReadSectionValues(S_USER_FORMATS, UserFormats);
    CheckUserFomat(UserFormats);
  end;
end;

procedure TQExport4FormatTextSQL.SaveProperties(IniFile: TQIniFile);
var
  i: Integer;
begin
  inherited;
  with IniFile do
  begin
    //--- Formats
    WriteString(S_FORMATS, S_Integer, Formats.IntegerFormat);
    WriteString(S_FORMATS, S_Float, Formats.FloatFormat);
    WriteString(S_FORMATS, S_Date, Formats.DateFormat);
    WriteString(S_FORMATS, S_Time, Formats.TimeFormat);
    WriteString(S_FORMATS, S_DateTime, Formats.DateTimeFormat);
    WriteString(S_FORMATS, S_Currency, Formats.CurrencyFormat);
    WriteString(S_FORMATS, S_BooleanTrue, Formats.BooleanTrue);
    WriteString(S_FORMATS, S_BooleanFalse, Formats.BooleanFalse);
    WriteString(S_FORMATS, S_NullString, Formats.NullString);
    //--- UserFormats
    EraseSection(S_USER_FORMATS);
    for i := 0 to UserFormats.Count - 1 do
      WriteString(S_USER_FORMATS, Format('%s%d', [S_Line, i]), UserFormats[i]);
  end;
end;

//{$IFNDEF NOGUI}
{$IFDEF QE_UNICODE}
function TWideClipboard.GetAsWideText: WideString;
var
  Data: THandle;
begin
  Open;
  Data := GetClipboardData(CF_UNICODETEXT);
  try
    if Data <> 0 then
      Result := PWideChar(GlobalLock(Data))
    else
      Result := '';
  finally
    if Data <> 0 then GlobalUnlock(Data);
    Close;
  end;
end;

procedure TWideClipboard.SetAsWideText(const Value: WideString);
begin
{$IFDEF VER130}
  SetVer130TextBuf(Value);
{$ELSE}
  SetBuffer(CF_UNICODETEXT, PWideChar(Value)^, (Length(Value) + 1) * SizeOf(WideChar));
{$ENDIF}
end;

{$IFDEF VER130}

procedure TWideClipboard.Adding;
begin
  if (FOpenRefCount <> 0) and not FEmptied then
  begin
    Clear;
    FEmptied := True;
  end;
end;

procedure TWideClipboard.SetVer130TextBuf(const Value: WideString);
var
  Data: THandle;
  DataPtr: Pointer;
  ASize: Integer;
begin
  Open;
  ASize := (Length(Value) + 1) * SizeOf(WideChar);
  try
    Data := GlobalAlloc(GMEM_MOVEABLE+GMEM_DDESHARE, ASize);
    try
      DataPtr := GlobalLock(Data);
      try
        Move(PWideChar(Value)^, DataPtr^, ASize);
        Adding;
        SetClipboardData(CF_UNICODETEXT, Data);
      finally
        GlobalUnlock(Data);
      end;
    except
      GlobalFree(Data);
      raise;
    end;
  finally
    Close;
  end;
end;
{$ENDIF}   

{$ENDIF}
//{$ENDIF}

{ TShowResultThread }

constructor TShowResultThread.Create(AExport: TQExport4);
begin
  inherited Create(True);
  FreeOnTerminate := True;
  FExport := AExport;
  Resume;
end;

procedure TShowResultThread.Execute;
begin
  Sleep(1);
  Synchronize(SyncShowResult);
end;

procedure TShowResultThread.SyncShowResult;
begin
  FExport.DoShowResult;
end;

initialization

finalization
  Locale.Free;
  Locale := nil;
end.


