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 
31 #include <unotools/streamwrap.hxx>
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/lang/XMultiServiceFactory.hpp>
39 
40 using namespace ::com::sun::star;
41 
42 namespace
43 {
45 class SwRTFReader : public Reader
46 {
47  ErrCode Read(SwDoc& rDoc, const OUString& rBaseURL, SwPaM& rPam,
48  const OUString& rFileName) override;
49 };
50 }
51 
52 ErrCode SwRTFReader::Read(SwDoc& rDoc, const OUString& /*rBaseURL*/, SwPaM& rPam,
53  const OUString& /*rFileName*/)
54 {
55  if (!m_pStream)
56  return ERR_SWG_READ_ERROR;
57 
58  // We want to work in an empty paragraph.
59  // Step 1: XTextRange will be updated when content is inserted, so we know
60  // the end position.
61  const uno::Reference<text::XTextRange> xInsertPosition
62  = SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), nullptr);
63  auto pSttNdIdx = std::make_shared<SwNodeIndex>(rDoc.GetNodes());
64  const SwPosition* pPos = rPam.GetPoint();
65 
66  // Step 2: Split once and remember the node that has been split.
67  rDoc.getIDocumentContentOperations().SplitNode(*pPos, false);
68  *pSttNdIdx = pPos->nNode.GetIndex() - 1;
69 
70  // Step 3: Split again.
71  rDoc.getIDocumentContentOperations().SplitNode(*pPos, false);
72  auto pSttNdIdx2 = std::make_shared<SwNodeIndex>(rDoc.GetNodes());
73  *pSttNdIdx2 = pPos->nNode.GetIndex();
74 
75  // Step 4: Insert all content into the new node
76  rPam.Move(fnMoveBackward);
77  rDoc.SetTextFormatColl(
79 
80  SwDocShell* pDocShell(rDoc.GetDocShell());
81  uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
83  uno::Reference<uno::XInterface> xInterface(
84  xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
85  uno::UNO_SET_THROW);
86 
87  uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
88  uno::Reference<lang::XComponent> xDstDoc(pDocShell->GetModel(), uno::UNO_QUERY_THROW);
89  xImporter->setTargetDocument(xDstDoc);
90 
91  const uno::Reference<text::XTextRange> xInsertTextRange
92  = SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), nullptr);
93 
94  uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
95  uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
96  { { "InputStream",
97  uno::Any(uno::Reference<io::XStream>(new utl::OStreamWrapper(*m_pStream))) },
98  { "InsertMode", uno::Any(true) },
99  { "TextInsertModeRange", uno::Any(xInsertTextRange) } }));
100  auto ret = ERRCODE_NONE;
101  try
102  {
103  xFilter->filter(aDescriptor);
104  }
105  catch (uno::Exception const&)
106  {
107  TOOLS_WARN_EXCEPTION("sw.rtf", "SwRTFReader::Read()");
108  ret = ERR_SWG_READ_ERROR;
109  }
110 
111  // Clean up the fake paragraphs.
112  SwUnoInternalPaM aPam(rDoc);
113  ::sw::XTextRangeToSwPaM(aPam, xInsertPosition);
114  if (pSttNdIdx->GetIndex())
115  {
116  // If we are in insert mode, join the split node that is in front
117  // of the new content with the first new node. Or in other words:
118  // Revert the first split node.
119  SwTextNode* pTextNode = pSttNdIdx->GetNode().GetTextNode();
120  SwNodeIndex aNxtIdx(*pSttNdIdx);
121  if (pTextNode && pTextNode->CanJoinNext(&aNxtIdx)
122  && pSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex())
123  {
124  // If the PaM points to the first new node, move the PaM to the
125  // end of the previous node.
126  if (aPam.GetPoint()->nNode == aNxtIdx)
127  {
128  aPam.GetPoint()->nNode = *pSttNdIdx;
129  aPam.GetPoint()->nContent.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  pTextNode->ChgFormatColl(pDelNd->GetTextColl());
139  pTextNode->JoinNext();
140  }
141  }
142 
143  if (pSttNdIdx2->GetIndex())
144  {
145  // If we are in insert mode, join the split node that is after
146  // the new content with the last new node. Or in other words:
147  // Revert the second split node.
148  SwTextNode* pTextNode = pSttNdIdx2->GetNode().GetTextNode();
149  SwNodeIndex aPrevIdx(*pSttNdIdx2);
150  if (pTextNode && pTextNode->CanJoinPrev(&aPrevIdx)
151  && pSttNdIdx2->GetIndex() - 1 == aPrevIdx.GetIndex())
152  {
153  // If the last new node isn't empty, convert the node's text
154  // attributes into hints. Otherwise, set the new node's
155  // paragraph style at the next (empty) node.
156  SwTextNode* pDelNd = aPrevIdx.GetNode().GetTextNode();
157  if (pTextNode->GetText().getLength())
158  pDelNd->FormatToTextAttr(pTextNode);
159  else
160  pTextNode->ChgFormatColl(pDelNd->GetTextColl());
161  pTextNode->JoinPrev();
162  }
163  }
164 
165  return ret;
166 }
167 
168 extern "C" SAL_DLLPUBLIC_EXPORT Reader* ImportRTF() { return new SwRTFReader; }
169 
170 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportRTF(SvStream& rStream)
171 {
173 
174  SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
175  xDocSh->DoInitNew();
176 
177  uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
179  uno::Reference<uno::XInterface> xInterface(
180  xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
181  uno::UNO_SET_THROW);
182 
183  uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
184  uno::Reference<lang::XComponent> xDstDoc(xDocSh->GetModel(), uno::UNO_QUERY_THROW);
185  xImporter->setTargetDocument(xDstDoc);
186 
187  uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
188  uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
189  { { "InputStream",
190  uno::Any(uno::Reference<io::XStream>(new utl::OStreamWrapper(rStream))) } }));
191  bool bRet = true;
192  try
193  {
194  xFilter->filter(aDescriptor);
195  }
196  catch (...)
197  {
198  bRet = false;
199  }
200  return bRet;
201 }
202 
203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Marks a position in the document model.
Definition: pam.hxx:35
const OUString & GetText() const
Definition: ndtxt.hxx:210
SwDocShell * GetDocShell()
Definition: doc.hxx:1346
Definition: doc.hxx:185
css::uno::Reference< css::frame::XModel > GetModel() const
SAL_DLLPUBLIC_EXPORT Reader * ImportRTF()
Definition: swparrtf.cxx:168
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:314
bool CanJoinNext(SwNodeIndex *pIdx=nullptr) const
Is it possible to join two nodes? In pIdx the second position can be returned.
Definition: node.cxx:1788
virtual SwContentNode * JoinNext() override
Definition: ndtxt.cxx:938
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter .
Definition: docfmt.cxx:1064
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:425
static OUString Read(SvStream &rStream)
Definition: ww8scan.cxx:6618
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)
Definition: unoobj2.cxx:950
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
bool Move(SwMoveFnCollection const &fnMove=fnMoveForward, SwGoInDoc fnGo=GoInContent)
Movement of cursor.
Definition: pam.cxx:495
#define TOOLS_WARN_EXCEPTION(area, stream)
const SwPosition * GetPoint() const
Definition: pam.hxx:207
bool CanJoinPrev(SwNodeIndex *pIdx=nullptr) const
Can we join two Nodes? We can return the 2nd position in pIdx.
Definition: node.cxx:1812
void ensure()
Definition: swdll.cxx:67
virtual SwFormatColl * ChgFormatColl(SwFormatColl *) override
Definition: ndtxt.cxx:3920
Marks a node in the document model.
Definition: ndindex.hxx:31
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
Reference< XMultiServiceFactory > getProcessServiceFactory()
#define ERRCODE_NONE
virtual ErrCode Read(SwDoc &, const OUString &rBaseURL, SwPaM &, const OUString &)=0
bool DoInitNew(SfxMedium *pMedium=nullptr)
SwNodes & GetNodes()
Definition: doc.hxx:403
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
SwMoveFnCollection const & fnMoveBackward
Definition: paminit.cxx:58
virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart)=0
Split a node at rPos (implemented only for TextNode).
#define ERR_SWG_READ_ERROR
Definition: swerror.h:25
SAL_DLLPUBLIC_EXPORT bool TestImportRTF(SvStream &rStream)
Definition: swparrtf.cxx:170
static css::uno::Reference< css::text::XTextRange > CreateXTextRange(SwDoc &rDoc, const SwPosition &rPos, const SwPosition *const pMark)
Definition: unoobj2.cxx:1052
void JoinPrev()
Definition: ndtxt.cxx:1036
void FormatToTextAttr(SwTextNode *pNd)
Convey attributes of an AttrSet (AutoFormat) to SwpHintsArray.
Definition: thints.cxx:2495
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:842
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:836