lazarus/components/fpvectorial/odtvectorialwriter.pas

1871 lines
83 KiB
ObjectPascal

{
Writes an ODT Document
License: The same modified LGPL as the Free Pascal RTL
See the file COPYING.modifiedLGPL for more details
An OpenDocument document is a compressed ZIP file with the following files inside:
content.xml - Actual contents
meta.xml - Authoring data
settings.xml - User persistent viewing information, such as zoom, cursor position, etc.
styles.xml - Styles, which are the only way to do formatting
mimetype - application/vnd.oasis.opendocument.text
META-INF\manifest.xml - Describes the other files in the archive
Specifications obtained from:
http://docs.oasis-open.org/office/v1.1/OS/OpenDocument-v1.1.pdf
Example of content.xml structure:
<?xml version="1.0" encoding="UTF-8"?>
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" .....>
<office:scripts/>
<office:automatic-styles>
<style:style style:name="dp1" style:family="drawing-page"/>
<style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard">
....
</office:automatic-styles>
<office:body>
<office:drawing>
<draw:page draw:name="page1" draw:style-name="dp1" draw:master-page-name="Oletus">
<draw:ellipse draw:style-name="gr2" draw:text-style-name="P1" draw:layer="layout" svg:width="11cm" svg:height="3cm" svg:x="5.5cm" svg:y="6.5cm">
<text:p/>
</draw:ellipse>
... other elements in the page...
</draw:page>
</office:drawing>
</office:body>
</office:document-content>
Validator for ODF 1.0
http://opendocumentfellowship.com/validator
Validator for ODF 1.2
http://odf-validator2.rhcloud.com/odf-validator2/
AUTHORS: Felipe Monteiro de Carvalho
}
unit odtvectorialwriter;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
zipper, zstream, {NOTE: might require zipper from FPC 2.6.2+ }
fpimage, fpcanvas,
fpvectorial, fpvutils, lazutf8;
type
// Forward declarations
TvODTVectorialWriter = class;
{ TListStyle_Style }
TListStyle_Style = Class
Style : TvStyle;
ListStyle : TvListStyle;
End;
{ TListStyle_StyleList }
TListStyle_StyleList = Class(TFPList)
Writer : TvODTVectorialWriter;
Data : TvVectorialDocument;
destructor Destroy; override;
function AddCrossReference(AStyle : TvStyle; AListStyle: TvListStyle) : Integer;
function AsText(AIndex : Integer) : String;
End;
{ TvODTVectorialWriter }
// Writes ODT 1.2 with LibreOffice extensions...
TvODTVectorialWriter = class(TvCustomVectorialWriter)
private
FDateCount : Integer; // Used to track Date Style Formats...
FPointSeparator: TFormatSettings;
// Strings with the contents of files
FMeta, FSettings, FStyles, FContent, FMimetype: string;
FAutomaticStyles, FMasterStyles: string; // built during writedocument, used during writestyle
FAutomaticStyleID : Integer;
FContentAutomaticStyles : string; // built during writedocument, used during writedocument
FRasterImageFileNames:TStringList;
FList_StyleCrossRef : TListStyle_StyleList;
FNewPageSequence : Boolean;
FMetaInfManifest, FManifestRDF: string;
// helper routines
function StyleNameToODTStyleName(AData: TvVectorialDocument; AStyleIndex: Integer; AToContentAutoStyle: Boolean = False): string; overload;
function StyleNameToODTStyleName(AData: TvVectorialDocument; AStyle: TvStyle; AToContentAutoStyle: Boolean = False): string; overload;
function ListStyleNameToODTText(AData: TvVectorialDocument; AListStyle : TvListStyle) : string;
function FloatToODTText(AFloat: Double): string;
function BordersToString(ATableBorders, ACellBorders: TvTableBorders; ATopCell,
ABottomCell, ALeftCell, ARightCell: Boolean): String;
// Routines to write those files
procedure WriteMimetype;
procedure WriteMetaInfManifest;
procedure WriteManifestRDF;
procedure WriteMeta;
procedure WriteSettings;
procedure WriteStyles(AData: TvVectorialDocument);
procedure WriteDocument(AData: TvVectorialDocument);
procedure WritePage(ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
//
procedure WriteParagraph(AEntity: TvParagraph; ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
procedure WriteTable(ATable: TvTable; ACurPage: TvTextPageSequence;
AData: TvVectorialDocument);
procedure WriteTextSpan(AEntity: TvText; AParagraph: TvParagraph;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
procedure WriteField(AEntity: TvField; AParagraph: TvParagraph;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
procedure WriteList(AEntity: TvList; ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
procedure WriteRasterImage(AEntity:TvRasterImage; AParagraph: TvParagraph;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
// Routines to write parts of those files
function WriteStylesXMLAsString: string;
//
public
{ General reading methods }
constructor Create; override;
destructor Destroy; override;
procedure WriteToFile(AFileName: string; AData: TvVectorialDocument); override;
procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); override;
end;
implementation
uses
htmlelements, FPWritePNG, Math;
const
{ OpenDocument general XML constants }
XML_HEADER = '<?xml version="1.0" encoding="utf-8" ?>';
{ OpenDocument Directory structure constants }
OPENDOC_PATH_CONTENT = 'content.xml';
OPENDOC_PATH_META = 'meta.xml';
OPENDOC_PATH_SETTINGS = 'settings.xml';
OPENDOC_PATH_STYLES = 'styles.xml';
OPENDOC_PATH_MIMETYPE = 'mimetype';
OPENDOC_PATH_METAINF = 'META-INF' + '/';
OPENDOC_PATH_METAINF_MANIFEST = 'META-INF' + '/' + 'manifest.xml';
OPENDOC_PATH_MANIFESTRDF = 'manifest.rdf';
{ OpenDocument schemas constants }
SCHEMAS_XMLNS = 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties';
SCHEMAS_XMLNS_CALCEXT = 'urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0';
SCHEMAS_XMLNS_CHART = 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0';
SCHEMAS_XMLNS_CONFIG = 'urn:oasis:names:tc:opendocument:xmlns:config:1.0';
SCHEMAS_XMLNS_CSS3T = 'http://www.w3.org/TR/css3-text/';
SCHEMAS_XMLNS_DC = 'http://purl.org/dc/elements/1.1/';
SCHEMAS_XMLNS_DCTERMS = 'http://purl.org/dc/terms/';
SCHEMAS_XMLNS_DOM = 'http://www.w3.org/2001/xml-events';
SCHEMAS_XMLNS_DR3D = 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0';
SCHEMAS_XMLNS_DRAW = 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0';
SCHEMAS_XMLNS_DRAWOOO = 'http://openoffice.org/2010/draw';
SCHEMAS_XMLNS_FIELD = 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0';
SCHEMAS_XMLNS_FO = 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0';
SCHEMAS_XMLNS_FORM = 'urn:oasis:names:tc:opendocument:xmlns:form:1.0';
SCHEMAS_XMLNS_FORMX = 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0';
SCHEMAS_XMLNS_GRDDL = 'http://www.w3.org/2003/g/data-view#';
SCHEMAS_XMLNS_MANIFEST = 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0';
SCHEMAS_XMLNS_MATH = 'http://www.w3.org/1998/Math/MathML';
SCHEMAS_XMLNS_META = 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0';
SCHEMAS_XMLNS_NUMBER = 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0';
SCHEMAS_XMLNS_OF = 'urn:oasis:names:tc:opendocument:xmlns:of:1.2';
SCHEMAS_XMLNS_OFFICE = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0';
SCHEMAS_XMLNS_OFFICEOOO= 'http://openoffice.org/2009/office';
SCHEMAS_XMLNS_OOO = 'http://openoffice.org/2004/office';
SCHEMAS_XMLNS_OOOC = 'http://openoffice.org/2004/calc';
SCHEMAS_XMLNS_OOOW = 'http://openoffice.org/2004/writer';
SCHEMAS_XMLNS_RPT = 'http://openoffice.org/2005/report';
SCHEMAS_XMLNS_SCRIPT = 'urn:oasis:names:tc:opendocument:xmlns:script:1.0';
SCHEMAS_XMLNS_STYLE = 'urn:oasis:names:tc:opendocument:xmlns:style:1.0';
SCHEMAS_XMLNS_SVG = 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0';
SCHEMAS_XMLNS_TABLE = 'urn:oasis:names:tc:opendocument:xmlns:table:1.0';
SCHEMAS_XMLNS_TABLEOOO = 'http://openoffice.org/2009/table';
SCHEMAS_XMLNS_TEXT = 'urn:oasis:names:tc:opendocument:xmlns:text:1.0';
SCHEMAS_XMLNS_V = 'urn:schemas-microsoft-com:vml';
SCHEMAS_XMLNS_XFORMS = 'http://www.w3.org/2002/xforms';
SCHEMAS_XMLNS_XHTML = 'http://www.w3.org/1999/xhtml';
SCHEMAS_XMLNS_XLINK = 'http://www.w3.org/1999/xlink';
SCHEMAS_XMLNS_XSD = 'http://www.w3.org/2001/XMLSchema';
SCHEMAS_XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
// SVG requires hardcoding a DPI value
// The Opera Browser and Inkscape use 90 DPI, so we follow that
// 1 Inch = 25.4 milimiters
// 90 inches per pixel = (1 / 90) * 25.4 = 0.2822
// FLOAT_MILIMETERS_PER_PIXEL = 0.3528; // DPI 72 = 1 / 72 inches per pixel
FLOAT_MILIMETERS_PER_PIXEL = 0.2822; // DPI 90 = 1 / 90 inches per pixel
FLOAT_PIXELS_PER_MILIMETER = 3.5433; // DPI 90 = 1 / 90 inches per pixel
// Lookups
LU_ALIGN: Array [TvStyleAlignment] Of String =
('start', 'end', 'justify', 'center');
LU_V_ALIGN: Array[TvVerticalAlignment] Of String =
('top', 'bottom', 'middle', 'automatic');
LU_NUMBERFORMAT: Array [TvNumberFormat] Of String =
('1', 'a', 'i', 'A', 'I');
LU_BORDERTYPE: Array[TvTableBorderType] Of String =
('solid', 'dashed', 'solid', 'none', 'default');
// ('solid', 'dashed', 'double', 'none', 'default'); // NOTE: double not supported
{ TListStyle_StyleList }
destructor TListStyle_StyleList.Destroy;
begin
while (Count>0) do
begin
TListStyle_Style(Last).Free;
Delete(Count-1);
end;
inherited destroy;
end;
function TListStyle_StyleList.AddCrossReference(AStyle: TvStyle;
AListStyle: TvListStyle): Integer;
Var
i : Integer;
oCrossRef : TListStyle_Style;
begin
// Only add unique instances of the cross references
Result := -1;
for i := 0 To Count-1 Do
begin
oCrossRef := TListStyle_Style(Items[i]);
if (oCrossRef.Style = AStyle) And (oCrossRef.ListStyle=AListStyle) Then
exit(i);
end;
// We will only get here if the supplied combination is not already in the list
oCrossRef := TListStyle_Style.Create;
oCrossRef.Style := AStyle;
oCrossRef.ListStyle := AListStyle;
Result := Add(oCrossRef);
end;
function TListStyle_StyleList.AsText(AIndex: Integer): String;
begin
if (AIndex>=0) And (AIndex<Count) Then
with (TListStyle_Style(Items[AIndex])) Do
Result := Writer.StyleNameToODTStyleName(Data, Style, False) + '_' +
Writer.ListStyleNameToODTText(Data, ListStyle)
else
raise exception.create('index out of bounds');
end;
function TvODTVectorialWriter.StyleNameToODTStyleName(
AData: TvVectorialDocument; AStyleIndex: Integer; AToContentAutoStyle: Boolean): string;
var
lStyle: TvStyle;
begin
lStyle := AData.GetStyle(AStyleIndex);
if AToContentAutoStyle then
begin
Result := 'P' + IntToStr(AStyleIndex);
end
else
begin
Result := StringReplace(lStyle.Name, ' ', '_', [rfReplaceAll, rfIgnoreCase]);
end;
end;
function TvODTVectorialWriter.StyleNameToODTStyleName(
AData: TvVectorialDocument; AStyle: TvStyle; AToContentAutoStyle: Boolean
): string;
var
lStyleIndex: Integer;
begin
lStyleIndex := AData.FindStyleIndex(AStyle);
Result := StyleNameToODTStyleName(AData, lStyleIndex, AToContentAutoStyle);
end;
function TvODTVectorialWriter.ListStyleNameToODTText(
AData: TvVectorialDocument; AListStyle: TvListStyle): string;
begin
Result := StringReplace(AListStyle.Name, ' ', '', [rfReplaceAll]);
If Result='' Then
Result := Format('List_%d', [AData.FindListStyleIndex(AListStyle)]);
end;
function TvODTVectorialWriter.FloatToODTText(AFloat: Double): string;
begin
Result := FloatToStr(AFloat, FPointSeparator);
end;
procedure TvODTVectorialWriter.WriteMimetype;
begin
FMimetype := 'application/vnd.oasis.opendocument.text';
end;
procedure TvODTVectorialWriter.WriteMetaInfManifest;
var
i:integer;
begin
FMetaInfManifest :=
XML_HEADER + LineEnding +
'<manifest:manifest xmlns:manifest="' + SCHEMAS_XMLNS_MANIFEST + '" manifest:version="1.2">' + LineEnding +
' <manifest:file-entry manifest:full-path="/" manifest:media-type="application/vnd.oasis.opendocument.text" />' + LineEnding; // manifest:version="1.2"
for i:= 0 to FRasterImageFileNames.Count-1 do
begin
FMetaInfManifest := FMetaInfManifest+
' <manifest:file-entry manifest:media-type="image/png" manifest:full-path="'+FRasterImageFileNames[i]+'" />' + LineEnding;
end;
FMetaInfManifest := FMetaInfManifest+
' <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml" />' + LineEnding +
' <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml" />' + LineEnding +
' <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml" />' + LineEnding +
' <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="settings.xml" />' + LineEnding +
' <manifest:file-entry manifest:full-path="manifest.rdf" manifest:media-type="application/rdf+xml"/>' + LineEnding +
'</manifest:manifest>';
end;
procedure TvODTVectorialWriter.WriteManifestRDF;
begin
FManifestRDF :=
XML_HEADER + LineEnding +
'<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">' + LineEnding +
' <rdf:Description rdf:about="styles.xml">' + LineEnding +
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/odf#StylesFile"/>' + LineEnding +
' </rdf:Description>' + LineEnding +
' <rdf:Description rdf:about="">' + LineEnding +
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="styles.xml"/>' + LineEnding +
' </rdf:Description>' + LineEnding +
' <rdf:Description rdf:about="content.xml">' + LineEnding +
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/odf#ContentFile"/>' + LineEnding +
' </rdf:Description>' + LineEnding +
' <rdf:Description rdf:about="">' + LineEnding +
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="content.xml"/>' + LineEnding +
' </rdf:Description>' + LineEnding +
' <rdf:Description rdf:about="">' + LineEnding +
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#Document"/>' + LineEnding +
' </rdf:Description>' + LineEnding +
'</rdf:RDF>' + LineEnding;
end;
procedure TvODTVectorialWriter.WriteMeta;
begin
FMeta :=
XML_HEADER + LineEnding +
'<office:document-meta xmlns:office="' + SCHEMAS_XMLNS_OFFICE + '"' +
' xmlns:xlink="' + SCHEMAS_XMLNS_XLINK + '"' +
' xmlns:dc="' + SCHEMAS_XMLNS_DC + '"' +
' xmlns:ooo="' + SCHEMAS_XMLNS_OOO + '"' +
' xmlns:grddl="' + SCHEMAS_XMLNS_GRDDL + '"' +
' xmlns:meta="' + SCHEMAS_XMLNS_META + '"' +
' xmlns="' + SCHEMAS_XMLNS + '"' +
' xmlns:ex="' + SCHEMAS_XMLNS + '" office:version="1.2">' + LineEnding +
' <office:meta>' + LineEnding +
// <meta:creation-date>2013-07-21T09:29:41.06</meta:creation-date>
// <dc:date>2013-07-21T20:13:32.29</dc:date>
' <meta:generator>FPVectorial Library</meta:generator>' + LineEnding +
// <meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="19" meta:word-count="312" meta:character-count="2028" meta:non-whitespace-character-count="2028" />
' </office:meta>' + LineEnding +
'</office:document-meta>';
end;
procedure TvODTVectorialWriter.WriteSettings;
begin
FSettings :=
XML_HEADER + LineEnding +
'<office:document-settings xmlns:office="' + SCHEMAS_XMLNS_OFFICE + '"' +
' xmlns:xlink="' + SCHEMAS_XMLNS_XLINK + '"' +
' xmlns:config="' + SCHEMAS_XMLNS_CONFIG + '"' +
' xmlns:ooo="' + SCHEMAS_XMLNS_OOO + '" office:version="1.2">' + LineEnding +
'<office:settings>' + LineEnding +
' <config:config-item-set config:name="ooo:view-settings">' + LineEnding +
' <config:config-item config:name="ViewAreaTop" config:type="int">0</config:config-item>' + LineEnding +
' <config:config-item config:name="ViewAreaLeft" config:type="int">0</config:config-item>' + LineEnding +
' <config:config-item config:name="ViewAreaWidth" config:type="int">25534</config:config-item>' + LineEnding +
' <config:config-item config:name="ViewAreaHeight" config:type="int">9289</config:config-item>' + LineEnding +
{
<config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
<config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
<config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="int">4267</config:config-item>
<config:config-item config:name="ViewTop" config:type="int">2925</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="int">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="int">0</config:config-item>
<config:config-item config:name="VisibleRight" config:type="int">25532</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="int">9287</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
<config:config-item config:name="ZoomFactor" config:type="short">100</config:config-item>
<config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item>
</config:config-item-map-entry>
</config:config-item-map-indexed>
</config:config-item-set>
}
' </config:config-item-set>' + LineEnding +
' <config:config-item-set config:name="ooo:configuration-settings">' + LineEnding +
' <config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>' + LineEnding +
{
<config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item>
<config:config-item config:name="Rsid" config:type="int">490666</config:config-item>
<config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item>
<config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseCommand" config:type="string" />
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item>
<config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item>
<config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
<config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintEmptyPages" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item>
<config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item>
<config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">470846</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
<config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="RedlineProtectionKey" config:type="base64Binary" />
<config:config-item config:name="PrinterSetup" config:type="base64Binary" />
<config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterName" config:type="string" />
<config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item>
<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintFaxName" config:type="string" />
<config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item>
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item>
<config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseDataSource" config:type="string" />
<config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
<config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item>
</config:config-item-set>
}
' </config:config-item-set>' + LineEnding +
' </office:settings>' + LineEnding +
'</office:document-settings>';
end;
procedure TvODTVectorialWriter.WriteStyles(AData: TvVectorialDocument);
var
i: Integer;
CurStyle: TvStyle;
lTextPropsStr, lParagraphPropsStr, lCurStyleTmpStr, CurStyleParent : string;
CurListStyle: TvListStyle;
j: Integer;
CurListLevelStyle: TvListLevelStyle;
CurLevel, sLevelAttr: String;
begin
FStyles :=
XML_HEADER + LineEnding +
'<office:document-styles xmlns:office="' + SCHEMAS_XMLNS_OFFICE + '"' +
' xmlns:style="' + SCHEMAS_XMLNS_STYLE + '"' +
' xmlns:text="' + SCHEMAS_XMLNS_TEXT + '"' +
' xmlns:table="' + SCHEMAS_XMLNS_TABLE + '"' +
' xmlns:draw="' + SCHEMAS_XMLNS_DRAW + '"' +
' xmlns:fo="' + SCHEMAS_XMLNS_FO + '"' +
' xmlns:xlink="' + SCHEMAS_XMLNS_XLINK + '"' +
' xmlns:dc="' + SCHEMAS_XMLNS_DC + '"' +
' xmlns:meta="' + SCHEMAS_XMLNS_META + '"' +
' xmlns:number="' + SCHEMAS_XMLNS_NUMBER + '"' +
' xmlns:svg="' + SCHEMAS_XMLNS_SVG + '"' +
' xmlns:chart="' + SCHEMAS_XMLNS_CHART + '"' +
' xmlns:dr3d="' + SCHEMAS_XMLNS_DR3D + '"' +
' xmlns:math="' + SCHEMAS_XMLNS_MATH + '"' +
' xmlns:form="' + SCHEMAS_XMLNS_FORM + '"' +
' xmlns:script="' + SCHEMAS_XMLNS_SCRIPT + '"' +
' xmlns:ooo="' + SCHEMAS_XMLNS_OOO + '"' +
' xmlns:ooow="' + SCHEMAS_XMLNS_OOOW + '"' +
' xmlns:oooc="' + SCHEMAS_XMLNS_OOOC + '"' +
' xmlns:dom="' + SCHEMAS_XMLNS_DOM + '"' +
' xmlns:rpt="' + SCHEMAS_XMLNS_RPT + '"' +
' xmlns:of="' + SCHEMAS_XMLNS_OF + '"' +
' xmlns:xhtml="' + SCHEMAS_XMLNS_XHTML + '"' +
' xmlns:grddl="' + SCHEMAS_XMLNS_GRDDL + '"' +
' xmlns:officeooo="' + SCHEMAS_XMLNS_OFFICEOOO + '"' +
' xmlns:tableooo="' + SCHEMAS_XMLNS_TABLEOOO + '"' +
' xmlns:drawooo="' + SCHEMAS_XMLNS_DRAWOOO + '"' +
' xmlns:calcext="' + SCHEMAS_XMLNS_CALCEXT + '"' +
' xmlns:css3t="' + SCHEMAS_XMLNS_CSS3T + '"' +
' office:version="1.2">' + LineEnding;
// TODO: Parse Styles for Fonts not included in the list below...
FStyles := FStyles +
'<office:font-face-decls>' + LineEnding +
' <style:font-face style:name="Mangal1" svg:font-family="Mangal" />' + LineEnding +
' <style:font-face style:name="OpenSymbol" svg:font-family="OpenSymbol" />' + LineEnding +
' <style:font-face style:name="Times New Roman" svg:font-family="Times New Roman" style:font-family-generic="roman" style:font-pitch="variable" />' + LineEnding +
' <style:font-face style:name="Arial" svg:font-family="Arial" />' + LineEnding +
' <style:font-face style:name="Verdana" svg:font-family="Verdana" />' + LineEnding +
' <style:font-face style:name="Mangal" svg:font-family="Mangal" style:font-family-generic="system" style:font-pitch="variable" />' + LineEnding +
' <style:font-face style:name="Microsoft YaHei" svg:font-family="''Microsoft YaHei''" style:font-family-generic="system" style:font-pitch="variable" />' + LineEnding +
' <style:font-face style:name="SimSun" svg:font-family="SimSun" style:font-family-generic="system" style:font-pitch="variable" />' + LineEnding +
'</office:font-face-decls>' + LineEnding;
// ----------------------------
// Styles
// ----------------------------
FStyles := FStyles +
'<office:styles>' + LineEnding;
FStyles := FStyles +
' <style:default-style style:family="graphic">' + LineEnding +
' <style:graphic-properties svg:stroke-color="#3465af" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false" />' + LineEnding +
' <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">' + LineEnding +
' <style:tab-stops />' + LineEnding +
' </style:paragraph-properties>' + LineEnding +
' <style:text-properties style:use-window-font-color="true" fo:font-size="12pt" fo:language="fi" fo:country="FI" style:letter-kerning="true" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" />' + LineEnding +
' </style:default-style>' + LineEnding +
' <style:default-style style:family="paragraph">' + LineEnding +
' <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page" />' + LineEnding +
' <style:text-properties style:use-window-font-color="true" style:font-name="Times New Roman" fo:font-size="12pt" fo:language="fi" fo:country="FI" style:letter-kerning="true" style:font-name-asian="SimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Mangal" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" />' + LineEnding +
' </style:default-style>' + LineEnding +
' <style:default-style style:family="table">' + LineEnding +
' <style:table-properties table:border-model="collapsing" />' + LineEnding +
' </style:default-style>' + LineEnding +
' <style:default-style style:family="table-row">' + LineEnding +
' <style:table-row-properties fo:keep-together="auto" />' + LineEnding +
' </style:default-style>' + LineEnding;
FStyles := FStyles +
' <style:style style:name="Standard" style:family="paragraph" style:class="text" />' + LineEnding;
for i := 0 to AData.GetStyleCount() - 1 do
begin
lTextPropsStr := '';
lParagraphPropsStr := '';
CurStyle := AData.GetStyle(i);
if CurStyle.Parent = nil then CurStyleParent := 'Standard'
else CurStyleParent := StyleNameToODTStyleName(AData, AData.FindStyleIndex(CurStyle.Parent), False);
if spbfFontSize in CurStyle.SetElements then
begin
lTextPropsStr := lTextPropsStr + ' fo:font-size="'+IntToStr(CurStyle.Font.Size)+'pt" ';
lTextPropsStr := lTextPropsStr + ' fo:font-size-asian="'+IntToStr(CurStyle.Font.Size)+'pt" ';
lTextPropsStr := lTextPropsStr + ' fo:font-size-complex="'+IntToStr(CurStyle.Font.Size)+'pt" ';
end;
if spbfFontName in CurStyle.SetElements then
begin
lTextPropsStr := lTextPropsStr + ' style:font-name="'+CurStyle.Font.Name+'" ';
lTextPropsStr := lTextPropsStr + ' style:font-name-asian="Microsoft YaHei" ';
lTextPropsStr := lTextPropsStr + ' style:font-name-complex="Mangal" ';
end;
if (spbfFontBold in CurStyle.SetElements) then
begin
if CurStyle.Font.Bold then
begin
lTextPropsStr := lTextPropsStr + ' fo:font-weight="bold" ';
lTextPropsStr := lTextPropsStr + ' style:font-weight-asian="bold" ';
lTextPropsStr := lTextPropsStr + ' style:font-weight-complex="bold" ';
end
else
begin
lTextPropsStr := lTextPropsStr + ' fo:font-weight="normal" ';
lTextPropsStr := lTextPropsStr + ' style:font-weight-asian="normal" ';
lTextPropsStr := lTextPropsStr + ' style:font-weight-complex="normal" ';
end;
end;
if (spbfFontItalic in CurStyle.SetElements) then
begin
if CurStyle.Font.Italic then
begin
lTextPropsStr := lTextPropsStr + ' fo:font-style="italic" ';
lTextPropsStr := lTextPropsStr + ' style:font-style-asian="italic" ';
lTextPropsStr := lTextPropsStr + ' style:font-style-complex="italic" ';
end
else
begin
// ToDo
end;
end;
if CurStyle.GetKind() = vskTextSpan then
begin
{
<style:style style:name="MT2" style:family="text">
<style:text-properties fo:font-style="italic" fo:font-weight="normal" officeooo:rsid="0009f49c" style:font-style-asian="italic" style:font-weight-asian="normal" style:font-style-complex="italic" style:font-weight-complex="normal" />
</style:style>
}
lCurStyleTmpStr := // tmp string to help see the text in the debugger
' <style:style style:name="'+StyleNameToODTStyleName(AData, i, False)+'" style:display-name="'+ CurStyle.Name +'" style:family="text" style:parent-style-name="'+CurStyleParent+'" >' + LineEnding +
' <style:text-properties '+lTextPropsStr+' />' + LineEnding +
' </style:style>' + LineEnding;
FStyles := FStyles + lCurStyleTmpStr;
end
// Paragraph kind
else
begin
lParagraphPropsStr := '';
// If any one value in here is set, then ALL inherited values are overridden
// In other words, we must fully define the style paragraph properties,
// we can't rely on LibreOffice Style Inheritance...
// TODO: Confirm if this applies to Text Properties as well...
if sseMarginTop in CurStyle.SetElements then
lParagraphPropsStr := lParagraphPropsStr + 'fo:margin-top="'+FloatToODTText(CurStyle.MarginTop)+'mm" ';
if sseMarginBottom in CurStyle.SetElements then
lParagraphPropsStr := lParagraphPropsStr + 'fo:margin-bottom="'+FloatToODTText(CurStyle.MarginBottom)+'mm" ';
if sseMarginLeft in CurStyle.SetElements then
lParagraphPropsStr := lParagraphPropsStr + 'fo:margin-left="'+FloatToODTText(CurStyle.MarginLeft)+'mm" ';
if sseMarginRight in CurStyle.SetElements then
lParagraphPropsStr := lParagraphPropsStr + 'fo:margin-right="'+FloatToODTText(CurStyle.MarginRight)+'mm" ';
if (spbfAlignment in CurStyle.SetElements) then
lParagraphPropsStr := lParagraphPropsStr + 'fo:text-align="'+LU_ALIGN[CurStyle.Alignment]+'" ';
if CurStyle.SuppressSpacingBetweenSameParagraphs then
lParagraphPropsStr := lParagraphPropsStr + 'style:contextual-spacing="true" ';
//else
// lParagraphPropsStr := lParagraphPropsStr + 'style:contextual-spacing="false" ';
lCurStyleTmpStr := // tmp string to help see the text in the debugger
' <style:style style:name="'+StyleNameToODTStyleName(AData, i, False)+'" style:display-name="'+ CurStyle.Name +'" style:family="paragraph" style:parent-style-name="'+CurStyleParent+'" style:class="text">' + LineEnding +
' <style:paragraph-properties '+lParagraphPropsStr+' />' + LineEnding +
' <style:text-properties '+lTextPropsStr+' />' + LineEnding +
' </style:style>' + LineEnding;
FStyles := FStyles + lCurStyleTmpStr;
end;
{
<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" fo:keep-with-next="always" />
<style:text-properties style:font-name="Arial" fo:font-size="14pt" style:font-name-asian="Microsoft YaHei" style:font-size-asian="14pt" style:font-name-complex="Mangal" style:font-size-complex="14pt" />
</style:style>
<style:style style:name="List" style:family="paragraph" style:parent-style-name="Text_20_body" style:class="list">
<style:text-properties style:font-size-asian="12pt" style:font-name-complex="Mangal1" />
</style:style>
<style:style style:name="Caption" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
<style:paragraph-properties fo:margin-top="0.212cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" text:number-lines="false" text:line-number="0" />
<style:text-properties fo:font-size="12pt" fo:font-style="italic" style:font-size-asian="12pt" style:font-style-asian="italic" style:font-name-complex="Mangal1" style:font-size-complex="12pt" style:font-style-complex="italic" />
</style:style>
<style:style style:name="Index" style:family="paragraph" style:parent-style-name="Standard" style:class="index">
<style:paragraph-properties text:number-lines="false" text:line-number="0" />
<style:text-properties style:font-size-asian="12pt" style:font-name-complex="Mangal1" />
</style:style>
<style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="1" style:class="text">
<style:text-properties fo:font-size="115%" fo:font-weight="bold" style:font-size-asian="115%" style:font-weight-asian="bold" style:font-size-complex="115%" style:font-weight-complex="bold" />
</style:style>
<style:style style:name="Heading_20_2" style:display-name="Heading 2" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="2" style:class="text">
<style:text-properties fo:font-size="14pt" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="14pt" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-style-complex="italic" style:font-weight-complex="bold" />
</style:style>
<style:style style:name="Heading_20_3" style:display-name="Heading 3" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="3" style:class="text">
<style:text-properties fo:font-size="14pt" fo:font-weight="bold" style:font-size-asian="14pt" style:font-weight-asian="bold" style:font-size-complex="14pt" style:font-weight-complex="bold" />
</style:style>
<style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text">
<style:text-properties fo:color="#000080" fo:language="zxx" fo:country="none" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none" />
</style:style>
}
end;
FStyles := FStyles +
' <style:style style:name="Bullet_20_Symbols" style:display-name="Bullet Symbols" style:family="text">' + LineEnding +
' <style:text-properties style:font-name="OpenSymbol" style:font-name-asian="OpenSymbol" style:font-name-complex="OpenSymbol" />' + LineEnding +
' </style:style>' + LineEnding;
FStyles := FStyles +
' <text:outline-style style:name="Outline">' + LineEnding +
' <text:outline-level-style text:level="1" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.762cm" fo:text-indent="-0.762cm" fo:margin-left="0.762cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="2" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.016cm" fo:text-indent="-1.016cm" fo:margin-left="1.016cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="3" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.27cm" fo:text-indent="-1.27cm" fo:margin-left="1.27cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="4" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.524cm" fo:text-indent="-1.524cm" fo:margin-left="1.524cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="5" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.778cm" fo:text-indent="-1.778cm" fo:margin-left="1.778cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="6" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.032cm" fo:text-indent="-2.032cm" fo:margin-left="2.032cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="7" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.286cm" fo:text-indent="-2.286cm" fo:margin-left="2.286cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="8" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.54cm" fo:text-indent="-2.54cm" fo:margin-left="2.54cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="9" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.794cm" fo:text-indent="-2.794cm" fo:margin-left="2.794cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' <text:outline-level-style text:level="10" style:num-format="">' + LineEnding +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.048cm" fo:text-indent="-3.048cm" fo:margin-left="3.048cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding +
' </text:outline-level-style>' + LineEnding +
' </text:outline-style>' + LineEnding;
// Build up the List definitions - store in Styles.xml, not content.xml
For i := 0 To AData.GetListStyleCount-1 Do
begin
CurListStyle := AData.GetListStyle(i);
FStyles := FStyles +
' <text:list-style style:name="'+ListStyleNameToODTText(AData, CurListStyle)+'">' + LineEnding;
For j := 0 To CurListStyle.GetListLevelStyleCount-1 Do
Begin
CurListLevelStyle := CurListStyle.GetListLevelStyle(j);
CurLevel := IntToStr(CurListLevelStyle.Level+1); // Note the +1...
// Open Bullet or Number...
If CurListLevelStyle.Kind=vlskBullet Then
FStyles := FStyles +
' <text:list-level-style-bullet text:level="'+CurLevel+'" '+
'text:style-name="Bullet_20_Symbols" '+
'text:bullet-char="'+CurListLevelStyle.Bullet+'">' + LineEnding
Else
Begin
sLevelAttr:='text:level="'+CurLevel+'" ';
If CurListLevelStyle.Prefix<>'' Then
sLevelAttr := Format('%s style:num-prefix="%s"', [sLevelAttr, CurListLevelStyle.Prefix]);
If CurListLevelStyle.Suffix<>'' Then
sLevelAttr := Format('%s style:num-suffix="%s"', [sLevelAttr, CurListLevelStyle.Suffix]);
sLevelAttr := sLevelAttr + ' style:num-format="'+LU_NUMBERFORMAT[CurListLevelStyle.NumberFormat]+'"';
// Display previous levels in Leader?
If (CurListLevelStyle.DisplayLevels) And (CurLevel<>'1') Then
sLevelAttr := Format('%s text:display-levels="%s"', [sLevelAttr, CurLevel]);
FStyles := FStyles +
' <text:list-level-style-number ' + sLevelAttr +'>' + LineEnding;
End;
// Common Level properties
FStyles:=FStyles +
' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">' + LineEnding +
' <style:list-level-label-alignment text:label-followed-by="listtab" '+
// 'text:list-tab-stop-position="'+FloatToODTText(CurListLevelStyle.MarginLeft/10)+'cm" '+
'fo:text-indent="-'+FloatToODTText(CurListLevelStyle.HangingIndent/10)+'cm" '+
'fo:margin-left="'+FloatToODTText(CurListLevelStyle.MarginLeft/10)+'cm" />' + LineEnding +
' </style:list-level-properties>' + LineEnding;
// Close Bullet or Number
If CurListLevelStyle.Kind=vlskBullet Then
FStyles:=FStyles + ' </text:list-level-style-bullet>' + LineEnding
Else
FStyles:=FStyles + ' </text:list-level-style-number>' + LineEnding
end;
FStyles := FStyles + ' </text:list-style>' + LineEnding;
end;
FStyles := FStyles +
' <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document" />' + LineEnding;
FStyles := FStyles +
' <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0" />' + LineEnding;
FStyles := FStyles +
' <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5" />' + LineEnding;
FStyles := FStyles +
'</office:styles>' + LineEnding;
// ----------------------------
// Automatic Styles
// ----------------------------
FStyles := FStyles +
'<office:automatic-styles>' + LineEnding +
FAutomaticStyles + LineEnding +
'</office:automatic-styles>' + LineEnding;
FStyles := FStyles +
'<office:master-styles>' + LineEnding +
FMasterStyles + LineEnding +
'</office:master-styles>' + LineEnding;
FStyles := FStyles +
'</office:document-styles>';
end;
procedure TvODTVectorialWriter.WriteDocument(AData: TvVectorialDocument);
var
i: Integer;
sPrefix : String;
sAutomaticStyles : String;
CurPage: TvPage;
CurTextPage: TvTextPageSequence absolute CurPage;
oCrossRef: TListStyle_Style;
begin
// content.xml will be built up by
// sPrefix + sAutomaticStyles + FContent
sPrefix :=
XML_HEADER + LineEnding +
'<office:document-content xmlns:office="' + SCHEMAS_XMLNS_OFFICE + '"' +
' xmlns:style="' + SCHEMAS_XMLNS_STYLE + '"' +
' xmlns:text="' + SCHEMAS_XMLNS_TEXT + '"' +
' xmlns:table="' + SCHEMAS_XMLNS_TABLE + '"' +
' xmlns:draw="' + SCHEMAS_XMLNS_DRAW + '"' +
' xmlns:fo="' + SCHEMAS_XMLNS_FO + '"' +
' xmlns:xlink="' + SCHEMAS_XMLNS_XLINK + '"' +
' xmlns:dc="' + SCHEMAS_XMLNS_DC + '"' +
' xmlns:meta="' + SCHEMAS_XMLNS_META + '"' +
' xmlns:number="' + SCHEMAS_XMLNS_NUMBER + '"' +
' xmlns:svg="' + SCHEMAS_XMLNS_SVG + '"' +
' xmlns:chart="' + SCHEMAS_XMLNS_CHART + '"' +
' xmlns:dr3D="' + SCHEMAS_XMLNS_DR3D + '"' +
' xmlns:math="' + SCHEMAS_XMLNS_MATH + '"' +
' xmlns:form="' + SCHEMAS_XMLNS_FORM + '"' +
' xmlns:script="' + SCHEMAS_XMLNS_SCRIPT + '"' +
' xmlns:ooo="' + SCHEMAS_XMLNS_OOO + '"' +
' xmlns:oooc="' + SCHEMAS_XMLNS_OOOC + '"' +
' xmlns:xforms="' + SCHEMAS_XMLNS_XFORMS + '"' +
' xmlns:xsi="' + SCHEMAS_XMLNS_XSI + '"' +
' xmlns:rpt="' + SCHEMAS_XMLNS_RPT + '"' +
' xmlns:of="' + SCHEMAS_XMLNS_OF + '"' +
' xmlns:xhtml="' + SCHEMAS_XMLNS_XHTML + '"' +
' xmlns:grddl="' + SCHEMAS_XMLNS_GRDDL + '"' +
' xmlns:officeooo="' + SCHEMAS_XMLNS_OFFICEOOO + '"' +
' xmlns:tableooo="' + SCHEMAS_XMLNS_TABLEOOO + '"' +
' xmlns:drawooo="' + SCHEMAS_XMLNS_DRAWOOO + '"' +
' xmlns:calcext="' + SCHEMAS_XMLNS_CALCEXT + '"' +
' xmlns:field="' + SCHEMAS_XMLNS_FIELD + '"' +
' xmlns:formx="' + SCHEMAS_XMLNS_FORMX + '"' +
' xmlns:css3t="' + SCHEMAS_XMLNS_CSS3T + '"' +
' office:version="1.2">' + LineEnding;
sPrefix := sPrefix +
' <office:scripts />' + LineEnding;
sPrefix := sPrefix +
' <office:font-face-decls>' + LineEnding +
' <style:font-face style:name="Mangal1" svg:font-family="Mangal" />' + LineEnding +
' <style:font-face style:name="OpenSymbol" svg:font-family="OpenSymbol" />' + LineEnding +
' <style:font-face style:name="Times New Roman" svg:font-family="''Times New Roman''" style:font-family-generic="roman" style:font-pitch="variable" />' + LineEnding +
' <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable" />' + LineEnding +
' <style:font-face style:name="Mangal" svg:font-family="Mangal" style:font-family-generic="system" style:font-pitch="variable" />' + LineEnding +
' <style:font-face style:name="Microsoft YaHei" svg:font-family="''Microsoft YaHei''" style:font-family-generic="system" style:font-pitch="variable" />' + LineEnding +
' <style:font-face style:name="SimSun" svg:font-family="SimSun" style:font-family-generic="system" style:font-pitch="variable" />' + LineEnding +
' </office:font-face-decls>' + LineEnding;
// Build the main content of the document
FContent := ' <office:body>' + LineEnding;
FContent := FContent +
' <office:text>' + LineEnding;
FContent := FContent +
' <text:sequence-decls>' + LineEnding +
' <text:sequence-decl text:display-outline-level="0" text:name="Illustration" />' + LineEnding +
' <text:sequence-decl text:display-outline-level="0" text:name="Table" />' + LineEnding +
' <text:sequence-decl text:display-outline-level="0" text:name="Text" />' + LineEnding +
' <text:sequence-decl text:display-outline-level="0" text:name="Drawing" />' + LineEnding +
' </text:sequence-decls>' + LineEnding;
FNewPageSequence := False;
// During each WritePage (and nested calls) FContentAutomaticStyles gets built up
for i := 0 to AData.GetPageCount()-1 do
begin
CurPage := AData.GetPage(i);
if CurPage is TvTextPageSequence then
WritePage(CurTextPage, AData);
end;
FContent := FContent +
' </office:text>' + LineEnding;
FContent := FContent +
' </office:body>' + LineEnding;
FContent := FContent +
'</office:document-content>' + LineEnding;
// Build up the automatic styles detailed in the content.xml
sAutomaticStyles := ' <office:automatic-styles>' + LineEnding;
// Add all the List Definition / Paragraph Style
// cross references
for i := 0 to FList_StyleCrossRef.Count-1 Do
begin
oCrossRef := TListStyle_Style(FList_StyleCrossRef[i]);
sAutomaticStyles := sAutomaticStyles +
' <style:style style:name="'+FList_StyleCrossRef.AsText(i)+'" '+
'style:family="paragraph" '+
'style:parent-style-name="'+StyleNameToODTStyleName(AData, oCrossRef.Style, False)+'" '+
'style:list-style-name="'+ListStyleNameToODTText(AData, oCrossRef.ListStyle)+'" />' + LineEnding;
end;
// Now add any Automatic Styles built during WritePage..
sAutomaticStyles := sAutomaticStyles + FContentAutomaticStyles;
sAutomaticStyles := sAutomaticStyles +
' </office:automatic-styles>' + LineEnding;
// Now piece it all together
FContent := sPrefix + sAutomaticStyles + FContent;
end;
procedure TvODTVectorialWriter.WritePage(ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
var
i: Integer;
lCurEntity: TvEntity;
begin
FNewPageSequence := True;
for i := 0 to ACurPage.GetEntitiesCount()-1 do
begin
lCurEntity := ACurPage.GetEntity(i);
if (lCurEntity is TvParagraph) then
WriteParagraph(TvParagraph(lCurEntity), ACurPage, AData);
if (lCurEntity is TvList) then
WriteList(TvList(lCurEntity), ACurPage, AData);
if (lCurEntity is TvTable) then
WriteTable(TvTable(lCurEntity), ACurPage, AData);
end;
end;
procedure TvODTVectorialWriter.WriteParagraph(AEntity: TvParagraph;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
var
EntityKindName, AEntityStyleName, lOutlineLevel: string;
sAutoStyleName, sPageMasterName, sPageLayoutName : String;
sOrientation : String;
i: Integer;
lCurEntity: TvEntity;
dWidth, dHeight : Double;
begin
lOutlineLevel := '';
if AEntity.Style = nil then
begin
EntityKindName := 'p';
AEntityStyleName := 'Standard';
end
else
begin
case AEntity.Style.GetKind() of
vskHeading:
begin
EntityKindName := 'h';
lOutlineLevel := 'text:outline-level="'+IntToStr(AEntity.Style.HeadingLevel)+'" ';
end;
else // vskTextBody;
EntityKindName := 'p';
end;
AEntityStyleName := StyleNameToODTStyleName(AData, AEntity.Style, False);
end;
If FNewPageSequence Then
begin
// Create an automatic style in both content.xml and style.xml
// and reference the newly created style in the text we're just
// about to write
// TODO: Find out how to deal with new Page Sequences with other
// objects at the start of the page...
Inc(FAutomaticStyleID);
i := AData.GetPageIndex(ACurPage);
sAutoStyleName := AEntityStyleName+'_P' + IntToStr(FAutomaticStyleID);
sPageMasterName := 'Page_Sequence_'+IntToStr(i+1);
sPageLayoutName := 'MPM'+IntToStr(i+1);
// Create an automatic style descended from AEntityStyleName
FContentAutomaticStyles := FContentAutomaticStyles +
'<style:style style:name="'+sAutoStyleName+'"' +
' style:family="paragraph"' +
' style:master-page-name="'+sPageMasterName+'"' +
' style:parent-style-name="'+ AEntityStyleName +'">' +
LineEnding +
'</style:style>'+ LineEnding;
// Define the MasterStyles in Styles.xml
// TODO: Add Header and Footer content to FMasterStyles
FMasterStyles := FMasterStyles +
'<style:master-page style:name="'+sPageMasterName+'" style:page-layout-name="'+sPageLayoutName+'"/>' + LineEnding;
dWidth := ACurPage.Width;
If dWidth=0 Then
dWidth := AData.Width;
If dWidth=0 Then
dWidth := 210; // Default A4
dHeight := ACurPage.Height;
If dHeight=0 Then
dHeight := AData.Height;
If dHeight=0 Then
dHeight := 297; // Default A4
If dWidth>dHeight Then
sOrientation := 'landscape'
else
sOrientation := 'portrait';
// Define the page layout in Styles.xml
// TODO: Add Page Margins...
FAutomaticStyles := FAutomaticStyles +
'<style:page-layout style:name="'+sPageLayoutName+'">'+ LineEnding+
' <style:page-layout-properties '+
' fo:page-width="'+FloatToODTText(dWidth)+'mm"'+
' fo:page-height="'+FloatToODTText(dHeight)+'mm"'+
' style:print-orientation="'+sOrientation+'"'+
' style:num-format="1" fo:margin-top="0.7874in" fo:margin-bottom="0.7874in" fo:margin-left="0.7874in" fo:margin-right="0.7874in" style:writing-mode="lr-tb" style:footnote-max-height="0in">'+ LineEnding;
FAutomaticStyles := FAutomaticStyles +
' <style:footnote-sep style:width="0.0071in" style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>'+ LineEnding+
' </style:page-layout-properties>'+ LineEnding+
' <style:header-style/>'+ LineEnding+
' <style:footer-style/>'+ LineEnding+
'</style:page-layout>' + LineEnding;
// Ensure the text is written out using the new Automatic Style
AEntityStyleName:=sAutoStyleName;
FNewPageSequence:=False;
end;
FContent := FContent +
' <text:'+EntityKindName+' text:style-name="'+AEntityStyleName+'" ' + lOutlineLevel +'>';
for i := 0 to AEntity.GetEntitiesCount()-1 do
begin
lCurEntity := AEntity.GetEntity(i);
if (lCurEntity is TvText) then
WriteTextSpan(TvText(lCurEntity), AEntity, ACurPage, AData)
else if (lCurEntity is TvField) then
WriteField(TvField(lCurEntity), AEntity, ACurPage, AData)
else if (lCurEntity is TvRasterImage) then
WriteRasterImage(TvRasterImage(lCurEntity), AEntity, ACurPage, AData)
else
raise exception.create('TvParagraph subentity '+lCurEntity.ClassName+' not handled');
end;
FContent := FContent +
'</text:'+EntityKindName+'>' + LineEnding;
end;
procedure TvODTVectorialWriter.WriteTextSpan(AEntity: TvText; AParagraph: TvParagraph;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
var
AEntityStyleName: string;
lStyle: TvStyle;
sText: String;
begin
lStyle := AEntity.Style;
If lStyle<>Nil Then
AEntityStyleName:=StyleNameToODTStyleName(AData, lStyle, False);
// No need to all GetCombinedStyle as Paragraph Style already applied in text:p tag
(*
lStyle := AEntity.GetCombinedStyle(AParagraph);
if lStyle = nil then
begin
AEntityStyleName := 'Standard';
end
else
begin
AEntityStyleName := StyleNameToODTStyleName(AData, lStyle, False);
end;
*)
{
<text:p text:style-name="P2">
Lazaru
<text:span text:style-name="T2">s is a fre</text:span>
e and open sou
<text:span text:style-name="T5">rce development tool for</text:span>
the Free Pascal compiler, which is also free and open source.
</text:p>
}
// Note that here we write only text spans!
sText := EscapeHTML(AEntity.Value.Text);
// Trim extra CRLF appended by TStringList.Text
If DefaultTextLineBreakStyle = tlbsCRLF Then
sText := Copy(sText, 1, Length(sText) - 2)
Else
sText := Copy(sText, 1, Length(sText) - 1);
sText := StringReplace(sText, ' ', ' <text:s/>', [rfReplaceAll]);
sText := StringReplace(sText, #09, '<text:tab/>', [rfReplaceAll]);
sText := StringReplace(sText, #13, '<text:line-break/>', [rfReplaceAll]);
sText := StringReplace(sText, #10, '', [rfReplaceAll]);
If lStyle<>Nil Then
FContent := FContent + '<text:span text:style-name="'+AEntityStyleName+'">' +
sText + '</text:span>'
Else
FContent := FContent + '<text:span>' + sText + '</text:span>'
end;
procedure TvODTVectorialWriter.WriteField(AEntity: TvField;
AParagraph: TvParagraph; ACurPage: TvTextPageSequence;
AData: TvVectorialDocument);
Var
sDateStyleName : String;
i: Integer;
cCurrChar: Char;
cPrevChar: Char;
sTag: String;
iLen: Integer;
begin
// <number:day number:calendar="gregorian"/>
// <number:text>/</number:text>
// <number:month number:style="long" number:calendar="gregorian"/>
// <number:text>/</number:text>
// <number:year number:style="long" number:calendar="gregorian"/>
// <number:text> </number:text>
// <number:hours/>
// <number:text>:</number:text>
// <number:minutes number:style="long"/>
// <number:text> </number:text>
// <number:am-pm/>
if AEntity.Kind in [vfkDate, vfkDateCreated] Then
begin
inc(FDateCount);
sDateStyleName := Format('Date_%d', [FDateCount]);
FContentAutomaticStyles:=FContentAutomaticStyles +
' <number:date-style style:name="'+sDateStyleName+'"> '+LineEnding;
cPrevChar := Chr(0);
i := 1;
while (i<=Length(AEntity.DateFormat)) do
begin
cCurrChar := AEntity.DateFormat[i];
iLen := 1;
if cCurrChar<>cPrevChar Then
begin
// Find out how many characters repeat in a row...
while (i+iLen<=Length(AEntity.DateFormat)) And (AEntity.DateFormat[i+iLen]=cCurrChar) do
inc(iLen);
sTag := '';
case cCurrChar Of
'd' :
begin
Case iLen Of
1 : sTag := '<number:day/>';
2 : sTag := '<number:day number:style="long"/>';
3 : sTag := '<number:day-of-week/>';
else
sTag := '<number:day-of-week number:style="long"/>';
end;
end;
'M' :
begin
case iLen Of
1 : sTag := '<number:month/>';
2 : sTag := '<number:month number:style="long"/>';
3 : sTag := '<number:month number:textual="true"/>';
else
sTag := '<number:month number:textual="true" number:style="long"/>';
end;
end;
'y' :
begin
if iLen=2 then
sTag := '<number:year/>'
else
sTag := '<number:year number:style="long"/>';
end;
'h' :
begin
if iLen=1 then
sTag := '<number:hours/>'
else
sTag := '<number:hours number:style="long"/>';
end;
'm' :
begin
if iLen=1 then
sTag := '<number:minutes/>'
else
sTag := '<number:minutes number:style="long"/>';
end;
's' :
begin
if iLen=1 then
sTag := '<number:seconds/>'
else
sTag := '<number:seconds number:style="long"/>';
end;
'a' :
begin
sTag := '<number:am-pm/>';
iLen := 5;
end;
else
sTag := '<number:text>'+cCurrChar+'</number:text>';
end;
cPrevChar := cCurrChar;
end;
FContentAutomaticStyles:=FContentAutomaticStyles +
' '+sTag + LineEnding;
Inc(i, iLen);
end;
FContentAutomaticStyles:=FContentAutomaticStyles +
' </number:date-style> '+LineEnding;
end;
case AEntity.Kind of
vfkNumPages:
begin
FContent:=FContent +
'<text:page-count style:num-format="'+LU_NUMBERFORMAT[AEntity.NumberFormat]+
'">'+IntToStr(AData.GetPageCount)+'</text:page-count>';
end;
vfkPage:
begin
FContent:=FContent +
'<text:page-number style:num-format="'+LU_NUMBERFORMAT[AEntity.NumberFormat]+
'" text:fixed="false">'+IntToStr(AData.GetPageIndex(ACurPage))+'</text:page-number>';
end;
vfkAuthor:
begin
FContent:=FContent +
'<text:initial-creator text:fixed="false">FPVECTORIAL</text:initial-creator>';
end;
vfkDateCreated:
begin
FContent:=FContent +
'<text:creation-date style:data-style-name="'+sDateStyleName+'">'+DateToStr(Now)+'</text:creation-date>';
end;
vfkDate:
begin
FContent:=FContent +
'<text:date style:data-style-name="'+sDateStyleName+'">'+DateToStr(Now)+'</text:date>';
end;
end;
end;
function TvODTVectorialWriter.BordersToString(ATableBorders, ACellBorders : TvTableBorders;
ATopCell, ABottomCell, ALeftCell, ARightCell : Boolean):String;
(*
double line thickness requires a completely different configuration, so for now, we won't
support it...
<style:table-cell-properties style:vertical-align="middle"
style:border-line-width-left="0.28mm 0.28mm 0.28mm"
style:border-line-width-top="0.28mm 0.28mm 0.28mm"
fo:padding="0mm"
fo:border-left="2.35pt double #ff0000"
fo:border-right="0.5pt solid #ff0000"
fo:border-top="2.35pt double #ff0000"
fo:border-bottom="0.5pt solid #ff0000"/>
From the OASIS Open Office Specification:
The style:border-line-width specifies the line widths of all four sides,
while the other attributes specify the line widths of one side only.
The value of the attributes can be a list of three space-separated lengths,
as follows:
• The first value specifies the width of the inner line
• The second value specified the distance between the two lines
• The third value specifies the width of the outer line
The result of specifying a border line width without specifying a border
width style of double for the same border is undefined.
*)
Function BorderToString(AAttrib : String; ABorder: TvTableBorder) : String;
Begin
Result := '';
If ABorder.LineType<>tbtDefault Then
Begin
If ABorder.LineType=tbtNone Then
Result := 'none'
Else
Begin
If ABorder.Width <> 0 Then
Result := Format('%s %smm', [Result, FloatToODTText(ABorder.Width)])
Else
Result := Format('%s 0.05pt', [Result]);
Result := Format('%s %s', [Result, LU_BORDERTYPE[ABorder.LineType]]);
Result := Format('%s #%s', [Result, FPColorToRGBHexString(ABorder.Color)]);
end;
Result := Format('%s="%s"', [AAttrib, Trim(Result)]);
end;
end;
Var
sLeft, sRight, sTop, sBottom : String;
Begin
(*
OpenDocument does not support setting borders at the Table Level,
only at the cell level. For end user convenience, FPVectorial supports
setting borders at the table level, but allows the end user fine control,
if they prefer, by providing support for borders at the cell level as well.
This means we're going to need to calculate actual border
based on TvTable.Borders (which includes InsideHoriz and InsideVert) as
default values, which can be overridden if specific TvTableCell.Borders
are defined (ie LineType<>tbtDefault)
Matters are complicated by the need to work out if we need to draw the right
and top borders (if we always draw right borders then two lines will be visible
on internal border, the left border from the cell to the right and the right
border from this cell). To deal with this, we only set the Right and Top
borders if either the Cell.Borders specify (they overrule all), or if we're
actually at the top or right cells (which the calling function will calculate
for us)
*)
sLeft := BorderToString('fo:border-left', ACellBorders.Left);
if sLeft='' then
begin
if ALeftCell then
sLeft := BorderToString('fo:border-left', ATableBorders.Left)
else
// Really need to look at cell to the left and determine if it has overriding Cell.Borders.Right :-(
sLeft := BorderToString('fo:border-left', ATableBorders.InsideVert);
end;
sRight := BorderToString('fo:border-right', ACellBorders.Right);
if sRight='' then
begin
if ARightCell then
sRight := BorderToString('fo:border-right', ATableBorders.Right)
else
sRight := 'fo:border-right="none"';
end;
sTop := BorderToString('fo:border-top', ACellBorders.Top);
if sTop='' then
begin
if ATopCell then
sTop := BorderToString('fo:border-top', ATableBorders.Top)
else
sTop := 'fo:border-top="none"';
end;
sBottom := BorderToString('fo:border-bottom', ACellBorders.Bottom);
if sBottom='' then
begin
if ABottomCell then
sBottom := BorderToString('fo:border-bottom', ATableBorders.Bottom)
else
// Really need to look at cell below, and determine if it has overriding Cell.Borders.Top :-(
sBottom := BorderToString('fo:border-bottom', ATableBorders.InsideHoriz);
end;
Result := Format('%s %s %s %s', [sLeft, sRight, sTop, sBottom]);
end;
procedure TvODTVectorialWriter.WriteTable(ATable: TvTable;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
procedure AddBody(AString : String);
begin
FContent := FContent + ' ' + AString + LineEnding;
end;
procedure AddStyle(AString : String);
begin
FContentAutomaticStyles:=FContentAutomaticStyles + ' ' + AString + LineEnding;
end;
Var
iRow, iCell, iCol, k: Integer;
oRow: TvTableRow;
oCell: TvTableCell;
lCurEntity: TvEntity;
sTableName : String;
iColCount : Integer;
sTableStyle,
sColStyle,
sRowStyle,
sCellStyle,
sTemp, sTemp2: String;
bInHeader: Boolean;
Begin
// TODO: Add support for TvTableBorder.Spacing
// TODO: Add support for TvTableRow.CellSpacing
// TODO: Add support for TvTable.CellSpacing
if ATable.GetRowCount=0 Then
Exit;
// Style information stored in content.xml -> office:automatic-styles
// Table information stored in content.xml -> office:body
sTableName := Trim(ATable.Name);
If sTableName='' Then
sTableName := Format('Table_%d.%d', [AData.GetPageIndex(ACurPage)+1, ACurPage.GetEntityIndex(ATable)+1]);
sTableStyle := sTableName;
// Table meta properties
AddStyle('<style:style style:name="'+sTableStyle+'" style:family="table">');
Case ATable.PreferredWidth.Units of
dimMillimeter: sTemp := 'style:width="'+FloatToODTText(ATable.PreferredWidth.Value)+'mm"';
dimPoint: sTemp := 'style:width="'+FloatToODTText(ATable.PreferredWidth.Value)+'pt"';
dimPercent: sTemp := 'style:rel-width="'+FloatToODTText(ATable.PreferredWidth.Value)+'%"';
End;
if ATable.BackgroundColor <> FPColor(0, 0, 0, 0) Then
sTemp := sTemp + ' fo:background-color="#'+FPColorToRGBHexString(ATable.BackgroundColor)+'"';
AddStyle(' <style:table-properties '+sTemp+' table:align="margins"/>');
AddStyle('</style:style>');
AddBody(Format('<table:table table:name="%s" table:style-name="%s">', [sTableName, sTableStyle]));
// Now define any column specific properties
If Length(ATable.ColWidths)>0 Then
iColCount := Length(ATable.ColWidths)
Else
// No ColWidths defined means simple tables only (no merged cells)
iColCount := TvTableRow(ATable.GetRow(0)).GetCellCount;
For iCol := 0 To iColCount-1 Do
Begin
sColStyle := Format('%s.Col_%d', [sTableStyle, iCol+1]);
If Length(ATable.ColWidths)>0 Then
begin
AddStyle('<style:style style:name="'+sColStyle+'" style:family="table-column">');
Case ATable.ColWidthsUnits Of
dimMillimeter: sTemp := 'style:column-width="'+FloatToODTText(ATable.ColWidths[iCol])+'mm"';
dimPoint: sTemp := 'style:column-width="'+FloatToODTText(ATable.ColWidths[iCol])+'pt"';
dimPercent: sTemp := 'style:rel-column-width="'+FloatToODTText(65535 * ATable.ColWidths[iCol] / 100)+'*"';
End;
AddStyle(' <style:table-column-properties '+sTemp+'/>');
AddStyle('</style:style>');
end;
AddBody(' <table:table-column table:style-name="'+sColStyle+'" table:number-columns-repeated="1"/>');
end;
// Write out the table row by row, defining row and cell styles as we go..
bInHeader := False;
For iRow := 0 To ATable.GetRowCount-1 Do
Begin
oRow := ATable.GetRow(iRow);
// Current Header functionality will only work
// if header rows correctly defined...
If (bInHeader) And not (oRow.Header) Then
Begin
bInHeader := False;
// Close header rows...
AddBody(' </table:table-header-rows>');
end;
If (oRow.Header) And (iRow=0) Then
Begin
bInHeader := True;
// Open header rows
AddBody(' <table:table-header-rows>');
end;
sTemp := '';
sRowStyle := Format('%s.Row_%d', [sTableStyle, iRow+1]);
if oRow.BackgroundColor <> FPColor(0, 0, 0, 0) Then
sTemp := sTemp + ' fo:background-color="#'+FPColorToRGBHexString(oRow.BackgroundColor)+'"';
If oRow.Height<>0 Then
sTemp := sTemp + ' style:row-height="'+FloatToODTText(oRow.Height)+'mm"';
if Not oRow.AllowSplitAcrossPage Then
sTemp := sTemp + ' fo:keep-together="always"';
// else
// sTemp := sTemp + ' fo:keep-together="auto"';
// Only define the style if it is required...
If sTemp<>'' Then
begin
AddStyle('<style:style style:name="'+sRowStyle+'" style:family="table-row">');
AddStyle(' <style:table-row-properties '+sTemp+'/>');
AddStyle('</style:style>');
AddBody(' <table:table-row table:style-name="'+sRowStyle+'">');
end
Else
AddBody(' <table:table-row>');
For iCell := 0 To oRow.GetCellCount-1 Do
Begin
oCell := oRow.GetCell(iCell);
sTemp := '';
sCellStyle := Format('%s.Cell_%dx%d', [sTableStyle, iRow + 1, iCell + 1]);
(* // I cannot find a mechanism for setting cell width in ODT...
If oCell.PreferredWidth.Value<>0 Then
Begin
Case oCell.PreferredWidth.Units Of
dimMillimeter: sTemp := sTemp + 'style:cell-width="'+FloatToODTText(oCell.PreferredWidth)+'mm"';
dimPoint: sTemp := sTemp + 'style:cell-width="'+FloatToODTText(oCell.PreferredWidth)+'pt"';
dimPercent: sTemp := sTemp + 'style:rel-cell-width="'+FloatToODTText(65535 * oCell.PreferredWidth / 100)+'*"';
End;
end;
*)
// Top is default in LibreOffice Write
If oCell.VerticalAlignment<>vaTop Then
sTemp := sTemp + ' style:vertical-align="'+LU_V_ALIGN[oCell.VerticalAlignment]+'"';
if oCell.BackgroundColor <> FPColor(0, 0, 0, 0) Then
sTemp := sTemp + ' fo:background-color="#'+FPColorToRGBHexString(oCell.BackgroundColor)+'"';
sTemp := sTemp + ' ' + BordersToString(ATable.Borders, oCell.Borders,
iRow=0, iRow=ATable.GetRowCount-1,
iCell=0, iCell=oRow.GetCellCount-1);
sTemp2 := '';
If oCell.SpannedCols>1 Then
sTemp2 := 'table:number-columns-spanned="'+IntToStr(oCell.SpannedCols)+'" ';
// Only define the style if it is required...
sTemp := Trim(sTemp);
if sTemp<>'' Then
begin
AddStyle('<style:style style:name="'+sCellStyle+'" style:family="table-cell">');
AddStyle(' <style:table-cell-properties '+sTemp+'/>');
AddStyle('</style:style>');
AddBody(' <table:table-cell table:style-name="'+sCellStyle+'" '+sTemp2+'office:value-type="string">');
end
Else
AddBody(' <table:table-cell '+sTemp2+'office:value-type="string">');
FContent := FContent + ' ';
// oCell is a TvRichText descendant, so process it similarly...
for k := 0 to oCell.GetEntitiesCount()-1 do
begin
lCurEntity := oCell.GetEntity(k);
if (lCurEntity is TvParagraph) then
WriteParagraph(TvParagraph(lCurEntity), ACurPage, AData);
if (lCurEntity is TvList) then
WriteList(TvList(lCurEntity), ACurPage, AData);
if (lCurEntity is TvTable) then
WriteTable(TvTable(lCurEntity), ACurPage, AData);
end;
AddBody(' </table:table-cell>');
// FPVectorial doesn't directly support covered (merged) cells,
// instead they're implied by SpannedCols count > 1
for k := 2 to oCell.SpannedCols Do
AddBody('<table:covered-table-cell />');
end;
AddBody(' </table:table-row>');
end;
AddBody('</table:table>');
end;
procedure TvODTVectorialWriter.WriteList(AEntity: TvList;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
var
i, j: Integer;
lCurEntity, lCurSubEntity: TvEntity;
lCurParagraph: TvParagraph;
iCrossRef: Integer;
begin
// See http://docs.oasis-open.org/office/v1.1/OS/OpenDocument-v1.1.pdf
// page 75 "Example: Lists and sublists"
FContent := FContent +
' <text:list text:style-name="'+ListStyleNameToODTText(AData, AEntity.ListStyle)+'">' + LineEnding;
for i := 0 to AEntity.GetEntitiesCount()-1 do
begin
lCurEntity := AEntity.GetEntity(i);
FContent := FContent +
' <text:list-item>' + LineEnding;
if (lCurEntity is TvParagraph) then
begin
lCurParagraph := lCurEntity as TvParagraph;
iCrossRef := FList_StyleCrossRef.AddCrossReference(AEntity.Style, AEntity.ListStyle);
// Special Style correlating the Paragraph Style and the List style
// should be added to Content.xml Automatic Styles
FContent := FContent +
' <text:p text:style-name="'+FList_StyleCrossRef.AsText(iCrossRef)+'">';
for j := 0 to lCurParagraph.GetEntitiesCount()-1 do
begin
lCurSubEntity := lCurParagraph.GetEntity(j);
if (lCurSubEntity is TvText) then
WriteTextSpan(TvText(lCurSubEntity), lCurParagraph, ACurPage, AData);
end;
FContent := FContent +
' </text:p>' + LineEnding;
end
else if lCurEntity Is TvList Then
WriteList(TvList(lCurEntity), ACurPage, AData);
FContent := FContent +
' </text:list-item>' + LineEnding;
end;
FContent := FContent +
' </text:list>' + LineEnding;
end;
procedure TvODTVectorialWriter.WriteRasterImage(AEntity: TvRasterImage; AParagraph: TvParagraph;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
var
FRasterImageName:string;
FRasterImageHeight:double;
FRasterImageWidth:double;
begin
if AEntity.RasterImage=nil then
Exit;
if IsZero(AEntity.Height) then
FRasterImageHeight:=RoundTo((AEntity.RasterImage.Height*2.54)/96,-3) // default 96 dpi of document, unit used cm
else
FRasterImageHeight:=AEntity.Height;
if IsZero(AEntity.Width) then
FRasterImageWidth:=RoundTo((AEntity.RasterImage.Width*2.54)/96,-3) // default 96 dpi of document, unit used cm
else
FRasterImageWidth:=AEntity.Width;
FRasterImageName:='Pictures/'+IntTostr(FRasterImageFileNames.Count+1)+'.png';
FContent:=FContent+'<draw:frame draw:name="Image'+IntTostr(FRasterImageFileNames.Count+1)+'" svg:width="'+FloatToODTText(FRasterImageWidth)+'cm" svg:height="'+FloatToODTText(FRasterImageHeight)+'cm" text:anchor-type="as-char" draw:z-index="2">';
FContent:=FContent+'<draw:image xlink:href="'+FRasterImageName+'" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>';
FContent:=FContent+'</draw:frame>';
FRasterImageFileNames.AddObject(FRasterImageName,AEntity);
end;
function TvODTVectorialWriter.WriteStylesXMLAsString: string;
begin
end;
constructor TvODTVectorialWriter.Create;
begin
inherited Create;
FPointSeparator := DefaultFormatSettings;
FPointSeparator.DecimalSeparator := '.';
FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
FAutomaticStyles := '';
FMasterStyles := '';
FList_StyleCrossRef := TListStyle_StyleList.Create;
FList_StyleCrossRef.Writer := Self;
FDateCount := 0;
FRasterImageFileNames:=TStringList.Create;
end;
destructor TvODTVectorialWriter.Destroy;
begin
FRasterImageFileNames.Free;
FList_StyleCrossRef.Free;
inherited Destroy;
end;
procedure TvODTVectorialWriter.WriteToFile(AFileName: string;
AData: TvVectorialDocument);
Var
oStream: TFileStream;
Begin
If ExtractFileExt(AFilename) = '' Then
AFilename := AFilename + STR_ODT_EXTENSION;
oStream := TFileStream.Create(AFileName, fmCreate);
Try
WriteToStream(oStream, AData);
Finally
FreeAndNil(oStream);
End;
End;
procedure TvODTVectorialWriter.WriteToStream(AStream: TStream;
AData: TvVectorialDocument);
var
FZip: TZipper;
// Streams with the contents of files
FSMeta, FSSettings, FSStyles, FSContent, FSMimetype: TStringStream;
FSMetaInfManifest, FSManifestRDF: TStringStream;
FSRasterImage:TMemoryStream;
i:integer;
WriterPNG:TFPWriterPNG;
FRasterImageStreamList:TFPList;
begin
FList_StyleCrossRef.Data := AData;
{ Fill the strings with the contents of the files }
WriteMimetype();
WriteManifestRDF();
WriteMeta();
WriteSettings();
// Reversed order of Document and Styles to allow embedding Automatic Styles
// built up during WriteDocument...
WriteDocument(AData);
WriteStyles(AData);
WriteMetaInfManifest();
{ Write the data to streams }
FSMeta := TStringStream.Create(FMeta);
FSSettings := TStringStream.Create(FSettings);
FSStyles := TStringStream.Create(FStyles);
FSContent := TStringStream.Create(FContent);
FSMimetype := TStringStream.Create(FMimetype);
FSMetaInfManifest := TStringStream.Create(FMetaInfManifest);
FSManifestRDF := TStringStream.Create(FManifestRDF);
FRasterImageStreamList:=nil;
WriterPNG:=TFPWriterPNG.Create;
WriterPNG.UseAlpha:=true;
{ Now compress the files }
FZip := TZipper.Create;
try
// MimeType must be first file, and should be uncompressed
// TODO: CompressionLevel is not working. Bug, or misuse?
// See http://mantis.freepascal.org/view.php?id=24897 for patch...
FZip.Entries.AddFileEntry(FSMimetype, OPENDOC_PATH_MIMETYPE).CompressionLevel:=clNone;
FZip.Entries.AddFileEntry(FSMeta, OPENDOC_PATH_META);
FZip.Entries.AddFileEntry(FSSettings, OPENDOC_PATH_SETTINGS);
FZip.Entries.AddFileEntry(FSStyles, OPENDOC_PATH_STYLES);
FZip.Entries.AddFileEntry(FSContent, OPENDOC_PATH_CONTENT);
FZip.Entries.AddFileEntry(FSMetaInfManifest, OPENDOC_PATH_METAINF_MANIFEST);
FZip.Entries.AddFileEntry(FSManifestRDF, OPENDOC_PATH_MANIFESTRDF);
FRasterImageStreamList:=TFPList.Create;
for i:=0 to FRasterImageFileNames.Count-1 do
begin
FSRasterImage:=TMemoryStream.Create;
TvRasterImage(FRasterImageFileNames.Objects[i]).RasterImage.SaveToStream(FSRasterImage,WriterPNG);
FRasterImageStreamList.Add(FSRasterImage);
FSRasterImage.Seek(0,soFromBeginning);
FZip.Entries.AddFileEntry(FSRasterImage, FRasterImageFileNames[i]);
end;
FZip.SaveToStream(AStream);
finally
if FRasterImageStreamList<> nil then
begin
for i:=0 to FRasterImageStreamList.Count-1 do
TvRasterImage(FRasterImageStreamList[i]).Free;
FRasterImageStreamList.Free;
end;
FZip.Free;
FSMeta.Free;
FSSettings.Free;
FSStyles.Free;
FSContent.Free;
FSMimetype.Free;
FSMetaInfManifest.Free;
FSManifestRDF.Free;
WriterPNG.Free;
end;
end;
initialization
RegisterVectorialWriter(TvODTVectorialWriter, vfODT);
end.