unit QExport4BaseODFClass;

{$I QExport4VerCtrl.inc}

interface

uses
  {$IFDEF VCL16}
    System.Classes,
    System.SysUtils,
    System.StrUtils,
    Vcl.Graphics,
    {$IFNDEF NOGUI}
      Vcl.ExtCtrls,
    {$ENDIF}
  {$ELSE}
    Classes,
    SysUtils,
    {$IFDEF VCL6}
      StrUtils,
    {$ENDIF}
    {$IFNDEF NOGUI}
      ExtCtrls,
    {$ENDIF}
    Graphics,
  {$ENDIF}
  QExport4BaseArchiveClass,
  QXMLWriter,
  QExport4Types,
  QExport4IniFiles,
  QExport4Common;

const
  odfIntegerFormat  = 0;
  odfFloatFormat    = 1;
  odfDateFormat     = 2;
  odfDateTimeFormat = 3;
  odfTimeFormat     = 4;
  odfCurrencyFormat = 5;

  odfStringTypeName = 'string';

  odfNumericCellTypeName : array [0..5] of string = (
    'float', // integer
    'float',
    'date',
    'date', // datetime
    'time',
    'float' // currency
    );
  odfNumericDisplayFormat : array [0..5] of string = (
    '#,###,##0',
    '#,###,##0.00',
    'dd.mm.yyyy',
    'dd.mm.yyyy hh:nn:ss',
    'hh:nn:ss',
    '#,###,##0.00' //'$ #,###,##0.00'
    //TODO
{
  <table:table-cell office:value-type="currency" office:currency="USD" office:value="0">
  <text:p>0,00$</text:p>
  </table:table-cell>
}
    );
  odfNumericValueFormat : array [0..5] of string = (
    '0',
    '0.00',
    'yyyy-mm-dd',
    'yyyy-mm-ddThh:nn:ss',
    'PThhHnnMssS',
    '0.00'
    );
type
  TODFTextAlignment = (taODFLeft, taODFRight, taODFCenter, taODFJustify);

  TODFTextVerticalAligment = (taODFTop, taODFMiddle, taODFBottom);

  TODFStripStyleType = (sstNone, sstColumn, sstRow);

  TODFBorderStyle = (bsODFNone, bsODFSolid);

  TODSParagraphStyle = class(TCollectionItem)
  private
    FFont: TFont;
    FBackgroundColor: TColor;
    FAllowBackground: boolean;
    FAlignment: TODFTextAlignment;
    procedure SetFont(const Value: TFont);
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function IsDefault: Boolean; virtual;
    procedure SetDefault; virtual;
    procedure LoadFromIniFile(IniFile: TQIniFile; const Section: string); virtual;
    procedure SaveToIniFile(IniFile: TQIniFile; const Section: string); virtual;
  published
    property Font: TFont read FFont write SetFont;
    property BackgroundColor: TColor read FBackgroundColor
      write FBackgroundColor default clWhite;
    property AllowBackground: boolean read FAllowBackground
      write FAllowBackground default true;
    property Alignment: TODFTextAlignment read FAlignment
      write FAlignment default taODFLeft;
  end;

  TODTParagraphStyle = class(TODSParagraphStyle)
  private
    FHighlightColor: TColor;
    FAllowHighlight: boolean;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function IsDefault: Boolean; override;
    procedure SetDefault; override;
    procedure LoadFromIniFile(IniFile: TQIniFile; const Section: string); override;
    procedure SaveToIniFile(IniFile: TQIniFile; const Section: string); override;
  published
    property HighlightColor: TColor read FHighlightColor
      write FHighlightColor default clWhite;
    property AllowHighlight: boolean read FAllowHighlight
      write FAllowHighLight default false;
  end;

  TODFBorder = class(TPersistent)
  private
    FBorderStyle: TODFBorderStyle;
    FBorderWidth: Integer;
    FBorderColor: TColor;

    procedure SetBorderWidth(const Value: Integer);
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
    //function IsDefault: Boolean;
    procedure SetDefault;
  published
    property BorderStyle: TODFBorderStyle read FBorderStyle
      write FBorderStyle default bsODFNone;
    property BorderWidth: Integer read FBorderWidth
      write SetBorderWidth default 1;
    property BorderColor: TColor read FBorderColor write FBorderColor
      default clBlack;
  end;

  TODSCellParagraphStyle = class(TODSParagraphStyle)
  private
    FVerticalAligment: TODFTextVerticalAligment;
    FBorder: TODFBorder;

    procedure SetBorder(const Value: TODFBorder);
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function IsDefault: Boolean; override;
    procedure SetDefault; override;
    procedure LoadFromIniFile(IniFile: TQIniFile; const Section: string); override;
    procedure SaveToIniFile(IniFile: TQIniFile; const Section: string); override;
  published
    property VerticalAligment: TODFTextVerticalAligment read FVerticalAligment
      write FVerticalAligment default taODFBottom;
    property Border: TODFBorder read FBorder write SetBorder;
  end;

  TODSStripCellParagraphStyle = class(TODSCellParagraphStyle)
  private
    FStyleName: string; // DataStyle or FieldName+'Style'+RowStripNo
    FNumericFormat: string; // float, date, time   (odfNumericCellTypeName)
    FUseDataStyleBorder: Boolean;

    procedure SetStyleName(Value: string);
    procedure SetNumericFormat(Value: string);
    function GetStripBorder: TODFBorder;
  public
    constructor Create(Collection: TCollection); override;
    procedure Assign(Source: TPersistent); override;
    function IsDefault: Boolean; override;
    procedure SetDefault; override;
    property StripBorder: TODFBorder read GetStripBorder;
    procedure LoadFromIniFile(IniFile: TQIniFile; const Section: string); override;
    procedure SaveToIniFile(IniFile: TQIniFile; const Section: string); override;

    property StyleName : string read FStyleName write SetStyleName;
    property NumericFormat: string read FNumericFormat write SetNumericFormat;

  published
    property UseDataStyleBorder: Boolean read FUseDataStyleBorder write
      FUseDataStyleBorder default True;
  end;

  TODTCellParagraphStyle = class(TODTParagraphStyle)
  private
    FVerticalAligment: TODFTextVerticalAligment;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function IsDefault: Boolean; override;
    procedure SetDefault; override;
    procedure LoadFromIniFile(IniFile: TQIniFile; const Section: string); override;
    procedure SaveToIniFile(IniFile: TQIniFile; const Section: string); override;
  published
    property VerticalAligment: TODFTextVerticalAligment read FVerticalAligment
      write FVerticalAligment default taODFBottom;
  end;

  TODTStylesList = class(TCollection)
  private
    FHolder: TPersistent;
  protected
    function GetOwner: TPersistent; override;
    function GetItem(Index: integer): TODTCellParagraphStyle;
    procedure SetItem(Index: integer; Value: TODTCellParagraphStyle);
  public
    constructor Create(Holder: TPersistent);
    property Holder: TPersistent read FHolder;

    function Add: TODTCellParagraphStyle;
    property Items[Index: Integer]: TODTCellParagraphStyle read GetItem
      write SetItem; default;
  end;

  TODSStylesList = class(TCollection)
  private
    FHolder: TPersistent;
  protected
    function GetOwner: TPersistent; override;
    function GetItem(Index: integer): TODSStripCellParagraphStyle;
    procedure SetItem(Index: integer; Value: TODSStripCellParagraphStyle);
  public
    constructor Create(Holder: TPersistent);
    property Holder: TPersistent read FHolder;

    function Add: TODSStripCellParagraphStyle;
    property Items[Index: Integer]: TODSStripCellParagraphStyle read GetItem
      write SetItem; default;
  end;

  TBaseODFType = (odfUndefined, odfText, odfSpreadsheet);

  TBaseODFFile = class(TBaseArchiveClass)
  private
    FExportStream: TStream;
    FExportWriter: TQXMLWriter;
    FTypeConvert: TBaseODFType;
  public
    constructor Create; override;
    destructor Destroy; override;

    procedure OpenStream(FName: string);
    procedure OpenWriter;
    procedure CloseStream;
    procedure CloseWriter;
    procedure CheckStatus;
    procedure MakeAll;
    procedure EndFormingContent;
    procedure Renew;
    procedure DeleteList(FileNames: array of WideString);
    procedure MergeContent(Name: WideString; FileNames: array of WideString);
    procedure WriteSpecificNode(const NodeNum: Integer; const Text: WideString;
      const AttNames, AttValues: array of WideString);
    function CreateCommonStructure: Boolean;

    property TypeConvert: TBaseODFType read FTypeConvert write FTypeConvert;
  end;

{$IFNDEF NOGUI}
procedure DrawODSSample(PaintBox: TPaintBox; odsStyle: TODSCellParagraphStyle);
procedure DrawODTTextSample(PaintBox: TPaintBox; odtStyle: TODTParagraphStyle);
procedure DrawODTCellSample(PaintBox: TPaintBox; odtStyle: TODTCellParagraphStyle);
{$ENDIF}
function ReplaceSymbols(var Value: WideString): WideString;
function ExportTypeToODFType(const ExportType: TQExportColType): WideString;

{
function IntegerToODFDisplayValue(const Value: Integer; const Mask: string = ''): string;
function IntegerToODFValue(const Value: Integer; const Mask: string = ''): string;
function FloatToODFDisplayValue(const Value: Extended; const Mask: string = ''): string;
function FloatToODFValue(const Value: Extended; const Mask: string = ''): string;
function DateToODFDisplayValue(const Value: TDateTime; const Mask: string = ''): string;
function DateToODFValue(const Value: TDateTime; const Mask: string = ''): string;
function DateTimeToODFDisplayValue(const Value: TDateTime; const Mask: string = ''): string;
function DateTimeToODFValue(const Value: TDateTime; const Mask: string = ''): string;
function TimeToODFDisplayValue(const Value: TDateTime; const Mask: string = ''): string;
function TimeToODFValue(const Value: TDateTime; const Mask: string = ''): string;
function CurrencyToODFDisplayValue(const Value: Currency; const Mask: string = ''): string;
function CurrencyToODFValue(const Value: Currency; const Mask: string = ''): string;
}

implementation

uses
  {$IFDEF VCL16}
    Vcl.StdCtrls,
    {$IFNDEF VCL6}
      Vcl.FileCtrl,
    {$ENDIF}
    {$IFDEF MSWINDOWS}
      Winapi.Windows,
    {$ENDIF}
  {$ELSE}
    StdCtrls,
    {$IFNDEF VCL6}
      FileCtrl,
    {$ENDIF}
    {$IFDEF MSWINDOWS}
      Windows,
    {$ENDIF}
  {$ENDIF}
  {$IFDEF VCL17}
    System.UITypes,
  {$ENDIF}
  QExport4ODS,
  QExport4EmsWideStrUtils;

const
  LF = #13#10;
  sFileNameNotDefined = 'File name is not defined';
  sStructureCreateFailed = 'Failed to create basic structure';
  sConvertWrong = 'Convert is not defined';

  odfDefaultBackground = clWhite;
  odfDefaultAlignment = taODFLeft;
  odfDefaultVerticalAlignment = taODFBottom;
  odfDefaultHighlight = clWhite;
  odfDefaultBorderStyle = bsODFNone;
  odfDefaultBorderWidth = 1;
  odfDefaultBorderColor = clBlack;

var
  odfDefaultFont: TFont;

{
function IntegerToODFDisplayValue(const Value: Integer; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    Result := FormatFloat(odfNumericDisplayFormat[odfIntegerFormat], Value )
  else
  begin
    // TODO: use min-integer-digits
  end;
end;

function IntegerToODFValue(const Value: Integer; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    Result := IntToStr(Value)
  else
  begin
    // TODO: use min-integer-digits
  end;
end;

// ###0,00
function FloatToODFDisplayValue(const Value: Extended; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    Result := FormatFloat(odfNumericDisplayFormat[odfFloatFormat], Value)
  else
  begin
    // TODO: use min-integer-digits & decimal-places
  end;
end;

// 0.0
function FloatToODFValue(const Value: Extended; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    Result := SysUtils.StringReplace(
                                      FloatToStr(Value),
                                      string(DecimalSeparator),
                                      '.',
                                      [rfReplaceAll, rfIgnoreCase]
                                    )
  else
  begin
    // TODO: use min-integer-digits & decimal-places
  end;
end;

// dd.mm.yyyy
function DateToODFDisplayValue(const Value: TDateTime; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    DateTimeToString(Result, odfNumericDisplayFormat[odfDateFormat], Value)
  else
  begin
    // TODO
  end;
end;

// yyyy-mm-dd
function DateToODFValue(const Value: TDateTime; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    DateTimeToString(Result, odfNumericValueFormat[odfDateFormat], Value)
  else
  begin
    // TODO
  end;
end;

// dd.mm.yyyy hh:mm:ss
function DateTimeToODFDisplayValue(const Value: TDateTime; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    DateTimeToString(Result, odfNumericDisplayFormat[odfDateTimeFormat], Value)
  else
  begin
    // TODO
  end;
end;

// yyyy-mm-ddThh:mm:ss
function DateTimeToODFValue(const Value: TDateTime; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    DateTimeToString(Result, odfNumericValueFormat[odfDateTimeFormat], Value)
  else
  begin
    // TODO
  end;
end;

// hh:mm:ss
function TimeToODFDisplayValue(const Value: TDateTime; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    DateTimeToString(Result, odfNumericDisplayFormat[odfTimeFormat], Value)
  else
  begin
    // TODO
  end;
end;

// PThhHnnMssS
function TimeToODFValue(const Value: TDateTime; const Mask: string = ''): string;
//var
//  s: string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    DateTimeToString(Result, odfNumericValueFormat[odfTimeFormat], Value)
  else
  begin
    // TODO
  end;
end;

function CurrencyToODFDisplayValue(const Value: Currency; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    Result := FormatFloat(odfNumericDisplayFormat[odfCurrencyFormat], Value)  // todo
  else
  begin
    // todo
  end;
end;

function CurrencyToODFValue(const Value: Currency; const Mask: string = ''): string;
begin
  Result := '';
  if Mask = QEGetEmptyStr then
    Result := SysUtils.StringReplace(
                                      FloatToStr(Value),
                                      string(DecimalSeparator),
                                      '.',
                                      [rfReplaceAll, rfIgnoreCase]
                                    )    // todo
  else
  begin
    // todo
  end;
end;
}

function ExportTypeToODFType(const ExportType: TQExportColType): WideString;
begin
  case ExportType of
    ectInteger,
    ectBigint:
      Result := odfNumericCellTypeName[odfIntegerFormat];
    ectFloat, ectNumeric:
      Result := odfNumericCellTypeName[odfFloatFormat];
    ectCurrency:
      Result := odfNumericCellTypeName[odfCurrencyFormat];
    ectDate:
      Result := odfNumericCellTypeName[odfDateFormat];
    ectTime:
      Result := odfNumericCellTypeName[odfTimeFormat];
    ectDateTime:
      Result := odfNumericCellTypeName[odfDateTimeFormat];
    else
      Result := odfStringTypeName;
  end;
end;

function ReplaceSymbols(var Value: WideString): WideString;
var
  p, i: Integer;
const
  SearchSym: array [0..4] of WideString = ('&', '>', '<', '"', ' ');
  ReplSym: array [0..4] of WideString = ('&amp;', '&gt;', '&lt;', '&quot;', '&#160;');
begin
  for i := 0 to Length(SearchSym) - 1 do
  begin
    p := 1;
    while p > 0 do
    begin
      p := WideStringPosEx(SearchSym[i], Value, p);
      if p > 0 then
      begin
        Delete(Value, p, 1);
        Insert(ReplSym[i], Value, p);
        if SearchSym[i] <> #0 then
          Inc(p, 4);
      end;
    end;
  end;
  Result := Value;
end;

{ TBaseODFFile }

constructor TBaseODFFile.Create;
begin
  inherited;
  TypeConvert := odfUndefined;
end;

function TBaseODFFile.CreateCommonStructure: Boolean;
var
  FileHandle: Integer;
begin
  Result := false;
  if not (ForceDirectories(TempDir))
     or not(ForceDirectories(TempDir + '\Configurations2'))
     or not(ForceDirectories(TempDir + '\Configurations2\accelerator'))
     or not(ForceDirectories(TempDir + '\Configurations2\floater'))
     or not(ForceDirectories(TempDir + '\Configurations2\images'))
     or not(ForceDirectories(TempDir + '\Configurations2\images\Bitmaps'))
     or not(ForceDirectories(TempDir + '\Configurations2\menubar'))
     or not(ForceDirectories(TempDir + '\Configurations2\popupmenu'))
     or not(ForceDirectories(TempDir + '\Configurations2\progressbar'))
     or not(ForceDirectories(TempDir + '\Configurations2\statusbar'))
     or not(ForceDirectories(TempDir + '\Configurations2\toolbar'))
     or not(ForceDirectories(TempDir + '\META-INF'))
     or not(ForceDirectories(TempDir + '\Thumbnails')) then
    Exit;
  FileHandle := FileCreate(TempDir +
    '\Configurations2\accelerator\current.xml');
  if FileHandle = -1 then
    Exit;
  FileClose(FileHandle);
  FileHandle := FileCreate(TempDir + '\Thumbnails\thumbnail.png');
  if FileHandle = -1 then
    Exit;
  FileClose(FileHandle);
  Result := true;
end;

procedure TBaseODFFile.WriteSpecificNode(const NodeNum: Integer;
  const Text: WideString; const AttNames, AttValues: array of WideString);
var
  CurrDate: TDateTime;
  TempString: String;
  I: Integer;
begin
  //Standard XML Header
  case NodeNum of
  1:
    FExportWriter.CreateProcessingInstruction('1.0', 'UTF-8', '');
  //Standard Meta Header - just start and entire meta.xml file will be formed
  2: begin
        FExportWriter.BeginNode('office:document-meta', '',
          ['xmlns:office', 'xmlns:xlink', 'xmlns:dc', 'xmlns:meta', 'xmlns:ooo',
          'office:version'], ['urn:oasis:names:tc:opendocument:xmlns:office:1.0',
          'http://www.w3.org/1999/xlink', 'http://purl.org/dc/elements/1.1/',
          'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
          'http://openoffice.org/2004/office', '1.0']);
        FExportWriter.BeginNode('office:meta', '', [], []);
        FExportWriter.CreateFullNode('meta:generator', '', [], []);
        CurrDate := Now;
        DateTimeToString(TempString, 'yyyy-mm-dd hh:nn:ss', CurrDate);
        FExportWriter.CreateFullNode('meta:creation-date', TempString, [], []);
        FExportWriter.CreateFullNode('dc:date', TempString +
          'T' + TimeToStr(CurrDate), [], []);
        FExportWriter.CreateFullNode('dc:language', 'en-EN', [], []);
        FExportWriter.CreateFullNode('meta:editing-cycles', '0', [], []);
        FExportWriter.CreateFullNode('meta:editing-duration', '', [], []);
        for I := 1 to 4 do
          FExportWriter.CreateFullNode('meta:user-defined', '',
            ['meta:name'], ['Info ' + IntToStr(I)]);
        FExportWriter.CreateFullNode('meta:document-statistic', '', [], []);
        FExportWriter.EndNode('office:meta');
        FExportWriter.EndNode('office:document-meta');
    end;
  //For back compatibility with old interface version third number is missed
  //Manifest file spreadsheet
  104: begin
         FExportWriter.BeginNode('manifest:manifest', '',
           ['xmlns:manifest'],
           ['urn:oasis:names:tc:opendocument:xmlns:manifest:1.0']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['application/vnd.oasis.opendocument.spreadsheet', '/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/statusbar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/accelerator/current.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/accelerator/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/floater/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/popupmenu/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/progressbar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/menubar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/toolbar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/images/Bitmaps/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/images/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['application/vnd.sun.xml.ui.configuration', 'Configurations2/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'content.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'styles.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'meta.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Thumbnails/thumbnail.png']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Thumbnails/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Thumbnails/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'settings.xml']);
         FExportWriter.EndNode('manifest:manifest');
       end;
  //Manifest file text
  204: begin
         FExportWriter.BeginNode('manifest:manifest', '',
           ['xmlns:manifest'],
           ['urn:oasis:names:tc:opendocument:xmlns:manifest:1.0']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['application/vnd.oasis.opendocument.text', '/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/statusbar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/accelerator/current.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/accelerator/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/floater/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/popupmenu/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/progressbar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/menubar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/toolbar/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/images/Bitmaps/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Configurations2/images/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['application/vnd.sun.xml.ui.configuration', 'Configurations2/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'content.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'styles.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'meta.xml']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Thumbnails/thumbnail.png']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Thumbnails/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['', 'Thumbnails/']);
         FExportWriter.CreateFullNode('manifest:file-entry', '',
           ['manifest:media-type', 'manifest:full-path'],
           ['text/xml', 'settings.xml']);
         FExportWriter.EndNode('manifest:manifest');
       end;
  //5, 6 and 7 properties aren't used for back compatibility
  //Main Header for content.xml
  8: begin
       FExportWriter.BeginNode('office:document-content', '',
         ['xmlns:office', 'xmlns:style', 'xmlns:text', 'xmlns:table',
         'xmlns:draw', 'xmlns:fo', 'xmlns:xlink', 'xmlns:dc', 'xmlns:meta',
         'xmlns:number', 'xmlns:svg', 'xmlns:chart', 'xmlns:dr3d', 'xmlns:math',
         'xmlns:form', 'xmlns:script', 'xmlns:ooo', 'xmlns:ooow', 'xmlns:oooc',
         'xmlns:dom', 'xmlns:xforms', 'xmlns:xsd', 'xmlns:xsi', 'office:version'],
         ['urn:oasis:names:tc:opendocument:xmlns:office:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
         'http://www.w3.org/1999/xlink', 'http://purl.org/dc/elements/1.1/',
         'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:chart:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0',
         'http://www.w3.org/1998/Math/MathML',
         'urn:oasis:names:tc:opendocument:xmlns:form:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:script:1.0',
         'http://openoffice.org/2004/office', 'http://openoffice.org/2004/writer',
         'http://openoffice.org/2004/calc', 'http://www.w3.org/2001/xml-events',
         'http://www.w3.org/2002/xforms', 'http://www.w3.org/2001/XMLSchema',
         'http://www.w3.org/2001/XMLSchema-instance', '1.0']);
     end;
  //Office-scripts tag - definition only
  9: begin
       FExportWriter.CreateFullNode('office:scripts', '', [], []);
     end;
  //Office-face fonts declaration
  10: begin
        FExportWriter.BeginNode('office:font-face-decls', '', [], []);
     end;
  //Office automatic styles
  11: begin
        FExportWriter.BeginNode('office:automatic-styles', '', [], []);
      end;
  211: begin
         FExportWriter.CreateFullNode('office:automatic-styles', '', [], []);
       end;
  //Tag only
  12: begin
        FExportWriter.BeginNode('office:body', '', [], []);
      end;
  //root for spreadsheet document
  13: begin
        FExportWriter.BeginNode('office:spreadsheet', '', [], []);
      end;
  //root for text document
  14: begin
        FExportWriter.BeginNode('office:text', '', [], []);
      end;
  //Common element for all tables
  15: begin
        FExportWriter.BeginNode('table:table', '', AttNames, AttValues);
      end;
  //Common element for all tables
  16: begin
        FExportWriter.BeginNode('table:table-row', '', AttNames, AttValues);
      end;
  //Common element for all tables
  17: begin
        FExportWriter.BeginNode('table:table-cell', '', AttNames, AttValues);
      end;
  //Common element for all tables
  18: begin
        FExportWriter.CreateFullNode('text:p', Text, AttNames, AttValues);
      end;
  //Column tag - very important for text document tables
  19: begin
        FExportWriter.CreateFullNode('table:table-column', '', AttNames, AttValues);
      end;
  //Common style-font-face
  20: begin
        FExportWriter.CreateFullNode('style:font-face', '', AttNames, AttValues);
      end;
  //main style-style tag
  21: begin
        FExportWriter.BeginNode('style:style', '', AttNames, AttValues);
      end;
  //For whole table
  22: begin
        FExportWriter.CreateFullNode('style:table-properties', '',
          AttNames, AttValues);
      end;
  //For column
  23: begin
        FExportWriter.CreateFullNode('style:table-column-properties', '',
          AttNames, AttValues);
      end;
  //For row
  24: begin
        FExportWriter.CreateFullNode('style:table-row-properties', '',
          AttNames, AttValues);
      end;
  //For cell
  25: begin
        FExportWriter.CreateFullNode('style:table-cell-properties', '',
          AttNames, AttValues);
      end;
  //For text
  26: begin
        FExportWriter.CreateFullNode('style:text-properties', '',
          AttNames, AttValues);
      end;
  //Base style node
  27: begin
        FExportWriter.BeginNode('office:styles', '', [], []);
      end;
  //Common header for styles.xml
  28: begin
       FExportWriter.BeginNode('office:document-styles', '',
         ['xmlns:office', 'xmlns:style', 'xmlns:text', 'xmlns:table',
         'xmlns:draw', 'xmlns:fo', 'xmlns:xlink', 'xmlns:dc', 'xmlns:meta',
         'xmlns:number', 'xmlns:svg', 'xmlns:chart', 'xmlns:dr3d', 'xmlns:math',
         'xmlns:form', 'xmlns:script', 'xmlns:ooo', 'xmlns:ooow', 'xmlns:oooc',
         'xmlns:dom', 'xmlns:xforms', 'xmlns:xsd', 'xmlns:xsi', 'office:version'],
         ['urn:oasis:names:tc:opendocument:xmlns:office:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
         'http://www.w3.org/1999/xlink', 'http://purl.org/dc/elements/1.1/',
         'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:chart:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0',
         'http://www.w3.org/1998/Math/MathML',
         'urn:oasis:names:tc:opendocument:xmlns:form:1.0',
         'urn:oasis:names:tc:opendocument:xmlns:script:1.0',
         'http://openoffice.org/2004/office', 'http://openoffice.org/2004/writer',
         'http://openoffice.org/2004/calc', 'http://www.w3.org/2001/xml-events',
         'http://www.w3.org/2002/xforms', 'http://www.w3.org/2001/XMLSchema',
         'http://www.w3.org/2001/XMLSchema-instance', '1.0']);
      end;
  //Paragraph property node
  29: begin
        FExportWriter.CreateFullNode('style:paragraph-properties', '',
          AttNames, AttValues);
      end;
  //Header-Row tag
  30: begin
        FExportWriter.BeginNode('table:table-header-rows', '', [], []);
      end;
  // NumericFormat Integer
  31: begin
        FExportWriter.BeginNode('number:number-style', '', ['style:name'], ['IntegerFormat']);
        FExportWriter.CreateFullNode('number:number', '',
          ['number:decimal-places', 'number:min-integer-digits'], ['0', '1']);
       FExportWriter.EndNode('number:number-style');
      end;
  // NumericFormat Float
  32: begin
        FExportWriter.BeginNode('number:number-style', '', ['style:name'], ['FloatFormat']);
        FExportWriter.CreateFullNode('number:number', '',
          ['number:decimal-places', 'number:min-integer-digits'], ['2', '1']);
       FExportWriter.EndNode('number:number-style');
      end;
  // NumericFormat Date
  33: begin
        FExportWriter.BeginNode('number:date-style', '',
          ['style:name', 'number:automatic-order'], ['DateFormat', 'true']);
        FExportWriter.CreateFullNode('number:day', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', '.', [], []);
        FExportWriter.CreateFullNode('number:month', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', '.', [], []);
        FExportWriter.CreateFullNode('number:year', '', ['number:style'], ['long']);
        FExportWriter.EndNode('number:date-style');
      end;
  // NumericFormat Time
  34: begin
        FExportWriter.BeginNode('number:time-style', '',
          ['style:name', 'number:automatic-order'], ['TimeFormat', 'true']);
        FExportWriter.CreateFullNode('number:hours', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', ':', [], []);
        FExportWriter.CreateFullNode('number:minutes', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', ':', [], []);
        FExportWriter.CreateFullNode('number:seconds', '', ['number:style'], ['long']);
        FExportWriter.EndNode('number:time-style');
      end;
  // NumericFormat DateTime
  35: begin
        FExportWriter.BeginNode('number:date-style', '',
          ['style:name', 'number:automatic-order'], ['DateTimeFormat', 'true']);
        FExportWriter.CreateFullNode('number:day', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', '.', [], []);
        FExportWriter.CreateFullNode('number:month', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', '.', [], []);
        FExportWriter.CreateFullNode('number:year', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', '', [], []);
        FExportWriter.CreateFullNode('number:hours', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', ':', [], []);
        FExportWriter.CreateFullNode('number:minutes', '', ['number:style'], ['long']);
        FExportWriter.CreateFullNode('number:text', ':', [], []);
        FExportWriter.CreateFullNode('number:seconds', '', ['number:style'], ['long']);
        FExportWriter.EndNode('number:date-style');
      end;
  //End tag for root header
  108: begin
       FExportWriter.EndNode('office:document-content');
     end;
  //Office-face fonts declaration end tag
  1010: begin
        FExportWriter.EndNode('office:font-face-decls');
     end;
  //Office automatic styles end tag
  1011: begin
        FExportWriter.EndNode('office:automatic-styles');
      end;
  //end tag for body
  1012: begin
        FExportWriter.EndNode('office:body');
      end;
  //end tag for spreadsheet document
  1013: begin
        FExportWriter.EndNode('office:spreadsheet');
      end;
  //end tag for text document
  1014: begin
        FExportWriter.EndNode('office:text');
      end;
  //end tag for all tables
  1015: begin
        FExportWriter.EndNode('table:table');
      end;
  //end tag for all tables
  1016: begin
        FExportWriter.EndNode('table:table-row');
      end;
  //end tag for all tables
  1017: begin
        FExportWriter.EndNode('table:table-cell');
      end;
  //main style-style end tag
  1021: begin
        FExportWriter.EndNode('style:style');
      end;
  //Base style node
  1027: begin
        FExportWriter.EndNode('office:styles');
      end;
  //Common end tag header for styles.xml
  1028: begin
       FExportWriter.EndNode('office:document-styles');
      end;
  //Header-Row end tag
  1030: begin
        FExportWriter.EndNode('table:table-header-rows');
      end;
  end;
end;

destructor TBaseODFFile.Destroy;
begin
//
end;

procedure TBaseODFFile.EndFormingContent;
begin
//first common part of content file
  try
    FExportStream := TFileStream.Create(TempDir + '\first.xml', fmCreate);
      try
        FExportWriter := TQXMLWriter.Create(FExportStream);
        WriteSpecificNode(1, '', [], []);
        WriteSpecificNode(8, '', [], []);
        WriteSpecificNode(9, '', [], []);
        WriteSpecificNode(10, '', [], []);
      finally
        FExportWriter.Free;
      end;
  finally
    FExportStream.Free;
  end;
  try
    FExportStream := TFileStream.Create(TempDir + '\firstSt.xml', fmCreate);
      try
        FExportWriter := TQXMLWriter.Create(FExportStream);
        WriteSpecificNode(1, '', [], []);
        WriteSpecificNode(28, '', [], []);
        WriteSpecificNode(10, '', [], []);
      finally
        FExportWriter.Free;
      end;
  finally
    FExportStream.Free;
  end;

//last common part of content file
  try
    FExportStream := TFileStream.Create(TempDir + '\last.xml', fmCreate);
      try
        FExportWriter := TQXMLWriter.Create(FExportStream);
        if TypeConvert = odfText then
          WriteSpecificNode(1014, '', [], [])
        else
          WriteSpecificNode(1013, '', [], []);
        WriteSpecificNode(1012, '', [], []);
        WriteSpecificNode(108, '', [], []);
      finally
        FExportWriter.Free;
      end;
  finally
    FExportStream.Free;
  end;

end;

procedure TBaseODFFile.MakeAll;
begin
  if FileName = '' then
    raise Exception.Create(sFileNameNotDefined);
  if not CreateCommonStructure then
    raise Exception.Create(sStructureCreateFailed);
  if TypeConvert = odfUndefined then
    raise Exception.Create(sConvertWrong);
  //meta.xml form
  try
    FExportStream := TFileStream.Create(TempDir + '\meta.xml', fmCreate);
      try
        FExportWriter := TQXMLWriter.Create(FExportStream);
        WriteSpecificNode(1, '', [], []);
        WriteSpecificNode(2, '', [], []);
      finally
        FExportWriter.Free;
      end;
  finally
    FExportStream.Free;
  end;
  //manifest.xml of both types
  try
    FExportStream := TFileStream.Create(TempDir + '\META-INF\manifest.xml',
      fmCreate);
      try
        FExportWriter := TQXMLWriter.Create(FExportStream);
        WriteSpecificNode(1, '', [], []);
        if (TypeConvert = odfText) then
          WriteSpecificNode(204, '', [], [])
        else
          WriteSpecificNode(104, '', [], []);
      finally
        FExportWriter.Free;
      end;
  finally
    FExportStream.Free;
  end;
end;

procedure TBaseODFFile.Renew;
begin
  DeleteTempFolder;
  TypeConvert := odfUndefined;
end;

procedure TBaseODFFile.OpenStream(FName: string);
begin
  FExportStream := TFileStream.Create(TempDir + '\' + FName, fmCreate);
end;

procedure TBaseODFFile.OpenWriter;
begin
  FExportWriter := TQXMLWriter.Create(FExportStream);
end;

procedure TBaseODFFile.CloseStream;
begin
  FExportStream.Free;
end;

procedure TBaseODFFile.CloseWriter;
begin
  FExportWriter.Free;
end;

procedure TBaseODFFile.CheckStatus;
begin
  if not assigned(FExportStream) or not assigned(FExportWriter) then
    raise Exception.Create('Could not initialize temporary files');
end;

procedure TBaseODFFile.MergeContent(Name: WideString;
  FileNames: array of WideString);
var
  Stream1, Stream2: TStream;
  i: Integer;
begin
  Stream1 := TFileStream.Create(TempDir + '\' + Name, fmCreate);
  for i := 0 to length(FileNames) - 1 do
  begin
   Stream2 := TFileStream.Create(TempDir + '\' + FileNames[i], fmOpenRead);
   Stream1.CopyFrom(Stream2, 0);
   Stream2.Free;
  end;
  Stream1.Free;
end;

procedure TBaseODFFile.DeleteList(FileNames: array of WideString);
var
  i: Integer;
begin
  for i := 0 to length(FileNames) - 1 do
  begin
    if not FileExists(TempDir + '\' + FileNames[i]) then
      raise Exception.Create('Temporary file not found')
    else
      if not {$IFDEF VCL16}System.SysUtils{$ELSE}SysUtils{$ENDIF}.DeleteFile(TempDir + '\' + FileNames[i]) then
        raise Exception.Create('Could not delete temporary file');
  end;
end;

{ TODSParagraphStyle }

procedure TODSParagraphStyle.Assign(Source: TPersistent);
begin
  if Source is TODSParagraphStyle then
  begin
    Font := (Source as TODSParagraphStyle).Font;
    BackgroundColor := (Source as TODSParagraphStyle).BackgroundColor;
    AllowBackground := (Source as TODSParagraphStyle).AllowBackground;
    Alignment := (Source as TODSParagraphStyle).Alignment;
    Exit;
  end;
  inherited;
end;

constructor TODSParagraphStyle.Create(Collection: TCollection);
begin
  inherited;
  FFont := TFont.Create;
  SetDefault;
end;

destructor TODSParagraphStyle.Destroy;
begin
  FFont.Free;
  inherited;
end;

procedure TODSParagraphStyle.LoadFromIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  with IniFile do begin
    Font.Name := ReadString(Section, S_ODF_FontName, odfDefaultFont.Name);
    Font.Size := ReadInteger(Section, S_ODF_FontSize, odfDefaultFont.Size);
    Font.Color := ReadInteger(Section, S_ODF_FontColor, odfDefaultFont.Color);
    if ReadBool(Section, S_ODF_FontBold, false)
      then Font.Style := Font.Style + [fsBold]
      else Font.Style := Font.Style - [fsBold];
    if ReadBool(Section, S_ODF_FontItalic, false)
      then Font.Style := Font.Style + [fsItalic]
      else Font.Style := Font.Style - [fsItalic];
    if ReadBool(Section, S_ODF_FontStrikeOut, false)
      then Font.Style := Font.Style + [fsStrikeOut]
      else Font.Style := Font.Style - [fsStrikeOut];
    if ReadBool(Section, S_ODF_FontUnderline, false)
      then Font.Style := Font.Style + [fsUnderline]
      else Font.Style := Font.Style - [fsUnderline];
    AllowBackground := ReadBool(Section, S_ODF_AllowBackground, true);
    BackgroundColor := ReadInteger(Section, S_ODF_BackgroundColor, odfDefaultBackground);
    Alignment := TODFTextAlignment(ReadInteger(Section, S_ODF_HorAlignment,
      Integer(odfDefaultAlignment)));
  end;
end;

procedure TODSParagraphStyle.SaveToIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  with IniFile do begin
    WriteString(Section, S_ODF_FontName, Font.Name);
    WriteInteger(Section, S_ODF_FontSize, Font.Size);
    WriteInteger(Section, S_ODF_FontColor, Font.Color);
    if fsBold in Font.Style then
      WriteBool(Section, S_ODF_FontBold, true)
    else
      WriteBool(Section, S_ODF_FontBold, false);
    if fsItalic in Font.Style then
      WriteBool(Section, S_ODF_FontItalic, true)
    else
      WriteBool(Section, S_ODF_FontItalic, false);
    if fsStrikeOut in Font.Style then
      WriteBool(Section, S_ODF_FontStrikeOut, true)
    else
      WriteBool(Section, S_ODF_FontStrikeOut, false);
    if fsUnderline in Font.Style then
      WriteBool(Section, S_ODF_FontUnderline, true)
    else
      WriteBool(Section, S_ODF_FontUnderline, false);
    WriteBool(Section, S_ODF_AllowBackground, AllowBackground);
    WriteInteger(Section, S_ODF_BackgroundColor, BackgroundColor);
    WriteInteger(Section, S_ODF_HorAlignment, Integer(Alignment));
  end;
end;

function TODSParagraphStyle.IsDefault: Boolean;
begin
  Result := (FFont.Name = odfDefaultFont.Name)
    and (FFont.Size = odfDefaultFont.Size)
    and (FFont.Style = odfDefaultFont.Style)
    and (FFont.Color = odfDefaultFont.Color)
    and (FBackgroundColor = odfDefaultBackground)
    and (FAllowBackground = True)
    and (FAlignment = odfDefaultAlignment);
end;

procedure TODSParagraphStyle.SetDefault;
begin
  FFont.Name := odfDefaultFont.Name;
  FFont.Size := odfDefaultFont.Size;
  FFont.Style := odfDefaultFont.Style;
  FFont.Color := odfDefaultFont.Color;
  FBackgroundColor := odfDefaultBackground;
  FAllowBackground := True;   /// ??? зачем всегда приметь бэкграунд?
  FAlignment := odfDefaultAlignment;
end;

procedure TODSParagraphStyle.SetFont(const Value: TFont);
begin
  FFont.Assign(Value);
end;

{ TODTParagraphStyle }

procedure TODTParagraphStyle.Assign(Source: TPersistent);
begin
  if Source is TODTParagraphStyle then
  begin
    HighlightColor := (Source as TODTParagraphStyle).HighlightColor;
    AllowHighlight := (Source as TODTParagraphStyle).AllowHighlight;
    inherited Assign(Source as TODSParagraphStyle);
    Exit;
  end;
  inherited;
end;

constructor TODTParagraphStyle.Create(Collection: TCollection);
begin
  inherited Create(Collection);
end;

destructor TODTParagraphStyle.Destroy;
begin
  inherited;
end;

procedure TODTParagraphStyle.LoadFromIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    AllowHighlight := ReadBool(Section, S_ODT_AllowHighlight, false);
    HighlightColor := ReadInteger(Section, S_ODT_HighlightColor, clWhite);
  end;
end;

procedure TODTParagraphStyle.SaveToIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    WriteBool(Section, S_ODT_AllowHighlight, AllowHighlight);
    WriteInteger(Section, S_ODT_HighlightColor, HighlightColor);
  end;
end;

function TODTParagraphStyle.IsDefault: Boolean;
begin
  Result := inherited IsDefault
  and (FHighlightColor = odfDefaultHighlight)
  and (FAllowHighlight = False);
end;

procedure TODTParagraphStyle.SetDefault;
begin
  inherited SetDefault;
  FHighlightColor := odfDefaultHighlight;
  FAllowHighlight := false;
end;

{ TODTStylesList }

function TODTStylesList.Add: TODTCellParagraphStyle;
begin
  Result := TODTCellParagraphStyle(inherited Add);
end;

constructor TODTStylesList.Create(Holder: TPersistent);
begin
  inherited Create(TODTCellParagraphStyle);
  FHolder := Holder;
end;

function TODTStylesList.GetItem(Index: Integer): TODTCellParagraphStyle;
begin
  Result := inherited GetItem(Index) as TODTCellParagraphStyle;
end;

function TODTStylesList.GetOwner: TPersistent;
begin
  Result := FHolder;
end;

procedure TODTStylesList.SetItem(Index: integer; Value: TODTCellParagraphStyle);
begin
 inherited SetItem(Index, Value);
end;

{ TODSStylesList }

function TODSStylesList.Add: TODSStripCellParagraphStyle;
begin
  Result := TODSStripCellParagraphStyle(inherited Add);
end;

constructor TODSStylesList.Create(Holder: TPersistent);
begin
  inherited Create(TODSStripCellParagraphStyle);
  FHolder := Holder;
end;

function TODSStylesList.GetItem(Index: Integer): TODSStripCellParagraphStyle;
begin
  Result := inherited GetItem(Index) as TODSStripCellParagraphStyle;
end;

function TODSStylesList.GetOwner: TPersistent;
begin
  Result := FHolder;
end;

procedure TODSStylesList.SetItem(Index: integer; Value: TODSStripCellParagraphStyle);
begin
 inherited SetItem(Index, Value);
end;

{ TODSCellParagraphStyle }

procedure TODSCellParagraphStyle.Assign(Source: TPersistent);
begin
  if Source is TODSCellParagraphStyle then
  begin
    VerticalAligment := (Source as TODSCellParagraphStyle).VerticalAligment;
    Border := (Source as TODSCellParagraphStyle).Border;
    inherited Assign(Source as TODSParagraphStyle);
    Exit;
  end;
  inherited;
end;

constructor TODSCellParagraphStyle.Create(Collection: TCollection);
begin
  inherited;
end;

destructor TODSCellParagraphStyle.Destroy;
begin
  inherited;
  FBorder.Free;
end;

procedure TODSCellParagraphStyle.LoadFromIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    VerticalAligment := TODFTextVerticalAligment(ReadInteger(Section,
      S_ODF_VertAlignment, Integer(odfDefaultVerticalAlignment)));
    Border.BorderStyle := TODFBorderStyle(ReadInteger(Section, S_ODF_BorderStyle,
      Integer(odfDefaultBorderStyle)));
    Border.BorderWidth := ReadInteger(Section, S_ODF_BorderWidth,
      odfDefaultBorderWidth);
    Border.BorderColor := ReadInteger(Section, S_ODF_BorderColor,
      odfDefaultBorderColor);
  end;
end;

procedure TODSCellParagraphStyle.SaveToIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    WriteInteger(Section, S_ODF_VertAlignment, Integer(VerticalAligment));
    WriteInteger(Section, S_ODF_BorderStyle, Integer(Border.BorderStyle));
    WriteInteger(Section, S_ODF_BorderWidth, Border.BorderWidth);
    WriteInteger(Section, S_ODF_BorderColor, Border.BorderColor);
  end;
end;

procedure TODSCellParagraphStyle.SetBorder(const Value: TODFBorder);
begin
  FBorder.Assign(Value);
end;

function TODSCellParagraphStyle.IsDefault: Boolean;
begin
  Result := inherited IsDefault
  and (FVerticalAligment = odfDefaultVerticalAlignment)
  and (FBorder.BorderColor = odfDefaultBorderColor)
  and (FBorder.BorderStyle = odfDefaultBorderStyle)
  and (FBorder.BorderWidth = odfDefaultBorderWidth);
end;

procedure TODSCellParagraphStyle.SetDefault;
begin
  inherited SetDefault;
  FVerticalAligment := odfDefaultVerticalAlignment;
  FBorder := TODFBorder.Create;
end;

{ TODTCellParagraphStyle }

procedure TODTCellParagraphStyle.Assign(Source: TPersistent);
begin
  if Source is TODTCellParagraphStyle then
  begin
    VerticalAligment := (Source as TODTCellParagraphStyle).VerticalAligment;
    inherited Assign(Source as TODTParagraphStyle);
    Exit;
  end;
  inherited;
end;

constructor TODTCellParagraphStyle.Create(Collection: TCollection);
begin
  inherited;
end;

destructor TODTCellParagraphStyle.Destroy;
begin
  inherited;
end;


procedure TODTCellParagraphStyle.LoadFromIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    VerticalAligment := TODFTextVerticalAligment(ReadInteger(Section,
      S_ODF_VertAlignment, Integer(taODFBottom)));
  end;
end;

procedure TODTCellParagraphStyle.SaveToIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    WriteInteger(Section, S_ODF_VertAlignment, Integer(VerticalAligment));
  end;
end;

function TODTCellParagraphStyle.IsDefault: Boolean;
begin
  Result := inherited IsDefault
  and (FVerticalAligment = odfDefaultVerticalAlignment);
end;

procedure TODTCellParagraphStyle.SetDefault;
begin
  inherited SetDefault;
  FVerticalAligment := odfDefaultVerticalAlignment;
end;

{ TODFBorder }

procedure TODFBorder.Assign(Source: TPersistent);
begin
  if Source is TODFBorder then
  begin
    BorderStyle := (Source as TODFBorder).BorderStyle;
    BorderWidth := (Source as TODFBorder).BorderWidth;
    BorderColor := (Source as TODFBorder).BorderColor;
    Exit;
  end;
  inherited;
end;

constructor TODFBorder.Create;
begin
  SetDefault;
end;


procedure TODFBorder.SetBorderWidth(const Value: Integer);
begin
  if (Value <> BorderWidth) then
  begin
    if (Value <= 0) then
      FBorderWidth := 0;
    if (Value > 10) then
      FBorderWidth := 10;
    if (Value <= 10) and (Value > 0) then
      FBorderWidth := Value;
  end;
end;

procedure TODFBorder.SetDefault;
begin
  FBorderStyle := odfDefaultBorderStyle;
  FBorderWidth := odfDefaultBorderWidth;
  FBorderColor := odfDefaultBorderColor;
end;

{$IFNDEF NOGUI}
procedure DrawODTCellSample(PaintBox: TPaintBox; odtStyle: TODTCellParagraphStyle);
  procedure FillBackground;
  begin
    if odtStyle.AllowBackground
      then  PaintBox.Canvas.Brush.Color := odtStyle.BackgroundColor
      else  PaintBox.Canvas.Brush.Color := clWhite;
    PaintBox.Canvas.FillRect(Rect(0, 0, PaintBox.Width, PaintBox.Height));
  end;

  procedure OutText;
  const
    TXT = 'Aa Zz';
  var
    H, W, X, Y: integer;
  begin
    with PaintBox.Canvas.Font do begin
      Name := odtStyle.Font.Name;
      Size := odtStyle.Font.Size;
      Charset := odtStyle.Font.Charset;
      Color := odtStyle.Font.Color;
      Style := odtStyle.Font.Style;
    end;

    H := PaintBox.Canvas.TextHeight(TXT);
    W := PaintBox.Canvas.TextWidth(TXT);
    if H > PaintBox.Height then
      H := PaintBox.Height;
    if W > PaintBox.Width then
      W := PaintBox.Width;

    case odtStyle.Alignment of
      taODFLeft,
      taODFJustify: X := 5;
      taODFCenter: X := (PaintBox.Width - PaintBox.Canvas.TextWidth(TXT)) div 2;
      taODFRight: X := PaintBox.Width - 5 - PaintBox.Canvas.TextWidth(TXT);
      else X := 0;
    end;

    case odtStyle.VerticalAligment of
      taODFTop: Y := 5;
      taODFMiddle: Y := (PaintBox.Height - PaintBox.Canvas.TextHeight(TXT)) div 2;
      taODFBottom: Y := PaintBox.Height - 5 - PaintBox.Canvas.TextHeight(TXT);
      else Y := 0;
    end;

    if odtStyle.AllowHighlight and
         (odtStyle.HighlightColor <> odtStyle.BackgroundColor) then begin
      PaintBox.Canvas.Brush.Color := odtStyle.HighlightColor;
      PaintBox.Canvas.FillRect(Rect(X, Y, X + W, Y + H));
    end;

    PaintBox.Canvas.TextOut(X, Y, TXT);

  end;

begin
  FillBackground;
  OutText;
end;

procedure DrawODTTextSample(PaintBox: TPaintBox; odtStyle: TODTParagraphStyle);
  procedure FillBackground;
  begin
    if odtStyle.AllowBackground
      then  PaintBox.Canvas.Brush.Color := odtStyle.BackgroundColor
      else  PaintBox.Canvas.Brush.Color := clWhite;
    PaintBox.Canvas.FillRect(Rect(0, 0, PaintBox.Width, PaintBox.Height));
  end;

  procedure OutText;
  const
    TXT = 'Aa Zz';
  var
    H, W, X, Y: integer;
  begin
    with PaintBox.Canvas.Font do begin
      Name := odtStyle.Font.Name;
      Size := odtStyle.Font.Size;
      Charset := odtStyle.Font.Charset;
      Color := odtStyle.Font.Color;
      Style := odtStyle.Font.Style;
    end;

    H := PaintBox.Canvas.TextHeight(TXT);
    W := PaintBox.Canvas.TextWidth(TXT);
    if H > PaintBox.Height then
      H := PaintBox.Height;
    if W > PaintBox.Width then
      W := PaintBox.Width;

    case odtStyle.Alignment of
      taODFLeft,
      taODFJustify: X := 5;
      taODFCenter: X := (PaintBox.Width - PaintBox.Canvas.TextWidth(TXT)) div 2;
      taODFRight: X := PaintBox.Width - 5 - PaintBox.Canvas.TextWidth(TXT);
      else X := 0;
    end;
    Y := (PaintBox.Height - PaintBox.Canvas.TextHeight(TXT)) div 2;

    if odtStyle.AllowHighlight and
         (odtStyle.HighlightColor <> odtStyle.BackgroundColor) then begin
      PaintBox.Canvas.Brush.Color := odtStyle.HighlightColor;
      PaintBox.Canvas.FillRect(Rect(X, Y, X + W, Y + H));
    end;

    PaintBox.Canvas.TextOut(X, Y, TXT);

  end;

begin
  FillBackground;
  OutText;
end;

procedure DrawODSSample(PaintBox: TPaintBox; odsStyle: TODSCellParagraphStyle);

  procedure FillBackground;
  begin
    if odsStyle.AllowBackground
      then  PaintBox.Canvas.Brush.Color := odsStyle.BackgroundColor
      else  PaintBox.Canvas.Brush.Color := clWhite;
    PaintBox.Canvas.FillRect(Rect(0, 0, PaintBox.Width, PaintBox.Height));
  end;

  procedure OutText;
  const
    TXT = 'Aa Zz';
  var
    X, Y: integer;
  begin
    with PaintBox.Canvas.Font do begin
      Name := odsStyle.Font.Name;
      Size := odsStyle.Font.Size;
      Charset := odsStyle.Font.Charset;
      Color := odsStyle.Font.Color;
      Style := odsStyle.Font.Style;
    end;

    case odsStyle.Alignment of
      taODFLeft,
      taODFJustify: X := 5;
      taODFCenter: X := (PaintBox.Width - PaintBox.Canvas.TextWidth(TXT)) div 2;
      taODFRight: X := PaintBox.Width - 5 - PaintBox.Canvas.TextWidth(TXT);
      else X := 0;
    end;

    case odsStyle.VerticalAligment of
      taODFTop: Y := 5;
      taODFMiddle: Y := (PaintBox.Height - PaintBox.Canvas.TextHeight(TXT)) div 2;
      taODFBottom: Y := PaintBox.Height - 5 - PaintBox.Canvas.TextHeight(TXT);
      else Y := 0;
    end;
    PaintBox.Canvas.TextOut(X, Y, TXT);
  end;

begin
  FillBackground;
  OutText;
end;
{$ENDIF}

{ TODSStripCellParagraphStyle }

procedure TODSStripCellParagraphStyle.Assign(Source: TPersistent);
begin
  if Source is TODSStripCellParagraphStyle then
  begin
    FUseDataStyleBorder :=
      (Source as TODSStripCellParagraphStyle).UseDataStyleBorder;
    inherited Assign(Source as TODSCellParagraphStyle);
    Exit;
  end;
  inherited;
end;

constructor TODSStripCellParagraphStyle.Create(Collection: TCollection);
begin
  inherited;
end;

procedure TODSStripCellParagraphStyle.SetStyleName(Value: string);
begin
  FStyleName := Value;
end;

procedure TODSStripCellParagraphStyle.SetNumericFormat(Value: string);
begin
  FNumericFormat := Value;
end;

function TODSStripCellParagraphStyle.GetStripBorder: TODFBorder;
begin
  Result := nil;
  if FUseDataStyleBorder and (Collection is TODSStylesList) and
    (TODSStylesList(Collection).Holder is TQExportODSOptions) then
      Result := TQExportODSOptions(TODSStylesList(Collection).Holder).DataStyle.Border
  else
  if not FUseDataStyleBorder then
    Result := Border;
end;

procedure TODSStripCellParagraphStyle.LoadFromIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    UseDataStyleBorder := ReadBool(Section, S_ODS_UseDataStyleBorder, true);
  end;
end;

procedure TODSStripCellParagraphStyle.SaveToIniFile(IniFile: TQIniFile;
  const Section: string);
begin
  inherited;
  with IniFile do begin
    WriteBool(Section, S_ODS_UseDataStyleBorder, UseDataStyleBorder);
  end;
end;

function TODSStripCellParagraphStyle.IsDefault: Boolean;
begin
  Result := inherited IsDefault
  and (FUseDataStyleBorder = True);
end;

procedure TODSStripCellParagraphStyle.SetDefault;
begin
  inherited SetDefault;
  FUseDataStyleBorder := True;
end;

initialization
  odfDefaultFont := TFont.Create;
  odfDefaultFont.Name := 'Arial';
  odfDefaultFont.Size := 10;
  odfDefaultFont.Style := [];
  odfDefaultFont.Color := clBlack;

finalization
  odfDefaultFont.Free;

end.
