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 
43 class SwRTFReader : public Reader
44 {
45  ErrCode Read(SwDoc& rDoc, const OUString& rBaseURL, SwPaM& rPam,
46  const OUString& rFileName) override;
47 };
48 
49 ErrCode SwRTFReader::Read(SwDoc& rDoc, const OUString& /*rBaseURL*/, SwPaM& rPam,
50  const OUString& /*rFileName*/)
51 {
52  if (!m_pStream)
53  return ERR_SWG_READ_ERROR;
54 
55  // We want to work in an empty paragraph.
56  // Step 1: XTextRange will be updated when content is inserted, so we know
57  // the end position.
58  const uno::Reference<text::XTextRange> xInsertPosition
59  = SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), nullptr);
60  std::shared_ptr<SwNodeIndex> pSttNdIdx(new SwNodeIndex(rDoc.GetNodes()));
61  const SwPosition* pPos = rPam.GetPoint();
62 
63  // Step 2: Split once and remember the node that has been split.
64  rDoc.getIDocumentContentOperations().SplitNode(*pPos, false);
65  *pSttNdIdx = pPos->nNode.GetIndex() - 1;
66 
67  // Step 3: Split again.
68  rDoc.getIDocumentContentOperations().SplitNode(*pPos, false);
69  std::shared_ptr<SwNodeIndex> pSttNdIdx2(new SwNodeIndex(rDoc.GetNodes()));
70  *pSttNdIdx2 = pPos->nNode.GetIndex();
71 
72  // Step 4: Insert all content into the new node
73  rPam.Move(fnMoveBackward);
74  rDoc.SetTextFormatColl(
76 
77  SwDocShell* pDocShell(rDoc.GetDocShell());
78  uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
80  uno::Reference<uno::XInterface> xInterface(
81  xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
82  uno::UNO_SET_THROW);
83 
84  uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
85  uno::Reference<lang::XComponent> xDstDoc(pDocShell->GetModel(), uno::UNO_QUERY_THROW);
86  xImporter->setTargetDocument(xDstDoc);
87 
88  const uno::Reference<text::XTextRange> xInsertTextRange
89  = SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), nullptr);
90 
91  uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
92  uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
93  { { "InputStream",
94  uno::Any(uno::Reference<io::XStream>(new utl::OStreamWrapper(*m_pStream))) },
95  { "InsertMode", uno::Any(true) },
96  { "TextInsertModeRange", uno::Any(xInsertTextRange) } }));
97  auto ret = ERRCODE_NONE;
98  try
99  {
100  xFilter->filter(aDescriptor);
101  }
102  catch (uno::Exception const&)
103  {
104  TOOLS_WARN_EXCEPTION("sw.rtf", "SwRTFReader::Read()");
105  ret = ERR_SWG_READ_ERROR;
106  }
107 
108  // Clean up the fake paragraphs.
109  SwUnoInternalPaM aPam(rDoc);
110  ::sw::XTextRangeToSwPaM(aPam, xInsertPosition);
111  if (pSttNdIdx->GetIndex())
112  {
113  // If we are in insert mode, join the split node that is in front
114  // of the new content with the first new node. Or in other words:
115  // Revert the first split node.
116  SwTextNode* pTextNode = pSttNdIdx->GetNode().GetTextNode();
117  SwNodeIndex aNxtIdx(*pSttNdIdx);
118  if (pTextNode && pTextNode->CanJoinNext(&aNxtIdx)
119  && pSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex())
120  {
121  // If the PaM points to the first new node, move the PaM to the
122  // end of the previous node.
123  if (aPam.GetPoint()->nNode == aNxtIdx)
124  {
125  aPam.GetPoint()->nNode = *pSttNdIdx;
126  aPam.GetPoint()->nContent.Assign(pTextNode, pTextNode->GetText().getLength());
127  }
128  // If the first new node isn't empty, convert the node's text
129  // attributes into hints. Otherwise, set the new node's
130  // paragraph style at the previous (empty) node.
131  SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode();
132  if (pTextNode->GetText().getLength())
133  pDelNd->FormatToTextAttr(pTextNode);
134  else
135  pTextNode->ChgFormatColl(pDelNd->GetTextColl());
136  pTextNode->JoinNext();
137  }
138  }
139 
140  if (pSttNdIdx2->GetIndex())
141  {
142  // If we are in insert mode, join the split node that is after
143  // the new content with the last new node. Or in other words:
144  // Revert the second split node.
145  SwTextNode* pTextNode = pSttNdIdx2->GetNode().GetTextNode();
146  SwNodeIndex aPrevIdx(*pSttNdIdx2);
147  if (pTextNode && pTextNode->CanJoinPrev(&aPrevIdx)
148  && pSttNdIdx2->GetIndex() - 1 == aPrevIdx.GetIndex())
149  {
150  // If the last new node isn't empty, convert the node's text
151  // attributes into hints. Otherwise, set the new node's
152  // paragraph style at the next (empty) node.
153  SwTextNode* pDelNd = aPrevIdx.GetNode().GetTextNode();
154  if (pTextNode->GetText().getLength())
155  pDelNd->FormatToTextAttr(pTextNode);
156  else
157  pTextNode->ChgFormatColl(pDelNd->GetTextColl());
158  pTextNode->JoinPrev();
159  }
160  }
161 
162  return ret;
163 }
164 
165 extern "C" SAL_DLLPUBLIC_EXPORT Reader* ImportRTF() { return new SwRTFReader; }
166 
167 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportRTF(SvStream& rStream)
168 {
170 
171  SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
172  xDocSh->DoInitNew();
173 
174  uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
176  uno::Reference<uno::XInterface> xInterface(
177  xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
178  uno::UNO_SET_THROW);
179 
180  uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
181  uno::Reference<lang::XComponent> xDstDoc(xDocSh->GetModel(), uno::UNO_QUERY_THROW);
182  xImporter->setTargetDocument(xDstDoc);
183 
184  uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
185  uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
186  { { "InputStream",
187  uno::Any(uno::Reference<io::XStream>(new utl::OStreamWrapper(rStream))) } }));
188  bool bRet = true;
189  try
190  {
191  xFilter->filter(aDescriptor);
192  }
193  catch (...)
194  {
195  bRet = false;
196  }
197  return bRet;
198 }
199 
200 /* 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:1340
SwNodeIndex nNode
Definition: pam.hxx:37
Definition: doc.hxx:185
SwNode & GetNode() const
Definition: ndindex.hxx:118
css::uno::Reference< css::frame::XModel > GetModel() const
SAL_DLLPUBLIC_EXPORT Reader * ImportRTF()
Definition: swparrtf.cxx:165
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:347
bool CanJoinNext(SwNodeIndex *pIdx=nullptr) const
Is it possible to join two nodes? In pIdx the second position can be returned.
Definition: node.cxx:1775
virtual SwContentNode * JoinNext() override
Definition: ndtxt.cxx:949
SwIndex nContent
Definition: pam.hxx:38
ErrCode Read(SwDoc &rDoc, const OUString &rBaseURL, SwPaM &rPam, const OUString &rFileName) override
Definition: swparrtf.cxx:49
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:1096
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:458
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
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:1009
Glue class to call RtfImport as an internal filter, needed by copy&paste support. ...
Definition: swparrtf.cxx:43
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:483
#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:1799
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:198
void ensure()
Definition: swdll.cxx:69
virtual SwFormatColl * ChgFormatColl(SwFormatColl *) override
Definition: ndtxt.cxx:3927
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
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.
SvStream * m_pStream
Definition: shellio.hxx:210
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:167
static css::uno::Reference< css::text::XTextRange > CreateXTextRange(SwDoc &rDoc, const SwPosition &rPos, const SwPosition *const pMark)
Definition: unoobj2.cxx:1113
void JoinPrev()
Definition: ndtxt.cxx:1047
void FormatToTextAttr(SwTextNode *pNd)
Convey attributes of an AttrSet (AutoFormat) to SwpHintsArray.
Definition: thints.cxx:2479
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:843
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:837