Bug Summary

File:home/maarten/src/libreoffice/core/sw/inc/pam.hxx
Warning:line 213, column 26
Forming reference to null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name pam.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/crsr/pam.cxx

/home/maarten/src/libreoffice/core/sw/source/core/crsr/pam.cxx

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 <sal/config.h>
21
22#include <string_view>
23
24#include <tools/gen.hxx>
25#include <editeng/protitem.hxx>
26#include <cntfrm.hxx>
27#include <pagefrm.hxx>
28#include <doc.hxx>
29#include <IDocumentLayoutAccess.hxx>
30#include <docary.hxx>
31#include <pam.hxx>
32#include <pamtyp.hxx>
33#include <txtfrm.hxx>
34#include <fmtcntnt.hxx>
35#include <frmatr.hxx>
36#include <flyfrm.hxx>
37#include <fmteiro.hxx>
38#include <section.hxx>
39#include <sectfrm.hxx>
40#include <ndtxt.hxx>
41#include <swcrsr.hxx>
42
43#include <IMark.hxx>
44#include <DocumentSettingManager.hxx>
45#include <hints.hxx>
46#include <txatbase.hxx>
47#include <xmloff/odffields.hxx>
48#include <rtl/ustrbuf.hxx>
49
50#include <editsh.hxx>
51
52// for the dump "MSC-" compiler
53static sal_Int32 GetSttOrEnd( bool bCondition, const SwContentNode& rNd )
54{
55 return bCondition ? 0 : rNd.Len();
56}
57
58SwPosition::SwPosition( const SwNodeIndex & rNodeIndex, const SwIndex & rContent )
59 : nNode( rNodeIndex ), nContent( rContent )
60{
61}
62
63SwPosition::SwPosition( const SwNodeIndex & rNodeIndex )
64 : nNode( rNodeIndex ), nContent( nNode.GetNode().GetContentNode() )
65{
66}
67
68SwPosition::SwPosition( const SwNode& rNode )
69 : nNode( rNode ), nContent( nNode.GetNode().GetContentNode() )
70{
71}
72
73SwPosition::SwPosition( SwContentNode & rNode, const sal_Int32 nOffset )
74 : nNode( rNode ), nContent( &rNode, nOffset )
75{
76}
77
78bool SwPosition::operator<(const SwPosition &rPos) const
79{
80 if( nNode < rPos.nNode )
81 return true;
82 if( nNode == rPos.nNode )
83 {
84 // note that positions with text node but no SwIndex registered are
85 // created for text frames anchored at para (see SwXFrame::getAnchor())
86 SwIndexReg const*const pThisReg(nContent.GetIdxReg());
87 SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
88 if (pThisReg && pOtherReg)
89 {
90 return (nContent < rPos.nContent);
91 }
92 else // by convention position with no index is smaller
93 {
94 return pOtherReg != nullptr;
95 }
96 }
97 return false;
98}
99
100bool SwPosition::operator>(const SwPosition &rPos) const
101{
102 if(nNode > rPos.nNode )
103 return true;
104 if( nNode == rPos.nNode )
105 {
106 // note that positions with text node but no SwIndex registered are
107 // created for text frames anchored at para (see SwXFrame::getAnchor())
108 SwIndexReg const*const pThisReg(nContent.GetIdxReg());
109 SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
110 if (pThisReg && pOtherReg)
111 {
112 return (nContent > rPos.nContent);
113 }
114 else // by convention position with no index is smaller
115 {
116 return pThisReg != nullptr;
117 }
118 }
119 return false;
120}
121
122bool SwPosition::operator<=(const SwPosition &rPos) const
123{
124 if(nNode < rPos.nNode )
125 return true;
126 if( nNode == rPos.nNode )
127 {
128 // note that positions with text node but no SwIndex registered are
129 // created for text frames anchored at para (see SwXFrame::getAnchor())
130 SwIndexReg const*const pThisReg(nContent.GetIdxReg());
131 SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
132 if (pThisReg && pOtherReg)
133 {
134 return (nContent <= rPos.nContent);
135 }
136 else // by convention position with no index is smaller
137 {
138 return pThisReg == nullptr;
139 }
140 }
141 return false;
142}
143
144bool SwPosition::operator>=(const SwPosition &rPos) const
145{
146 if(nNode > rPos.nNode )
147 return true;
148 if( nNode == rPos.nNode )
149 {
150 // note that positions with text node but no SwIndex registered are
151 // created for text frames anchored at para (see SwXFrame::getAnchor())
152 SwIndexReg const*const pThisReg(nContent.GetIdxReg());
153 SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
154 if (pThisReg && pOtherReg)
155 {
156 return (nContent >= rPos.nContent);
157 }
158 else // by convention position with no index is smaller
159 {
160 return pOtherReg == nullptr;
161 }
162 }
163 return false;
164}
165
166bool SwPosition::operator==(const SwPosition &rPos) const
167{
168 return (nNode == rPos.nNode)
169 && (nContent == rPos.nContent);
170}
171
172bool SwPosition::operator!=(const SwPosition &rPos) const
173{
174 return (nNode != rPos.nNode)
175 || (nContent != rPos.nContent);
176}
177
178SwDoc& SwPosition::GetDoc() const
179{
180 return nNode.GetNode().GetDoc();
181}
182
183void SwPosition::dumpAsXml(xmlTextWriterPtr pWriter) const
184{
185 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("SwPosition"));
186 xmlTextWriterWriteAttribute(pWriter, BAD_CAST(xmlChar *)("nNode"), BAD_CAST(xmlChar *)(OString::number(nNode.GetIndex()).getStr()));
187 xmlTextWriterWriteAttribute(pWriter, BAD_CAST(xmlChar *)("nContent"), BAD_CAST(xmlChar *)(OString::number(nContent.GetIndex()).getStr()));
188 xmlTextWriterEndElement(pWriter);
189}
190
191std::ostream &operator <<(std::ostream& s, const SwPosition& position)
192{
193 return s << "SwPosition (node " << position.nNode.GetIndex() << ", offset " << position.nContent.GetIndex() << ")";
194}
195
196namespace {
197
198enum CHKSECTION { Chk_Both, Chk_One, Chk_None };
199
200}
201
202static CHKSECTION lcl_TstIdx( sal_uLong nSttIdx, sal_uLong nEndIdx, const SwNode& rEndNd )
203{
204 sal_uLong nStt = rEndNd.StartOfSectionIndex(), nEnd = rEndNd.GetIndex();
205 CHKSECTION eSec = nStt < nSttIdx && nEnd >= nSttIdx ? Chk_One : Chk_None;
206 if( nStt < nEndIdx && nEnd >= nEndIdx )
207 return( eSec == Chk_One ? Chk_Both : Chk_One );
208 return eSec;
209}
210
211static bool lcl_ChkOneRange( CHKSECTION eSec, bool bChkSections,
212 const SwNode& rBaseEnd, sal_uLong nStt, sal_uLong nEnd )
213{
214 if( eSec != Chk_Both )
215 return false;
216
217 if( !bChkSections )
218 return true;
219
220 // search the surrounding section
221 const SwNodes& rNds = rBaseEnd.GetNodes();
222 const SwNode *pTmp, *pNd = rNds[ nStt ];
223 if( !pNd->IsStartNode() )
224 pNd = pNd->StartOfSectionNode();
225
226 if( pNd == rNds[ nEnd ]->StartOfSectionNode() )
227 return true; // same StartNode, same section
228
229 // already on a base node => error
230 if( !pNd->StartOfSectionIndex() )
231 return false;
232
233 for (;;)
234 {
235 pTmp = pNd->StartOfSectionNode();
236 if (pTmp->EndOfSectionNode() == &rBaseEnd )
237 break;
238 pNd = pTmp;
239 }
240
241 sal_uLong nSttIdx = pNd->GetIndex(), nEndIdx = pNd->EndOfSectionIndex();
242 return nSttIdx <= nStt && nStt <= nEndIdx &&
243 nSttIdx <= nEnd && nEnd <= nEndIdx;
244}
245
246/** Check if the given range is inside one of the defined top-level sections.
247 *
248 * The top-level sections are Content, AutoText, PostIts, Inserts, and Redlines.
249 *
250 * @param bChkSection if true, also check that the given range is inside
251 * a single second-level section inside any of the
252 * top-level sections, except for the Content section.
253 *
254 * @return <true> if valid range
255 */
256bool CheckNodesRange( const SwNodeIndex& rStt,
257 const SwNodeIndex& rEnd, bool bChkSection )
258{
259 const SwNodes& rNds = rStt.GetNodes();
260 sal_uLong nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex();
261 CHKSECTION eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfContent() );
262 if( Chk_None != eSec )
263 return eSec == Chk_Both;
264
265 eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfAutotext() );
266 if( Chk_None != eSec )
267 return lcl_ChkOneRange( eSec, bChkSection,
268 rNds.GetEndOfAutotext(), nStt, nEnd );
269
270 eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfPostIts() );
271 if( Chk_None != eSec )
272 return lcl_ChkOneRange( eSec, bChkSection,
273 rNds.GetEndOfPostIts(), nStt, nEnd );
274
275 eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfInserts() );
276 if( Chk_None != eSec )
277 return lcl_ChkOneRange( eSec, bChkSection,
278 rNds.GetEndOfInserts(), nStt, nEnd );
279
280 eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfRedlines() );
281 if( Chk_None != eSec )
282 return lcl_ChkOneRange( eSec, bChkSection,
283 rNds.GetEndOfRedlines(), nStt, nEnd );
284
285 return false; // somewhere in between => error
286}
287
288bool GoNext(SwNode* pNd, SwIndex * pIdx, sal_uInt16 nMode )
289{
290 if( pNd->IsContentNode() )
291 return static_cast<SwContentNode*>(pNd)->GoNext( pIdx, nMode );
292 return false;
293}
294
295bool GoPrevious( SwNode* pNd, SwIndex * pIdx, sal_uInt16 nMode )
296{
297 if( pNd->IsContentNode() )
298 return static_cast<SwContentNode*>(pNd)->GoPrevious( pIdx, nMode );
299 return false;
300}
301
302SwContentNode* GoNextNds( SwNodeIndex* pIdx, bool bChk )
303{
304 SwNodeIndex aIdx( *pIdx );
305 SwContentNode* pNd = aIdx.GetNodes().GoNext( &aIdx );
306 if( pNd )
307 {
308 if( bChk && 1 != aIdx.GetIndex() - pIdx->GetIndex() &&
309 !CheckNodesRange( *pIdx, aIdx, true ) )
310 pNd = nullptr;
311 else
312 *pIdx = aIdx;
313 }
314 return pNd;
315}
316
317SwContentNode* GoPreviousNds( SwNodeIndex * pIdx, bool bChk )
318{
319 SwNodeIndex aIdx( *pIdx );
320 SwContentNode* pNd = SwNodes::GoPrevious( &aIdx );
321 if( pNd )
322 {
323 if( bChk && 1 != pIdx->GetIndex() - aIdx.GetIndex() &&
324 !CheckNodesRange( *pIdx, aIdx, true ) )
325 pNd = nullptr;
326 else
327 *pIdx = aIdx;
328 }
329 return pNd;
330}
331
332SwPaM::SwPaM( const SwPosition& rPos, SwPaM* pRing )
333 : Ring( pRing )
334 , m_Bound1( rPos )
335 , m_Bound2( rPos.nNode.GetNode().GetNodes() ) // default initialize
336 , m_pPoint( &m_Bound1 )
337 , m_pMark( m_pPoint )
338 , m_bIsInFrontOfLabel( false )
339{
340}
341
342SwPaM::SwPaM( const SwPosition& rMark, const SwPosition& rPoint, SwPaM* pRing )
343 : Ring( pRing )
344 , m_Bound1( rMark )
345 , m_Bound2( rPoint )
346 , m_pPoint( &m_Bound2 )
347 , m_pMark( &m_Bound1 )
348 , m_bIsInFrontOfLabel( false )
349{
350}
351
352SwPaM::SwPaM( const SwNodeIndex& rMark, const SwNodeIndex& rPoint,
353 long nMarkOffset, long nPointOffset, SwPaM* pRing )
354 : Ring( pRing )
355 , m_Bound1( rMark )
356 , m_Bound2( rPoint )
357 , m_pPoint( &m_Bound2 )
358 , m_pMark( &m_Bound1 )
359 , m_bIsInFrontOfLabel( false )
360{
361 if ( nMarkOffset )
362 {
363 m_pMark->nNode += nMarkOffset;
364 }
365 if ( nPointOffset )
366 {
367 m_pPoint->nNode += nPointOffset;
368 }
369 m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetContentNode(), 0 );
370 m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetContentNode(), 0 );
371}
372
373SwPaM::SwPaM( const SwNode& rMark, const SwNode& rPoint,
374 long nMarkOffset, long nPointOffset, SwPaM* pRing )
375 : Ring( pRing )
376 , m_Bound1( rMark )
377 , m_Bound2( rPoint )
378 , m_pPoint( &m_Bound2 )
379 , m_pMark( &m_Bound1 )
380 , m_bIsInFrontOfLabel( false )
381{
382 if ( nMarkOffset )
383 {
384 m_pMark->nNode += nMarkOffset;
385 }
386 if ( nPointOffset )
387 {
388 m_pPoint->nNode += nPointOffset;
389 }
390 m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetContentNode(), 0 );
391 m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetContentNode(), 0 );
392}
393
394SwPaM::SwPaM( const SwNodeIndex& rMark, sal_Int32 nMarkContent,
395 const SwNodeIndex& rPoint, sal_Int32 nPointContent, SwPaM* pRing )
396 : Ring( pRing )
397 , m_Bound1( rMark )
398 , m_Bound2( rPoint )
399 , m_pPoint( &m_Bound2 )
400 , m_pMark( &m_Bound1 )
401 , m_bIsInFrontOfLabel( false )
402{
403 m_pPoint->nContent.Assign( rPoint.GetNode().GetContentNode(), nPointContent);
404 m_pMark ->nContent.Assign( rMark .GetNode().GetContentNode(), nMarkContent );
405}
406
407SwPaM::SwPaM( const SwNode& rMark, sal_Int32 nMarkContent,
408 const SwNode& rPoint, sal_Int32 nPointContent, SwPaM* pRing )
409 : Ring( pRing )
410 , m_Bound1( rMark )
411 , m_Bound2( rPoint )
412 , m_pPoint( &m_Bound2 )
413 , m_pMark( &m_Bound1 )
414 , m_bIsInFrontOfLabel( false )
415{
416 m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetContentNode(),
417 nPointContent);
418 m_pMark ->nContent.Assign( m_pMark ->nNode.GetNode().GetContentNode(),
419 nMarkContent );
420}
421
422SwPaM::SwPaM( const SwNode& rNode, sal_Int32 nContent, SwPaM* pRing )
423 : Ring( pRing )
424 , m_Bound1( rNode )
425 , m_Bound2( m_Bound1.nNode.GetNode().GetNodes() ) // default initialize
426 , m_pPoint( &m_Bound1 )
427 , m_pMark( &m_Bound1 )
428 , m_bIsInFrontOfLabel( false )
429{
430 m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetContentNode(),
431 nContent );
432}
433
434SwPaM::SwPaM( const SwNodeIndex& rNodeIdx, sal_Int32 nContent, SwPaM* pRing )
435 : Ring( pRing )
436 , m_Bound1( rNodeIdx )
437 , m_Bound2( rNodeIdx.GetNode().GetNodes() ) // default initialize
438 , m_pPoint( &m_Bound1 )
439 , m_pMark( &m_Bound1 )
440 , m_bIsInFrontOfLabel( false )
441{
442 m_pPoint->nContent.Assign( rNodeIdx.GetNode().GetContentNode(), nContent );
443}
444
445SwPaM::~SwPaM() {}
446
447SwPaM::SwPaM(SwPaM const& rPam, SwPaM *const pRing)
448 : Ring(pRing)
449 , m_Bound1( *(rPam.m_pPoint) )
450 , m_Bound2( *(rPam.m_pMark) )
451 , m_pPoint( &m_Bound1 ), m_pMark( rPam.HasMark() ? &m_Bound2 : m_pPoint )
452 , m_bIsInFrontOfLabel( false )
453{
454}
455
456// @@@ semantic: no copy assignment for super class Ring.
457SwPaM &SwPaM::operator=( const SwPaM &rPam )
458{
459 if(this == &rPam)
460 return *this;
461
462 *m_pPoint = *( rPam.m_pPoint );
463 if ( rPam.HasMark() )
464 {
465 SetMark();
466 *m_pMark = *( rPam.m_pMark );
467 }
468 else
469 {
470 DeleteMark();
471 }
472 return *this;
473}
474
475void SwPaM::SetMark()
476{
477 if (m_pPoint == &m_Bound1)
478 {
479 m_pMark = &m_Bound2;
480 }
481 else
482 {
483 m_pMark = &m_Bound1;
484 }
485 (*m_pMark) = *m_pPoint;
486}
487
488#ifdef DBG_UTIL
489void SwPaM::Exchange()
490{
491 if (m_pPoint != m_pMark)
492 {
493 SwPosition *pTmp = m_pPoint;
494 m_pPoint = m_pMark;
495 m_pMark = pTmp;
496 }
497}
498#endif
499
500/// movement of cursor
501bool SwPaM::Move( SwMoveFnCollection const & fnMove, SwGoInDoc fnGo )
502{
503 const bool bRet = (*fnGo)( *this, fnMove );
504
505 m_bIsInFrontOfLabel = false;
506 return bRet;
507}
508
509namespace sw {
510
511/** make a new region
512
513 Sets the first SwPaM onto the given SwPaM, or to the beginning or end of a
514 document. SPoint stays at its position, GetMark will be changed respectively.
515
516 @param fnMove Contains information if beginning or end of document.
517 @param pOrigRg The given region.
518
519 @return Newly created range, in Ring with parameter pOrigRg.
520*/
521std::unique_ptr<SwPaM> MakeRegion(SwMoveFnCollection const & fnMove,
522 const SwPaM & rOrigRg)
523{
524 std::unique_ptr<SwPaM> pPam;
525 {
526 pPam.reset(new SwPaM(rOrigRg, const_cast<SwPaM*>(&rOrigRg))); // given search range
527 // make sure that SPoint is on the "real" start position
528 // FORWARD: SPoint always smaller than GetMark
529 // BACKWARD: SPoint always bigger than GetMark
530 if( (pPam->GetMark()->*fnMove.fnCmpOp)( *pPam->GetPoint() ) )
531 pPam->Exchange();
532 }
533 return pPam;
534}
535
536} // namespace sw
537
538void SwPaM::Normalize(bool bPointFirst)
539{
540 if (HasMark())
541 if ( ( bPointFirst && *m_pPoint > *m_pMark) ||
542 (!bPointFirst && *m_pPoint < *m_pMark) )
543 {
544 Exchange();
545 }
546}
547
548/// return page number at cursor (for reader and page bound frames)
549sal_uInt16 SwPaM::GetPageNum( bool bAtPoint, const Point* pLayPos )
550{
551 const SwContentFrame* pCFrame;
552 const SwPageFrame *pPg;
553 const SwContentNode *pNd ;
554 const SwPosition* pPos = bAtPoint ? m_pPoint : m_pMark;
555
556 std::pair<Point, bool> tmp;
557 if (pLayPos)
558 {
559 tmp.first = *pLayPos;
560 tmp.second = false;
561 }
562 if( nullptr != ( pNd = pPos->nNode.GetNode().GetContentNode() ) &&
563 nullptr != (pCFrame = pNd->getLayoutFrame(pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), pPos, pLayPos ? &tmp : nullptr)) &&
564 nullptr != ( pPg = pCFrame->FindPageFrame() ))
565 return pPg->GetPhyPageNum();
566 return 0;
567}
568
569// form view - see also SwCursorShell::IsCursorReadonly()
570static const SwFrame* lcl_FindEditInReadonlyFrame( const SwFrame& rFrame )
571{
572 const SwFrame* pRet = nullptr;
573
574 const SwFlyFrame* pFly;
575 const SwSectionFrame* pSectionFrame;
576
577 if( rFrame.IsInFly() &&
578 (pFly = rFrame.FindFlyFrame())->GetFormat()->GetEditInReadonly().GetValue() &&
579 pFly->Lower() &&
580 !pFly->Lower()->IsNoTextFrame() )
581 {
582 pRet = pFly;
583 }
584 else if ( rFrame.IsInSct() &&
585 nullptr != ( pSectionFrame = rFrame.FindSctFrame() )->GetSection() &&
586 pSectionFrame->GetSection()->IsEditInReadonlyFlag() )
587 {
588 pRet = pSectionFrame;
589 }
590
591 return pRet;
592}
593
594/// is in protected section or selection surrounds something protected
595bool SwPaM::HasReadonlySel( bool bFormView ) const
596{
597 bool bRet = false;
598
599 const SwContentNode* pNd = GetPoint()->nNode.GetNode().GetContentNode();
600 const SwContentFrame *pFrame = nullptr;
601 if ( pNd != nullptr )
1
Taking false branch
602 {
603 Point aTmpPt;
604 std::pair<Point, bool> const tmp(aTmpPt, false);
605 pFrame = pNd->getLayoutFrame(
606 pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
607 GetPoint(), &tmp);
608 }
609
610 // Will be set if point are inside edit-in-readonly environment
611 const SwFrame* pPointEditInReadonlyFrame = nullptr;
612 if ( pFrame != nullptr
613 && ( pFrame->IsProtected()
614 || ( bFormView
615 && nullptr == ( pPointEditInReadonlyFrame = lcl_FindEditInReadonlyFrame( *pFrame ) ) ) ) )
616 {
617 bRet = true;
618 }
619 else if( pNd != nullptr )
2
Taking false branch
620 {
621 const SwSectionNode* pSNd = pNd->GetSectionNode();
622 if ( pSNd != nullptr
623 && ( pSNd->GetSection().IsProtectFlag()
624 || ( bFormView
625 && !pSNd->GetSection().IsEditInReadonlyFlag()) ) )
626 {
627 bRet = true;
628 }
629 else
630 {
631 const SwSectionNode* pParentSectionNd = pNd->FindSectionNode();
632 if ( pParentSectionNd != nullptr
633 && ( pParentSectionNd->GetSection().IsProtectFlag()
634 || ( bFormView && !pParentSectionNd->GetSection().IsEditInReadonlyFlag()) ) )
635 {
636 bRet = true;
637 }
638 }
639 }
640
641 if ( !bRet
2.1
'bRet' is false
2.1
'bRet' is false
642 && HasMark() 643 && GetPoint()->nNode != GetMark()->nNode ) 644 { 645 pNd = GetMark()->nNode.GetNode().GetContentNode(); 646 pFrame = nullptr; 647 if ( pNd != nullptr ) 648 { 649 Point aTmpPt; 650 std::pair<Point, bool> const tmp(aTmpPt, false); 651 pFrame = pNd->getLayoutFrame( 652 pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), 653 GetMark(), &tmp); 654 } 655 656 const SwFrame* pMarkEditInReadonlyFrame = nullptr; 657 if ( pFrame != nullptr 658 && ( pFrame->IsProtected() 659 || ( bFormView 660 && nullptr == ( pMarkEditInReadonlyFrame = lcl_FindEditInReadonlyFrame( *pFrame ) ) ) ) ) 661 { 662 bRet = true; 663 } 664 else if( pNd != nullptr ) 665 { 666 const SwSectionNode* pSNd = pNd->GetSectionNode(); 667 if ( pSNd != nullptr 668 && ( pSNd->GetSection().IsProtectFlag() 669 || ( bFormView 670 && !pSNd->GetSection().IsEditInReadonlyFlag()) ) ) 671 { 672 bRet = true; 673 } 674 } 675 676 if ( !bRet && bFormView ) 677 { 678 // Check if start and end frame are inside the _same_ 679 // edit-in-readonly-environment. Otherwise we better return 'true' 680 if ( pPointEditInReadonlyFrame != pMarkEditInReadonlyFrame ) 681 bRet = true; 682 } 683 684 // check for protected section inside the selection 685 if( !bRet ) 686 { 687 sal_uLong nSttIdx = GetMark()->nNode.GetIndex(), 688 nEndIdx = GetPoint()->nNode.GetIndex(); 689 if( nEndIdx <= nSttIdx ) 690 { 691 sal_uLong nTmp = nSttIdx; 692 nSttIdx = nEndIdx; 693 nEndIdx = nTmp; 694 } 695 696 // If a protected section should be between nodes, then the 697 // selection needs to contain already x nodes. 698 // (TextNd, SectNd, TextNd, EndNd, TextNd ) 699 if( nSttIdx + 3 < nEndIdx ) 700 { 701 const SwSectionFormats& rFormats = GetDoc().GetSections(); 702 for( SwSectionFormats::size_type n = rFormats.size(); n; ) 703 { 704 const SwSectionFormat* pFormat = rFormats[ --n ]; 705 if( pFormat->GetProtect().IsContentProtected() ) 706 { 707 const SwFormatContent& rContent = pFormat->GetContent(false); 708 OSL_ENSURE( rContent.GetContentIdx(), "where is the SectionNode?" )do { if (true && (!(rContent.GetContentIdx()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/crsr/pam.cxx"
":" "708" ": "), "%s", "where is the SectionNode?"); } } while
(false)
; 709 sal_uLong nIdx = rContent.GetContentIdx()->GetIndex(); 710 if( nSttIdx <= nIdx && nEndIdx >= nIdx && 711 rContent.GetContentIdx()->GetNode().GetNodes().IsDocNodes() ) 712 { 713 bRet = true; 714 break; 715 } 716 } 717 } 718 } 719 } 720 } 721 722 const SwDoc& rDoc = GetDoc(); 723 // Legacy text/combo/checkbox: never return read-only when inside these form fields. 724 const IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess(); 725 sw::mark::IFieldmark* pA = GetPoint() ? pMarksAccess->getFieldmarkFor( *GetPoint( ) ) : nullptr;
3
'?' condition is true
726 sw::mark::IFieldmark* pB = GetMark() ? pMarksAccess->getFieldmarkFor( *GetMark( ) ) : pA;
4
Assuming pointer value is null
5
'?' condition is false
727 // prevent the user from accidentally deleting the field itself when modifying the text. 728 const bool bAtStartA = (pA != nullptr) && (pA->GetMarkStart() == *GetPoint());
6
Assuming the condition is false
729 const bool bAtStartB = (pB != nullptr) && (pB->GetMarkStart() == *GetMark()); 730 731 if (!bRet
6.1
'bRet' is false
6.1
'bRet' is false
)
7
Taking true branch
732 { 733 bool bUnhandledMark = pA
7.1
'pA' is null
7.1
'pA' is null
&& pA->GetFieldname( ) == ODF_UNHANDLED"vnd.oasis.opendocument.field.UNHANDLED"; 734 // Unhandled fieldmarks case shouldn't be edited manually to avoid breaking anything 735 if ( ( pA
7.2
'pA' is equal to 'pB'
7.2
'pA' is equal to 'pB'
== pB ) && bUnhandledMark
7.3
'bUnhandledMark' is false
7.3
'bUnhandledMark' is false
)
8
Taking false branch
736 bRet = true; 737 else 738 { 739 if ((pA
8.1
'pA' is equal to 'pB'
8.1
'pA' is equal to 'pB'
== pB) && (bAtStartA
8.2
'bAtStartA' is equal to 'bAtStartB'
8.2
'bAtStartA' is equal to 'bAtStartB'
!= bAtStartB))
9
Taking false branch
740 bRet = true; 741 else if (pA
9.1
'pA' is equal to 'pB'
9.1
'pA' is equal to 'pB'
!= pB)
10
Taking false branch
742 { 743 // If both points are either outside or at marks edges (i.e. selection either 744 // touches fields, or fully encloses it), then don't disable editing 745 bRet = !( ( !pA || bAtStartA ) && ( !pB || bAtStartB ) ); 746 } 747 if( !bRet
10.1
'bRet' is false
10.1
'bRet' is false
&& rDoc.GetDocumentSettingManager().get( DocumentSettingId::PROTECT_FORM ) && (pA || pB) )
11
Assuming the condition is false
748 { 749 // Form protection case 750 bRet = ( pA == nullptr ) || ( pB == nullptr ) || bAtStartA || bAtStartB; 751 } 752 } 753 } 754 else 755 { 756 // Allow editing when the cursor/selection is fully inside of a legacy form field. 757 bRet = !( pA != nullptr && !bAtStartA && !bAtStartB && pA == pB ); 758 } 759 760 if (!bRet
11.1
'bRet' is false
11.1
'bRet' is false
)
12
Taking true branch
761 { 762 // Paragraph Signatures and Classification fields are read-only. 763 if (rDoc.GetEditShell())
13
Assuming the condition is false
14
Taking false branch
764 bRet = rDoc.GetEditShell()->IsCursorInParagraphMetadataField(); 765 } 766 767 if (!bRet
14.1
'bRet' is false
14.1
'bRet' is false
&&
16
Taking false branch
768 rDoc.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
15
Assuming the condition is false
769 { 770 if (rDoc.getIDocumentMarkAccess()->isBookmarkDeleted(*this)) 771 { 772 return true; 773 } 774 } 775 if (!bRet
16.1
'bRet' is false
16.1
'bRet' is false
&&
18
Taking true branch
776 rDoc.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FIELDS))
17
Assuming the condition is true
777 { 778 SwPosition const& rStart(*Start());
19
Calling 'SwPaM::Start'
779 SwPosition const& rEnd(*End()); 780 for (SwNodeIndex n = rStart.nNode; n <= rEnd.nNode; ++n) 781 { 782 if (SwTextNode const*const pNode = n.GetNode().GetTextNode()) 783 { 784 if (SwpHints const*const pHints = pNode->GetpSwpHints()) 785 { 786 for (size_t i = 0; i < pHints->Count(); ++i) 787 { 788 SwTextAttr const*const pHint(pHints->Get(i)); 789 if (n == rStart.nNode && pHint->GetStart() < rStart.nContent.GetIndex()) 790 { 791 continue; // before selection 792 } 793 if (n == rEnd.nNode && rEnd.nContent.GetIndex() <= pHint->GetStart()) 794 { 795 break; // after selection 796 } 797 if (pHint->Which() == RES_TXTATR_FIELD 798 // placeholders don't work if you can't delete them 799 && pHint->GetFormatField().GetField()->GetTyp()->Which() != SwFieldIds::JumpEdit) 800 { 801 return true; 802 } 803 } 804 } 805 } 806 } 807 } 808 809 return bRet; 810} 811 812/// This function returns the next node in direction of search. If there is no 813/// left or the next is out of the area, then a null-pointer is returned. 814/// @param rbFirst If <true> then first time request. If so than the position of 815/// the PaM must not be changed! 816SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & fnMove, 817 bool const bInReadOnly, SwRootFrame const*const i_pLayout) 818{ 819 SwRootFrame const*const pLayout(i_pLayout ? i_pLayout : 820 rPam.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()); 821 SwContentNode * pNd = nullptr; 822 if( ((*rPam.GetPoint()).*fnMove.fnCmpOp)( *rPam.GetMark() ) || 823 ( *rPam.GetPoint() == *rPam.GetMark() && rbFirst ) ) 824 { 825 if( rbFirst ) 826 { 827 rbFirst = false; 828 pNd = rPam.GetContentNode(); 829 if( pNd ) 830 { 831 SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); 832 if( 833 ( 834 nullptr == pFrame || 835 ( !bInReadOnly && pFrame->IsProtected() ) || 836 (pFrame->IsTextFrame() && static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) 837 ) || 838 ( !bInReadOnly && pNd->FindSectionNode() && 839 pNd->FindSectionNode()->GetSection().IsProtect() 840 ) 841 ) 842 { 843 pNd = nullptr; 844 } 845 } 846 } 847 848 if( !pNd ) // is the cursor not on a ContentNode? 849 { 850 SwPosition aPos( *rPam.GetPoint() ); 851 bool bSrchForward = &fnMove == &fnMoveForward; 852 SwNodes& rNodes = aPos.nNode.GetNodes(); 853 854 // go to next/previous ContentNode 855 while( true ) 856 { 857 if (i_pLayout && aPos.nNode.GetNode().IsTextNode()) 858 { 859 auto const fal(sw::GetFirstAndLastNode(*pLayout, aPos.nNode)); 860 aPos.nNode = bSrchForward ? *fal.second : *fal.first; 861 } 862 863 pNd = bSrchForward 864 ? rNodes.GoNextSection( &aPos.nNode, true, !bInReadOnly ) 865 : SwNodes::GoPrevSection( &aPos.nNode, true, !bInReadOnly ); 866 if( pNd ) 867 { 868 aPos.nContent.Assign( pNd, ::GetSttOrEnd( bSrchForward,*pNd )); 869 // is the position still in the area 870 if( (aPos.*fnMove.fnCmpOp)( *rPam.GetMark() ) ) 871 { 872 // only in AutoTextSection can be nodes that are hidden 873 SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); 874 if (nullptr == pFrame || 875 ( !bInReadOnly && pFrame->IsProtected() ) || 876 ( pFrame->IsTextFrame() && 877 static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow())) 878 { 879 pNd = nullptr; 880 continue; 881 } 882 *rPam.GetPoint() = aPos; 883 } 884 else 885 pNd = nullptr; // no valid node 886 break; 887 } 888 break; 889 } 890 } 891 } 892 return pNd; 893} 894 895void GoStartDoc( SwPosition * pPos ) 896{ 897 SwNodes& rNodes = pPos->nNode.GetNodes(); 898 pPos->nNode = *rNodes.GetEndOfContent().StartOfSectionNode(); 899 // we always need to find a ContentNode! 900 SwContentNode* pCNd = rNodes.GoNext( &pPos->nNode ); 901 if( pCNd ) 902 pCNd->MakeStartIndex( &pPos->nContent ); 903} 904 905void GoEndDoc( SwPosition * pPos ) 906{ 907 SwNodes& rNodes = pPos->nNode.GetNodes(); 908 pPos->nNode = rNodes.GetEndOfContent(); 909 SwContentNode* pCNd = GoPreviousNds( &pPos->nNode, true ); 910 if( pCNd ) 911 pCNd->MakeEndIndex( &pPos->nContent ); 912} 913 914void GoStartSection( SwPosition * pPos ) 915{ 916 // jump to section's beginning 917 SwNodes& rNodes = pPos->nNode.GetNodes(); 918 sal_uInt16 nLevel = SwNodes::GetSectionLevel( pPos->nNode ); 919 if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() ) 920 nLevel--; 921 do { SwNodes::GoStartOfSection( &pPos->nNode ); } while( nLevel-- ); 922 923 // already on a ContentNode 924 pPos->nNode.GetNode().GetContentNode()->MakeStartIndex( &pPos->nContent ); 925} 926 927/// go to the end of the current base section 928void GoEndSection( SwPosition * pPos ) 929{ 930 // jump to section's beginning/end 931 SwNodes& rNodes = pPos->nNode.GetNodes(); 932 sal_uInt16 nLevel = SwNodes::GetSectionLevel( pPos->nNode ); 933 if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() ) 934 nLevel--; 935 do { SwNodes::GoEndOfSection( &pPos->nNode ); } while( nLevel-- ); 936 937 // now on an EndNode, thus to the previous ContentNode 938 if( GoPreviousNds( &pPos->nNode, true ) ) 939 pPos->nNode.GetNode().GetContentNode()->MakeEndIndex( &pPos->nContent ); 940} 941 942bool GoInDoc( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 943{ 944 (*fnMove.fnDoc)( rPam.GetPoint() ); 945 return true; 946} 947 948bool GoInSection( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 949{ 950 (*fnMove.fnSections)( rPam.GetPoint() ); 951 return true; 952} 953 954bool GoInNode( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 955{ 956 SwContentNode *pNd = (*fnMove.fnNds)( &rPam.GetPoint()->nNode, true ); 957 if( pNd ) 958 rPam.GetPoint()->nContent.Assign( pNd, 959 ::GetSttOrEnd( &fnMove == &fnMoveForward, *pNd ) ); 960 return pNd; 961} 962 963bool GoInContent( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 964{ 965 if( (*fnMove.fnNd)( &rPam.GetPoint()->nNode.GetNode(), 966 &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS )) 967 return true; 968 return GoInNode( rPam, fnMove ); 969} 970 971bool GoInContentCells( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 972{ 973 if( (*fnMove.fnNd)( &rPam.GetPoint()->nNode.GetNode(), 974 &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS )) 975 return true; 976 return GoInNode( rPam, fnMove ); 977} 978 979bool GoInContentSkipHidden( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 980{ 981 if( (*fnMove.fnNd)( &rPam.GetPoint()->nNode.GetNode(), 982 &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS | CRSR_SKIP_HIDDEN ) ) 983 return true; 984 return GoInNode( rPam, fnMove ); 985} 986 987bool GoInContentCellsSkipHidden( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 988{ 989 if( (*fnMove.fnNd)( &rPam.GetPoint()->nNode.GetNode(), 990 &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS | CRSR_SKIP_HIDDEN ) ) 991 return true; 992 return GoInNode( rPam, fnMove ); 993} 994 995bool GoPrevPara( SwPaM & rPam, SwMoveFnCollection const & aPosPara ) 996{ 997 if( rPam.Move( fnMoveBackward, GoInNode ) ) 998 { 999 // always on a ContentNode 1000 SwPosition& rPos = *rPam.GetPoint(); 1001 SwContentNode * pNd = rPos.nNode.GetNode().GetContentNode(); 1002 rPos.nContent.Assign( pNd, 1003 ::GetSttOrEnd( &aPosPara == &fnMoveForward, *pNd ) ); 1004 return true; 1005 } 1006 return false; 1007} 1008 1009bool GoCurrPara( SwPaM & rPam, SwMoveFnCollection const & aPosPara ) 1010{ 1011 SwPosition& rPos = *rPam.GetPoint(); 1012 SwContentNode * pNd = rPos.nNode.GetNode().GetContentNode(); 1013 if( pNd ) 1014 { 1015 const sal_Int32 nOld = rPos.nContent.GetIndex(); 1016 const sal_Int32 nNew = &aPosPara == &fnMoveForward ? 0 : pNd->Len(); 1017 // if already at beginning/end then to the next/previous 1018 if( nOld != nNew ) 1019 { 1020 rPos.nContent.Assign( pNd, nNew ); 1021 return true; 1022 } 1023 } 1024 // move node to next/previous ContentNode 1025 if( ( &aPosPara==&fnParaStart && nullptr != ( pNd = 1026 GoPreviousNds( &rPos.nNode, true ))) || 1027 ( &aPosPara==&fnParaEnd && nullptr != ( pNd = 1028 GoNextNds( &rPos.nNode, true ))) ) 1029 { 1030 rPos.nContent.Assign( pNd, 1031 ::GetSttOrEnd( &aPosPara == &fnMoveForward, *pNd )); 1032 return true; 1033 } 1034 return false; 1035} 1036 1037bool GoNextPara( SwPaM & rPam, SwMoveFnCollection const & aPosPara ) 1038{ 1039 if( rPam.Move( fnMoveForward, GoInNode ) ) 1040 { 1041 // always on a ContentNode 1042 SwPosition& rPos = *rPam.GetPoint(); 1043 SwContentNode * pNd = rPos.nNode.GetNode().GetContentNode(); 1044 rPos.nContent.Assign( pNd, 1045 ::GetSttOrEnd( &aPosPara == &fnMoveForward, *pNd ) ); 1046 return true; 1047 } 1048 return false; 1049} 1050 1051bool GoCurrSection( SwPaM & rPam, SwMoveFnCollection const & fnMove ) 1052{ 1053 SwPosition& rPos = *rPam.GetPoint(); 1054 SwPosition aSavePos( rPos ); // position for comparison 1055 (fnMove.fnSection)( &rPos.nNode ); 1056 SwContentNode *pNd; 1057 if( nullptr == ( pNd = rPos.nNode.GetNode().GetContentNode()) && 1058 nullptr == ( pNd = (*fnMove.fnNds)( &rPos.nNode, true )) ) 1059 { 1060 rPos = aSavePos; // do not change cursor 1061 return false; 1062 } 1063 1064 rPos.nContent.Assign( pNd, 1065 ::GetSttOrEnd( &fnMove == &fnMoveForward, *pNd ) ); 1066 return aSavePos != rPos; 1067} 1068 1069OUString SwPaM::GetText() const 1070{ 1071 OUStringBuffer aResult; 1072 1073 SwNodeIndex aNodeIndex = Start()->nNode; 1074 1075 // The first node can be already the end node. 1076 // Use a "forever" loop with an exit condition in the middle 1077 // of its body, in order to correctly handle all cases. 1078 bool bIsStartNode = true; 1079 for (;;) 1080 { 1081 const bool bIsEndNode = aNodeIndex == End()->nNode; 1082 SwTextNode * pTextNode = aNodeIndex.GetNode().GetTextNode(); 1083 1084 if (pTextNode != nullptr) 1085 { 1086 if (!bIsStartNode) 1087 { 1088 aResult.append(CH_TXTATR_NEWLINEu'\n'); // use newline for para break 1089 } 1090 const OUString& aTmpStr = pTextNode->GetText(); 1091 1092 if (bIsStartNode || bIsEndNode) 1093 { 1094 // Handle corner cases of start/end node(s) 1095 const sal_Int32 nStart = bIsStartNode 1096 ? Start()->nContent.GetIndex() 1097 : 0; 1098 const sal_Int32 nEnd = bIsEndNode 1099 ? End()->nContent.GetIndex() 1100 : aTmpStr.getLength(); 1101 1102 aResult.append(std::u16string_view(aTmpStr).substr(nStart, nEnd-nStart)); 1103 } 1104 else 1105 { 1106 aResult.append(aTmpStr); 1107 } 1108 } 1109 1110 if (bIsEndNode) 1111 { 1112 break; 1113 } 1114 1115 ++aNodeIndex; 1116 bIsStartNode = false; 1117 } 1118 1119 return aResult.makeStringAndClear(); 1120} 1121 1122void SwPaM::InvalidatePaM() 1123{ 1124 const SwNode &_pNd = GetNode(); 1125 const SwTextNode *_pTextNd = _pNd.GetTextNode(); 1126 if (_pTextNd != nullptr) 1127 { 1128 // pretend that the PaM marks inserted text to recalc the portion... 1129 SwInsText aHint( Start()->nContent.GetIndex(), 1130 End()->nContent.GetIndex() - Start()->nContent.GetIndex() + 1 ); 1131 SwModify *_pModify=const_cast<SwModify*>(static_cast<SwModify const *>(_pTextNd)); 1132 _pModify->ModifyNotification( nullptr, &aHint); 1133 } 1134} 1135 1136void SwPaM::dumpAsXml(xmlTextWriterPtr pWriter) const 1137{ 1138 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("SwPaM")); 1139 1140 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("point")); 1141 GetPoint()->dumpAsXml(pWriter); 1142 xmlTextWriterEndElement(pWriter); 1143 1144 if (HasMark()) 1145 { 1146 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("mark")); 1147 GetMark()->dumpAsXml(pWriter); 1148 xmlTextWriterEndElement(pWriter); 1149 } 1150 1151 xmlTextWriterEndElement(pWriter); 1152} 1153 1154std::ostream &operator <<(std::ostream& s, const SwPaM& pam) 1155{ 1156 if( pam.HasMark()) 1157 return s << "SwPaM (point " << *pam.GetPoint() << ", mark " << *pam.GetMark() << ")"; 1158 else 1159 return s << "SwPaM (point " << *pam.GetPoint() << ")"; 1160} 1161 1162 1163/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/pam.hxx

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#ifndef INCLUDED_SW_INC_PAM_HXX
20#define INCLUDED_SW_INC_PAM_HXX
21
22#include <sal/types.h>
23#include "ring.hxx"
24#include "index.hxx"
25#include "ndindex.hxx"
26#include "swdllapi.h"
27
28#include <iostream>
29
30class SwDoc;
31class SwPaM;
32class Point;
33
34/// Marks a position in the document model.
35struct SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPosition
36{
37 SwNodeIndex nNode;
38 SwIndex nContent;
39
40 SwPosition( const SwNodeIndex &rNode, const SwIndex &rContent );
41 explicit SwPosition( const SwNodeIndex &rNode );
42 explicit SwPosition( const SwNode& rNode );
43 explicit SwPosition( SwContentNode& rNode, const sal_Int32 nOffset = 0 );
44
45 /**
46 Returns the document this position is in.
47
48 @return the document this position is in.
49 */
50 SwDoc& GetDoc() const;
51
52 bool operator < (const SwPosition &) const;
53 bool operator > (const SwPosition &) const;
54 bool operator <=(const SwPosition &) const;
55 bool operator >=(const SwPosition &) const;
56 bool operator ==(const SwPosition &) const;
57 bool operator !=(const SwPosition &) const;
58 void dumpAsXml(xmlTextWriterPtr pWriter) const;
59};
60
61SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPosition& position);
62
63// Result of comparing positions.
64enum class SwComparePosition {
65 Before, ///< Pos1 before Pos2.
66 Behind, ///< Pos1 behind Pos2.
67 Inside, ///< Pos1 completely contained in Pos2.
68 Outside, ///< Pos2 completely contained in Pos1.
69 Equal, ///< Pos1 is as large as Pos2.
70 OverlapBefore, ///< Pos1 overlaps Pos2 at the beginning.
71 OverlapBehind, ///< Pos1 overlaps Pos2 at the end.
72 CollideStart, ///< Pos1 start touches at Pos2 end.
73 CollideEnd ///< Pos1 end touches at Pos2 start.
74};
75
76template<typename T>
77SwComparePosition ComparePosition(
78 const T& rStt1, const T& rEnd1,
79 const T& rStt2, const T& rEnd2 )
80{
81 SwComparePosition nRet;
82 if( rStt1 < rStt2 )
83 {
84 if( rEnd1 > rStt2 )
85 {
86 if( rEnd1 >= rEnd2 )
87 nRet = SwComparePosition::Outside;
88 else
89 nRet = SwComparePosition::OverlapBefore;
90
91 }
92 else if( rEnd1 == rStt2 )
93 nRet = SwComparePosition::CollideEnd;
94 else
95 nRet = SwComparePosition::Before;
96 }
97 else if( rEnd2 > rStt1 )
98 {
99 if( rEnd2 >= rEnd1 )
100 {
101 if( rEnd2 == rEnd1 && rStt2 == rStt1 )
102 nRet = SwComparePosition::Equal;
103 else
104 nRet = SwComparePosition::Inside;
105 }
106 else
107 {
108 if (rStt1 == rStt2)
109 nRet = SwComparePosition::Outside;
110 else
111 nRet = SwComparePosition::OverlapBehind;
112 }
113 }
114 else if( rEnd2 == rStt1 )
115 nRet = SwComparePosition::CollideStart;
116 else
117 nRet = SwComparePosition::Behind;
118 return nRet;
119}
120
121/// SwPointAndMark / SwPaM
122struct SwMoveFnCollection;
123SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveForward; ///< SwPam::Move()/Find() default argument.
124SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveBackward;
125
126using SwGoInDoc = auto (*)(SwPaM& rPam, SwMoveFnCollection const & fnMove) -> bool;
127SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInDoc( SwPaM&, SwMoveFnCollection const &);
128bool GoInSection( SwPaM&, SwMoveFnCollection const &);
129SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInNode( SwPaM&, SwMoveFnCollection const &);
130SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInContent( SwPaM&, SwMoveFnCollection const &);
131bool GoInContentCells( SwPaM&, SwMoveFnCollection const &);
132bool GoInContentSkipHidden( SwPaM&, SwMoveFnCollection const &);
133bool GoInContentCellsSkipHidden( SwPaM&, SwMoveFnCollection const &);
134
135/// PaM is Point and Mark: a selection of the document model.
136class SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPaM : public sw::Ring<SwPaM>
137{
138 SwPosition m_Bound1;
139 SwPosition m_Bound2;
140 SwPosition * m_pPoint; ///< points at either m_Bound1 or m_Bound2
141 SwPosition * m_pMark; ///< points at either m_Bound1 or m_Bound2
142 bool m_bIsInFrontOfLabel;
143
144 SwPaM(SwPaM const& rPaM) = delete;
145
146public:
147 explicit SwPaM( const SwPosition& rPos, SwPaM* pRing = nullptr );
148 SwPaM( const SwPosition& rMk, const SwPosition& rPt, SwPaM* pRing = nullptr );
149 SwPaM( const SwNodeIndex& rMk, const SwNodeIndex& rPt,
150 long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr );
151 SwPaM( const SwNode& rMk, const SwNode& rPt,
152 long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr );
153 SwPaM( const SwNodeIndex& rMk, sal_Int32 nMkContent,
154 const SwNodeIndex& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
155 SwPaM( const SwNode& rMk, sal_Int32 nMkContent,
156 const SwNode& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
157 SwPaM( const SwNode& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
158 SwPaM( const SwNodeIndex& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
159 virtual ~SwPaM() override;
160
161 /// this takes a second parameter, which indicates the Ring that
162 /// the new PaM should be part of (may be null)
163 SwPaM(SwPaM const& rPaM, SwPaM * pRing);
164 /// @@@ semantic: no copy assignment for super class Ring.
165 SwPaM& operator=( const SwPaM & );
166
167 /// Movement of cursor.
168 bool Move( SwMoveFnCollection const & fnMove = fnMoveForward,
169 SwGoInDoc fnGo = GoInContent );
170
171 bool IsInFrontOfLabel() const { return m_bIsInFrontOfLabel; }
172 void SetInFrontOfLabel_( bool bNew ) { m_bIsInFrontOfLabel = bNew; }
173
174 /// Unless this is called, the getter method of Mark will return Point.
175 virtual void SetMark();
176
177 void DeleteMark()
178 {
179 if (m_pMark != m_pPoint)
180 {
181 /** clear the mark position; this helps if mark's SwIndex is
182 registered at some node, and that node is then deleted */
183 *m_pMark = SwPosition( SwNodeIndex( GetNode().GetNodes() ) );
184 m_pMark = m_pPoint;
185 }
186 }
187#ifdef DBG_UTIL
188 void Exchange();
189
190#else
191 void Exchange()
192 {
193 if (m_pPoint != m_pMark)
194 {
195 SwPosition *pTmp = m_pPoint;
196 m_pPoint = m_pMark;
197 m_pMark = pTmp;
198 }
199 }
200#endif
201
202 /** A PaM marks a selection if Point and Mark are distinct positions.
203 @return true if the PaM spans a selection
204 */
205 bool HasMark() const { return m_pPoint != m_pMark; }
206
207 const SwPosition *GetPoint() const { return m_pPoint; }
208 SwPosition *GetPoint() { return m_pPoint; }
209 const SwPosition *GetMark() const { return m_pMark; }
210 SwPosition *GetMark() { return m_pMark; }
211
212 const SwPosition *Start() const
213 { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
20
Forming reference to null pointer
214 SwPosition *Start()
215 { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
216
217 const SwPosition *End() const
218 { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; }
219 SwPosition *End()
220 { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; }
221
222 /// @return current Node at Point/Mark
223 SwNode & GetNode ( bool bPoint = true ) const
224 {
225 return ( bPoint ? m_pPoint->nNode : m_pMark->nNode ).GetNode();
226 }
227
228 /// @return current ContentNode at Point/Mark
229 SwContentNode* GetContentNode( bool bPoint = true ) const
230 {
231 return GetNode(bPoint).GetContentNode();
232 }
233
234 /**
235 Normalizes PaM, i.e. sort point and mark.
236
237 @param bPointFirst true: If the point is behind the mark then swap.
238 false: If the mark is behind the point then swap.
239 */
240 void Normalize(bool bPointFirst = true);
241
242 /// @return the document (SwDoc) at which the PaM is registered
243 SwDoc& GetDoc() const { return m_pPoint->nNode.GetNode().GetDoc(); }
244
245 SwPosition& GetBound( bool bOne = true )
246 { return bOne ? m_Bound1 : m_Bound2; }
247 const SwPosition& GetBound( bool bOne = true ) const
248 { return bOne ? m_Bound1 : m_Bound2; }
249
250 /// Get number of page which contains cursor.
251 sal_uInt16 GetPageNum( bool bAtPoint = true, const Point* pLayPos = nullptr );
252
253 /** Is in something protected (readonly) or selection contains
254 something protected. */
255 bool HasReadonlySel( bool bFormView ) const;
256
257 bool ContainsPosition(const SwPosition & rPos) const
258 {
259 return *Start() <= rPos && rPos <= *End();
260 }
261
262 OUString GetText() const;
263 void InvalidatePaM();
264 SwPaM* GetNext()
265 { return GetNextInRing(); }
266 const SwPaM* GetNext() const
267 { return GetNextInRing(); }
268 SwPaM* GetPrev()
269 { return GetPrevInRing(); }
270 const SwPaM* GetPrev() const
271 { return GetPrevInRing(); }
272 bool IsMultiSelection() const
273 { return !unique(); }
274
275 void dumpAsXml(xmlTextWriterPtr pWriter) const;
276};
277
278SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPaM& pam);
279
280bool CheckNodesRange(const SwNodeIndex&, const SwNodeIndex&, bool bChkSection);
281
282#endif // INCLUDED_SW_INC_PAM_HXX
283
284/* vim:set shiftwidth=4 softtabstop=4 expandtab: */