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 <editeng/fontitem.hxx>
24 #include <pam.hxx>
25 #include <doc.hxx>
26 #include <ndtxt.hxx>
28 #include <redline.hxx>
29 #include "wrtasc.hxx"
30 #include <txatbase.hxx>
31 #include <fchrfmt.hxx>
32 #include <txtfld.hxx>
33 #include <txtatr.hxx>
34 #include <fmtftn.hxx>
35 #include <charfmt.hxx>
36 #include <fmtfld.hxx>
37 #include <fldbas.hxx>
38 #include <ftninfo.hxx>
39 #include <numrule.hxx>
40 
41 #include <algorithm>
42 
43 /*
44  * This file contains all output functions of the ASCII-Writer;
45  * For all nodes, attributes, formats and chars.
46  */
47 
49 {
51  const SwTextNode& rNd;
52  sal_Int32 nCurrentSwPos;
53 
54  sal_Int32 SearchNext( sal_Int32 nStartPos );
55 
56 public:
57  SwASC_AttrIter( SwASCWriter& rWrt, const SwTextNode& rNd, sal_Int32 nStt );
58 
59  void NextPos()
60  {
61  nCurrentSwPos = SearchNext( nCurrentSwPos + 1 );
62  }
63 
64  sal_Int32 WhereNext() const
65  {
66  return nCurrentSwPos;
67  }
68 
69  bool OutAttr( sal_Int32 nSwPos );
70 };
71 
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().aFormat.
154  GetNumStr( rFootnote.GetNumber() );
155  else
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 
172 {
173 private:
177 
178 public:
179  SwASC_RedlineIter(SwASCWriter const& rWriter, SwTextNode const& rNode)
180  : m_rNode(rNode)
181  , m_rIDRA(rNode.GetDoc()->getIDocumentRedlineAccess())
182  , m_nextRedline(rWriter.m_bHideDeleteRedlines
183  ? m_rIDRA.GetRedlinePos(m_rNode, nsRedlineType_t::REDLINE_DELETE)
184  : SwRedlineTable::npos)
185  {
186  }
187 
189  {
190  if (m_nextRedline == SwRedlineTable::npos)
191  {
192  return false;
193  }
194  SwRangeRedline const*const pRedline(m_rIDRA.GetRedlineTable()[m_nextRedline]);
195  return pRedline->Start()->nNode.GetIndex() < m_rNode.GetIndex()
196  && m_rNode.GetIndex() < pRedline->End()->nNode.GetIndex();
197  }
198 
199  std::pair<sal_Int32, sal_Int32> GetNextRedlineSkip()
200  {
201  sal_Int32 nRedlineStart(COMPLETE_STRING);
202  sal_Int32 nRedlineEnd(COMPLETE_STRING);
203  for ( ; m_nextRedline < m_rIDRA.GetRedlineTable().size(); ++m_nextRedline)
204  {
205  SwRangeRedline const*const pRedline(m_rIDRA.GetRedlineTable()[m_nextRedline]);
206  if (pRedline->GetType() != nsRedlineType_t::REDLINE_DELETE)
207  {
208  continue;
209  }
210  SwPosition const*const pStart(pRedline->Start());
211  SwPosition const*const pEnd(pRedline->End());
212  if (m_rNode.GetIndex() < pStart->nNode.GetIndex())
213  {
214  m_nextRedline = SwRedlineTable::npos;
215  break; // done
216  }
217  if (nRedlineStart == COMPLETE_STRING)
218  {
219  nRedlineStart = pStart->nNode.GetIndex() == m_rNode.GetIndex()
220  ? pStart->nContent.GetIndex()
221  : 0;
222  }
223  else
224  {
225  if (pStart->nContent.GetIndex() != nRedlineEnd)
226  {
227  assert(nRedlineEnd < pStart->nContent.GetIndex());
228  break; // no increment, revisit it next call
229  }
230  }
231  nRedlineEnd = pEnd->nNode.GetIndex() == m_rNode.GetIndex()
232  ? pEnd->nContent.GetIndex()
233  : COMPLETE_STRING;
234  }
235  return std::make_pair(nRedlineStart, nRedlineEnd);
236  }
237 };
238 
239 // Output of the node
240 
242 {
243  const SwTextNode& rNd = static_cast<SwTextNode&>(rNode);
244 
245  sal_Int32 nStrPos = rWrt.m_pCurrentPam->GetPoint()->nContent.GetIndex();
246  const sal_Int32 nNodeEnd = rNd.Len();
247  sal_Int32 nEnd = nNodeEnd;
248  bool bLastNd = rWrt.m_pCurrentPam->GetPoint()->nNode == rWrt.m_pCurrentPam->GetMark()->nNode;
249  if( bLastNd )
250  nEnd = rWrt.m_pCurrentPam->GetMark()->nContent.GetIndex();
251 
252  bool bIsOneParagraph = rWrt.m_pOrigPam->Start()->nNode == rWrt.m_pOrigPam->End()->nNode;
253 
254  SwASC_AttrIter aAttrIter( static_cast<SwASCWriter&>(rWrt), rNd, nStrPos );
255  SwASC_RedlineIter redlineIter(static_cast<SwASCWriter&>(rWrt), rNd);
256 
257  if (redlineIter.CheckNodeDeleted())
258  {
259  return rWrt;
260  }
261 
262  const SwNumRule* pNumRule = rNd.GetNumRule();
263  if (pNumRule && !nStrPos && rWrt.m_bExportPargraphNumbering && !bIsOneParagraph)
264  {
265  bool bIsOutlineNumRule = pNumRule == rNd.GetDoc()->GetOutlineNumRule();
266 
267  // indent each numbering level by 4 spaces
268  OUString level;
269  if (!bIsOutlineNumRule)
270  {
271  for (int i = 0; i <= rNd.GetActualListLevel(); ++i)
272  level += " ";
273  }
274 
275  // set up bullets or numbering
276  OUString numString(rNd.GetNumString());
277  if (numString.isEmpty() && !bIsOutlineNumRule)
278  {
279  if (rNd.HasBullet() && !rNd.HasVisibleNumberingOrBullet())
280  numString = " ";
281  else if (rNd.HasBullet())
282  numString = OUString(numfunc::GetBulletChar(rNd.GetActualListLevel()));
283  else if (!rNd.HasBullet() && !rNd.HasVisibleNumberingOrBullet())
284  numString = " ";
285  }
286 
287  if (!level.isEmpty() || !numString.isEmpty())
288  rWrt.Strm().WriteUnicodeOrByteText(level + numString + " ");
289  }
290 
291  OUString aStr( rNd.GetText() );
292  if( rWrt.m_bASCII_ParaAsBlank )
293  aStr = aStr.replace(0x0A, ' ');
294 
295  const bool bExportSoftHyphens = RTL_TEXTENCODING_UCS2 == rWrt.GetAsciiOptions().GetCharSet() ||
296  RTL_TEXTENCODING_UTF8 == rWrt.GetAsciiOptions().GetCharSet();
297 
298  std::pair<sal_Int32, sal_Int32> curRedline(redlineIter.GetNextRedlineSkip());
299  for (;;) {
300  const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
301 
302  bool isOutAttr(false);
303  if (nStrPos < curRedline.first || curRedline.second <= nStrPos)
304  {
305  isOutAttr = aAttrIter.OutAttr(nStrPos);
306  }
307 
308  if (!isOutAttr)
309  {
310  OUStringBuffer buf;
311  while (true)
312  {
313  if (nNextAttr <= curRedline.first)
314  {
315  buf.append(aStr.copy(nStrPos, nNextAttr - nStrPos));
316  break;
317  }
318  else if (nStrPos < curRedline.second)
319  {
320  if (nStrPos < curRedline.first)
321  {
322  buf.append(aStr.copy(nStrPos, curRedline.first - nStrPos));
323  }
324  if (curRedline.second <= nNextAttr)
325  {
326  nStrPos = curRedline.second;
327  curRedline = redlineIter.GetNextRedlineSkip();
328  }
329  else
330  {
331  nStrPos = nNextAttr;
332  break;
333  }
334  }
335  else
336  {
337  curRedline = redlineIter.GetNextRedlineSkip();
338  }
339  }
340  OUString aOutStr(buf.makeStringAndClear());
341  if ( !bExportSoftHyphens )
342  aOutStr = aOutStr.replaceAll(OUStringLiteral1(CHAR_SOFTHYPHEN), "");
343 
344  // all INWORD/BREAKWORD should be already removed by OutAttr
345  // but the field-marks are not attributes so filter those
346  static sal_Unicode const forbidden [] = {
352  0
353  };
354  aOutStr = comphelper::string::removeAny(aOutStr, forbidden);
355 
356  rWrt.Strm().WriteUnicodeOrByteText( aOutStr );
357  }
358  nStrPos = nNextAttr;
359  if (nStrPos >= nEnd)
360  {
361  break;
362  }
363  aAttrIter.NextPos();
364  }
365 
366  if( !bLastNd ||
367  ( ( !rWrt.m_bWriteClipboardDoc && !rWrt.m_bASCII_NoLastLineEnd )
368  && !nStrPos && nEnd == nNodeEnd ) )
369  rWrt.Strm().WriteUnicodeOrByteText( static_cast<SwASCWriter&>(rWrt).GetLineEnd());
370 
371  return rWrt;
372 }
373 
374 /*
375  * Create the table for the ASCII function pointers to the output
376  * function.
377  * There are local structures that only need to be known to the ASCII DLL.
378  */
379 
381 /* RES_TXTNODE */ OutASC_SwTextNode,
382 /* RES_GRFNODE */ nullptr,
383 /* RES_OLENODE */ nullptr
384 };
385 
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 & GetStart()
start position
Definition: txatbase.hxx:77
rtl_TextEncoding GetCharSet() const
Definition: shellio.hxx:76
sal_uLong GetIndex() const
Definition: node.hxx:282
bool HasBullet() const
Returns if this text node has a bullet.
Definition: ndtxt.cxx:3113
Marks a position in the document model.
Definition: pam.hxx:35
const OUString & GetText() const
Definition: ndtxt.hxx:211
SwPaM * m_pCurrentPam
Definition: shellio.hxx:406
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:219
SwNodeIndex nNode
Definition: pam.hxx:37
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
const SwPosition * GetMark() const
Definition: pam.hxx:209
FnNodeOut SwNodeFnTab[RES_NODE_END-RES_NODE_BEGIN]
Definition: wrt_fn.hxx:50
SwRedlineTable::size_type m_nextRedline
Definition: ascatr.cxx:176
bool HasDummyChar() const
Definition: txatbase.hxx:96
bool IsEndNote() const
Definition: fmtftn.hxx:73
sal_uInt16 Which() const
Definition: txatbase.hxx:105
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:50
int GetActualListLevel() const
Returns the actual list level of this text node, when it is a list item.
Definition: ndtxt.cxx:4097
#define CHAR_SOFTHYPHEN
Definition: swtypes.hxx:174
size_type size() const
Definition: docary.hxx:370
sal_uInt16 sal_Unicode
sal_Int32 WhereNext() const
Definition: ascatr.cxx:64
SwTextNode const & m_rNode
Definition: ascatr.cxx:174
std::pair< sal_Int32, sal_Int32 > GetNextRedlineSkip()
Definition: ascatr.cxx:199
SwIndex nContent
Definition: pam.hxx:38
bool OutAttr(sal_Int32 nSwPos)
Definition: ascatr.cxx:123
bool m_bASCII_ParaAsBlank
Definition: shellio.hxx:412
sal_Unicode GetBulletChar(sal_uInt8 nLevel)
retrieve unicode of character used for the default bullet list for the given list level ...
Definition: number.cxx:1267
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:47
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
SvxNumberType aFormat
Definition: ftninfo.hxx:46
const OUString & GetNumStr() const
Definition: fmtftn.hxx:70
const RedlineType_t REDLINE_DELETE
bool m_bWriteClipboardDoc
Definition: shellio.hxx:409
bool m_bASCII_NoLastLineEnd
Definition: shellio.hxx:413
SwPaM * m_pOrigPam
Definition: shellio.hxx:405
size_t Count() const
Definition: ndhints.hxx:152
#define SAL_MAX_INT32
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:154
const SwPosition * GetPoint() const
Definition: pam.hxx:207
#define RES_TXTATR_FTN
Definition: hintids.hxx:152
static Writer & OutASC_SwTextNode(Writer &rWrt, SwContentNode &rNode)
Definition: ascatr.cxx:241
bool HasContent() const
Definition: txatbase.hxx:101
int i
vector_type::size_type size_type
Definition: docary.hxx:331
SwDoc * GetDoc()
Definition: node.hxx:702
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:52
SwNumRule * GetNumRule(bool bInParent=true) const
Returns numbering rule of this text node.
Definition: ndtxt.cxx:2814
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:231
const SwFormatFootnote & GetFootnote() const
Definition: txatbase.hxx:194
OUString removeAny(OUString const &rIn, sal_Unicode const *const pChars)
const SwPosition * Start() const
Definition: pam.hxx:212
const SwTextNode & rNd
Definition: ascatr.cxx:51
void NextPos()
Definition: ascatr.cxx:59
sal_Int32 nCurrentSwPos
Definition: ascatr.cxx:52
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
SwASCWriter & rWrt
Definition: ascatr.cxx:50
SwNodeFnTab aASCNodeFnTab
Definition: ascatr.cxx:380
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:48
#define RES_TXTATR_FIELD
Definition: hintids.hxx:150
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:76
IDocumentRedlineAccess const & m_rIDRA
Definition: ascatr.cxx:175
#define RES_TXTATR_ANNOTATION
Definition: hintids.hxx:153
sal_Int32 GetIndex() const
Definition: index.hxx:95
const SwPosition * End() const
Definition: pam.hxx:217
const sal_Int32 * End() const
Definition: txatbase.hxx:142
SwASC_RedlineIter(SwASCWriter const &rWriter, SwTextNode const &rNode)
Definition: ascatr.cxx:179
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:53
OUString GetNumString(const bool _bInclPrefixAndSuffixStrings=true, const unsigned int _nRestrictToThisLevel=MAXLEVEL, SwRootFrame const *pLayout=nullptr) const
Returns outline of numbering string.
Definition: ndtxt.cxx:3131
SvStream & Strm()
Definition: writer.cxx:221
bool WriteUnicodeOrByteText(const OUString &rStr, rtl_TextEncoding eDestCharSet)
const SwAsciiOptions & GetAsciiOptions() const
Definition: shellio.hxx:437
bool HasVisibleNumberingOrBullet() const
Returns if the paragraph has a visible numbering or bullet.
Definition: ndtxt.cxx:4132
virtual const SwRedlineTable & GetRedlineTable() const =0
SwASC_AttrIter(SwASCWriter &rWrt, const SwTextNode &rNd, sal_Int32 nStt)
Definition: ascatr.cxx:72
bool m_bExportPargraphNumbering
Definition: shellio.hxx:415
sal_Int32 nPos
static constexpr size_type npos
Definition: docary.hxx:332
#define RES_TXTATR_INPUTFIELD
Definition: hintids.hxx:145
sal_uInt16 GetNumber() const
Definition: fmtftn.hxx:71
aStr
const SwFootnoteInfo & GetFootnoteInfo() const
Definition: doc.hxx:624
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
const SwEndNoteInfo & GetEndNoteInfo() const
Definition: doc.hxx:626
SwDoc * m_pDoc
Definition: shellio.hxx:404
SwNumRule * GetOutlineNumRule() const
Definition: doc.hxx:1013
sal_Int32 SearchNext(sal_Int32 nStartPos)
Definition: ascatr.cxx:83
bool CheckNodeDeleted()
Definition: ascatr.cxx:188