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
44namespace {
45
46class 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
54public:
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
66SwASC_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
74sal_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
114bool 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;
152 {
153 // Downgrade the clearing break to a simple linebreak.
154 sOut = OUStringChar(GetCharOfTextAttr(*pHt));
155 break;
156 }
157 }
158 if( !sOut.isEmpty() )
159 m_rWrt.Strm().WriteUnicodeOrByteText(sOut);
160 }
161 else if( nSwPos < pHt->GetStart() )
162 break;
163 }
164 }
165 return bRet;
166}
167
168namespace {
169
170class SwASC_RedlineIter
171{
172private:
173 SwTextNode const& m_rNode;
174 IDocumentRedlineAccess const& m_rIDRA;
175 SwRedlineTable::size_type m_nextRedline;
176
177public:
178 SwASC_RedlineIter(SwASCWriter const& rWriter, SwTextNode const& rNode)
179 : m_rNode(rNode)
180 , m_rIDRA(rNode.GetDoc().getIDocumentRedlineAccess())
181 , m_nextRedline(rWriter.m_bHideDeleteRedlines
182 ? m_rIDRA.GetRedlinePos(m_rNode, RedlineType::Delete)
183 : SwRedlineTable::npos)
184 {
185 }
186
187 bool CheckNodeDeleted()
188 {
189 if (m_nextRedline == SwRedlineTable::npos)
190 {
191 return false;
192 }
193 SwRangeRedline const*const pRedline(m_rIDRA.GetRedlineTable()[m_nextRedline]);
194 return pRedline->Start()->GetNodeIndex() < m_rNode.GetIndex()
195 && m_rNode.GetIndex() < pRedline->End()->GetNodeIndex();
196 }
197
198 std::pair<sal_Int32, sal_Int32> GetNextRedlineSkip()
199 {
200 sal_Int32 nRedlineStart(COMPLETE_STRING);
201 sal_Int32 nRedlineEnd(COMPLETE_STRING);
202 for ( ; m_nextRedline < m_rIDRA.GetRedlineTable().size(); ++m_nextRedline)
203 {
204 SwRangeRedline const*const pRedline(m_rIDRA.GetRedlineTable()[m_nextRedline]);
205 if (pRedline->GetType() != RedlineType::Delete)
206 {
207 continue;
208 }
209 auto [pStart, pEnd] = pRedline->StartEnd(); // SwPosition*
210 if (m_rNode.GetIndex() < pStart->GetNodeIndex())
211 {
212 m_nextRedline = SwRedlineTable::npos;
213 break; // done
214 }
215 if (nRedlineStart == COMPLETE_STRING)
216 {
217 nRedlineStart = pStart->GetNodeIndex() == m_rNode.GetIndex()
218 ? pStart->GetContentIndex()
219 : 0;
220 }
221 else
222 {
223 if (pStart->GetContentIndex() != nRedlineEnd)
224 {
225 assert(nRedlineEnd < pStart->GetContentIndex());
226 break; // no increment, revisit it next call
227 }
228 }
229 nRedlineEnd = pEnd->GetNodeIndex() == m_rNode.GetIndex()
230 ? pEnd->GetContentIndex()
232 }
233 return std::make_pair(nRedlineStart, nRedlineEnd);
234 }
235};
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()->GetContentIndex();
246 const sal_Int32 nNodeEnd = rNd.Len();
247 sal_Int32 nEnd = nNodeEnd;
248 bool bLastNd = rWrt.m_pCurrentPam->GetPoint()->GetNode() == rWrt.m_pCurrentPam->GetMark()->GetNode();
249 if( bLastNd )
250 nEnd = rWrt.m_pCurrentPam->GetMark()->GetContentIndex();
251
252 bool bIsOneParagraph = rWrt.m_pOrigPam->Start()->GetNode() == rWrt.m_pOrigPam->End()->GetNode() && !getenv("SW_ASCII_COPY_NUMBERING");
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_bExportParagraphNumbering && !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(Concat2View(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.subView(nStrPos, nNextAttr - nStrPos));
316 break;
317 }
318 else if (nStrPos < curRedline.second)
319 {
320 if (nStrPos < curRedline.first)
321 {
322 buf.append(aStr.subView(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(OUStringChar(CHAR_SOFTHYPHEN), "");
343
344 // all INWORD should be already removed by OutAttr
345 // but the field-marks are not attributes so filter those
346 static sal_Unicode const forbidden [] = {
354 0
355 };
356 aOutStr = comphelper::string::removeAny(aOutStr, forbidden);
357
358 rWrt.Strm().WriteUnicodeOrByteText( aOutStr );
359 }
360 nStrPos = nNextAttr;
361 if (nStrPos >= nEnd)
362 {
363 break;
364 }
365 aAttrIter.NextPos();
366 }
367
368 if( !bLastNd ||
370 && !nStrPos && nEnd == nNodeEnd ) )
371 rWrt.Strm().WriteUnicodeOrByteText( static_cast<SwASCWriter&>(rWrt).GetLineEnd());
372
373 return rWrt;
374}
375
376/*
377 * Create the table for the ASCII function pointers to the output
378 * function.
379 * There are local structures that only need to be known to the ASCII DLL.
380 */
381
383/* RES_TXTNODE */ OutASC_SwTextNode,
384/* RES_GRFNODE */ nullptr,
385/* RES_OLENODE */ nullptr
386};
387
388/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static Writer & OutASC_SwTextNode(Writer &rWrt, SwContentNode &rNode)
Definition: ascatr.cxx:241
SwNodeFnTab aASCNodeFnTab
Definition: ascatr.cxx:382
virtual const SwRedlineTable & GetRedlineTable() const =0
bool WriteUnicodeOrByteText(std::u16string_view rStr, rtl_TextEncoding eDestCharSet)
rtl_TextEncoding GetCharSet() const
Definition: shellio.hxx:76
SwNumRule * GetOutlineNumRule() const
Definition: doc.hxx:1039
SfxPoolItem subclass for footnotes and endnotes, stored in the anchor text node.
Definition: fmtftn.hxx:47
sal_uInt16 GetNumber() const
Definition: fmtftn.hxx:73
const OUString & GetNumStr() const
Definition: fmtftn.hxx:72
bool IsEndNote() const
Definition: fmtftn.hxx:75
SwNodeOffset GetIndex() const
Definition: node.hxx:312
SwDoc & GetDoc()
Definition: node.hxx:233
const SwPosition * End() const
Definition: pam.hxx:263
const SwPosition * Start() const
Definition: pam.hxx:258
static constexpr size_type npos
Definition: docary.hxx:224
vector_type::size_type size_type
Definition: docary.hxx:223
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
const sal_Int32 * End() const
Definition: txatbase.hxx:156
const SwFormatFootnote & GetFootnote() const
Definition: txatbase.hxx:208
sal_Int32 GetStart() const
Definition: txatbase.hxx:88
bool HasContent() const
Definition: txatbase.hxx:112
bool HasDummyChar() const
Definition: txatbase.hxx:107
sal_uInt16 Which() const
Definition: txatbase.hxx:116
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
bool HasBullet() const
Returns if this text node has a bullet.
Definition: ndtxt.cxx:3229
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:291
bool HasVisibleNumberingOrBullet() const
Returns if the paragraph has a visible numbering or bullet.
Definition: ndtxt.cxx:4284
SwNumRule * GetNumRule(bool bInParent=true) const
Returns numbering rule of this text node.
Definition: ndtxt.cxx:2921
int GetActualListLevel(SwListRedlineType eRedline=SwListRedlineType::SHOW) const
Returns the actual list level of this text node, when it is a list item.
Definition: ndtxt.cxx:4248
OUString GetNumString(const bool _bInclPrefixAndSuffixStrings=true, const unsigned int _nRestrictToThisLevel=MAXLEVEL, SwRootFrame const *pLayout=nullptr, SwListRedlineType eRedline=SwListRedlineType::SHOW) const
Returns outline of numbering string.
Definition: ndtxt.cxx:3247
const OUString & GetText() const
Definition: ndtxt.hxx:244
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:68
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
size_t Count() const
Definition: ndhints.hxx:142
SwPaM * m_pOrigPam
Definition: shellio.hxx:408
SvStream & Strm()
Definition: writer.cxx:193
const SwAsciiOptions & GetAsciiOptions() const
Definition: shellio.hxx:440
std::shared_ptr< SwUnoCursor > m_pCurrentPam
Definition: shellio.hxx:409
bool m_bExportParagraphNumbering
Definition: shellio.hxx:418
bool m_bASCII_NoLastLineEnd
Definition: shellio.hxx:416
bool m_bWriteClipboardDoc
Definition: shellio.hxx:412
bool m_bASCII_ParaAsBlank
Definition: shellio.hxx:415
RedlineType
#define CH_TXT_ATR_FIELDSEP
Definition: hintids.hxx:184
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:178
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:181
constexpr TypedWhichId< SwFormatFootnote > RES_TXTATR_FTN(59)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(60)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
constexpr TypedWhichId< SwFormatLineBreak > RES_TXTATR_LINEBREAK(61)
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:179
constexpr TypedWhichId< SwFormatField > RES_TXTATR_INPUTFIELD(55)
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:185
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:183
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:174
sal_uInt16 nPos
aStr
size
OUString removeAny(std::u16string_view rIn, sal_Unicode const *const pChars)
int i
sal_Unicode GetBulletChar(sal_uInt8 nLevel)
retrieve unicode of character used for the default bullet list for the given list level
Definition: number.cxx:1377
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
SwNode & GetNode() const
Definition: pam.hxx:81
#define CHAR_SOFTHYPHEN
Definition: swtypes.hxx:175
constexpr sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:57
sal_Unicode GetCharOfTextAttr(const SwTextAttr &rAttr)
Definition: thints.cxx:3539
#define SAL_MAX_INT32
sal_uInt16 sal_Unicode
FnNodeOut SwNodeFnTab[RES_NODE_END - RES_NODE_BEGIN]
Definition: wrt_fn.hxx:51