Line data Source code
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 <tools/gen.hxx>
21 : #include <hintids.hxx>
22 : #include <editeng/protitem.hxx>
23 : #include <cntfrm.hxx>
24 : #include <pagefrm.hxx>
25 : #include <doc.hxx>
26 : #include <docary.hxx>
27 : #include <pam.hxx>
28 : #include <pamtyp.hxx>
29 : #include <txtfrm.hxx>
30 : #include <fmtcntnt.hxx>
31 : #include <frmatr.hxx>
32 : #include <swtable.hxx>
33 : #include <crsskip.hxx>
34 :
35 : // Formular view
36 : #include <flyfrm.hxx>
37 : #include <fmteiro.hxx>
38 : #include <section.hxx>
39 : #include <sectfrm.hxx>
40 : #include <ndtxt.hxx>
41 :
42 : #include <IMark.hxx>
43 : #include <hints.hxx>
44 : #include <xmloff/odffields.hxx>
45 :
46 : // for the dump "MSC-" compiler
47 0 : inline sal_Int32 GetSttOrEnd( bool bCondition, const SwCntntNode& rNd )
48 : {
49 0 : return bCondition ? 0 : rNd.Len();
50 : }
51 :
52 0 : SwPosition::SwPosition( const SwNodeIndex & rNodeIndex, const SwIndex & rCntnt )
53 0 : : nNode( rNodeIndex ), nContent( rCntnt )
54 : {
55 0 : }
56 :
57 0 : SwPosition::SwPosition( const SwNodeIndex & rNodeIndex )
58 0 : : nNode( rNodeIndex ), nContent( nNode.GetNode().GetCntntNode() )
59 : {
60 0 : }
61 :
62 0 : SwPosition::SwPosition( const SwNode& rNode )
63 0 : : nNode( rNode ), nContent( nNode.GetNode().GetCntntNode() )
64 : {
65 0 : }
66 :
67 0 : SwPosition::SwPosition( SwCntntNode & rNode, const sal_Int32 nOffset )
68 0 : : nNode( rNode ), nContent( &rNode, nOffset )
69 : {
70 0 : }
71 :
72 0 : SwPosition::SwPosition( const SwPosition & rPos )
73 0 : : nNode( rPos.nNode ), nContent( rPos.nContent )
74 : {
75 0 : }
76 :
77 0 : SwPosition &SwPosition::operator=(const SwPosition &rPos)
78 : {
79 0 : nNode = rPos.nNode;
80 0 : nContent = rPos.nContent;
81 0 : return *this;
82 : }
83 :
84 0 : bool SwPosition::operator<(const SwPosition &rPos) const
85 : {
86 0 : if( nNode < rPos.nNode )
87 0 : return true;
88 0 : if( nNode == rPos.nNode )
89 : {
90 : // note that positions with text node but no SwIndex registered are
91 : // created for text frames anchored at para (see SwXFrame::getAnchor())
92 0 : SwIndexReg const*const pThisReg(nContent.GetIdxReg());
93 0 : SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
94 0 : if (pThisReg && pOtherReg)
95 : {
96 0 : return (nContent < rPos.nContent);
97 : }
98 : else // by convention position with no index is smaller
99 : {
100 0 : return (pOtherReg) ? true : false;
101 : }
102 : }
103 0 : return false;
104 : }
105 :
106 0 : bool SwPosition::operator>(const SwPosition &rPos) const
107 : {
108 0 : if(nNode > rPos.nNode )
109 0 : return true;
110 0 : if( nNode == rPos.nNode )
111 : {
112 : // note that positions with text node but no SwIndex registered are
113 : // created for text frames anchored at para (see SwXFrame::getAnchor())
114 0 : SwIndexReg const*const pThisReg(nContent.GetIdxReg());
115 0 : SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
116 0 : if (pThisReg && pOtherReg)
117 : {
118 0 : return (nContent > rPos.nContent);
119 : }
120 : else // by convention position with no index is smaller
121 : {
122 0 : return (pThisReg) ? true : false;
123 : }
124 : }
125 0 : return false;
126 : }
127 :
128 0 : bool SwPosition::operator<=(const SwPosition &rPos) const
129 : {
130 0 : if(nNode < rPos.nNode )
131 0 : return true;
132 0 : if( nNode == rPos.nNode )
133 : {
134 : // note that positions with text node but no SwIndex registered are
135 : // created for text frames anchored at para (see SwXFrame::getAnchor())
136 0 : SwIndexReg const*const pThisReg(nContent.GetIdxReg());
137 0 : SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
138 0 : if (pThisReg && pOtherReg)
139 : {
140 0 : return (nContent <= rPos.nContent);
141 : }
142 : else // by convention position with no index is smaller
143 : {
144 0 : return (pThisReg) ? false : true;
145 : }
146 : }
147 0 : return false;
148 : }
149 :
150 0 : bool SwPosition::operator>=(const SwPosition &rPos) const
151 : {
152 0 : if(nNode > rPos.nNode )
153 0 : return true;
154 0 : if( nNode == rPos.nNode )
155 : {
156 : // note that positions with text node but no SwIndex registered are
157 : // created for text frames anchored at para (see SwXFrame::getAnchor())
158 0 : SwIndexReg const*const pThisReg(nContent.GetIdxReg());
159 0 : SwIndexReg const*const pOtherReg(rPos.nContent.GetIdxReg());
160 0 : if (pThisReg && pOtherReg)
161 : {
162 0 : return (nContent >= rPos.nContent);
163 : }
164 : else // by convention position with no index is smaller
165 : {
166 0 : return (pOtherReg) ? false : true;
167 : }
168 : }
169 0 : return false;
170 : }
171 :
172 0 : bool SwPosition::operator==(const SwPosition &rPos) const
173 : {
174 0 : return (nNode == rPos.nNode)
175 : // GetIndexReg may be null for FLY_AT_PARA frame anchor position
176 0 : && (nContent.GetIdxReg() == rPos.nContent.GetIdxReg())
177 0 : && (nContent == rPos.nContent);
178 : }
179 :
180 0 : bool SwPosition::operator!=(const SwPosition &rPos) const
181 : {
182 0 : return (nNode != rPos.nNode)
183 : // GetIndexReg may be null for FLY_AT_PARA frame anchor position
184 0 : || (nContent.GetIdxReg() != rPos.nContent.GetIdxReg())
185 0 : || (nContent != rPos.nContent);
186 : }
187 :
188 0 : SwDoc * SwPosition::GetDoc() const
189 : {
190 0 : return nNode.GetNode().GetDoc();
191 : }
192 :
193 : enum CHKSECTION { Chk_Both, Chk_One, Chk_None };
194 :
195 0 : static CHKSECTION lcl_TstIdx( sal_uLong nSttIdx, sal_uLong nEndIdx, const SwNode& rEndNd )
196 : {
197 0 : sal_uLong nStt = rEndNd.StartOfSectionIndex(), nEnd = rEndNd.GetIndex();
198 0 : CHKSECTION eSec = nStt < nSttIdx && nEnd >= nSttIdx ? Chk_One : Chk_None;
199 0 : if( nStt < nEndIdx && nEnd >= nEndIdx )
200 0 : return( eSec == Chk_One ? Chk_Both : Chk_One );
201 0 : return eSec;
202 : }
203 :
204 0 : static bool lcl_ChkOneRange( CHKSECTION eSec, bool bChkSections,
205 : const SwNode& rBaseEnd, sal_uLong nStt, sal_uLong nEnd )
206 : {
207 0 : if( eSec != Chk_Both )
208 0 : return false;
209 :
210 0 : if( !bChkSections )
211 0 : return true;
212 :
213 : // search the surrounding section
214 0 : const SwNodes& rNds = rBaseEnd.GetNodes();
215 0 : const SwNode *pTmp, *pNd = rNds[ nStt ];
216 0 : if( !pNd->IsStartNode() )
217 0 : pNd = pNd->StartOfSectionNode();
218 :
219 0 : if( pNd == rNds[ nEnd ]->StartOfSectionNode() )
220 0 : return true; // same StartNode, same section
221 :
222 : // already on a base node => error
223 0 : if( !pNd->StartOfSectionIndex() )
224 0 : return false;
225 :
226 0 : while( ( pTmp = pNd->StartOfSectionNode())->EndOfSectionNode() !=
227 : &rBaseEnd )
228 0 : pNd = pTmp;
229 :
230 0 : sal_uLong nSttIdx = pNd->GetIndex(), nEndIdx = pNd->EndOfSectionIndex();
231 0 : return nSttIdx <= nStt && nStt <= nEndIdx &&
232 0 : nSttIdx <= nEnd && nEnd <= nEndIdx;
233 : }
234 :
235 0 : bool CheckNodesRange( const SwNodeIndex& rStt,
236 : const SwNodeIndex& rEnd, bool bChkSection )
237 : {
238 0 : const SwNodes& rNds = rStt.GetNodes();
239 0 : sal_uLong nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex();
240 0 : CHKSECTION eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfContent() );
241 0 : if( Chk_None != eSec )
242 0 : return eSec == Chk_Both;
243 :
244 0 : eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfAutotext() );
245 0 : if( Chk_None != eSec )
246 : return lcl_ChkOneRange( eSec, bChkSection,
247 0 : rNds.GetEndOfAutotext(), nStt, nEnd );
248 :
249 0 : eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfPostIts() );
250 0 : if( Chk_None != eSec )
251 : return lcl_ChkOneRange( eSec, bChkSection,
252 0 : rNds.GetEndOfPostIts(), nStt, nEnd );
253 :
254 0 : eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfInserts() );
255 0 : if( Chk_None != eSec )
256 : return lcl_ChkOneRange( eSec, bChkSection,
257 0 : rNds.GetEndOfInserts(), nStt, nEnd );
258 :
259 0 : eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfRedlines() );
260 0 : if( Chk_None != eSec )
261 : return lcl_ChkOneRange( eSec, bChkSection,
262 0 : rNds.GetEndOfRedlines(), nStt, nEnd );
263 :
264 0 : return false; // somewhere in between => error
265 : }
266 :
267 0 : sal_Bool GoNext(SwNode* pNd, SwIndex * pIdx, sal_uInt16 nMode )
268 : {
269 0 : if( pNd->IsCntntNode() )
270 0 : return ((SwCntntNode*)pNd)->GoNext( pIdx, nMode );
271 0 : return sal_False;
272 : }
273 :
274 0 : sal_Bool GoPrevious( SwNode* pNd, SwIndex * pIdx, sal_uInt16 nMode )
275 : {
276 0 : if( pNd->IsCntntNode() )
277 0 : return ((SwCntntNode*)pNd)->GoPrevious( pIdx, nMode );
278 0 : return sal_False;
279 : }
280 :
281 0 : SwCntntNode* GoNextNds( SwNodeIndex* pIdx, sal_Bool bChk )
282 : {
283 0 : SwNodeIndex aIdx( *pIdx );
284 0 : SwCntntNode* pNd = aIdx.GetNodes().GoNext( &aIdx );
285 0 : if( pNd )
286 : {
287 0 : if( bChk && 1 != aIdx.GetIndex() - pIdx->GetIndex() &&
288 0 : !CheckNodesRange( *pIdx, aIdx, true ) )
289 0 : pNd = 0;
290 : else
291 0 : *pIdx = aIdx;
292 : }
293 0 : return pNd;
294 : }
295 :
296 0 : SwCntntNode* GoPreviousNds( SwNodeIndex * pIdx, sal_Bool bChk )
297 : {
298 0 : SwNodeIndex aIdx( *pIdx );
299 0 : SwCntntNode* pNd = aIdx.GetNodes().GoPrevious( &aIdx );
300 0 : if( pNd )
301 : {
302 0 : if( bChk && 1 != pIdx->GetIndex() - aIdx.GetIndex() &&
303 0 : !CheckNodesRange( *pIdx, aIdx, true ) )
304 0 : pNd = 0;
305 : else
306 0 : *pIdx = aIdx;
307 : }
308 0 : return pNd;
309 : }
310 :
311 0 : SwPaM::SwPaM( const SwPosition& rPos, SwPaM* pRing )
312 : : Ring( pRing )
313 : , m_Bound1( rPos )
314 0 : , m_Bound2( rPos.nNode.GetNode().GetNodes() ) // default initialize
315 : , m_pPoint( &m_Bound1 )
316 : , m_pMark( m_pPoint )
317 0 : , m_bIsInFrontOfLabel( false )
318 : {
319 0 : }
320 :
321 0 : SwPaM::SwPaM( const SwPosition& rMark, const SwPosition& rPoint, SwPaM* pRing )
322 : : Ring( pRing )
323 : , m_Bound1( rMark )
324 : , m_Bound2( rPoint )
325 : , m_pPoint( &m_Bound2 )
326 : , m_pMark( &m_Bound1 )
327 0 : , m_bIsInFrontOfLabel( false )
328 : {
329 0 : }
330 :
331 0 : SwPaM::SwPaM( const SwNodeIndex& rMark, const SwNodeIndex& rPoint,
332 : long nMarkOffset, long nPointOffset, SwPaM* pRing )
333 : : Ring( pRing )
334 : , m_Bound1( rMark )
335 : , m_Bound2( rPoint )
336 : , m_pPoint( &m_Bound2 )
337 : , m_pMark( &m_Bound1 )
338 0 : , m_bIsInFrontOfLabel( false )
339 : {
340 0 : if ( nMarkOffset )
341 : {
342 0 : m_pMark->nNode += nMarkOffset;
343 : }
344 0 : if ( nPointOffset )
345 : {
346 0 : m_pPoint->nNode += nPointOffset;
347 : }
348 0 : m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetCntntNode(), 0 );
349 0 : m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetCntntNode(), 0 );
350 0 : }
351 :
352 0 : SwPaM::SwPaM( const SwNode& rMark, const SwNode& 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 0 : , m_bIsInFrontOfLabel( false )
360 : {
361 0 : if ( nMarkOffset )
362 : {
363 0 : m_pMark->nNode += nMarkOffset;
364 : }
365 0 : if ( nPointOffset )
366 : {
367 0 : m_pPoint->nNode += nPointOffset;
368 : }
369 0 : m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetCntntNode(), 0 );
370 0 : m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetCntntNode(), 0 );
371 0 : }
372 :
373 0 : SwPaM::SwPaM( const SwNodeIndex& rMark, sal_Int32 nMarkCntnt,
374 : const SwNodeIndex& rPoint, sal_Int32 nPointCntnt, SwPaM* pRing )
375 : : Ring( pRing )
376 : , m_Bound1( rMark )
377 : , m_Bound2( rPoint )
378 : , m_pPoint( &m_Bound2 )
379 : , m_pMark( &m_Bound1 )
380 0 : , m_bIsInFrontOfLabel( false )
381 : {
382 0 : m_pPoint->nContent.Assign( rPoint.GetNode().GetCntntNode(), nPointCntnt);
383 0 : m_pMark ->nContent.Assign( rMark .GetNode().GetCntntNode(), nMarkCntnt );
384 0 : }
385 :
386 0 : SwPaM::SwPaM( const SwNode& rMark, sal_Int32 nMarkCntnt,
387 : const SwNode& rPoint, sal_Int32 nPointCntnt, SwPaM* pRing )
388 : : Ring( pRing )
389 : , m_Bound1( rMark )
390 : , m_Bound2( rPoint )
391 : , m_pPoint( &m_Bound2 )
392 : , m_pMark( &m_Bound1 )
393 0 : , m_bIsInFrontOfLabel( false )
394 : {
395 0 : m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetCntntNode(),
396 0 : nPointCntnt);
397 0 : m_pMark ->nContent.Assign( m_pMark ->nNode.GetNode().GetCntntNode(),
398 0 : nMarkCntnt );
399 0 : }
400 :
401 0 : SwPaM::SwPaM( const SwNode& rNode, sal_Int32 nCntnt, SwPaM* pRing )
402 : : Ring( pRing )
403 : , m_Bound1( rNode )
404 0 : , m_Bound2( m_Bound1.nNode.GetNode().GetNodes() ) // default initialize
405 : , m_pPoint( &m_Bound1 )
406 : , m_pMark( &m_Bound1 )
407 0 : , m_bIsInFrontOfLabel( false )
408 : {
409 0 : m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetCntntNode(),
410 0 : nCntnt );
411 0 : }
412 :
413 0 : SwPaM::SwPaM( const SwNodeIndex& rNodeIdx, sal_Int32 nCntnt, SwPaM* pRing )
414 : : Ring( pRing )
415 : , m_Bound1( rNodeIdx )
416 0 : , m_Bound2( rNodeIdx.GetNode().GetNodes() ) // default initialize
417 : , m_pPoint( &m_Bound1 )
418 : , m_pMark( &m_Bound1 )
419 0 : , m_bIsInFrontOfLabel( false )
420 : {
421 0 : m_pPoint->nContent.Assign( rNodeIdx.GetNode().GetCntntNode(), nCntnt );
422 0 : }
423 :
424 0 : SwPaM::~SwPaM() {}
425 :
426 : // @@@ semantic: no copy ctor.
427 0 : SwPaM::SwPaM( SwPaM &rPam )
428 : : Ring( &rPam )
429 : , m_Bound1( *(rPam.m_pPoint) )
430 : , m_Bound2( *(rPam.m_pMark) )
431 0 : , m_pPoint( &m_Bound1 ), m_pMark( rPam.HasMark() ? &m_Bound2 : m_pPoint )
432 0 : , m_bIsInFrontOfLabel( false )
433 : {
434 0 : }
435 :
436 : // @@@ semantic: no copy assignment for super class Ring.
437 0 : SwPaM &SwPaM::operator=( const SwPaM &rPam )
438 : {
439 0 : *m_pPoint = *( rPam.m_pPoint );
440 0 : if ( rPam.HasMark() )
441 : {
442 0 : SetMark();
443 0 : *m_pMark = *( rPam.m_pMark );
444 : }
445 : else
446 : {
447 0 : DeleteMark();
448 : }
449 0 : return *this;
450 : }
451 :
452 0 : void SwPaM::SetMark()
453 : {
454 0 : if (m_pPoint == &m_Bound1)
455 : {
456 0 : m_pMark = &m_Bound2;
457 : }
458 : else
459 : {
460 0 : m_pMark = &m_Bound1;
461 : }
462 0 : (*m_pMark) = (*m_pPoint);
463 0 : }
464 :
465 : #ifdef DBG_UTIL
466 : void SwPaM::Exchange()
467 : {
468 : if (m_pPoint != m_pMark)
469 : {
470 : SwPosition *pTmp = m_pPoint;
471 : m_pPoint = m_pMark;
472 : m_pMark = pTmp;
473 : }
474 : }
475 : #endif
476 :
477 : /// movement of cursor
478 0 : bool SwPaM::Move( SwMoveFn fnMove, SwGoInDoc fnGo )
479 : {
480 0 : const bool bRet = (*fnGo)( *this, fnMove );
481 :
482 0 : m_bIsInFrontOfLabel = false;
483 0 : return bRet;
484 : }
485 :
486 : /** make a new region
487 :
488 : Sets the first SwPaM onto the given SwPaM, or to the beginning or end of a
489 : document. SPoint stays at its position, GetMark will be changed respectively.
490 :
491 : @param fnMove Contains information if beginning or end of document.
492 : @param pOrigRg The given region.
493 :
494 : @return Newly created area.
495 : */
496 0 : SwPaM* SwPaM::MakeRegion( SwMoveFn fnMove, const SwPaM * pOrigRg )
497 : {
498 : SwPaM* pPam;
499 0 : if( pOrigRg == 0 )
500 : {
501 0 : pPam = new SwPaM( *m_pPoint );
502 0 : pPam->SetMark(); // set beginning
503 0 : pPam->Move( fnMove, fnGoSection); // to beginning or end of a node
504 :
505 : // set SPoint onto its old position; set GetMark to the "end"
506 0 : pPam->Exchange();
507 : }
508 : else
509 : {
510 0 : pPam = new SwPaM( *(SwPaM*)pOrigRg ); // given search area
511 : // make sure that SPoint is on the "real" start position
512 : // FORWARD: SPoint always smaller than GetMark
513 : // BACKWARD: SPoint always bigger than GetMark
514 0 : if( (pPam->GetMark()->*fnMove->fnCmpOp)( *pPam->GetPoint() ) )
515 0 : pPam->Exchange();
516 : }
517 0 : return pPam;
518 : }
519 :
520 0 : SwPaM & SwPaM::Normalize(bool bPointFirst)
521 : {
522 0 : if (HasMark())
523 0 : if ( ( bPointFirst && *m_pPoint > *m_pMark) ||
524 0 : (!bPointFirst && *m_pPoint < *m_pMark) )
525 : {
526 0 : Exchange();
527 : }
528 0 : return *this;
529 : }
530 :
531 : /// return page number at cursor (for reader and page bound frames)
532 0 : sal_uInt16 SwPaM::GetPageNum( bool bAtPoint, const Point* pLayPos )
533 : {
534 : const SwCntntFrm* pCFrm;
535 : const SwPageFrm *pPg;
536 : const SwCntntNode *pNd ;
537 0 : const SwPosition* pPos = bAtPoint ? m_pPoint : m_pMark;
538 :
539 0 : if( 0 != ( pNd = pPos->nNode.GetNode().GetCntntNode() ) &&
540 0 : 0 != ( pCFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout(), pLayPos, pPos, false )) &&
541 0 : 0 != ( pPg = pCFrm->FindPageFrm() ))
542 0 : return pPg->GetPhyPageNum();
543 0 : return 0;
544 : }
545 :
546 : // Formular view - See also SwCrsrShell::IsCrsrReadonly()
547 0 : static const SwFrm* lcl_FindEditInReadonlyFrm( const SwFrm& rFrm )
548 : {
549 0 : const SwFrm* pRet = 0;
550 :
551 : const SwFlyFrm* pFly;
552 : const SwSectionFrm* pSectionFrm;
553 :
554 0 : if( rFrm.IsInFly() &&
555 0 : (pFly = rFrm.FindFlyFrm())->GetFmt()->GetEditInReadonly().GetValue() &&
556 0 : pFly->Lower() &&
557 0 : !pFly->Lower()->IsNoTxtFrm() )
558 : {
559 0 : pRet = pFly;
560 : }
561 0 : else if ( rFrm.IsInSct() &&
562 0 : 0 != ( pSectionFrm = rFrm.FindSctFrm() )->GetSection() &&
563 0 : pSectionFrm->GetSection()->IsEditInReadonlyFlag() )
564 : {
565 0 : pRet = pSectionFrm;
566 : }
567 :
568 0 : return pRet;
569 : }
570 :
571 : /// is in protected section or selection surrounds something protected
572 0 : bool SwPaM::HasReadonlySel( bool bFormView, bool bAnnotationMode ) const
573 : {
574 0 : bool bRet = false;
575 :
576 0 : const SwCntntNode* pNd = GetPoint()->nNode.GetNode().GetCntntNode();
577 0 : const SwCntntFrm *pFrm = NULL;
578 0 : if ( pNd != NULL )
579 : {
580 0 : Point aTmpPt;
581 0 : pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout(), &aTmpPt, GetPoint(), false );
582 : }
583 :
584 : // Will be set if point are inside edit-in-readonly environment
585 0 : const SwFrm* pPointEditInReadonlyFrm = NULL;
586 0 : if ( pFrm != NULL
587 0 : && ( pFrm->IsProtected()
588 0 : || ( bFormView
589 0 : && 0 == ( pPointEditInReadonlyFrm = lcl_FindEditInReadonlyFrm( *pFrm ) ) ) ) )
590 : {
591 0 : bRet = true;
592 : }
593 0 : else if( pNd != NULL )
594 : {
595 0 : const SwSectionNode* pSNd = pNd->GetSectionNode();
596 0 : if ( pSNd != NULL
597 0 : && ( pSNd->GetSection().IsProtectFlag()
598 0 : || ( bFormView
599 0 : && !pSNd->GetSection().IsEditInReadonlyFlag()) ) )
600 : {
601 0 : bRet = true;
602 : }
603 : }
604 :
605 0 : if ( !bRet
606 0 : && HasMark()
607 0 : && GetPoint()->nNode != GetMark()->nNode )
608 : {
609 0 : pNd = GetMark()->nNode.GetNode().GetCntntNode();
610 0 : pFrm = NULL;
611 0 : if ( pNd != NULL )
612 : {
613 0 : Point aTmpPt;
614 0 : pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout(), &aTmpPt, GetMark(), false );
615 : }
616 :
617 0 : const SwFrm* pMarkEditInReadonlyFrm = NULL;
618 0 : if ( pFrm != NULL
619 0 : && ( pFrm->IsProtected()
620 0 : || ( bFormView
621 0 : && 0 == ( pMarkEditInReadonlyFrm = lcl_FindEditInReadonlyFrm( *pFrm ) ) ) ) )
622 : {
623 0 : bRet = true;
624 : }
625 0 : else if( pNd != NULL )
626 : {
627 0 : const SwSectionNode* pSNd = pNd->GetSectionNode();
628 0 : if ( pSNd != NULL
629 0 : && ( pSNd->GetSection().IsProtectFlag()
630 0 : || ( bFormView
631 0 : && !pSNd->GetSection().IsEditInReadonlyFlag()) ) )
632 : {
633 0 : bRet = true;
634 : }
635 : }
636 :
637 0 : if ( !bRet && bFormView )
638 : {
639 : // Check if start and end frame are inside the _same_
640 : // edit-in-readonly-environment. Otherwise we better return 'true'
641 0 : if ( pPointEditInReadonlyFrm != pMarkEditInReadonlyFrm )
642 0 : bRet = true;
643 : }
644 :
645 : // check for protected section inside the selection
646 0 : if( !bRet )
647 : {
648 0 : sal_uLong nSttIdx = GetMark()->nNode.GetIndex(),
649 0 : nEndIdx = GetPoint()->nNode.GetIndex();
650 0 : if( nEndIdx <= nSttIdx )
651 : {
652 0 : sal_uLong nTmp = nSttIdx;
653 0 : nSttIdx = nEndIdx;
654 0 : nEndIdx = nTmp;
655 : }
656 :
657 : // If a protected section should be between nodes, then the
658 : // selection needs to contain already x nodes.
659 : // (TxtNd, SectNd, TxtNd, EndNd, TxtNd )
660 0 : if( nSttIdx + 3 < nEndIdx )
661 : {
662 0 : const SwSectionFmts& rFmts = GetDoc()->GetSections();
663 0 : for( sal_uInt16 n = rFmts.size(); n; )
664 : {
665 0 : const SwSectionFmt* pFmt = rFmts[ --n ];
666 0 : if( pFmt->GetProtect().IsCntntProtected() )
667 : {
668 0 : const SwFmtCntnt& rCntnt = pFmt->GetCntnt(sal_False);
669 : OSL_ENSURE( rCntnt.GetCntntIdx(), "where is the SectionNode?" );
670 0 : sal_uLong nIdx = rCntnt.GetCntntIdx()->GetIndex();
671 0 : if( nSttIdx <= nIdx && nEndIdx >= nIdx &&
672 0 : rCntnt.GetCntntIdx()->GetNode().GetNodes().IsDocNodes() )
673 : {
674 0 : bRet = true;
675 0 : break;
676 : }
677 : }
678 : }
679 : }
680 : }
681 : }
682 :
683 : //FIXME FieldBk
684 : // TODO: Form Protection when Enhanced Fields are enabled
685 0 : const SwDoc *pDoc = GetDoc();
686 0 : const IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess();
687 0 : sw::mark::IMark* pA = GetPoint() ? pMarksAccess->getFieldmarkFor( *GetPoint( ) ) : NULL;
688 0 : sw::mark::IMark* pB = GetMark( ) ? pMarksAccess->getFieldmarkFor( *GetMark( ) ) : pA;
689 :
690 0 : bool bUnhandledMark = false;
691 0 : sw::mark::IFieldmark* pFieldmark = pMarksAccess->getFieldmarkFor( *GetPoint() );
692 0 : if ( pFieldmark )
693 0 : bUnhandledMark = pFieldmark->GetFieldname( ) == ODF_UNHANDLED;
694 :
695 0 : if (!bRet)
696 : {
697 : // Unhandled fieldmarks case shouldn't be edited manually to avoid breaking anything
698 0 : if ( ( pA == pB ) && bUnhandledMark )
699 0 : bRet = true;
700 : else
701 : {
702 : // Form protection case
703 0 : bool bAtStartA = pA != NULL && pA->GetMarkStart() == *GetPoint();
704 0 : bool bAtStartB = pB != NULL && pB->GetMarkStart() == *GetMark();
705 0 : bRet = ( pA != pB ) || bAtStartA || bAtStartB;
706 0 : bool bProtectForm = pDoc->get( IDocumentSettingAccess::PROTECT_FORM );
707 0 : if ( bProtectForm )
708 0 : bRet |= ( pA == NULL || pB == NULL );
709 : }
710 : }
711 : else
712 : {
713 0 : bRet = !( pA == pB && pA != NULL );
714 : }
715 :
716 : // Don't allow inserting characters between the 'field mark end' and
717 : // the 'comment anchor', unless the cursor is inside the annotation.
718 0 : if (!bRet && !bAnnotationMode)
719 : {
720 0 : if (!pA && GetPoint() && GetPoint()->nNode.GetNode().IsTxtNode() && GetPoint()->nContent.GetIndex() > 0)
721 : {
722 : // getFieldmarkFor() searches for >= start and < end, so check for
723 : // the previous character, to also get the fieldmark, if we're
724 : // exactly at the end.
725 0 : SwPosition aPrevChar(*GetPoint());
726 0 : aPrevChar.nContent--;
727 0 : pFieldmark = pMarksAccess->getFieldmarkFor(aPrevChar);
728 0 : if (pFieldmark && pFieldmark->GetMarkEnd() == *GetPoint())
729 0 : bRet = true;
730 : }
731 : }
732 :
733 0 : return bRet;
734 : }
735 :
736 : /// This function returns the next node in direction of search. If there is no
737 : /// left or the next is out of the area, then a null-pointer is returned.
738 : /// @param rbFirst If <true> than first time request. If so than the position of
739 : /// the PaM must not be changed!
740 0 : SwCntntNode* GetNode( SwPaM & rPam, sal_Bool& rbFirst, SwMoveFn fnMove,
741 : sal_Bool bInReadOnly )
742 : {
743 0 : SwCntntNode * pNd = 0;
744 : SwCntntFrm* pFrm;
745 0 : if( ((*rPam.GetPoint()).*fnMove->fnCmpOp)( *rPam.GetMark() ) ||
746 0 : ( *rPam.GetPoint() == *rPam.GetMark() && rbFirst ) )
747 : {
748 0 : if( rbFirst )
749 : {
750 0 : rbFirst = sal_False;
751 0 : pNd = rPam.GetCntntNode();
752 0 : if( pNd )
753 : {
754 0 : if(
755 : (
756 0 : 0 == ( pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout() ) ) ||
757 0 : ( !bInReadOnly && pFrm->IsProtected() ) ||
758 0 : (pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow())
759 0 : ) ||
760 0 : ( !bInReadOnly && pNd->FindSectionNode() &&
761 0 : pNd->FindSectionNode()->GetSection().IsProtect()
762 : )
763 : )
764 : {
765 0 : pNd = 0;
766 : }
767 : }
768 : }
769 :
770 0 : if( !pNd ) // is the cursor not on a CntntNode?
771 : {
772 0 : SwPosition aPos( *rPam.GetPoint() );
773 0 : sal_Bool bSrchForward = fnMove == fnMoveForward;
774 0 : SwNodes& rNodes = aPos.nNode.GetNodes();
775 :
776 : // go to next/previous CntntNode
777 : while( true )
778 : {
779 : pNd = bSrchForward
780 0 : ? rNodes.GoNextSection( &aPos.nNode, true, !bInReadOnly )
781 0 : : rNodes.GoPrevSection( &aPos.nNode, true, !bInReadOnly );
782 0 : if( pNd )
783 : {
784 0 : aPos.nContent.Assign( pNd, ::GetSttOrEnd( bSrchForward,*pNd ));
785 : // is the position still in the area
786 0 : if( (aPos.*fnMove->fnCmpOp)( *rPam.GetMark() ) )
787 : {
788 : // only in AutoTextSection can be nodes that are hidden
789 0 : if( 0 == ( pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout() ) ) ||
790 0 : ( !bInReadOnly && pFrm->IsProtected() ) ||
791 0 : ( pFrm->IsTxtFrm() &&
792 0 : ((SwTxtFrm*)pFrm)->IsHiddenNow() ) )
793 : {
794 0 : pNd = 0;
795 0 : continue;
796 : }
797 0 : *(SwPosition*)rPam.GetPoint() = aPos;
798 : }
799 : else
800 0 : pNd = 0; // no valid node
801 0 : break;
802 : }
803 0 : break;
804 0 : }
805 : }
806 : }
807 0 : return pNd;
808 : }
809 :
810 0 : void GoStartDoc( SwPosition * pPos )
811 : {
812 0 : SwNodes& rNodes = pPos->nNode.GetNodes();
813 0 : pPos->nNode = *rNodes.GetEndOfContent().StartOfSectionNode();
814 : // we always need to find a ContentNode!
815 0 : SwCntntNode* pCNd = rNodes.GoNext( &pPos->nNode );
816 0 : if( pCNd )
817 0 : pCNd->MakeStartIndex( &pPos->nContent );
818 0 : }
819 :
820 0 : void GoEndDoc( SwPosition * pPos )
821 : {
822 0 : SwNodes& rNodes = pPos->nNode.GetNodes();
823 0 : pPos->nNode = rNodes.GetEndOfContent();
824 0 : SwCntntNode* pCNd = GoPreviousNds( &pPos->nNode, sal_True );
825 0 : if( pCNd )
826 0 : pCNd->MakeEndIndex( &pPos->nContent );
827 0 : }
828 :
829 0 : void GoStartSection( SwPosition * pPos )
830 : {
831 : // jump to section's beginning
832 0 : SwNodes& rNodes = pPos->nNode.GetNodes();
833 0 : sal_uInt16 nLevel = rNodes.GetSectionLevel( pPos->nNode );
834 0 : if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() )
835 0 : nLevel--;
836 0 : do { rNodes.GoStartOfSection( &pPos->nNode ); } while( nLevel-- );
837 :
838 : // already on a CntntNode
839 0 : pPos->nNode.GetNode().GetCntntNode()->MakeStartIndex( &pPos->nContent );
840 0 : }
841 :
842 : /// go to the end of the current base section
843 0 : void GoEndSection( SwPosition * pPos )
844 : {
845 : // jump to section's beginning/end
846 0 : SwNodes& rNodes = pPos->nNode.GetNodes();
847 0 : sal_uInt16 nLevel = rNodes.GetSectionLevel( pPos->nNode );
848 0 : if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() )
849 0 : nLevel--;
850 0 : do { rNodes.GoEndOfSection( &pPos->nNode ); } while( nLevel-- );
851 :
852 : // now on a EndNode, thus to the previous CntntNode
853 0 : if( GoPreviousNds( &pPos->nNode, sal_True ) )
854 0 : pPos->nNode.GetNode().GetCntntNode()->MakeEndIndex( &pPos->nContent );
855 0 : }
856 :
857 0 : bool GoInDoc( SwPaM & rPam, SwMoveFn fnMove )
858 : {
859 0 : (*fnMove->fnDoc)( rPam.GetPoint() );
860 0 : return true;
861 : }
862 :
863 0 : bool GoInSection( SwPaM & rPam, SwMoveFn fnMove )
864 : {
865 0 : (*fnMove->fnSections)( (SwPosition*)rPam.GetPoint() );
866 0 : return true;
867 : }
868 :
869 0 : bool GoInNode( SwPaM & rPam, SwMoveFn fnMove )
870 : {
871 0 : SwCntntNode *pNd = (*fnMove->fnNds)( &rPam.GetPoint()->nNode, sal_True );
872 0 : if( pNd )
873 0 : rPam.GetPoint()->nContent.Assign( pNd,
874 0 : ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) );
875 0 : return pNd;
876 : }
877 :
878 0 : bool GoInCntnt( SwPaM & rPam, SwMoveFn fnMove )
879 : {
880 0 : if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
881 0 : &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS ))
882 0 : return true;
883 0 : return GoInNode( rPam, fnMove );
884 : }
885 :
886 0 : bool GoInCntntCells( SwPaM & rPam, SwMoveFn fnMove )
887 : {
888 0 : if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
889 0 : &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS ))
890 0 : return true;
891 0 : return GoInNode( rPam, fnMove );
892 : }
893 :
894 0 : bool GoInCntntSkipHidden( SwPaM & rPam, SwMoveFn fnMove )
895 : {
896 0 : if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
897 0 : &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS | CRSR_SKIP_HIDDEN ) )
898 0 : return true;
899 0 : return GoInNode( rPam, fnMove );
900 : }
901 :
902 0 : bool GoInCntntCellsSkipHidden( SwPaM & rPam, SwMoveFn fnMove )
903 : {
904 0 : if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
905 0 : &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS | CRSR_SKIP_HIDDEN ) )
906 0 : return true;
907 0 : return GoInNode( rPam, fnMove );
908 : }
909 :
910 0 : sal_Bool GoPrevPara( SwPaM & rPam, SwPosPara aPosPara )
911 : {
912 0 : if( rPam.Move( fnMoveBackward, fnGoNode ) )
913 : {
914 : // always on a CntntNode
915 0 : SwPosition& rPos = *rPam.GetPoint();
916 0 : SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode();
917 : rPos.nContent.Assign( pNd,
918 0 : ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ) );
919 0 : return sal_True;
920 : }
921 0 : return sal_False;
922 : }
923 :
924 0 : sal_Bool GoCurrPara( SwPaM & rPam, SwPosPara aPosPara )
925 : {
926 0 : SwPosition& rPos = *rPam.GetPoint();
927 0 : SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode();
928 0 : if( pNd )
929 : {
930 0 : const sal_Int32 nOld = rPos.nContent.GetIndex();
931 0 : const sal_Int32 nNew = aPosPara == fnMoveForward ? 0 : pNd->Len();
932 : // if already at beginning/end then to the next/previous
933 0 : if( nOld != nNew )
934 : {
935 0 : rPos.nContent.Assign( pNd, nNew );
936 0 : return sal_True;
937 : }
938 : }
939 : // move node to next/previous CntntNode
940 0 : if( ( aPosPara==fnParaStart && 0 != ( pNd =
941 0 : GoPreviousNds( &rPos.nNode, sal_True ))) ||
942 0 : ( aPosPara==fnParaEnd && 0 != ( pNd =
943 0 : GoNextNds( &rPos.nNode, sal_True ))) )
944 : {
945 : rPos.nContent.Assign( pNd,
946 0 : ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ));
947 0 : return sal_True;
948 : }
949 0 : return sal_False;
950 : }
951 :
952 0 : sal_Bool GoNextPara( SwPaM & rPam, SwPosPara aPosPara )
953 : {
954 0 : if( rPam.Move( fnMoveForward, fnGoNode ) )
955 : {
956 : // always on a CntntNode
957 0 : SwPosition& rPos = *rPam.GetPoint();
958 0 : SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode();
959 : rPos.nContent.Assign( pNd,
960 0 : ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ) );
961 0 : return sal_True;
962 : }
963 0 : return sal_False;
964 : }
965 :
966 0 : sal_Bool GoCurrSection( SwPaM & rPam, SwMoveFn fnMove )
967 : {
968 0 : SwPosition& rPos = *rPam.GetPoint();
969 0 : SwPosition aSavePos( rPos ); // position for comparison
970 0 : SwNodes& rNds = aSavePos.nNode.GetNodes();
971 0 : (rNds.*fnMove->fnSection)( &rPos.nNode );
972 : SwCntntNode *pNd;
973 0 : if( 0 == ( pNd = rPos.nNode.GetNode().GetCntntNode()) &&
974 0 : 0 == ( pNd = (*fnMove->fnNds)( &rPos.nNode, sal_True )) )
975 : {
976 0 : rPos = aSavePos; // do not change cursor
977 0 : return sal_False;
978 : }
979 :
980 : rPos.nContent.Assign( pNd,
981 0 : ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) );
982 0 : return aSavePos != rPos;
983 : }
984 :
985 0 : sal_Bool GoNextSection( SwPaM & rPam, SwMoveFn fnMove )
986 : {
987 0 : SwPosition& rPos = *rPam.GetPoint();
988 0 : SwPosition aSavePos( rPos ); // position for comparison
989 0 : SwNodes& rNds = aSavePos.nNode.GetNodes();
990 0 : rNds.GoEndOfSection( &rPos.nNode );
991 :
992 : // no other CntntNode existent?
993 0 : if( !GoInCntnt( rPam, fnMoveForward ) )
994 : {
995 0 : rPos = aSavePos; // do not change cursor
996 0 : return sal_False;
997 : }
998 0 : (rNds.*fnMove->fnSection)( &rPos.nNode );
999 0 : SwCntntNode *pNd = rPos.nNode.GetNode().GetCntntNode();
1000 : rPos.nContent.Assign( pNd,
1001 0 : ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) );
1002 0 : return sal_True;
1003 : }
1004 :
1005 0 : sal_Bool GoPrevSection( SwPaM & rPam, SwMoveFn fnMove )
1006 : {
1007 0 : SwPosition& rPos = *rPam.GetPoint();
1008 0 : SwPosition aSavePos( rPos ); // position for comparison
1009 0 : SwNodes& rNds = aSavePos.nNode.GetNodes();
1010 0 : rNds.GoStartOfSection( &rPos.nNode );
1011 :
1012 : // no further CntntNode existent?
1013 0 : if( !GoInCntnt( rPam, fnMoveBackward ))
1014 : {
1015 0 : rPos = aSavePos; // do not change cursor
1016 0 : return sal_False;
1017 : }
1018 0 : (rNds.*fnMove->fnSection)( &rPos.nNode );
1019 0 : SwCntntNode *pNd = rPos.nNode.GetNode().GetCntntNode();
1020 : rPos.nContent.Assign( pNd,
1021 0 : ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ));
1022 0 : return sal_True;
1023 : }
1024 :
1025 0 : OUString SwPaM::GetTxt() const
1026 : {
1027 0 : OUString aResult;
1028 :
1029 0 : SwNodeIndex aNodeIndex = Start()->nNode;
1030 :
1031 : // The first node can be already the end node.
1032 : // Use a "forever" loop with an exit condition in the middle
1033 : // of its body, in order to correctly handle all cases.
1034 0 : bool bIsStartNode = true;
1035 : for (;;)
1036 : {
1037 0 : const bool bIsEndNode = aNodeIndex == End()->nNode;
1038 0 : SwTxtNode * pTxtNode = aNodeIndex.GetNode().GetTxtNode();
1039 :
1040 0 : if (pTxtNode != NULL)
1041 : {
1042 0 : const OUString aTmpStr = pTxtNode->GetTxt();
1043 :
1044 0 : if (bIsStartNode || bIsEndNode)
1045 : {
1046 : // Handle corner cases of start/end node(s)
1047 : const sal_Int32 nStart = bIsStartNode
1048 0 : ? Start()->nContent.GetIndex()
1049 0 : : 0;
1050 : const sal_Int32 nEnd = bIsEndNode
1051 0 : ? End()->nContent.GetIndex()
1052 0 : : aTmpStr.getLength();
1053 :
1054 0 : aResult += aTmpStr.copy(nStart, nEnd-nStart);
1055 : }
1056 : else
1057 : {
1058 0 : aResult += aTmpStr;
1059 0 : }
1060 : }
1061 :
1062 0 : if (bIsEndNode)
1063 : {
1064 0 : break;
1065 : }
1066 :
1067 0 : ++aNodeIndex;
1068 0 : bIsStartNode = false;
1069 0 : }
1070 :
1071 0 : return aResult;
1072 : }
1073 :
1074 0 : void SwPaM::InvalidatePaM()
1075 : {
1076 0 : const SwNode *_pNd=this->GetNode();
1077 0 : const SwTxtNode *_pTxtNd=(_pNd!=NULL?_pNd->GetTxtNode():NULL);
1078 0 : if (_pTxtNd!=NULL)
1079 : {
1080 : // pretent that the PaM marks inserted text to recalc the portion...
1081 0 : SwInsTxt aHint( Start()->nContent.GetIndex(),
1082 0 : End()->nContent.GetIndex() - Start()->nContent.GetIndex() + 1 );
1083 0 : SwModify *_pModify=(SwModify*)_pTxtNd;
1084 0 : _pModify->ModifyNotification( 0, &aHint);
1085 : }
1086 0 : }
1087 :
1088 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|