1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <poolfmt.hxx>
21 #include <shellio.hxx>
25 #include <IDocumentStylePoolAccess.hxx>
29 #include <unotextrange.hxx>
31 #include <unotools/streamwrap.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/propertysequence.hxx>
34 #include <comphelper/diagnose_ex.hxx>
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>
41 using namespace ::com::sun::star
;
45 /// Glue class to call RtfImport as an internal filter, needed by copy&paste support.
46 class SwRTFReader
: public Reader
48 ErrCode
Read(SwDoc
& rDoc
, const OUString
& rBaseURL
, SwPaM
& rPam
,
49 const OUString
& rFileName
) override
;
53 ErrCode
SwRTFReader::Read(SwDoc
& rDoc
, const OUString
& /*rBaseURL*/, SwPaM
& rPam
,
54 const OUString
& /*rFileName*/)
57 return ERR_SWG_READ_ERROR
;
59 // We want to work in an empty paragraph.
60 // Step 1: XTextRange will be updated when content is inserted, so we know
62 const rtl::Reference
<SwXTextRange
> xInsertPosition
63 = SwXTextRange::CreateXTextRange(rDoc
, *rPam
.GetPoint(), nullptr);
64 auto pSttNdIdx
= std::make_shared
<SwNodeIndex
>(rDoc
.GetNodes());
65 const SwPosition
* pPos
= rPam
.GetPoint();
67 // Step 2: Split once and remember the node that has been split.
68 rDoc
.getIDocumentContentOperations().SplitNode(*pPos
, false);
69 *pSttNdIdx
= pPos
->GetNodeIndex() - 1;
71 // Step 3: Split again.
72 rDoc
.getIDocumentContentOperations().SplitNode(*pPos
, false);
73 auto pSttNdIdx2
= std::make_shared
<SwNodeIndex
>(rDoc
.GetNodes());
74 *pSttNdIdx2
= pPos
->GetNodeIndex();
76 // Step 4: Insert all content into the new node
77 rPam
.Move(fnMoveBackward
);
78 rDoc
.SetTextFormatColl(
79 rPam
, rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
, false));
81 SwDocShell
* pDocShell(rDoc
.GetDocShell());
82 uno::Reference
<lang::XMultiServiceFactory
> xMultiServiceFactory(
83 comphelper::getProcessServiceFactory());
84 uno::Reference
<uno::XInterface
> xInterface(
85 xMultiServiceFactory
->createInstance("com.sun.star.comp.Writer.RtfFilter"),
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
);
92 const rtl::Reference
<SwXTextRange
> xInsertTextRange
93 = SwXTextRange::CreateXTextRange(rDoc
, *rPam
.GetPoint(), nullptr);
95 uno::Reference
<document::XFilter
> xFilter(xInterface
, uno::UNO_QUERY_THROW
);
96 uno::Sequence
<beans::PropertyValue
> aDescriptor(comphelper::InitPropertySequence(
98 uno::Any(uno::Reference
<io::XStream
>(new utl::OStreamWrapper(*m_pStream
))) },
99 { "InsertMode", uno::Any(true) },
100 { "TextInsertModeRange",
101 uno::Any(uno::Reference
<text::XTextRange
>(xInsertTextRange
)) } }));
102 auto ret
= ERRCODE_NONE
;
105 xFilter
->filter(aDescriptor
);
107 catch (uno::Exception
const&)
109 TOOLS_WARN_EXCEPTION("sw.rtf", "SwRTFReader::Read()");
110 ret
= ERR_SWG_READ_ERROR
;
113 // Clean up the fake paragraphs.
114 SwUnoInternalPaM
aPam(rDoc
);
115 ::sw::XTextRangeToSwPaM(aPam
, xInsertPosition
);
116 if (pSttNdIdx
->GetIndex())
118 // If we are in insert mode, join the split node that is in front
119 // of the new content with the first new node. Or in other words:
120 // Revert the first split node.
121 SwTextNode
* pTextNode
= pSttNdIdx
->GetNode().GetTextNode();
122 SwNodeIndex
aNxtIdx(*pSttNdIdx
);
123 if (pTextNode
&& pTextNode
->CanJoinNext(&aNxtIdx
)
124 && pSttNdIdx
->GetIndex() + 1 == aNxtIdx
.GetIndex())
126 // If the PaM points to the first new node, move the PaM to the
127 // end of the previous node.
128 if (aPam
.GetPoint()->GetNode() == aNxtIdx
.GetNode())
130 aPam
.GetPoint()->Assign(*pTextNode
, pTextNode
->GetText().getLength());
132 // If the first new node isn't empty, convert the node's text
133 // attributes into hints. Otherwise, set the new node's
134 // paragraph style at the previous (empty) node.
135 SwTextNode
* pDelNd
= aNxtIdx
.GetNode().GetTextNode();
136 if (pTextNode
->GetText().getLength())
137 pDelNd
->FormatToTextAttr(pTextNode
);
140 pTextNode
->ChgFormatColl(pDelNd
->GetTextColl());
141 if (!pDelNd
->GetNoCondAttr(RES_PARATR_LIST_ID
, /*bInParents=*/false))
143 // Lists would need manual merging, but copy paragraph direct formatting
145 pDelNd
->CopyCollFormat(*pTextNode
);
148 pTextNode
->JoinNext();
152 if (pSttNdIdx2
->GetIndex())
154 // If we are in insert mode, join the split node that is after
155 // the new content with the last new node. Or in other words:
156 // Revert the second split node.
157 SwTextNode
* pTextNode
= pSttNdIdx2
->GetNode().GetTextNode();
158 SwNodeIndex
aPrevIdx(*pSttNdIdx2
);
159 if (pTextNode
&& pTextNode
->CanJoinPrev(&aPrevIdx
)
160 && pSttNdIdx2
->GetIndex() - 1 == aPrevIdx
.GetIndex())
162 // If the last new node isn't empty, convert the node's text
163 // attributes into hints. Otherwise, set the new node's
164 // paragraph style at the next (empty) node.
165 SwTextNode
* pDelNd
= aPrevIdx
.GetNode().GetTextNode();
166 if (pTextNode
->GetText().getLength())
167 pDelNd
->FormatToTextAttr(pTextNode
);
169 pTextNode
->ChgFormatColl(pDelNd
->GetTextColl());
170 pTextNode
->JoinPrev();
177 extern "C" SAL_DLLPUBLIC_EXPORT Reader
* ImportRTF() { return new SwRTFReader
; }
179 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportRTF(SvStream
& rStream
)
183 SfxObjectShellLock
xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL
));
186 uno::Reference
<lang::XMultiServiceFactory
> xMultiServiceFactory(
187 comphelper::getProcessServiceFactory());
188 uno::Reference
<uno::XInterface
> xInterface(
189 xMultiServiceFactory
->createInstance("com.sun.star.comp.Writer.RtfFilter"),
192 uno::Reference
<document::XImporter
> xImporter(xInterface
, uno::UNO_QUERY_THROW
);
193 uno::Reference
<lang::XComponent
> xDstDoc(xDocSh
->GetModel(), uno::UNO_QUERY_THROW
);
194 xImporter
->setTargetDocument(xDstDoc
);
196 uno::Reference
<document::XFilter
> xFilter(xInterface
, uno::UNO_QUERY_THROW
);
197 uno::Sequence
<beans::PropertyValue
> aDescriptor(comphelper::InitPropertySequence(
199 uno::Any(uno::Reference
<io::XStream
>(new utl::OStreamWrapper(rStream
))) } }));
203 xFilter
->filter(aDescriptor
);
212 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */