LibreOffice Module sw (master)  1
ascatr.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 <hintids.hxx>
21 #include <tools/stream.hxx>
22 #include <comphelper/string.hxx>
23 #include <pam.hxx>
24 #include <doc.hxx>
25 #include <ndtxt.hxx>
27 #include <redline.hxx>
28 #include "wrtasc.hxx"
29 #include <txatbase.hxx>
30 #include <txtfld.hxx>
31 #include <fmtftn.hxx>
32 #include <fmtfld.hxx>
33 #include <fldbas.hxx>
34 #include <ftninfo.hxx>
35 #include <numrule.hxx>
36 
37 #include <algorithm>
38 
39 /*
40  * This file contains all output functions of the ASCII-Writer;
41  * For all nodes, attributes, formats and chars.
42  */
43 
44 namespace {
45 
46 class SwASC_AttrIter
47 {
48  SwASCWriter& rWrt;
49  const SwTextNode& rNd;
50  sal_Int32 nCurrentSwPos;
51 
52  sal_Int32 SearchNext( sal_Int32 nStartPos );
53 
54 public:
55  SwASC_AttrIter( SwASCWriter& rWrt, const SwTextNode& rNd, sal_Int32 nStt );
56 
57  void NextPos()
58  {
59  nCurrentSwPos = SearchNext( nCurrentSwPos + 1 );
60  }
61 
62  sal_Int32 WhereNext() const
63  {
64  return nCurrentSwPos;
65  }
66 
67  bool OutAttr( sal_Int32 nSwPos );
68 };
69 
70 }
71 
72 SwASC_AttrIter::SwASC_AttrIter(
73  SwASCWriter& rWr,
74  const SwTextNode& rTextNd,
75  sal_Int32 nStt )
76  : rWrt( rWr )
77  , rNd( rTextNd )
78  , nCurrentSwPos( 0 )
79 {
80  nCurrentSwPos = SearchNext( nStt + 1 );
81 }
82 
83 sal_Int32 SwASC_AttrIter::SearchNext( sal_Int32 nStartPos )
84 {
85  sal_Int32 nMinPos = SAL_MAX_INT32;
86  const SwpHints* pTextAttrs = rNd.GetpSwpHints();
87  if( pTextAttrs )
88  {
89  // TODO: This can be optimized, if we make use of the fact that the TextAttrs
90  // are sorted by starting position. We would need to remember two indices, however.
91  for ( size_t i = 0; i < pTextAttrs->Count(); ++i )
92  {
93  const SwTextAttr* pHt = pTextAttrs->Get(i);
94  if ( pHt->HasDummyChar() )
95  {
96  sal_Int32 nPos = pHt->GetStart();
97 
98  if( nPos >= nStartPos && nPos <= nMinPos )
99  nMinPos = nPos;
100 
101  if( ( ++nPos ) >= nStartPos && nPos < nMinPos )
102  nMinPos = nPos;
103  }
104  else if ( pHt->HasContent() )
105  {
106  const sal_Int32 nHintStart = pHt->GetStart();
107  if ( nHintStart >= nStartPos && nHintStart <= nMinPos )
108  {
109  nMinPos = nHintStart;
110  }
111 
112  const sal_Int32 nHintEnd = pHt->End() ? *pHt->End() : COMPLETE_STRING;
113  if ( nHintEnd >= nStartPos && nHintEnd < nMinPos )
114  {
115  nMinPos = nHintEnd;
116  }
117  }
118  }
119  }
120  return nMinPos;
121 }
122 
123 bool SwASC_AttrIter::OutAttr( sal_Int32 nSwPos )
124 {
125  bool bRet = false;
126  const SwpHints* pTextAttrs = rNd.GetpSwpHints();
127  if( pTextAttrs )
128  {
129  for( size_t i = 0; i < pTextAttrs->Count(); ++i )
130  {
131  const SwTextAttr* pHt = pTextAttrs->Get(i);
132  if ( ( pHt->HasDummyChar()
133  || pHt->HasContent() )
134  && nSwPos == pHt->GetStart() )
135  {
136  bRet = true;
137  OUString sOut;
138  switch( pHt->Which() )
139  {
140  case RES_TXTATR_FIELD:
143  sOut = static_txtattr_cast<SwTextField const*>(pHt)
144  ->GetFormatField().GetField()->ExpandField(true, nullptr);
145  break;
146 
147  case RES_TXTATR_FTN:
148  {
149  const SwFormatFootnote& rFootnote = pHt->GetFootnote();
150  if( !rFootnote.GetNumStr().isEmpty() )
151  sOut = rFootnote.GetNumStr();
152  else if( rFootnote.IsEndNote() )
153  sOut = rWrt.m_pDoc->GetEndNoteInfo().m_aFormat.
154  GetNumStr( rFootnote.GetNumber() );
155  else
156  sOut = rWrt.m_pDoc->GetFootnoteInfo().m_aFormat.
157  GetNumStr( rFootnote.GetNumber() );
158  }
159  break;
160  }
161  if( !sOut.isEmpty() )
162  rWrt.Strm().WriteUnicodeOrByteText( sOut );
163  }
164  else if( nSwPos < pHt->GetStart() )
165  break;
166  }
167  }
168  return bRet;
169 }
170 
171 namespace {
172 
173 class SwASC_RedlineIter
174 {
175 private:
176  SwTextNode const& m_rNode;
177  IDocumentRedlineAccess const& m_rIDRA;
178  SwRedlineTable::size_type m_nextRedline;
179 
180 public:
181  SwASC_RedlineIter(SwASCWriter const& rWriter, SwTextNode const& rNode)
182  : m_rNode(rNode)
183  , m_rIDRA(rNode.GetDoc()->getIDocumentRedlineAccess())
184  , m_nextRedline(rWriter.m_bHideDeleteRedlines
185  ? m_rIDRA.GetRedlinePos(m_rNode, RedlineType::Delete)
186  : SwRedlineTable::npos)
187  {
188  }
189 
190  bool CheckNodeDeleted()
191  {
192  if (m_nextRedline == SwRedlineTable::npos)
193  {
194  return false;
195  }
196  SwRangeRedline const*const pRedline(m_rIDRA.GetRedlineTable()[m_nextRedline]);
197  return pRedline->Start()->nNode.GetIndex() < m_rNode.GetIndex()
198  && m_rNode.GetIndex() < pRedline->End()->nNode.GetIndex();
199  }
200 
201  std::pair<sal_Int32, sal_Int32> GetNextRedlineSkip()
202  {
203  sal_Int32 nRedlineStart(COMPLETE_STRING);
204  sal_Int32 nRedlineEnd(COMPLETE_STRING);
205  for ( ; m_nextRedline < m_rIDRA.GetRedlineTable().size(); ++m_nextRedline)
206  {
207  SwRangeRedline const*const pRedline(m_rIDRA.GetRedlineTable()[m_nextRedline]);
208  if (pRedline->GetType() != RedlineType::Delete)
209  {
210  continue;
211  }
212  SwPosition const*const pStart(pRedline->Start());
213  SwPosition const*const pEnd(pRedline->End());
214  if (m_rNode.GetIndex() < pStart->nNode.GetIndex())
215  {
216  m_nextRedline = SwRedlineTable::npos;
217  break; // done
218  }
219  if (nRedlineStart == COMPLETE_STRING)
220  {
221  nRedlineStart = pStart->nNode.GetIndex() == m_rNode.GetIndex()
222  ? pStart->nContent.GetIndex()
223  : 0;
224  }
225  else
226  {
227  if (pStart->nContent.GetIndex() != nRedlineEnd)
228  {
229  assert(nRedlineEnd < pStart->nContent.GetIndex());
230  break; // no increment, revisit it next call
231  }
232  }
233  nRedlineEnd = pEnd->nNode.GetIndex() == m_rNode.GetIndex()
234  ? pEnd->nContent.GetIndex()
235  : COMPLETE_STRING;
236  }
237  return std::make_pair(nRedlineStart, nRedlineEnd);
238  }
239 };
240 
241 }
242 
243 // Output of the node
244 
246 {
247  const SwTextNode& rNd = static_cast<SwTextNode&>(rNode);
248 
249  sal_Int32 nStrPos = rWrt.m_pCurrentPam->GetPoint()->nContent.GetIndex();
250  const sal_Int32 nNodeEnd = rNd.Len();
251  sal_Int32 nEnd = nNodeEnd;
252  bool bLastNd = rWrt.m_pCurrentPam->GetPoint()->nNode == rWrt.m_pCurrentPam->GetMark()->nNode;
253  if( bLastNd )
254  nEnd = rWrt.m_pCurrentPam->GetMark()->nContent.GetIndex();
255 
256  bool bIsOneParagraph = rWrt.m_pOrigPam->Start()->nNode == rWrt.m_pOrigPam->End()->nNode;
257 
258  SwASC_AttrIter aAttrIter( static_cast<SwASCWriter&>(rWrt), rNd, nStrPos );
259  SwASC_RedlineIter redlineIter(static_cast<SwASCWriter&>(rWrt), rNd);
260 
261  if (redlineIter.CheckNodeDeleted())
262  {
263  return rWrt;
264  }
265 
266  const SwNumRule* pNumRule = rNd.GetNumRule();
267  if (pNumRule && !nStrPos && rWrt.m_bExportPargraphNumbering && !bIsOneParagraph)
268  {
269  bool bIsOutlineNumRule = pNumRule == rNd.GetDoc()->GetOutlineNumRule();
270 
271  // indent each numbering level by 4 spaces
272  OUString level;
273  if (!bIsOutlineNumRule)
274  {
275  for (int i = 0; i <= rNd.GetActualListLevel(); ++i)
276  level += " ";
277  }
278 
279  // set up bullets or numbering
280  OUString numString(rNd.GetNumString());
281  if (numString.isEmpty() && !bIsOutlineNumRule)
282  {
283  if (rNd.HasBullet() && !rNd.HasVisibleNumberingOrBullet())
284  numString = " ";
285  else if (rNd.HasBullet())
286  numString = OUString(numfunc::GetBulletChar(rNd.GetActualListLevel()));
287  else if (!rNd.HasBullet() && !rNd.HasVisibleNumberingOrBullet())
288  numString = " ";
289  }
290 
291  if (!level.isEmpty() || !numString.isEmpty())
292  rWrt.Strm().WriteUnicodeOrByteText(level + numString + " ");
293  }
294 
295  OUString aStr( rNd.GetText() );
296  if( rWrt.m_bASCII_ParaAsBlank )
297  aStr = aStr.replace(0x0A, ' ');
298 
299  const bool bExportSoftHyphens = RTL_TEXTENCODING_UCS2 == rWrt.GetAsciiOptions().GetCharSet() ||
300  RTL_TEXTENCODING_UTF8 == rWrt.GetAsciiOptions().GetCharSet();
301 
302  std::pair<sal_Int32, sal_Int32> curRedline(redlineIter.GetNextRedlineSkip());
303  for (;;) {
304  const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
305 
306  bool isOutAttr(false);
307  if (nStrPos < curRedline.first || curRedline.second <= nStrPos)
308  {
309  isOutAttr = aAttrIter.OutAttr(nStrPos);
310  }
311 
312  if (!isOutAttr)
313  {
314  OUStringBuffer buf;
315  while (true)
316  {
317  if (nNextAttr <= curRedline.first)
318  {
319  buf.append(aStr.copy(nStrPos, nNextAttr - nStrPos));
320  break;
321  }
322  else if (nStrPos < curRedline.second)
323  {
324  if (nStrPos < curRedline.first)
325  {
326  buf.append(aStr.copy(nStrPos, curRedline.first - nStrPos));
327  }
328  if (curRedline.second <= nNextAttr)
329  {
330  nStrPos = curRedline.second;
331  curRedline = redlineIter.GetNextRedlineSkip();
332  }
333  else
334  {
335  nStrPos = nNextAttr;
336  break;
337  }
338  }
339  else
340  {
341  curRedline = redlineIter.GetNextRedlineSkip();
342  }
343  }
344  OUString aOutStr(buf.makeStringAndClear());
345  if ( !bExportSoftHyphens )
346  aOutStr = aOutStr.replaceAll(OUStringChar(CHAR_SOFTHYPHEN), "");
347 
348  // all INWORD/BREAKWORD should be already removed by OutAttr
349  // but the field-marks are not attributes so filter those
350  static sal_Unicode const forbidden [] = {
357  0
358  };
359  aOutStr = comphelper::string::removeAny(aOutStr, forbidden);
360 
361  rWrt.Strm().WriteUnicodeOrByteText( aOutStr );
362  }
363  nStrPos = nNextAttr;
364  if (nStrPos >= nEnd)
365  {
366  break;
367  }
368  aAttrIter.NextPos();
369  }
370 
371  if( !bLastNd ||
372  ( ( !rWrt.m_bWriteClipboardDoc && !rWrt.m_bASCII_NoLastLineEnd )
373  && !nStrPos && nEnd == nNodeEnd ) )
374  rWrt.Strm().WriteUnicodeOrByteText( static_cast<SwASCWriter&>(rWrt).GetLineEnd());
375 
376  return rWrt;
377 }
378 
379 /*
380  * Create the table for the ASCII function pointers to the output
381  * function.
382  * There are local structures that only need to be known to the ASCII DLL.
383  */
384 
386 /* RES_TXTNODE */ OutASC_SwTextNode,
387 /* RES_GRFNODE */ nullptr,
388 /* RES_OLENODE */ nullptr
389 };
390 
391 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
rtl_TextEncoding GetCharSet() const
Definition: shellio.hxx:77
sal_uLong GetIndex() const
Definition: node.hxx:282
bool HasBullet() const
Returns if this text node has a bullet.
Definition: ndtxt.cxx:3103
Marks a position in the document model.
Definition: pam.hxx:35
const OUString & GetText() const
Definition: ndtxt.hxx:210
SwNodeIndex nNode
Definition: pam.hxx:37
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:273
FnNodeOut SwNodeFnTab[RES_NODE_END-RES_NODE_BEGIN]
Definition: wrt_fn.hxx:50
bool HasDummyChar() const
Definition: txatbase.hxx:101
bool IsEndNote() const
Definition: fmtftn.hxx:74
sal_uInt16 Which() const
Definition: txatbase.hxx:110
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:143
int GetActualListLevel() const
Returns the actual list level of this text node, when it is a list item.
Definition: ndtxt.cxx:4088
#define CHAR_SOFTHYPHEN
Definition: swtypes.hxx:174
size_type size() const
Definition: docary.hxx:368
sal_uInt16 sal_Unicode
bool m_bASCII_ParaAsBlank
Definition: shellio.hxx:417
sal_Unicode GetBulletChar(sal_uInt8 nLevel)
retrieve unicode of character used for the default bullet list for the given list level ...
Definition: number.cxx:1274
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:140
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
const OUString & GetNumStr() const
Definition: fmtftn.hxx:71
bool m_bWriteClipboardDoc
Definition: shellio.hxx:414
bool m_bASCII_NoLastLineEnd
Definition: shellio.hxx:418
SwPaM * m_pOrigPam
Definition: shellio.hxx:410
size_t Count() const
Definition: ndhints.hxx:142
#define SAL_MAX_INT32
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
#define RES_TXTATR_FTN
Definition: hintids.hxx:246
static Writer & OutASC_SwTextNode(Writer &rWrt, SwContentNode &rNode)
Definition: ascatr.cxx:245
bool HasContent() const
Definition: txatbase.hxx:106
int i
vector_type::size_type size_type
Definition: docary.hxx:330
SwDoc * GetDoc()
Definition: node.hxx:702
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:145
SwNumRule * GetNumRule(bool bInParent=true) const
Returns numbering rule of this text node.
Definition: ndtxt.cxx:2804
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:237
const SwFormatFootnote & GetFootnote() const
Definition: txatbase.hxx:200
OUString removeAny(OUString const &rIn, sal_Unicode const *const pChars)
const SwPosition * Start() const
Definition: pam.hxx:212
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
SwNodeFnTab aASCNodeFnTab
Definition: ascatr.cxx:385
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:141
#define RES_TXTATR_FIELD
Definition: hintids.hxx:244
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
#define RES_TXTATR_ANNOTATION
Definition: hintids.hxx:247
const SwPosition * End() const
Definition: pam.hxx:217
const sal_Int32 * End() const
Definition: txatbase.hxx:148
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:147
std::shared_ptr< SwUnoCursor > m_pCurrentPam
Definition: shellio.hxx:411
OUString GetNumString(const bool _bInclPrefixAndSuffixStrings=true, const unsigned int _nRestrictToThisLevel=MAXLEVEL, SwRootFrame const *pLayout=nullptr) const
Returns outline of numbering string.
Definition: ndtxt.cxx:3121
SvStream & Strm()
Definition: writer.cxx:215
RedlineType
bool WriteUnicodeOrByteText(const OUString &rStr, rtl_TextEncoding eDestCharSet)
const SwAsciiOptions & GetAsciiOptions() const
Definition: shellio.hxx:442
bool HasVisibleNumberingOrBullet() const
Returns if the paragraph has a visible numbering or bullet.
Definition: ndtxt.cxx:4123
virtual const SwRedlineTable & GetRedlineTable() const =0
bool m_bExportPargraphNumbering
Definition: shellio.hxx:420
#define CH_TXT_ATR_FIELDSEP
Definition: hintids.hxx:146
static constexpr size_type npos
Definition: docary.hxx:331
#define RES_TXTATR_INPUTFIELD
Definition: hintids.hxx:239
sal_uInt16 GetNumber() const
Definition: fmtftn.hxx:72
aStr
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
sal_uInt16 nPos
SwNumRule * GetOutlineNumRule() const
Definition: doc.hxx:1019