diff --git a/components/fpvectorial/fpvectorial.pas b/components/fpvectorial/fpvectorial.pas index ea69c4a835..3a021bb157 100644 --- a/components/fpvectorial/fpvectorial.pas +++ b/components/fpvectorial/fpvectorial.pas @@ -114,7 +114,7 @@ type Bold: boolean; Italic: boolean; Underline: boolean; - StrikeTrough: boolean; + StrikeThrough: boolean; end; { Coordinates and polyline segments } @@ -264,6 +264,7 @@ type Pen: TvPen; constructor Create; override; procedure ApplyPenToCanvas(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo); + procedure AssignPen(APen: TvPen); procedure Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override; end; @@ -277,8 +278,10 @@ type Brush: TvBrush; constructor Create; override; procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas); + procedure AssignBrush(ABrush: TvBrush); 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; end; { TvEntityWithPenBrushAndFont } @@ -288,8 +291,10 @@ type Font: TvFont; constructor Create; override; procedure ApplyFontToCanvas(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; AMulX: Double = 1.0); + procedure AssignFont(AFont: TvFont); 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; end; TvClipMode = (vcmNonzeroWindingRule, vcmEvenOddRule); @@ -1113,6 +1118,13 @@ begin ADest.Pen.Style := Pen.Style; end; +procedure TvEntityWithPen.AssignPen(APen: TvPen); +begin + Pen.Style := APen.Style; + Pen.Color := APen.Color; + Pen.Width := APen.Width; +end; + procedure TvEntityWithPen.Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer; ADestY: Integer; AMulX: Double; AMulY: Double); begin @@ -1135,6 +1147,12 @@ begin ADest.Brush.Style := Brush.Style; end; +procedure TvEntityWithPenAndBrush.AssignBrush(ABrush: TvBrush); +begin + Brush.Style := ABrush.Style; + Brush.Color := ABrush.Color; +end; + procedure TvEntityWithPenAndBrush.Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer; ADestY: Integer; AMulX: Double; AMulY: Double); begin @@ -1142,6 +1160,22 @@ begin ApplyBrushToCanvas(ADest); end; +function TvEntityWithPenAndBrush.GenerateDebugTree( + ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; +var + lStr: string; + lCurPathSeg: TPathSegment; +begin + lStr := Format('[%s] Name=%s Pen.Color=%s Pen.Style=%s Brush.Color=%s Brush.Style=%s', + [Self.ClassName, Self.Name, + GenerateDebugStrForFPColor(Pen.Color), + GetEnumName(TypeInfo(TFPPenStyle), integer(Pen.Style)), + GenerateDebugStrForFPColor(Brush.Color), + GetEnumName(TypeInfo(TFPBrushStyle), integer(Brush.Style)) + ]); + Result := ADestRoutine(lStr, APageItem); +end; + { TvEntityWithPenBrushAndFont } @@ -1164,13 +1198,25 @@ begin ADest.Font.Bold := Font.Bold; ADest.Font.Italic := Font.Italic; ADest.Font.Underline := Font.Underline; - ADest.Font.StrikeTrough := Font.StrikeTrough; + ADest.Font.StrikeTrough := Font.StrikeThrough; {$ifdef USE_LCL_CANVAS} ALCLDest.Font.Orientation := Round(Font.Orientation * 16); {$endif} ADest.Font.FPColor := AdjustColorToBackground(Font.Color, ARenderInfo); end; +procedure TvEntityWithPenBrushAndFont.AssignFont(AFont: TvFont); +begin + Font.Color := AFont.Color; + Font.Size := AFont.Size; + Font.Name := AFont.Name; + Font.Orientation := AFont.Orientation; + Font.Bold := AFont.Bold; + Font.Italic := AFont.Italic; + Font.Underline := AFont.Underline; + Font.StrikeThrough := AFont.StrikeThrough; +end; + procedure TvEntityWithPenBrushAndFont.Render(ADest: TFPCustomCanvas; ARenderInfo: TvRenderInfo; ADestX: Integer; ADestY: Integer; AMulX: Double; AMulY: Double); @@ -1179,6 +1225,25 @@ begin ApplyFontToCanvas(ADest, ARenderInfo, AMulX); end; +function TvEntityWithPenBrushAndFont.GenerateDebugTree( + ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; +var + lStr: string; + lCurPathSeg: TPathSegment; +begin + Result := inherited GenerateDebugTree(ADestRoutine, APageItem); + // Add the font debug info in a sub-item + lStr := Format('[Font] Color=%s Size=%d Name=%s Orientation=%f Bold=%s Italic=%s Underline=%s StrikeThrough=%s', + [GenerateDebugStrForFPColor(Font.Color), + Font.Size, Font.Name, Font.Orientation, + BoolToStr(Font.Bold), + BoolToStr(Font.Italic), + BoolToStr(Font.Underline), + BoolToStr(Font.StrikeThrough) + ]); + ADestRoutine(lStr, Result); +end; + { TPath } constructor TPath.Create; diff --git a/components/fpvectorial/odgvectorialreader.pas b/components/fpvectorial/odgvectorialreader.pas index 9e046f9574..906ec91408 100644 --- a/components/fpvectorial/odgvectorialreader.pas +++ b/components/fpvectorial/odgvectorialreader.pas @@ -91,21 +91,52 @@ type procedure TokenizePathString(AStr: string); end; } + TODGMasterPage = class + public + Name: string; + PageLayoutName: string; + StyleName: string; + end; + + TODGStyle = class(TvEntityWithPenBrushAndFont) + public + end; + + TODGPageLayout = class + public + Name: string; + MarginTop, MarginBottom, MarginLeft, MarginRight: Double; + PageWidth, PageHeight: Double; + end; + { TvODGVectorialReader } TvODGVectorialReader = class(TvCustomVectorialReader) private FPointSeparator, FCommaSeparator: TFormatSettings; - FStyles: TFPList; // of TvEntityWithPenBrushAndFont; + FStyles: TFPList; // of TODGStyle; + FAutomaticStyles: TFPList; // of TODGStyle; + FPageLayouts: TFPList; // of TODGPageLayout; + FMasterPages: TFPList; // of TODGMasterPage; //FSVGPathTokenizer: TSVGPathTokenizer; // procedure DeleteStyle(data,arg:pointer); + procedure ApplyGraphicAttributeToEntity(ANodeName, ANodeValue: string; ADest: TvEntityWithPen); + procedure ApplyStyleByNameToEntity(AStyleName: string; ADest: TvEntityWithPen); + procedure ApplyTextStyleByNameToEntity(AStyleName: string; ADest: TvEntityWithPen); + procedure ApplyMasterPageToPage(AMasterPageName: string; ADest: TvVectorialPage); // procedure ReadStyleNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); procedure ReadStyleStyleNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); // procedure ReadElement(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); procedure ReadEllipseNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); + procedure ReadFrameNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); + procedure ReadLineNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); + procedure ReadPathNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); + // + procedure ReadStylesMasterPage(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); + procedure ReadStylesPageLayout(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument); // function ReadSVGColor(AValue: string): TFPColor; function GetAttrValue(ANode : TDOMNode; AAttrName : string) : string; @@ -123,6 +154,7 @@ type procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override; procedure ReadFromFile(AFileName: string; AData: TvVectorialDocument); override; procedure ReadFromContentXMLDocument(AXMLDocument: TXMLDocument; AData: TvVectorialDocument); + procedure ReadFromStylesXMLDocument(AXMLDocument: TXMLDocument; AData: TvVectorialDocument); end; implementation @@ -312,7 +344,188 @@ end;} procedure TvODGVectorialReader.DeleteStyle(data, arg: pointer); begin - TvEntityWithPenBrushAndFont(data).Free; + TObject(data).Free; +end; + +procedure TvODGVectorialReader.ApplyGraphicAttributeToEntity(ANodeName, + ANodeValue: string; ADest: TvEntityWithPen); +var + i: Integer; + lColor: TFPColor; + lDestBrush: TvEntityWithPenAndBrush absolute ADest; + lDestFont: TvEntityWithPenBrushAndFont absolute ADest; +begin + case ANodeName of + // "none", "solid" + 'draw:fill': + begin + if not (ADest is TvEntityWithPenAndBrush) then Exit; + case ANodeValue of + 'none': lDestBrush.Brush.Style := bsClear; + 'solid': lDestBrush.Brush.Style := bsSolid; + end; + end; + // "#ffffff" + 'draw:fill-color': + begin + if not (ADest is TvEntityWithPenAndBrush) then Exit; + lColor := ReadSVGColor(ANodeValue); + lDestBrush.Brush.Color := lColor; + end; + // Values: "justify", "center", "left" + 'draw:textarea-horizontal-align': + begin + end; + // Values: "middle" + 'draw:textarea-vertical-align': + begin + end; + // true-false + 'draw:auto-grow-height': + begin + end; + // true-false + 'draw:auto-grow-width': + begin + end; + // "none", "dash" + 'draw:stroke': + begin + case ANodeValue of + 'none': ADest.Pen.Style := psClear; + 'dash': ADest.Pen.Style := psDash; + end; + end; + // "Fine_20_Dashed_20__28_var_29_" + 'draw:stroke-dash': + begin + end; + // "Arrow" + 'draw:marker-start': + begin + end; + // "0.45cm" + 'draw:marker-start-width': + begin + end; + // "Circle" + 'draw:marker-end': + begin + end; + // "0.45cm" + 'draw:marker-end-width': + begin + end; + // "Transparency_20_1" + 'draw:opacity-name': + begin + end; + // "0.1cm" + 'svg:stroke-width': ADest.Pen.Width := Round(StringWithUnitToFloat(ANodeValue)); + // "#000000" + 'svg:stroke-color': ADest.Pen.Color := ReadSVGColor(ANodeValue); + // "0cm" + 'fo:min-height': + begin + end; + // "0cm" + 'fo:min-width': + begin + end; + // "wrap" + 'fo:wrap-option': + begin + end; + // "0.175cm" + 'fo:padding-top': + begin + end; + // "0.175cm" + 'fo:padding-bottom': + begin + end; + // "0.3cm" + 'fo:padding-left': + begin + end; + // "0.3cm" + 'fo:padding-right': + begin + end; + end; +end; + +// Don't apply font properties here, because there is a separate method for this +procedure TvODGVectorialReader.ApplyStyleByNameToEntity(AStyleName: string; + ADest: TvEntityWithPen); +var + i: Integer; + lCurStyle: TvEntityWithPenBrushAndFont; +begin + for i := 0 to FStyles.Count-1 do + begin + lCurStyle := TvEntityWithPenBrushAndFont(FStyles.Items[i]); + if lCurStyle.Name = AStyleName then + begin + ADest.AssignPen(lCurStyle.Pen); + if ADest is TvEntityWithPenAndBrush then + TvEntityWithPenAndBrush(ADest).AssignBrush(lCurStyle.Brush); + + Exit; + end; + end; +end; + +procedure TvODGVectorialReader.ApplyTextStyleByNameToEntity(AStyleName: string; + ADest: TvEntityWithPen); +var + i: Integer; + lCurStyle: TvEntityWithPenBrushAndFont; +begin + for i := 0 to FStyles.Count-1 do + begin + lCurStyle := TvEntityWithPenBrushAndFont(FStyles.Items[i]); + if lCurStyle.Name = AStyleName then + begin + if ADest is TvEntityWithPenBrushAndFont then + TvEntityWithPenBrushAndFont(ADest).AssignFont(lCurStyle.Font); + + Exit; + end; + end; +end; + +procedure TvODGVectorialReader.ApplyMasterPageToPage(AMasterPageName: string; + ADest: TvVectorialPage); +var + i: Integer; + lMasterPage: TODGMasterPage; + lMasterPageLayout: TODGPageLayout; +begin + // Find the Master Page + for i := 0 to FMasterPages.Count-1 do + begin + lMasterPage := TODGMasterPage(FMasterPages.Items[i]); + if lMasterPage.Name = AMasterPageName then Break + else lMasterPage := nil; + end; + + if lMasterPage = nil then + raise Exception.Create(Format('[TvODGVectorialReader.ApplyMasterPageToPage] Master page not found: %s', [AMasterPageName])); + + // Find the Master Page Properties + for i := 0 to FPageLayouts.Count-1 do + begin + lMasterPageLayout := TODGPageLayout(FPageLayouts.Items[i]); + if lMasterPageLayout.Name = lMasterPage.PageLayoutName then Break + else lMasterPageLayout := nil; + end; + + if lMasterPageLayout = nil then + raise Exception.Create(Format('[TvODGVectorialReader.ApplyMasterPageToPage] Master page layout not found: %s', [lMasterPage.PageLayoutName])); + + ADest.Width := lMasterPageLayout.PageWidth; + ADest.Height := lMasterPageLayout.PageHeight; end; procedure TvODGVectorialReader.ReadStyleNode(ANode: TDOMNode; @@ -338,22 +551,41 @@ var lStyle: TvEntityWithPenBrushAndFont; lGraphicPropertiesNode: TDOMNode; i: Integer; - lNodeName: DOMString; + lNodeName, lNodeValue: DOMString; begin - lStyle := TvEntityWithPenBrushAndFont.Create; + lStyle := TODGStyle.Create; + + // Read attributes of the main style tag + // ; + for i := 0 to lGraphicPropertiesNode.Attributes.Length - 1 do + begin + lNodeName := LowerCase(ANode.Attributes.Item[i].NodeName); + case lNodeName of + 'style:parent-style-name': + begin + lNodeValue := LowerCase(ANode.Attributes.Item[i].NodeValue); + case lNodeValue of + // "standard" + 'standard': Continue; + // "objectwithoutfill" + 'objectwithoutfill': + begin + lStyle.Brush.Style := bsClear; + end; + end; + end; + end; + end; + + // Read graphic properties lGraphicPropertiesNode := ANode.FindNode('style:graphic-properties'); if lGraphicPropertiesNode <> nil then begin for i := 0 to lGraphicPropertiesNode.Attributes.Length - 1 do begin - lNodeName := lGraphicPropertiesNode.Attributes.Item[i].NodeName; - case lNodeName of - //'draw:fill': - 'draw:fill-color': - begin - //lColor := lStyle.Brush.Color; - end; - end; + lNodeName := LowerCase(lGraphicPropertiesNode.Attributes.Item[i].NodeName); + lNodeValue := LowerCase(lGraphicPropertiesNode.Attributes.Item[i].NodeValue); + ApplyGraphicAttributeToEntity(lNodeName, lNodeValue, lStyle); end; end; FStyles.Add(lStyle); @@ -367,6 +599,9 @@ begin Str := LowerCase(ANode.NodeName); case Str of 'draw:ellipse': ReadEllipseNode(ANode, AData, ADoc); + 'draw:frame': ReadFrameNode(ANode, AData, ADoc); + 'draw:line': ReadLineNode(ANode, AData, ADoc); + 'draw:path': ReadPathNode(ANode, AData, ADoc); end; end; @@ -408,10 +643,14 @@ begin crx := StringWithUnitToFloat(ANode.Attributes.Item[i].NodeValue) / 2 else if lNodeName = 'svg:height' then cry := StringWithUnitToFloat(ANode.Attributes.Item[i].NodeValue) / 2 -// else if lNodeName = 'id' then -// lEllipse.Name := UTF16ToUTF8(ANode.Attributes.Item[i].NodeValue) -// else if lNodeName = 'draw:style-name' then -// AddStyleToElement(ANode.Attributes.Item[i].NodeValue, lEllipse); + else if lNodeName = 'draw:style-name' then + ApplyStyleByNameToEntity(ANode.Attributes.Item[i].NodeValue, lEllipse) + else if lNodeName = 'draw:text-style-name' then + ApplyTextStyleByNameToEntity(ANode.Attributes.Item[i].NodeValue, lEllipse) + // else if lNodeName = 'id' then + // lEllipse.Name := UTF16ToUTF8(ANode.Attributes.Item[i].NodeValue) + else + ApplyGraphicAttributeToEntity(lNodeName, ANode.Attributes.Item[i].NodeValue, lEllipse); end; // The svg:x and svg:y coordinates are relative to the top-left in ODG, @@ -419,7 +658,7 @@ begin cx := cx + crx; cy := cy + cry; - ConvertODGDeltaToFPVDelta( + ConvertODGCoordinatesToFPVCoordinates( AData, cx, cy, lEllipse.X, lEllipse.Y); ConvertODGDeltaToFPVDelta( AData, crx, cry, lEllipse.HorzHalfAxis, lEllipse.VertHalfAxis); @@ -427,6 +666,163 @@ begin AData.AddEntity(lEllipse); end; +{ + + Kesäyö + +} +procedure TvODGVectorialReader.ReadFrameNode(ANode: TDOMNode; + AData: TvVectorialPage; ADoc: TvVectorialDocument); +begin + +end; + +{ + + +} +procedure TvODGVectorialReader.ReadLineNode(ANode: TDOMNode; + AData: TvVectorialPage; ADoc: TvVectorialDocument); +var + x1, y1, x2, y2: double; + lPath: TPath; + i: Integer; + lNodeName: DOMString; +begin + x1 := 0.0; + y1 := 0.0; + x2 := 0.0; + y2 := 0.0; + + lPath := TPath.Create; + + // read the attributes + for i := 0 to ANode.Attributes.Length - 1 do + begin + lNodeName := ANode.Attributes.Item[i].NodeName; + if lNodeName = 'svg:x1' then + x1 := StringWithUnitToFloat(ANode.Attributes.Item[i].NodeValue) + else if lNodeName = 'svg:y1' then + y1 := StringWithUnitToFloat(ANode.Attributes.Item[i].NodeValue) + else if lNodeName = 'svg:x2' then + x2 := StringWithUnitToFloat(ANode.Attributes.Item[i].NodeValue) + else if lNodeName = 'svg:y2' then + y2 := StringWithUnitToFloat(ANode.Attributes.Item[i].NodeValue) + else if lNodeName = 'draw:style-name' then + ApplyStyleByNameToEntity(ANode.Attributes.Item[i].NodeValue, lPath) + else if lNodeName = 'draw:text-style-name' then + ApplyTextStyleByNameToEntity(ANode.Attributes.Item[i].NodeValue, lPath) +// else if lNodeName = 'id' then +// lEllipse.Name := UTF16ToUTF8(ANode.Attributes.Item[i].NodeValue) + else + ApplyGraphicAttributeToEntity(lNodeName, ANode.Attributes.Item[i].NodeValue, lPath); + end; + + ConvertODGCoordinatesToFPVCoordinates( + AData, x1, y1, x1, y1); + ConvertODGCoordinatesToFPVCoordinates( + AData, x2, y2, x2, y2); + + lPath.AppendMoveToSegment(x1, y1); + lPath.AppendLineToSegment(x2, y2); + AData.AddEntity(lPath); +end; + +{ + + +} +procedure TvODGVectorialReader.ReadPathNode(ANode: TDOMNode; + AData: TvVectorialPage; ADoc: TvVectorialDocument); +begin + +end; + +{ + + + +} +procedure TvODGVectorialReader.ReadStylesMasterPage(ANode: TDOMNode; + AData: TvVectorialPage; ADoc: TvVectorialDocument); +var + lMasterPage: TODGMasterPage; + i: Integer; + lNodeName, lNodeValue: string; +begin + lMasterPage := TODGMasterPage.Create; + + // Read properties + for i := 0 to ANode.Attributes.Length - 1 do + begin + lNodeName := LowerCase(ANode.Attributes.Item[i].NodeName); + lNodeValue := ANode.Attributes.Item[i].NodeValue; + + case lNodeName of + 'style:name': lMasterPage.Name := lNodeValue; + 'style:page-layout-name': lMasterPage.PageLayoutName := lNodeValue; + 'draw:style-name': lMasterPage.StyleName := lNodeValue; + end; + end; + FMasterPages.Add(lMasterPage); +end; + +{ + + + +} +procedure TvODGVectorialReader.ReadStylesPageLayout(ANode: TDOMNode; + AData: TvVectorialPage; ADoc: TvVectorialDocument); +var + lPageLayout: TODGPageLayout; + lPageLayoutPropertiesNode: TDOMNode; + i: Integer; + lNodeName, lNodeValue: string; +begin + lPageLayout := TODGPageLayout.Create; + + // Read properties + for i := 0 to ANode.Attributes.Length - 1 do + begin + lNodeName := LowerCase(ANode.Attributes.Item[i].NodeName); + lNodeValue := ANode.Attributes.Item[i].NodeValue; + + case lNodeName of + 'style:name': lPageLayout.Name := lNodeValue; + end; + end; + + // Read properties in the internal item + lPageLayoutPropertiesNode := ANode.FindNode('style:page-layout-properties'); + if lPageLayoutPropertiesNode <> nil then + begin + for i := 0 to lPageLayoutPropertiesNode.Attributes.Length - 1 do + begin + lNodeName := LowerCase(lPageLayoutPropertiesNode.Attributes.Item[i].NodeName); + lNodeValue := lPageLayoutPropertiesNode.Attributes.Item[i].NodeValue; + + case lNodeName of + 'fo:margin-top': lPageLayout.MarginTop := StringWithUnitToFloat(lNodeValue); + 'fo:margin-bottom':lPageLayout.MarginBottom := StringWithUnitToFloat(lNodeValue); + 'fo:margin-left': lPageLayout.MarginLeft := StringWithUnitToFloat(lNodeValue); + 'fo:margin-right':lPageLayout.MarginRight := StringWithUnitToFloat(lNodeValue); + 'fo:page-width': lPageLayout.PageWidth := StringWithUnitToFloat(lNodeValue); + 'fo:page-height': lPageLayout.PageHeight := StringWithUnitToFloat(lNodeValue); + end; + end; + end; + FPageLayouts.Add(lPageLayout); +end; + function TvODGVectorialReader.ReadSVGColor(AValue: string): TFPColor; var lValue, lStr: string; @@ -874,12 +1270,21 @@ begin // FSVGPathTokenizer := TSVGPathTokenizer.Create; FStyles := TFPList.Create; + FAutomaticStyles := TFPList.Create; + FPageLayouts := TFPList.Create; + FMasterPages := TFPList.Create; end; destructor TvODGVectorialReader.Destroy; begin FStyles.ForEachCall(@DeleteStyle, nil); FStyles.Free; + FAutomaticStyles.ForEachCall(@DeleteStyle, nil); + FAutomaticStyles.Free; + FPageLayouts.ForEachCall(@DeleteStyle, nil); + FPageLayouts.Free; + FMasterPages.ForEachCall(@DeleteStyle, nil); + FMasterPages.Free; // FSVGPathTokenizer.Free; inherited Destroy; @@ -929,6 +1334,7 @@ begin UnZip.OutputPath:=FilePath; FileList:=TStringList.Create; FileList.Add('content.xml'); + FileList.Add('styles.xml'); try Unzip.UnZipFiles(AFileName,FileList); finally @@ -938,21 +1344,30 @@ begin Doc:=nil; try - //process the xml file + // First read the master styles + ReadXMLFile(Doc,FilePath+'styles.xml'); + DeleteFile(FilePath+'styles.xml'); + ReadFromStylesXMLDocument(Doc, AData); + + // Now process the contents ReadXMLFile(Doc,FilePath+'content.xml'); DeleteFile(FilePath+'content.xml'); - ReadFromContentXMLDocument(Doc, AData); finally Doc.Free; end; end; +{ + +} procedure TvODGVectorialReader.ReadFromContentXMLDocument( AXMLDocument: TXMLDocument; AData: TvVectorialDocument); var BodyNode, DrawingNode, PageNode, ElementNode: TDOMNode; CurPage: TvVectorialPage; + i: Integer; + lNodeName, lNodeValue: String; begin BodyNode := AXMLDocument.DocumentElement.FindNode('office:body'); if not Assigned(BodyNode) then raise Exception.Create('[TvODGVectorialReader.ReadFromContentXMLDocument] node office:body not found'); @@ -967,6 +1382,16 @@ begin CurPage := aData.AddPage(); //CurPage..AddWorksheet(GetAttrValue(TableNode,'table:name')); + //process attributes of the page + for i := 0 to PageNode.Attributes.Length - 1 do + begin + lNodeName := LowerCase(PageNode.Attributes.Item[i].NodeName); + lNodeValue := PageNode.Attributes.Item[i].NodeValue; + case lNodeName of + 'draw:master-page-name': ApplyMasterPageToPage(lNodeValue, CurPage); + end; + end; + //process each element inside the page ElementNode := PageNode.FirstChild; while Assigned(ElementNode) do @@ -980,6 +1405,50 @@ begin end; //while Assigned(PageNode) end; +procedure TvODGVectorialReader.ReadFromStylesXMLDocument( + AXMLDocument: TXMLDocument; AData: TvVectorialDocument); +var + DocStylesNode, AutomaticStylesNode, MasterStylesNode, ElementNode: TDOMNode; + CurPage: TvVectorialPage; + i: Integer; + lNodeName: String; +begin + DocStylesNode := AXMLDocument.DocumentElement;//.FindNode('office:document-styles'); + if not Assigned(DocStylesNode) then raise Exception.Create('[TvODGVectorialReader.ReadFromStylesXMLDocument] node document-styles not found'); + + AutomaticStylesNode := DocStylesNode.FindNode('office:automatic-styles'); + if Assigned(AutomaticStylesNode) then + begin + //process each master style + ElementNode := AutomaticStylesNode.FirstChild; + while Assigned(ElementNode) do + begin + lNodeName := LowerCase(ElementNode.NodeName); + case lNodeName of + 'style:page-layout': ReadStylesPageLayout(ElementNode, CurPage, AData); + end; + + ElementNode := ElementNode.NextSibling; + end; //while Assigned(MasterStyleNode) + end; + + MasterStylesNode := DocStylesNode.FindNode('office:master-styles'); + if Assigned(MasterStylesNode) then + begin + //process each master style + ElementNode := MasterStylesNode.FirstChild; + while Assigned(ElementNode) do + begin + lNodeName := LowerCase(ElementNode.NodeName); + case lNodeName of + 'style:master-page': ReadStylesMasterPage(ElementNode, CurPage, AData); + end; + + ElementNode := ElementNode.NextSibling; + end; //while Assigned(MasterStyleNode) + end; +end; + initialization RegisterVectorialReader(TvODGVectorialReader, vfODG);