diff --git a/components/fpvectorial/docxvectorialwriter.pas b/components/fpvectorial/docxvectorialwriter.pas
index 296e4957a2..fcd04798de 100644
--- a/components/fpvectorial/docxvectorialwriter.pas
+++ b/components/fpvectorial/docxvectorialwriter.pas
@@ -606,9 +606,6 @@ Var
oDocXML.Add(Format('',
[StyleNameToStyleID(AParagraph.Style)]));
- If AParagraph.UseLocalAlignment Then
- oDocXML.Add('');
-
If Assigned(AParagraph.ListStyle) Then
Begin
oDocXML.Add('');
@@ -731,10 +728,14 @@ Var
dWidth := APageSequence.Width;
If dWidth = 0 Then
dWidth := FData.Width;
+ If dWidth=0 Then
+ dWidth := 210; // Default A4
dHeight := APageSequence.Height;
If dHeight = 0 Then
dHeight := FData.Height;
+ If dHeight=0 Then
+ dHeight := 297; // Default A4
If ((dWidth <> 0) And (dHeight <> 0)) Then
Begin
diff --git a/components/fpvectorial/examples/fpvtextwritetest2.pas b/components/fpvectorial/examples/fpvtextwritetest2.pas
index e99d26a061..72c32894d1 100644
--- a/components/fpvectorial/examples/fpvtextwritetest2.pas
+++ b/components/fpvectorial/examples/fpvtextwritetest2.pas
@@ -50,7 +50,8 @@ Begin
Vec.AddStandardTextDocumentStyles(vfODT);
Vec.StyleTextBody.MarginRight:=10;
- Vec.StyleTextBody.SetElements:= Vec.StyleTextBody.SetElements + [sseMarginRight];
+ Vec.StyleTextBody.MarginLeft:=10;
+ Vec.StyleTextBody.SetElements:= Vec.StyleTextBody.SetElements + [sseMarginLeft, sseMarginRight];
// Until a Template is available, create the Bold Style ourselves
BoldTextStyle := Vec.AddStyle();
@@ -338,11 +339,6 @@ Begin
CurParagraph := CurCell.AddParagraph;
CurParagraph.Style := Center2;
- Case j of
- 0: CurParagraph.LocalAlignment := vsaLeft;
- 1: CurParagraph.LocalAlignment := vsaRight;
- end;
-
CurParagraph.AddText(Format('Header %d', [j])).Style := BoldTextStyle
End;
@@ -367,11 +363,6 @@ Begin
CurParagraph := CurCell.AddParagraph;
CurParagraph.Style := Center2;
- Case j of
- 0: CurParagraph.LocalAlignment := vsaLeft;
- 1: CurParagraph.LocalAlignment := vsaRight;
- end;
-
If (iMax=3) And (j=3) Then
Begin
CurCell.SpannedCols := 2;
diff --git a/components/fpvectorial/fpvectorial.pas b/components/fpvectorial/fpvectorial.pas
index 6b8dddc371..9f144ff26a 100644
--- a/components/fpvectorial/fpvectorial.pas
+++ b/components/fpvectorial/fpvectorial.pas
@@ -795,6 +795,7 @@ type
function GetEntitiesCount: Integer;
function GetEntity(AIndex: Integer): TvEntity;
function AddEntity(AEntity: TvEntity): Integer;
+ function GetEntityIndex(AEntity : TvEntity) : Integer;
function DeleteEntity(AIndex: Cardinal): Boolean;
function RemoveEntity(AEntity: TvEntity; AFreeAfterRemove: Boolean = True): Boolean;
procedure Rotate(AAngle: Double; ABase: T3DPoint); override;
@@ -861,11 +862,7 @@ type
{ TvParagraph }
TvParagraph = class(TvEntityWithSubEntities)
- FLocalAlignment : TvStyleAlignment; // Provides localised overwrite of style alignment
- private
- procedure SetLocalAlignment(AValue: TvStyleAlignment);
- public // TODO: LocalAlignment subject to approval by Felipe
- UseLocalAlignment : Boolean; // Provides localised overwrite of style alignment
+ public
Width, Height: Double;
AutoExpand: TvRichTextAutoExpand;
ListStyle : TvListStyle; // For Bulleted or Numbered Lists...
@@ -876,8 +873,6 @@ type
procedure Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
-
- Property LocalAlignment : TvStyleAlignment Read FLocalAlignment Write SetLocalAlignment;
end;
{@@
@@ -1039,7 +1034,7 @@ type
Borders : TvTableBorders; // Defaults: single/black/inside and out
PreferredWidth : TvDimension; // Optional. Units mm.
CellSpacing : Double; // Units mm. Gap between Cells.
- BackgroundColor : TFPColor; // Optional. Units mm.
+ BackgroundColor : TFPColor; // Optional.
constructor create(APage : TvPage); override;
destructor destroy; override;
@@ -1102,6 +1097,7 @@ type
procedure GuessGoodZoomLevel(AScreenSize: Integer = 500);
{ Page methods }
function GetPage(AIndex: Integer): TvPage;
+ function GetPageIndex(APage : TvPage): Integer;
function GetPageAsVectorial(AIndex: Integer): TvVectorialPage;
function GetPageAsText(AIndex: Integer): TvTextPageSequence;
function GetPageCount: Integer;
@@ -1143,6 +1139,7 @@ type
function GetEntity(ANum: Cardinal): TvEntity; virtual; abstract;
function GetEntitiesCount: Integer; virtual; abstract;
function GetLastEntity(): TvEntity; virtual; abstract;
+ function GetEntityIndex(AEntity : TvEntity) : Integer; virtual; abstract;
function FindAndSelectEntity(Pos: TPoint): TvFindEntityResult; virtual; abstract;
function FindEntityWithNameAndType(AName: string; AType: TvEntityClass {= TvEntity}; ARecursively: Boolean = False): TvEntity; virtual; abstract;
{ Data removing methods }
@@ -1185,6 +1182,7 @@ type
function GetEntity(ANum: Cardinal): TvEntity; override;
function GetEntitiesCount: Integer; override;
function GetLastEntity(): TvEntity; override;
+ function GetEntityIndex(AEntity : TvEntity) : Integer; override;
function FindAndSelectEntity(Pos: TPoint): TvFindEntityResult; override;
function FindEntityWithNameAndType(AName: string; AType: TvEntityClass {= TvEntity}; ARecursively: Boolean = False): TvEntity; override;
{ Data removing methods }
@@ -1260,6 +1258,7 @@ type
function GetEntity(ANum: Cardinal): TvEntity; override;
function GetEntitiesCount: Integer; override;
function GetLastEntity(): TvEntity; override;
+ function GetEntityIndex(AEntity : TvEntity) : Integer; override;
function FindAndSelectEntity(Pos: TPoint): TvFindEntityResult; override;
function FindEntityWithNameAndType(AName: string; AType: TvEntityClass {= TvEntity}; ARecursively: Boolean = False): TvEntity; override;
{ Data removing methods }
@@ -4452,6 +4451,15 @@ begin
Result := FElements.Add(AEntity);
end;
+function TvEntityWithSubEntities.GetEntityIndex(AEntity: TvEntity): Integer;
+var
+ i: Integer;
+begin
+ Result := -1;
+ for i := 0 to FElements.Count-1 do
+ if TvEntity(FElements.Items[i]) = AEntity then Exit(i);
+end;
+
function TvEntityWithSubEntities.DeleteEntity(AIndex: Cardinal): Boolean;
var
lEntity: TvEntity;
@@ -4668,17 +4676,10 @@ end;
{ TvParagraph }
-procedure TvParagraph.SetLocalAlignment(AValue: TvStyleAlignment);
-begin
- UseLocalAlignment:=True;
- FLocalAlignment:=AValue;
-end;
-
constructor TvParagraph.Create(APage: TvPage);
begin
inherited Create(APage);
- UseLocalAlignment:=False;
end;
destructor TvParagraph.Destroy;
@@ -4893,6 +4894,15 @@ begin
Result:=TvEntity(FEntities.Last);
end;
+function TvVectorialPage.GetEntityIndex(AEntity: TvEntity): Integer;
+var
+ i: Integer;
+begin
+ Result := -1;
+ for i := 0 to GetEntitiesCount()-1 do
+ if TvEntity(FEntities.Items[i]) = AEntity then Exit(i);
+end;
+
function TvVectorialPage.FindAndSelectEntity(Pos: TPoint): TvFindEntityResult;
var
lEntity: TvEntity;
@@ -5518,7 +5528,12 @@ end;
function TvTextPageSequence.GetLastEntity: TvEntity;
begin
+ Result := MainText.GetEntity(MainText.GetEntitiesCount()-1);
+end;
+function TvTextPageSequence.GetEntityIndex(AEntity: TvEntity): Integer;
+begin
+ Result := MainText.GetEntityIndex(AEntity);
end;
function TvTextPageSequence.FindAndSelectEntity(Pos: TPoint
@@ -5854,6 +5869,15 @@ begin
Result := TvPage(FPages.Items[AIndex]);
end;
+function TvVectorialDocument.GetPageIndex(APage: TvPage): Integer;
+var
+ i: Integer;
+begin
+ Result := -1;
+ for i := 0 to FPages.Count-1 do
+ if TvPage(FPages.Items[i]) = APage then Exit(i);
+end;
+
function TvVectorialDocument.GetPageAsVectorial(AIndex: Integer): TvVectorialPage;
var
lPage: TvPage;
@@ -6043,7 +6067,7 @@ begin
for i := 0 To NUM_MAX_LISTSTYLES-1 Do
begin
lCurListStyle := AddListStyle;
- lCurListStyle.Kind := vlskDecimal;
+ lCurListStyle.Kind := vlskBullet;
lCurListStyle.Level := i;
lCurListStyle.Prefix := '·';
lCurListStyle.PrefixFontName := 'Symbol';
diff --git a/components/fpvectorial/odtvectorialwriter.pas b/components/fpvectorial/odtvectorialwriter.pas
index 24a7c72b56..45d0be3d73 100644
--- a/components/fpvectorial/odtvectorialwriter.pas
+++ b/components/fpvectorial/odtvectorialwriter.pas
@@ -53,9 +53,9 @@ unit odtvectorialwriter;
interface
uses
- Classes, SysUtils, math,
- zipper, {NOTE: might require zipper from FPC 2.6.2+ }
- fpimage, fpcanvas, fgl,
+ Classes, SysUtils,
+ zipper, zstream, {NOTE: might require zipper from FPC 2.6.2+ }
+ fpimage, fpcanvas,
fpvectorial, fpvutils, lazutf8;
type
@@ -67,11 +67,20 @@ type
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
+ FContentAutomaticStyleID : Integer;
+
+ 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 FloatToODTText(AFloat: Double): string;
+ function BordersToString(ATableBorders, ACellBorders: TvTableBorders; ATopCell,
+ ABottomCell, ALeftCell, ARightCell: Boolean): String;
// Routines to write those files
procedure WriteMimetype;
procedure WriteMetaInfManifest;
@@ -83,6 +92,8 @@ type
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 WriteBulletList(AEntity: TvBulletList; ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
@@ -100,7 +111,7 @@ type
implementation
uses
- strutils, htmlelements;
+ htmlelements;
const
{ OpenDocument general XML constants }
@@ -387,8 +398,10 @@ procedure TvODTVectorialWriter.WriteStyles(AData: TvVectorialDocument);
var
i: Integer;
CurStyle: TvStyle;
- lTextPropsStr, lParagraphPropsStr, lCurStyleTmpStr, CurStyleParent,
- lMarginStr: string;
+ lTextPropsStr, lParagraphPropsStr, lCurStyleTmpStr, CurStyleParent : string;
+Const
+ LU_ALIGN: Array [TvStyleAlignment] Of String =
+ ('start', 'end', 'justify', 'center');
begin
FStyles :=
XML_HEADER + LineEnding +
@@ -422,12 +435,15 @@ begin
' 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 +
'' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
+ ' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
@@ -528,15 +544,31 @@ begin
// Paragraph kind
else
begin
- lMarginStr := '';
+ 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
- lMarginStr := lMarginStr + 'fo:margin-top="'+FloatToODTText(CurStyle.MarginTop)+'mm" ';
+ lParagraphPropsStr := lParagraphPropsStr + 'fo:margin-top="'+FloatToODTText(CurStyle.MarginTop)+'mm" ';
if sseMarginBottom in CurStyle.SetElements then
- lMarginStr := lMarginStr + 'fo:margin-bottom="'+FloatToODTText(CurStyle.MarginTop)+'mm" ';
+ 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
' ' + LineEnding +
- ' ' + LineEnding +
+ ' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding;
FStyles := FStyles + lCurStyleTmpStr;
@@ -570,12 +602,13 @@ begin
}
- FStyles := FStyles +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding;
end;
+ FStyles := FStyles +
+ ' ' + LineEnding +
+ ' ' + LineEnding +
+ ' ' + LineEnding;
+
FStyles := FStyles +
' ' + LineEnding +
' ' + LineEnding +
@@ -645,6 +678,8 @@ begin
FStyles := FStyles +
'' + LineEnding +
+ FAutomaticStyles + LineEnding +
+(*
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
@@ -655,11 +690,15 @@ begin
' ' + LineEnding +
//
' ' + LineEnding +
+*)
'' + LineEnding;
FStyles := FStyles +
'' + LineEnding +
+ FMasterStyles + LineEnding +
+(*
' ' + LineEnding +
+*)
'' + LineEnding;
FStyles := FStyles +
@@ -669,12 +708,17 @@ end;
procedure TvODTVectorialWriter.WriteDocument(AData: TvVectorialDocument);
var
i: Integer;
+ sPrefix : String;
+ sAutomaticStyles : String;
CurLevel: String;
CurPage: TvPage;
CurTextPage: TvTextPageSequence absolute CurPage;
CurListStyle : TvListStyle;
begin
- FContent :=
+ // content.xml will be built up by
+ // sPrefix + sAutomaticStyles + FContent
+
+ sPrefix :=
XML_HEADER + LineEnding +
'' + LineEnding;
- FContent := FContent +
+ sPrefix := sPrefix +
' ' + LineEnding;
- FContent := FContent +
+ sPrefix := sPrefix +
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
@@ -720,23 +764,41 @@ begin
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding;
+
+ // Build the main content of the document
+ FContent := ' ' + LineEnding;
+
FContent := FContent +
+ ' ' + LineEnding;
+
+ FContent := FContent +
+ ' ' + LineEnding +
+ ' ' + LineEnding +
+ ' ' + LineEnding +
+ ' ' + LineEnding +
+ ' ' + LineEnding +
+ ' ' + 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 +
+ ' ' + LineEnding;
+ FContent := FContent +
+ ' ' + LineEnding;
+ FContent := FContent +
+ '' + LineEnding;
+
+ // Build up the automatic styles detailed in the content.xml
+ sAutomaticStyles := sAutomaticStyles +
' ' + LineEnding;
-{ ' ' + LineEnding +
- ' ' + LineEnding + //officeooo:rsid="00072f3e" officeooo:paragraph-rsid="00072f3e"
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +}
// MJT 2013-08-24 - This is the code to cycle over the ListStyles.
// - This is verified working for Level 0
@@ -745,102 +807,31 @@ begin
// (see note in WriteBulletStyle)
// - As I understand tOpenDocument-v1.1.pdf the following list style
// should work once we get nesting happening
- FContent := FContent + ' ' + LineEnding;
+
+ // TODO: Investigate if this should/could be moved into Styles.xml
+ sAutomaticStyles := sAutomaticStyles + ' ' + LineEnding;
For i := 0 To AData.GetListStyleCount-1 Do
begin
CurListStyle := AData.GetListStyle(i);
CurLevel := IntToStr(CurListStyle.Level+1); // Note the +1...
If CurListStyle.Kind=vlskBullet Then
- FContent := FContent + ' ' + LineEnding +
+ sAutomaticStyles := sAutomaticStyles + ' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding +
' ' + LineEnding;
end;
- FContent := FContent + ' ' + LineEnding;
+ sAutomaticStyles := sAutomaticStyles + ' ' + LineEnding;
- // Pre MJT code...
- //FContent := FContent +
- // ' ' + LineEnding +
- // ' ' + LineEnding +
- // ' ' + LineEnding +
- // ' ' + LineEnding +
- // ' ' + LineEnding +
- // ' ' + LineEnding +
- // ' ' + LineEnding;
-{
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- FContent := FContent +
+ // Now add any Automatic Styles built during WritePage..
+ sAutomaticStyles := sAutomaticStyles + FContentAutomaticStyles;
+
+ sAutomaticStyles := sAutomaticStyles +
' ' + LineEnding;
- FContent := FContent +
- ' ' + LineEnding;
-
- for i := 0 to AData.GetPageCount()-1 do
- begin
- CurPage := AData.GetPage(i);
- if CurPage is TvTextPageSequence then
- begin
- FContent := FContent +
- ' ' + LineEnding;
-
- WritePage(CurTextPage, AData);
-
- FContent := FContent +
- ' ' + LineEnding;
- end;
- end;
-
- FContent := FContent +
- ' ' + LineEnding;
- FContent := FContent +
- '' + LineEnding;
+ // Now piece it all together
+ FContent := sPrefix + sAutomaticStyles + FContent;
end;
procedure TvODTVectorialWriter.WritePage(ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
@@ -848,14 +839,7 @@ var
i: Integer;
lCurEntity: TvEntity;
begin
- FContent := FContent +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding +
- ' ' + LineEnding;
-
+ FNewPageSequence := True;
for i := 0 to ACurPage.GetEntitiesCount()-1 do
begin
lCurEntity := ACurPage.GetEntity(i);
@@ -864,6 +848,8 @@ begin
WriteParagraph(TvParagraph(lCurEntity), ACurPage, AData);
if (lCurEntity is TvBulletList) then
WriteBulletList(TvBulletList(lCurEntity), ACurPage, AData);
+ if (lCurEntity is TvTable) then
+ WriteTable(TvTable(lCurEntity), ACurPage, AData);
end;
end;
@@ -871,8 +857,11 @@ 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
@@ -895,6 +884,75 @@ begin
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 +
+ '' +
+ LineEnding +
+ ''+ LineEnding;
+
+
+ // Define the MasterStyles in Styles.xml
+ // TODO: Add Header and Footer content to FMasterStyles
+ FMasterStyles := FMasterStyles +
+ '' + 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 +
+ ''+ LineEnding+
+ ' '+ LineEnding;
+
+ FAutomaticStyles := FAutomaticStyles +
+ ' '+ LineEnding+
+ ' '+ LineEnding+
+ ' '+ LineEnding+
+ ' '+ LineEnding+
+ '' + LineEnding;
+
+ // Ensure the text is written out using the new Automatic Style
+ AEntityStyleName:=sAutoStyleName;
+ FNewPageSequence:=False;
+ end;
+
FContent := FContent +
' ';
@@ -960,7 +1018,6 @@ begin
Lazarus inherits three features from its use of the Free Pascal compiler: compile and execution speed, and cross-compilation. The Free Pascal compiler benefits from the Pascal language structure, which is rigid, and the steady advancements of Pascal compiler design, spanning several decades, to compile large applications quickly, often seconds.
}
-
end;
procedure TvODTVectorialWriter.WriteTextSpan(AEntity: TvText; AParagraph: TvParagraph;
@@ -1002,7 +1059,9 @@ begin
Else
sText := Copy(sText, 1, Length(sText) - 1);
- sText := StringReplace(sText, #11, '', [rfReplaceAll]);
+
+ sText := StringReplace(sText, ' ', ' ', [rfReplaceAll]);
+ sText := StringReplace(sText, #09, '', [rfReplaceAll]);
sText := StringReplace(sText, #13, '', [rfReplaceAll]);
sText := StringReplace(sText, #10, '', [rfReplaceAll]);
@@ -1010,6 +1069,332 @@ begin
sText + '';
end;
+function TvODTVectorialWriter.BordersToString(ATableBorders, ACellBorders : TvTableBorders;
+ ATopCell, ABottomCell, ALeftCell, ARightCell : Boolean):String;
+Const
+ LU_BORDERTYPE: Array[TvTableBorderType] Of String =
+ ('solid', 'dashed', 'solid', 'none', 'default');
+// ('solid', 'dashed', 'double', 'none', 'default');
+(*
+ double requires a completely different configuration, so for now, we won't
+ support it...
+
+
+
+ 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;
+ sPadding : 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;
+Const
+ LU_V_ALIGN: Array[TvVerticalAlignment] Of String = ('top', 'bottom', 'middle', 'automatic');
+
+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('');
+ 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(' ');
+ AddStyle('');
+
+ AddBody(Format('', [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('');
+ 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(' ');
+ AddStyle('');
+ end;
+
+ AddBody(' ');
+ 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(' ');
+ end;
+
+ If (oRow.Header) And (iRow=0) Then
+ Begin
+ bInHeader := True;
+ // Open header rows
+ AddBody(' ');
+ 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('');
+ AddStyle(' ');
+ AddStyle('');
+
+ AddBody(' ');
+ end
+ Else
+ AddBody(' ');
+
+ 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('');
+ AddStyle(' ');
+ AddStyle('');
+
+ AddBody(' ');
+ end
+ Else
+ AddBody(' ');
+
+ 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 TvBulletList) then
+ WriteBulletList(TvBulletList(lCurEntity), ACurPage, AData);
+ if (lCurEntity is TvTable) then
+ WriteTable(TvTable(lCurEntity), ACurPage, AData);
+ end;
+
+ AddBody(' ');
+
+ // FPVectorial doesn't directly support covered (merged) cells,
+ // instead they're implied by SpannedCols count > 1
+ for k := 2 to oCell.SpannedCols Do
+ AddBody('');
+ end;
+
+ AddBody(' ');
+ end;
+ AddBody('');
+end;
+
procedure TvODTVectorialWriter.WriteBulletList(AEntity: TvBulletList;
ACurPage: TvTextPageSequence; AData: TvVectorialDocument);
var
@@ -1071,6 +1456,9 @@ begin
FPointSeparator := DefaultFormatSettings;
FPointSeparator.DecimalSeparator := '.';
FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
+
+ FAutomaticStyles := '';
+ FMasterStyles := '';
end;
destructor TvODTVectorialWriter.Destroy;
@@ -1094,8 +1482,10 @@ begin
WriteManifestRDF();
WriteMeta();
WriteSettings();
- WriteStyles(AData);
+ // Reversed order of Document and Styles to allow embedding Automatic Styles
+ // built up during WriteDocument...
WriteDocument(AData);
+ WriteStyles(AData);
{ Write the data to streams }
@@ -1113,11 +1503,14 @@ begin
try
FZip.FileName := AFileName;
+ // MimeType must be first file, and should be uncompressed
+ // TODO: CompressionLevel is not working. Bug, or misuse?
+ 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(FSMimetype, OPENDOC_PATH_MIMETYPE);
FZip.Entries.AddFileEntry(FSMetaInfManifest, OPENDOC_PATH_METAINF_MANIFEST);
FZip.Entries.AddFileEntry(FSManifestRDF, OPENDOC_PATH_MANIFESTRDF);