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
