xref: /core/sw/source/filter/ww8/writerhelper.hxx (revision 7becd80d9773eb056b85945c5e51277b2481aa0e)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #ifndef INCLUDED_SW_SOURCE_FILTER_WW8_WRITERHELPER_HXX
21 #define INCLUDED_SW_SOURCE_FILTER_WW8_WRITERHELPER_HXX
22 
23 #include <vector>
24 #include <map>
25 #include <com/sun/star/embed/XEmbeddedObject.hpp>
26 
27 #include <sfx2/objsh.hxx>
28 #include <svl/itempool.hxx>
29 #include <svl/itemset.hxx>
30 #include <svx/svdtypes.hxx>
31 #include <node.hxx>
32 #include <pam.hxx>
33 #include <tools/poly.hxx>
34 #include <doc.hxx>
35 #include <vcl/graph.hxx>
36 
37 class SwTextFormatColl;
38 class SwCharFormat;
39 class SdrObject;
40 class SdrOle2Obj;
41 class SwNumFormat;
42 class SwTextNode;
43 class SwNoTextNode;
44 class SwFormatCharFormat;
45 class SwDoc;
46 class SwNumRule;
47 
48 namespace sw
49 {
50     namespace util
51     {
52         class ItemSort
53         {
54         public:
55             bool operator()(sal_uInt16 nA, sal_uInt16 nB) const;
56         };
57     }
58 }
59 
60 namespace ww8
61 {
62     /// STL container of Paragraph Styles (SwTextFormatColl)
63     typedef std::vector<SwTextFormatColl *> ParaStyles;
64     /// STL container of SfxPoolItems (Attributes)
65     typedef std::map<sal_uInt16, const SfxPoolItem *, sw::util::ItemSort> PoolItems;
66 
67     /** Make exporting a Writer Frame easy
68 
69         In word all frames are effectively anchored to character or as
70         character. This is nice and simple, writer is massively complex in this
71         area, so this ww8::Frame simplifies matters by providing a single unified
72         view of the multitude of elements in writer and their differing quirks.
73 
74         A ww8::Frame wraps a writer frame and is guaranteed to have a suitable
75         anchor position available from it. It hides much of the needless
76         complexity of the multitude of floating/inline elements in writer, it...
77 
78         Guarantees an anchor position for a frame.
79         Provides a readable way to see if we are anchored inline. (as character)
80         Provides a simple way to flag what type of entity this frame describes.
81         Provides the size of the element as drawn by writer.
82     */
83     class Frame
84     {
85     public:
86         enum WriterSource {eTextBox, eGraphic, eOle, eDrawing, eFormControl,eBulletGrf};
87     private:
88         const SwFrameFormat* mpFlyFrame;
89         SwPosition maPos;
90         Size maSize;
91         // #i43447# - Size of the frame in the layout.
92         // Especially needed for graphics, whose layout size can differ from its
93         // size, because it is scaled into its environment.
94         Size maLayoutSize;
95 
96         WriterSource meWriterType;
97         const SwNode *mpStartFrameContent;
98         bool mbIsInline;
99         bool mbForBullet:1;
100         Graphic maGrf;
101     public:
102         Frame(const SwFrameFormat &rFlyFrame, SwPosition aPos);
103         Frame(const Graphic&, SwPosition );
104 
105         /** Get the writer SwFrameFormat that this object describes
106 
107             @return
108             The wrapped SwFrameFormat
109         */
GetFrameFormat() const110         const SwFrameFormat &GetFrameFormat() const { return *mpFlyFrame; }
111 
112         /** Get the position this frame is anchored at
113 
114             @return
115             The anchor position of this frame
116         */
GetPosition() const117         const SwPosition &GetPosition() const { return maPos; }
SetPosition(SwPosition const & rPos)118         void SetPosition(SwPosition const& rPos) { maPos = rPos; }
119 
120         /** Get the node this frame is anchored into
121 
122             @return
123             The SwTextNode this frame is anchored inside
124         */
GetContentNode() const125         const SwContentNode *GetContentNode() const
126             { return maPos.GetNode().GetContentNode(); }
127 
128         /** Get the type of frame that this wraps
129 
130             @return
131             a WriterSource which describes the source type of this wrapper
132         */
GetWriterType() const133         WriterSource GetWriterType() const { return meWriterType; }
134 
135         /** Is this frame inline (as character)
136 
137             @return
138             whether this is inline or not
139         */
IsInline() const140         bool IsInline() const { return mbIsInline; }
141 
142         /** Even if the frame isn't an inline frame, force it to behave as one
143 
144             There are a variety of circumstances where word cannot have
145             anything except inline elements, e.g. inside frames. So its easier
146             to force this ww8::Frame into behaving as one, instead of special
147             casing export code all over the place.
148 
149         */
150         void ForceTreatAsInline();
151 
152         /** Get the first node of content in the frame
153 
154          @return
155          the first node of content in the frame, might not be any at all.
156         */
GetContent() const157         const SwNode *GetContent() const { return mpStartFrameContent; }
GetGraphic() const158         const Graphic &GetGraphic() const { return maGrf; }
HasGraphic() const159         bool HasGraphic() const { return mbForBullet; }
160 
161         /** Does this ww8::Frame refer to the same writer content as another
162 
163          @return
164          if the two ww8::Frames are handling the same writer frame
165         */
RefersToSameFrameAs(const Frame & rOther) const166         bool RefersToSameFrameAs(const Frame &rOther) const
167         {
168             if (mbForBullet && rOther.mbForBullet)
169                 return (maGrf == rOther.maGrf);
170             else if ((!mbForBullet) && (!rOther.mbForBullet))
171                 return (mpFlyFrame == rOther.mpFlyFrame);
172 
173             return false;
174         }
175 
176         /** The Size of the contained element
177 
178          @return
179          the best size to use to export to word
180         */
GetSize() const181         const Size& GetSize() const { return maSize; }
182 
183         /** The layout size of the contained element
184 
185             #i43447# - Needed for graphics, which are scaled into its environment
186 
187             @return layout size
188         */
GetLayoutSize() const189         const Size& GetLayoutSize() const
190         {
191             return maLayoutSize;
192         }
193     };
194 
195     /// STL container of Frames
196     typedef std::vector<Frame> Frames;
197     /// STL iterator for Frames
198     typedef std::vector<Frame>::iterator FrameIter;
199 }
200 
201 namespace sw
202 {
203     namespace util
204     {
205         /** Provide a dynamic_cast style cast for SfxPoolItems
206 
207             A SfxPoolItem generally need to be cast back to its original type
208             to be useful, which is both tedious and error prone. So item_cast is
209             a helper template to aid the process and test if the cast is
210             correct.
211 
212             @param rItem
213             The SfxPoolItem which is to be casted
214 
215             @tplparam T
216             A SfxPoolItem derived class to cast rItem to
217 
218             @return A rItem upcasted back to a T
219 
220             @exception std::bad_cast Thrown if the rItem was not a T
221         */
item_cast(const SfxPoolItem & rItem)222         template<class T> const T & item_cast(const SfxPoolItem &rItem)
223         {
224             assert(dynamic_cast<const T *>(&rItem) && "bad type cast");
225             return static_cast<const T &>(rItem);
226         }
227 
228         /** Provide a dynamic_cast style cast for SfxPoolItems
229 
230             A SfxPoolItem generally need to be cast back to its original type
231             to be useful, which is both tedious and error prone. So item_cast is
232             a helper template to aid the process and test if the cast is
233             correct.
234 
235             @param pItem
236             The SfxPoolItem which is to be casted
237 
238             @tplparam T
239             A SfxPoolItem derived class to cast pItem to
240 
241             @return A pItem upcasted back to a T or 0 if pItem was not a T
242         */
item_cast(const SfxPoolItem * pItem)243         template<class T> const T * item_cast(const SfxPoolItem *pItem)
244         {
245             return dynamic_cast<const T *>(pItem);
246         }
247 
248         /** Get the Paragraph Styles of a SwDoc
249 
250             Writer's styles are in one of those dreaded macro based pre-STL
251             containers. Give me an STL container of the paragraph styles
252             instead.
253 
254             @param rDoc
255             The SwDoc document to get the styles from
256 
257             @return A ParaStyles containing the SwDoc's Paragraph Styles
258         */
259         ww8::ParaStyles GetParaStyles(const SwDoc &rDoc);
260 
261         /** Get a Paragraph Style which fits a given name
262 
263             Its surprisingly tricky to get a style when all you have is a name,
264             but that's what this does
265 
266             @param rDoc
267             The SwDoc document to search in
268 
269             @param rName
270             The name of the style to search for
271 
272             @return A Paragraph Style if one exists which matches the name
273         */
274         SwTextFormatColl* GetParaStyle(SwDoc &rDoc, const UIName& rName);
275 
276         /** Get a Character Style which fits a given name
277 
278             Its surprisingly tricky to get a style when all you have is a name,
279             but that's what this does
280 
281             @param rDoc
282             The SwDoc document to search in
283 
284             @param rName
285             The name of the style to search for
286 
287             @return A Character Style if one exists which matches the name
288         */
289         SwCharFormat* GetCharStyle(SwDoc &rDoc, const UIName& rName);
290 
291         /** Sort sequence of Paragraph Styles by assigned outline style list level
292 
293             Sort ParaStyles in ascending order of assigned outline style list level,
294             e.g.  given Normal/Heading1/Heading2/.../Heading10 at their default
295             assigned outline style list levels of body level/level 1/level 2/.../level 10
296 
297             #i98791#
298             adjust the sorting algorithm due to introduced outline level attribute
299 
300             @param rStyles
301             The ParaStyles to sort
302         */
303         void SortByAssignedOutlineStyleListLevel(ww8::ParaStyles &rStyles);
304 
305         /** Get the SfxPoolItems of a SfxItemSet
306 
307             Writer's SfxPoolItems (attributes) are in one of those dreaded
308             macro based pre-STL containers. Give me an STL container of the
309             items instead.
310 
311             @param rSet
312             The SfxItemSet to get the items from
313 
314             @param rItems
315             The sw::PoolItems to put the items into
316         */
317         void GetPoolItems(const SfxItemSet &rSet, ww8::PoolItems &rItems, bool bExportParentItemSet );
318 
319         const SfxPoolItem *SearchPoolItems(const ww8::PoolItems &rItems,
320             sal_uInt16 eType);
321 
HasItem(const ww8::PoolItems & rItems,sal_uInt16 eType)322         template<class T> const T* HasItem(const ww8::PoolItems &rItems,
323             sal_uInt16 eType)
324         {
325             return item_cast<T>(SearchPoolItems(rItems, eType));
326         }
327 
328         /** Remove properties from an SfxItemSet which a SwFormatCharFormat overrides
329 
330             Given an SfxItemSet and a SwFormatCharFormat remove from the rSet all the
331             properties which the SwFormatCharFormat would override. An SfxItemSet
332             contains attributes, and a SwFormatCharFormat is a "Character Style",
333             so if the SfxItemSet contains bold and so does the character style
334             then delete bold from the SfxItemSet
335 
336             @param
337             rFormat the SwFormatCharFormat which describes the Character Style
338 
339             @param
340             rSet the SfxItemSet from which we want to remove any properties
341             which the rFormat would override
342 
343             @see #i24291# for examples
344         */
345         void ClearOverridesFromSet(const SwFormatCharFormat &rFormat, SfxItemSet &rSet);
346 
347         /** Get the Floating elements in a SwDoc
348 
349             Writer's FrameFormats may or may not be anchored to some text content,
350             e.g. Page Anchored elements will not be. For the winword export we
351             need them to have something to be anchored to. So this method
352             returns all the floating elements in a document as a STL container
353             of ww8::Frames which are guaranteed to have an appropriate anchor.
354 
355             @param rDoc
356             The SwDoc document to get the styles from
357 
358             @param pPaM
359             The SwPam to describe the selection in the document to get the
360             elements from. 0 means the entire document.
361 
362             @return A Frames containing the selections Floating elements
363         */
364         ww8::Frames GetFrames(const SwDoc &rDoc, SwPaM const *pPaM);
365 
366         /** fix up frame positions, must be called after SetRedlineFlags */
367         void UpdateFramePositions(ww8::Frames & rFrames);
368 
369         /** Get the Frames anchored to a given node
370 
371             Given a container of frames, find the ones anchored to a given node
372 
373             @param rFrames
374             The container of frames to search in
375 
376             @param rNode
377             The SwNode to check for anchors to
378 
379             @return the Frames in rFrames anchored to rNode
380         */
381         ww8::Frames GetFramesInNode(const ww8::Frames &rFrames, const SwNode &rNode);
382 
383         /** Get the Numbering Format used on a paragraph
384 
385             There are two differing types of numbering formats that may be on a
386             paragraph, normal and outline. The outline is that numbering you
387             see in tools->outline numbering. There's no difference in the
388             numbering itself, just how you get it from the SwTextNode. Needless
389             to say the filter generally couldn't care less what type of
390             numbering is in use.
391 
392             @param rTextNode
393             The SwTextNode that is the paragraph
394 
395             @return A SwNumFormat pointer that describes the numbering level
396             on this paragraph, or 0 if there is none.
397         */
398         const SwNumFormat* GetNumFormatFromTextNode(const SwTextNode &rTextNode);
399 
400         /** Get the Numbering Format for a given level from a numbering rule
401 
402             @param rRule
403             The numbering rule
404 
405             @param nLevel
406             The numbering level
407 
408             @return A SwNumFormat pointer that describes the numbering level
409             or 0 if the nLevel is out of range
410         */
411         const SwNumFormat* GetNumFormatFromSwNumRuleLevel(const SwNumRule &rRule,
412             int nLevel);
413 
414         const SwNumRule* GetNumRuleFromTextNode(const SwTextNode &rTextNd);
415         const SwNumRule* GetNormalNumRuleFromTextNode(const SwTextNode &rTextNd);
416 
417         /** Get the SwNoTextNode associated with a SwFrameFormat if here is one
418 
419             There are two differing types of numbering formats that may be on a
420             paragraph, normal and outline. The outline is that numbering you
421             see in tools->outline numbering. There's no difference in the
422             numbering itself, just how you get it from the SwTextNode. Needless
423             to say the filter generally couldn't care less what type of
424             numbering is in use.
425 
426             @param rFormat
427             The SwFrameFormat that may describe a graphic
428 
429             @return A SwNoTextNode pointer that describes the graphic of this
430             frame if there is one, or 0 if there is none.
431         */
432         SwNoTextNode *GetNoTextNodeFromSwFrameFormat(const SwFrameFormat &rFormat);
433 
434         /** Does a node have a "page break before" applied
435 
436             Both text nodes and tables in writer can have "page break before"
437             This function gives a unified view to both entities
438 
439             @param rNode
440             The SwNode to query the page break of
441 
442             @return true if there is a page break, false otherwise
443         */
444         bool HasPageBreak(const SwNode &rNode);
445 
446         /** Make a best fit Polygon from a PolyPolygon
447 
448             For custom contours in writer we use a PolyPolygon, while word uses
449             a simple polygon, so we need to try and make the best polygon from
450             a PolyPolygon
451 
452             @param rPolyPoly
453             The tools::PolyPolygon to try and turn into a Polygon
454 
455             @return best fit Polygon from rPolyPoly
456         */
457         tools::Polygon PolygonFromPolyPolygon(const tools::PolyPolygon &rPolyPoly);
458 
459         /// Undo all scaling / move tricks of the wrap polygon done during import.
460         tools::Polygon CorrectWordWrapPolygonForExport(const tools::PolyPolygon& rPolyPoly, const SwNoTextNode* pNd, bool bCorrectCrop);
461 
462         /** Make setting a drawing object's layer in a Writer document easy
463 
464             Word has the simple concept of a drawing object either in the
465             foreground and in the background. We have an additional complexity
466             that form components live in a separate layer, which seems
467             unnecessarily complicated. So in the winword filter we set the
468             object's layer through this class with either SendObjectToHell for
469             the bottom layer and SendObjectToHeaven for the top and we don't
470             worry about the odd form layer design wrinkle.
471         */
472         class SetLayer
473         {
474         private:
475             SdrLayerID mnHeavenLayer, mnHellLayer, mnFormLayer;
476             enum Layer {eHeaven, eHell};
477             void SetObjectLayer(SdrObject &rObject, Layer eLayer) const;
478         public:
479 
480             /** Make Object live in the bottom drawing layer
481 
482                 @param rObject
483                 The object to be set to the bottom layer
484             */
485             void SendObjectToHell(SdrObject &rObject) const;
486 
487             /** Make Object lives in the top layer
488 
489                 @param rObject
490                 The object to be set to the top layer
491             */
492             void SendObjectToHeaven(SdrObject &rObject) const;
493 
494             /** Normal constructor
495 
496                 @param rDoc
497                 The Writer document whose drawing layers we will be inserting
498                 objects into
499             */
500             explicit SetLayer(const SwDoc &rDoc);
501         };
502 
503         const SwCharFormat* GetSwCharFormat(const SwFormatINetFormat& rINet, SwDoc& rDoc);
504     }
505 
506     namespace hack
507     {
508             /** Map an ID valid in one SfxItemPool to its equivalent in another
509 
510             Given a WhichId (the id that identifies a property e.g. bold) which
511             is correct in a given SfxItemPool, get the equivalent whichId in
512             another SfxItemPool
513 
514             This arises because the drawing layer uses the same properties as
515             writer e.g. SvxWeight, but for some reason uses different ids
516             for the same properties as writer.
517 
518             @param rDestPool
519             The SfxItemPool in whose terms the Id is returned
520 
521             @param rSrcPool
522             The SfxItemPool in whose terms the Id is passed in
523 
524             @param nWhich
525             The Id to transform from source to dest
526 
527             @return 0 on failure, the correct property Id on success
528         */
529         sal_uInt16 TransformWhichBetweenPools(const SfxItemPool &rDestPool,
530             const SfxItemPool &rSrcPool, sal_uInt16 nWhich);
531 
532         /** Map a SwDoc WhichId to the equivalent Id for a given SfxItemSet
533 
534             Given a WhichId (the id that identifies a property e.g. bold) which
535             is correct for a Writer document, get the equivalent whichId which
536             for a given SfxItemSet.
537 
538             This arises because the drawing layer uses the same properties as
539             writer e.g. SvxWeight, but for some reason uses different ids
540             for the same properties as writer.
541 
542             This is effectively the same as TransformWhichBetweenPools except
543             at a slightly different layer.
544 
545             @param rSet
546             The SfxItemSet in whose terms the Id is returned
547 
548             @param rDoc
549             The SwDoc in whose terms the Id is passed in
550 
551             @param nWhich
552             The Id to transform from writer to the SfxItemSet's domain
553 
554             @return 0 on failure, the correct SfxItemSet Id on success
555         */
556         sal_uInt16 GetSetWhichFromSwDocWhich(const SfxItemSet &rSet,
557             const SwDoc &rDoc, sal_uInt16 nWhich);
558 
559         /** Make inserting an OLE object into a Writer document easy
560 
561             The rest of Office uses SdrOle2Obj for their OLE objects, Writer
562             doesn't, which makes things a bit difficult as this is the type of
563             object that the escher import code shared by the MSOffice filters
564             produces when it imports an OLE object.
565 
566             This utility class takes ownership of the OLE object away from a
567             SdrOle2Obj and can massage it into the condition best suited to
568             insertion into Writer.
569 
570             If the object was not transferred into Writer then it is deleted
571             during destruction.
572         */
573         class DrawingOLEAdaptor
574         {
575         private:
576             css::uno::Reference < css::embed::XEmbeddedObject > mxIPRef;
577             SfxObjectShell& mrPers;
578             const Graphic* mpGraphic;
579         public:
580             /** Take ownership of a SdrOle2Objs OLE object
581 
582                 @param rObj
583                 The SdrOle2Obj whose OLE object we want to take control of
584 
585                 @param rPers
586                 The SvPersist of a SwDoc (SwDoc::GetPersist()) into which we
587                 may want to move the object, or remove it from if unwanted.
588             */
589             DrawingOLEAdaptor(SdrOle2Obj &rObj, SfxObjectShell &rPers);
590 
591             /// Destructor will destroy the owned OLE object if not transferred
592             ~DrawingOLEAdaptor();
593 
594             /** Transfer ownership of the OLE object to a document's SvPersist
595 
596                 TransferToDoc moves the object into the persist under the name
597                 passed in. This name is then suitable to be used as an argument
598                 to SwDoc::InsertOLE.
599 
600                 The object is no longer owned by the adaptor after this call,
601                 subsequent calls are an error and return false.
602 
603                 @param rName
604                 The name to store the object under in the document.
605 
606                 @return On success true is returned, otherwise false. On
607                 success rName is then suitable for user with SwDoc::InsertOLE
608             */
609             bool TransferToDoc(OUString &rName);
610         private:
611             DrawingOLEAdaptor& operator=(const DrawingOLEAdaptor&) = delete;
612             DrawingOLEAdaptor(const DrawingOLEAdaptor &rDoc) = delete;
613         };
614     }
615 }
616 
617 #endif
618 
619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
620