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/frame/XModel.hpp>
39 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
40 
41 using namespace ::com::sun::star;
42 
43 namespace
44 {
46 class SwRTFReader : public Reader
47 {
48  ErrCode Read(SwDoc& rDoc, const OUString& rBaseURL, SwPaM& rPam,
49  const OUString& rFileName) override;
50 };
51 }
52 
53 ErrCode 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->nNode.GetIndex() - 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->nNode.GetIndex();
75 
76  // Step 4: Insert all content into the new node
77  rPam.Move(fnMoveBackward);
78  rDoc.SetTextFormatColl(
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()->nNode = *pSttNdIdx;
130  aPam.GetPoint()->nContent.Assign(pTextNode, pTextNode->GetText().getLength());
131  }
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);
138  else
139  pTextNode->ChgFormatColl(pDelNd->GetTextColl());
140  pTextNode->JoinNext();
141  }
142  }
143 
144  if (pSttNdIdx2->GetIndex())
145  {
146  // If we are in insert mode, join the split node that is after
147  // the new content with the last new node. Or in other words:
148  // Revert the second split node.
149  SwTextNode* pTextNode = pSttNdIdx2->GetNode().GetTextNode();
150  SwNodeIndex aPrevIdx(*pSttNdIdx2);
151  if (pTextNode && pTextNode->CanJoinPrev(&aPrevIdx)
152  && pSttNdIdx2->GetIndex() - 1 == aPrevIdx.GetIndex())
153  {
154  // If the last new node isn't empty, convert the node's text
155  // attributes into hints. Otherwise, set the new node's
156  // paragraph style at the next (empty) node.
157  SwTextNode* pDelNd = aPrevIdx.GetNode().GetTextNode();
158  if (pTextNode->GetText().getLength())
159  pDelNd->FormatToTextAttr(pTextNode);
160  else
161  pTextNode->ChgFormatColl(pDelNd->GetTextColl());
162  pTextNode->JoinPrev();
163  }
164  }
165 
166  return ret;
167 }
168 
169 extern "C" SAL_DLLPUBLIC_EXPORT Reader* ImportRTF() { return new SwRTFReader; }
170 
171 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportRTF(SvStream& rStream)
172 {
174 
175  SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
176  xDocSh->DoInitNew();
177 
178  uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
180  uno::Reference<uno::XInterface> xInterface(
181  xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
182  uno::UNO_SET_THROW);
183 
184  uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
185  uno::Reference<lang::XComponent> xDstDoc(xDocSh->GetModel(), uno::UNO_QUERY_THROW);
186  xImporter->setTargetDocument(xDstDoc);
187 
188  uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
189  uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
190  { { "InputStream",
191  uno::Any(uno::Reference<io::XStream>(new utl::OStreamWrapper(rStream))) } }));
192  bool bRet = true;
193  try
194  {
195  xFilter->filter(aDescriptor);
196  }
197  catch (...)
198  {
199  bRet = false;
200  }
201  return bRet;
202 }
203 
204 /* 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:211
SwDocShell * GetDocShell()
Definition: doc.hxx:1348
Definition: doc.hxx:184
css::uno::Reference< css::frame::XModel > GetModel() const
SAL_DLLPUBLIC_EXPORT Reader * ImportRTF()
Definition: swparrtf.cxx:169
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:1844
virtual SwContentNode * JoinNext() override
Definition: ndtxt.cxx:939
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:1072
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:425
static OUString Read(SvStream &rStream)
Definition: ww8scan.cxx:6622
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:952
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:501
#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:1868
void ensure()
Definition: swdll.cxx:67
virtual SwFormatColl * ChgFormatColl(SwFormatColl *) override
Definition: ndtxt.cxx:3921
Marks a node in the document model.
Definition: ndindex.hxx:31
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
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:171
static css::uno::Reference< css::text::XTextRange > CreateXTextRange(SwDoc &rDoc, const SwPosition &rPos, const SwPosition *const pMark)
Definition: unoobj2.cxx:1054
void JoinPrev()
Definition: ndtxt.cxx:1037
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:836
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:830