LibreOffice Module sw (master) 1
swparrtf.cxx
Go to the documentation of this file.
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#include <poolfmt.hxx>
21#include <shellio.hxx>
22#include <ndtxt.hxx>
23#include <doc.hxx>
24#include <docsh.hxx>
26#include <swdll.hxx>
27#include <swerror.h>
28
29#include <unotextrange.hxx>
30
34#include <tools/diagnose_ex.h>
35
36#include <com/sun/star/document/XFilter.hpp>
37#include <com/sun/star/document/XImporter.hpp>
38#include <com/sun/star/frame/XModel.hpp>
39#include <com/sun/star/lang/XMultiServiceFactory.hpp>
40
41using namespace ::com::sun::star;
42
43namespace
44{
46class SwRTFReader : public Reader
47{
48 ErrCode Read(SwDoc& rDoc, const OUString& rBaseURL, SwPaM& rPam,
49 const OUString& rFileName) override;
50};
51}
52
53ErrCode SwRTFReader::Read(SwDoc& rDoc, const OUString& /*rBaseURL*/, SwPaM& rPam,
54 const OUString& /*rFileName*/)
55{
56 if (!m_pStream)
57 return ERR_SWG_READ_ERROR;
58
59 // We want to work in an empty paragraph.
60 // Step 1: XTextRange will be updated when content is inserted, so we know
61 // the end position.
62 const uno::Reference<text::XTextRange> xInsertPosition
63 = SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), nullptr);
64 auto pSttNdIdx = std::make_shared<SwNodeIndex>(rDoc.GetNodes());
65 const SwPosition* pPos = rPam.GetPoint();
66
67 // Step 2: Split once and remember the node that has been split.
68 rDoc.getIDocumentContentOperations().SplitNode(*pPos, false);
69 *pSttNdIdx = pPos->GetNodeIndex() - 1;
70
71 // Step 3: Split again.
72 rDoc.getIDocumentContentOperations().SplitNode(*pPos, false);
73 auto pSttNdIdx2 = std::make_shared<SwNodeIndex>(rDoc.GetNodes());
74 *pSttNdIdx2 = pPos->GetNodeIndex();
75
76 // Step 4: Insert all content into the new node
77 rPam.Move(fnMoveBackward);
80
81 SwDocShell* pDocShell(rDoc.GetDocShell());
82 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
84 uno::Reference<uno::XInterface> xInterface(
85 xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
86 uno::UNO_SET_THROW);
87
88 uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
89 uno::Reference<lang::XComponent> xDstDoc(pDocShell->GetModel(), uno::UNO_QUERY_THROW);
90 xImporter->setTargetDocument(xDstDoc);
91
92 const uno::Reference<text::XTextRange> xInsertTextRange
93 = SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), nullptr);
94
95 uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
96 uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
97 { { "InputStream",
98 uno::Any(uno::Reference<io::XStream>(new utl::OStreamWrapper(*m_pStream))) },
99 { "InsertMode", uno::Any(true) },
100 { "TextInsertModeRange", uno::Any(xInsertTextRange) } }));
101 auto ret = ERRCODE_NONE;
102 try
103 {
104 xFilter->filter(aDescriptor);
105 }
106 catch (uno::Exception const&)
107 {
108 TOOLS_WARN_EXCEPTION("sw.rtf", "SwRTFReader::Read()");
109 ret = ERR_SWG_READ_ERROR;
110 }
111
112 // Clean up the fake paragraphs.
113 SwUnoInternalPaM aPam(rDoc);
114 ::sw::XTextRangeToSwPaM(aPam, xInsertPosition);
115 if (pSttNdIdx->GetIndex())
116 {
117 // If we are in insert mode, join the split node that is in front
118 // of the new content with the first new node. Or in other words:
119 // Revert the first split node.
120 SwTextNode* pTextNode = pSttNdIdx->GetNode().GetTextNode();
121 SwNodeIndex aNxtIdx(*pSttNdIdx);
122 if (pTextNode && pTextNode->CanJoinNext(&aNxtIdx)
123 && pSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex())
124 {
125 // If the PaM points to the first new node, move the PaM to the
126 // end of the previous node.
127 if (aPam.GetPoint()->nNode == aNxtIdx)
128 {
129 aPam.GetPoint()->Assign(*pTextNode, pTextNode->GetText().getLength());
130 }
131 // If the first new node isn't empty, convert the node's text
132 // attributes into hints. Otherwise, set the new node's
133 // paragraph style at the previous (empty) node.
134 SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode();
135 if (pTextNode->GetText().getLength())
136 pDelNd->FormatToTextAttr(pTextNode);
137 else
138 {
139 pTextNode->ChgFormatColl(pDelNd->GetTextColl());
140 if (!pDelNd->GetNoCondAttr(RES_PARATR_LIST_ID, /*bInParents=*/false))
141 {
142 // Lists would need manual merging, but copy paragraph direct formatting
143 // otherwise.
144 pDelNd->CopyCollFormat(*pTextNode);
145 }
146 }
147 pTextNode->JoinNext();
148 }
149 }
150
151 if (pSttNdIdx2->GetIndex())
152 {
153 // If we are in insert mode, join the split node that is after
154 // the new content with the last new node. Or in other words:
155 // Revert the second split node.
156 SwTextNode* pTextNode = pSttNdIdx2->GetNode().GetTextNode();
157 SwNodeIndex aPrevIdx(*pSttNdIdx2);
158 if (pTextNode && pTextNode->CanJoinPrev(&aPrevIdx)
159 && pSttNdIdx2->GetIndex() - 1 == aPrevIdx.GetIndex())
160 {
161 // If the last new node isn't empty, convert the node's text
162 // attributes into hints. Otherwise, set the new node's
163 // paragraph style at the next (empty) node.
164 SwTextNode* pDelNd = aPrevIdx.GetNode().GetTextNode();
165 if (pTextNode->GetText().getLength())
166 pDelNd->FormatToTextAttr(pTextNode);
167 else
168 pTextNode->ChgFormatColl(pDelNd->GetTextColl());
169 pTextNode->JoinPrev();
170 }
171 }
172
173 return ret;
174}
175
176extern "C" SAL_DLLPUBLIC_EXPORT Reader* ImportRTF() { return new SwRTFReader; }
177
178extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportRTF(SvStream& rStream)
179{
181
182 SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
183 xDocSh->DoInitNew();
184
185 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
187 uno::Reference<uno::XInterface> xInterface(
188 xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
189 uno::UNO_SET_THROW);
190
191 uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
192 uno::Reference<lang::XComponent> xDstDoc(xDocSh->GetModel(), uno::UNO_QUERY_THROW);
193 xImporter->setTargetDocument(xDstDoc);
194
195 uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
196 uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
197 { { "InputStream",
198 uno::Any(uno::Reference<io::XStream>(new utl::OStreamWrapper(rStream))) } }));
199 bool bRet = true;
200 try
201 {
202 xFilter->filter(aDescriptor);
203 }
204 catch (...)
205 {
206 bRet = false;
207 }
208 return bRet;
209}
210
211/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart)=0
Split a node at rPos (implemented only for TextNode).
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
virtual ErrCode Read(SwDoc &, const OUString &rBaseURL, SwPaM &, const OUString &)=0
css::uno::Reference< css::frame::XModel3 > GetModel() const
bool CanJoinNext(SwNodeIndex *pIdx=nullptr) const
Is it possible to join two nodes? In pIdx the second position can be returned.
Definition: node.cxx:1844
bool CanJoinPrev(SwNodeIndex *pIdx=nullptr) const
Can we join two Nodes? We can return the 2nd position in pIdx.
Definition: node.cxx:1868
const SfxPoolItem * GetNoCondAttr(sal_uInt16 nWhich, bool bInParents) const
Obtains attribute that is not delivered via conditional style!
Definition: node.cxx:1804
Definition: doc.hxx:192
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:316
SwNodes & GetNodes()
Definition: doc.hxx:413
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:427
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter <bResetListAttrs>.
Definition: docfmt.cxx:1082
SwDocShell * GetDocShell()
Definition: doc.hxx:1356
Marks a node in the document model.
Definition: ndindex.hxx:31
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:871
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:183
bool Move(SwMoveFnCollection const &fnMove=fnMoveForward, SwGoInDoc fnGo=GoInContent)
Movement of cursor.
Definition: pam.cxx:614
const SwPosition * GetPoint() const
Definition: pam.hxx:257
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:86
virtual SwContentNode * JoinNext() override
Definition: ndtxt.cxx:981
void FormatToTextAttr(SwTextNode *pNd)
Convey attributes of an AttrSet (AutoFormat) to SwpHintsArray.
Definition: thints.cxx:2534
void JoinPrev()
Definition: ndtxt.cxx:1096
virtual SwFormatColl * ChgFormatColl(SwFormatColl *) override
Definition: ndtxt.cxx:3978
void CopyCollFormat(SwTextNode &rDestNd, bool bUndoForChgFormatColl=true)
Copy collection with all auto formats to dest-node.
Definition: ndcopy.cxx:336
const OUString & GetText() const
Definition: ndtxt.hxx:222
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:865
static css::uno::Reference< css::text::XTextRange > CreateXTextRange(SwDoc &rDoc, const SwPosition &rPos, const SwPosition *const pMark)
Definition: unoobj2.cxx:1211
#define TOOLS_WARN_EXCEPTION(area, stream)
#define ERRCODE_NONE
constexpr TypedWhichId< SfxStringItem > RES_PARATR_LIST_ID(RES_PARATR_LIST_BEGIN)
static OUString Read(SvStream &rStream)
Definition: ww8scan.cxx:6697
void ensure()
Definition: swdll.cxx:67
Reference< XMultiServiceFactory > getProcessServiceFactory()
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
bool XTextRangeToSwPaM(SwUnoInternalPaM &rToFill, const uno::Reference< text::XTextRange > &xTextRange, ::sw::TextRangeMode const eMode)
Definition: unoobj2.cxx:1104
SwMoveFnCollection const & fnMoveBackward
Definition: paminit.cxx:58
@ RES_POOLCOLL_STANDARD
Standard.
Definition: poolfmt.hxx:250
Marks a position in the document model.
Definition: pam.hxx:37
SwNodeOffset GetNodeIndex() const
Definition: pam.hxx:77
#define ERR_SWG_READ_ERROR
Definition: swerror.h:25
SAL_DLLPUBLIC_EXPORT bool TestImportRTF(SvStream &rStream)
Definition: swparrtf.cxx:178
SAL_DLLPUBLIC_EXPORT Reader * ImportRTF()
Definition: swparrtf.cxx:176