android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / ascii / ascatr.cxx
blobc4f4d12490700ad880040c98f0c3d3c9d3a1250e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
26 #include <IDocumentRedlineAccess.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>
37 #include <algorithm>
40 * This file contains all output functions of the ASCII-Writer;
41 * For all nodes, attributes, formats and chars.
44 namespace {
46 class SwASC_AttrIter
48 SwASCWriter& m_rWrt;
49 const SwTextNode& m_rNd;
50 sal_Int32 m_nCurrentSwPos;
52 sal_Int32 SearchNext( sal_Int32 nStartPos );
54 public:
55 SwASC_AttrIter( SwASCWriter& rWrt, const SwTextNode& rNd, sal_Int32 nStt );
57 void NextPos() { m_nCurrentSwPos = SearchNext(m_nCurrentSwPos + 1); }
59 sal_Int32 WhereNext() const { return m_nCurrentSwPos; }
61 bool OutAttr( sal_Int32 nSwPos );
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)
71 m_nCurrentSwPos = SearchNext(nStt + 1);
74 sal_Int32 SwASC_AttrIter::SearchNext( sal_Int32 nStartPos )
76 sal_Int32 nMinPos = SAL_MAX_INT32;
77 const SwpHints* pTextAttrs = m_rNd.GetpSwpHints();
78 if( pTextAttrs )
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 )
84 const SwTextAttr* pHt = pTextAttrs->Get(i);
85 if ( pHt->HasDummyChar() )
87 sal_Int32 nPos = pHt->GetStart();
89 if( nPos >= nStartPos && nPos <= nMinPos )
90 nMinPos = nPos;
92 if( ( ++nPos ) >= nStartPos && nPos < nMinPos )
93 nMinPos = nPos;
95 else if ( pHt->HasContent() )
97 const sal_Int32 nHintStart = pHt->GetStart();
98 if ( nHintStart >= nStartPos && nHintStart <= nMinPos )
100 nMinPos = nHintStart;
103 const sal_Int32 nHintEnd = pHt->End() ? *pHt->End() : COMPLETE_STRING;
104 if ( nHintEnd >= nStartPos && nHintEnd < nMinPos )
106 nMinPos = nHintEnd;
111 return nMinPos;
114 bool SwASC_AttrIter::OutAttr( sal_Int32 nSwPos )
116 bool bRet = false;
117 const SwpHints* pTextAttrs = m_rNd.GetpSwpHints();
118 if( pTextAttrs )
120 for( size_t i = 0; i < pTextAttrs->Count(); ++i )
122 const SwTextAttr* pHt = pTextAttrs->Get(i);
123 if ( ( pHt->HasDummyChar()
124 || pHt->HasContent() )
125 && nSwPos == pHt->GetStart() )
127 bRet = true;
128 OUString sOut;
129 switch( pHt->Which() )
131 case RES_TXTATR_FIELD:
132 case RES_TXTATR_ANNOTATION:
133 case RES_TXTATR_INPUTFIELD:
134 sOut = static_txtattr_cast<SwTextField const*>(pHt)
135 ->GetFormatField().GetField()->ExpandField(true, nullptr);
136 break;
138 case RES_TXTATR_FTN:
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());
150 break;
151 case RES_TXTATR_LINEBREAK:
153 // Downgrade the clearing break to a simple linebreak.
154 sOut = OUStringChar(GetCharOfTextAttr(*pHt));
155 break;
158 if( !sOut.isEmpty() )
159 m_rWrt.Strm().WriteUnicodeOrByteText(sOut);
161 else if( nSwPos < pHt->GetStart() )
162 break;
165 return bRet;
168 namespace {
170 class SwASC_RedlineIter
172 private:
173 SwTextNode const& m_rNode;
174 IDocumentRedlineAccess const& m_rIDRA;
175 SwRedlineTable::size_type m_nextRedline;
177 public:
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)
187 bool CheckNodeDeleted()
189 if (m_nextRedline == SwRedlineTable::npos)
191 return false;
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();
198 std::pair<sal_Int32, sal_Int32> GetNextRedlineSkip()
200 sal_Int32 nRedlineStart(COMPLETE_STRING);
201 sal_Int32 nRedlineEnd(COMPLETE_STRING);
202 for ( ; m_nextRedline < m_rIDRA.GetRedlineTable().size(); ++m_nextRedline)
204 SwRangeRedline const*const pRedline(m_rIDRA.GetRedlineTable()[m_nextRedline]);
205 if (pRedline->GetType() != RedlineType::Delete)
207 continue;
209 auto [pStart, pEnd] = pRedline->StartEnd(); // SwPosition*
210 if (m_rNode.GetIndex() < pStart->GetNodeIndex())
212 m_nextRedline = SwRedlineTable::npos;
213 break; // done
215 if (nRedlineStart == COMPLETE_STRING)
217 nRedlineStart = pStart->GetNodeIndex() == m_rNode.GetIndex()
218 ? pStart->GetContentIndex()
219 : 0;
221 else
223 if (pStart->GetContentIndex() != nRedlineEnd)
225 assert(nRedlineEnd < pStart->GetContentIndex());
226 break; // no increment, revisit it next call
229 nRedlineEnd = pEnd->GetNodeIndex() == m_rNode.GetIndex()
230 ? pEnd->GetContentIndex()
231 : COMPLETE_STRING;
233 return std::make_pair(nRedlineStart, nRedlineEnd);
239 // Output of the node
241 static Writer& OutASC_SwTextNode( Writer& rWrt, SwContentNode& rNode )
243 const SwTextNode& rNd = static_cast<SwTextNode&>(rNode);
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();
252 bool bIsOneParagraph = rWrt.m_pOrigPam->Start()->GetNode() == rWrt.m_pOrigPam->End()->GetNode() && !getenv("SW_ASCII_COPY_NUMBERING");
254 SwASC_AttrIter aAttrIter( static_cast<SwASCWriter&>(rWrt), rNd, nStrPos );
255 SwASC_RedlineIter redlineIter(static_cast<SwASCWriter&>(rWrt), rNd);
257 if (redlineIter.CheckNodeDeleted())
259 return rWrt;
262 const SwNumRule* pNumRule = rNd.GetNumRule();
263 if (pNumRule && !nStrPos && rWrt.m_bExportParagraphNumbering && !bIsOneParagraph)
265 bool bIsOutlineNumRule = pNumRule == rNd.GetDoc().GetOutlineNumRule();
267 // indent each numbering level by 4 spaces
268 OUString level;
269 if (!bIsOutlineNumRule)
271 for (int i = 0; i <= rNd.GetActualListLevel(); ++i)
272 level += " ";
275 // set up bullets or numbering
276 OUString numString(rNd.GetNumString());
277 if (numString.isEmpty() && !bIsOutlineNumRule)
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 = " ";
287 if (!level.isEmpty() || !numString.isEmpty())
288 rWrt.Strm().WriteUnicodeOrByteText(Concat2View(level + numString + " "));
291 OUString aStr( rNd.GetText() );
292 if( rWrt.m_bASCII_ParaAsBlank )
293 aStr = aStr.replace(0x0A, ' ');
295 const bool bExportSoftHyphens = RTL_TEXTENCODING_UCS2 == rWrt.GetAsciiOptions().GetCharSet() ||
296 RTL_TEXTENCODING_UTF8 == rWrt.GetAsciiOptions().GetCharSet();
298 std::pair<sal_Int32, sal_Int32> curRedline(redlineIter.GetNextRedlineSkip());
299 for (;;) {
300 const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
302 bool isOutAttr(false);
303 if (nStrPos < curRedline.first || curRedline.second <= nStrPos)
305 isOutAttr = aAttrIter.OutAttr(nStrPos);
308 if (!isOutAttr)
310 OUStringBuffer buf;
311 while (true)
313 if (nNextAttr <= curRedline.first)
315 buf.append(aStr.subView(nStrPos, nNextAttr - nStrPos));
316 break;
318 else if (nStrPos < curRedline.second)
320 if (nStrPos < curRedline.first)
322 buf.append(aStr.subView(nStrPos, curRedline.first - nStrPos));
324 if (curRedline.second <= nNextAttr)
326 nStrPos = curRedline.second;
327 curRedline = redlineIter.GetNextRedlineSkip();
329 else
331 nStrPos = nNextAttr;
332 break;
335 else
337 curRedline = redlineIter.GetNextRedlineSkip();
340 OUString aOutStr(buf.makeStringAndClear());
341 if ( !bExportSoftHyphens )
342 aOutStr = aOutStr.replaceAll(OUStringChar(CHAR_SOFTHYPHEN), "");
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 [] = {
347 CH_TXT_ATR_INPUTFIELDSTART,
348 CH_TXT_ATR_INPUTFIELDEND,
349 CH_TXT_ATR_FORMELEMENT,
350 CH_TXT_ATR_FIELDSTART,
351 CH_TXT_ATR_FIELDSEP,
352 CH_TXT_ATR_FIELDEND,
353 CH_TXTATR_BREAKWORD,
356 aOutStr = comphelper::string::removeAny(aOutStr, forbidden);
358 rWrt.Strm().WriteUnicodeOrByteText( aOutStr );
360 nStrPos = nNextAttr;
361 if (nStrPos >= nEnd)
363 break;
365 aAttrIter.NextPos();
368 if( !bLastNd ||
369 ( ( !rWrt.m_bWriteClipboardDoc && !rWrt.m_bASCII_NoLastLineEnd )
370 && !nStrPos && nEnd == nNodeEnd ) )
371 rWrt.Strm().WriteUnicodeOrByteText( static_cast<SwASCWriter&>(rWrt).GetLineEnd());
373 return rWrt;
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.
382 SwNodeFnTab aASCNodeFnTab = {
383 /* RES_TXTNODE */ OutASC_SwTextNode,
384 /* RES_GRFNODE */ nullptr,
385 /* RES_OLENODE */ nullptr
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */