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