xref: /AOO41X/main/sw/source/core/crsr/pam.cxx (revision 5b11f0d37479a367cdfcf80f0923ccbf6b49ec3b)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <editeng/protitem.hxx>
30 #include <cntfrm.hxx>
31 #include <pagefrm.hxx>
32 #include <doc.hxx>
33 #include <docary.hxx>
34 #include <pam.hxx>
35 #include <pamtyp.hxx>
36 #include <txtfrm.hxx>
37 #include <section.hxx>
38 #include <fmtcntnt.hxx>
39 #include <frmatr.hxx>
40 #include <swtable.hxx>
41 #include <crsskip.hxx>
42 
43 // --> FME 2004-06-29 #114856# Formular view
44 #include <flyfrm.hxx>
45 #include <fmteiro.hxx>
46 #include <section.hxx>
47 #include <sectfrm.hxx>
48 // <--
49 #include <ndtxt.hxx> // #111827#
50 
51 #include <IMark.hxx>
52 #include <hints.hxx>
53 
54 // fuer den dummen ?MSC-? Compiler
55 inline xub_StrLen GetSttOrEnd( sal_Bool bCondition, const SwCntntNode& rNd )
56 {
57     return bCondition ? 0 : rNd.Len();
58 }
59 
60 /*************************************************************************
61 |*
62 |*  SwPosition
63 |*
64 |*  Beschreibung        PAM.DOC
65 |*  Ersterstellung      VB  4.3.91
66 |*  Letzte Aenderung    VB  4.3.91
67 |*
68 *************************************************************************/
69 
70 
71 SwPosition::SwPosition( const SwNodeIndex & rNodeIndex, const SwIndex & rCntnt )
72     : nNode( rNodeIndex ), nContent( rCntnt )
73 {
74 }
75 
76 SwPosition::SwPosition( const SwNodeIndex & rNodeIndex )
77     : nNode( rNodeIndex ), nContent( nNode.GetNode().GetCntntNode() )
78 {
79 }
80 
81 SwPosition::SwPosition( const SwNode& rNode )
82     : nNode( rNode ), nContent( nNode.GetNode().GetCntntNode() )
83 {
84 }
85 
86 SwPosition::SwPosition( SwCntntNode & rNode, const xub_StrLen nOffset )
87     : nNode( rNode ), nContent( &rNode, nOffset )
88 {
89 }
90 
91 
92 SwPosition::SwPosition( const SwPosition & rPos )
93     : nNode( rPos.nNode ), nContent( rPos.nContent )
94 {
95 }
96 
97 SwPosition &SwPosition::operator=(const SwPosition &rPos)
98 {
99     nNode = rPos.nNode;
100     nContent = rPos.nContent;
101     return *this;
102 }
103 
104 
105 sal_Bool SwPosition::operator<(const SwPosition &rPos) const
106 {
107     if( nNode < rPos.nNode )
108         return sal_True;
109     if( nNode == rPos.nNode )
110         return ( nContent < rPos.nContent );
111     return sal_False;
112 }
113 
114 
115 sal_Bool SwPosition::operator>(const SwPosition &rPos) const
116 {
117     if(nNode > rPos.nNode )
118         return sal_True;
119     if( nNode == rPos.nNode )
120         return ( nContent > rPos.nContent );
121     return sal_False;
122 }
123 
124 
125 sal_Bool SwPosition::operator<=(const SwPosition &rPos) const
126 {
127     if(nNode < rPos.nNode )
128         return sal_True;
129     if( nNode == rPos.nNode )
130         return ( nContent <= rPos.nContent );
131     return sal_False;
132 }
133 
134 
135 sal_Bool SwPosition::operator>=(const SwPosition &rPos) const
136 {
137     if(nNode > rPos.nNode )
138         return sal_True;
139     if( nNode == rPos.nNode )
140         return ( nContent >= rPos.nContent );
141     return sal_False;
142 }
143 
144 
145 sal_Bool SwPosition::operator==(const SwPosition &rPos) const
146 {
147     return
148         ( ( nNode == rPos.nNode ) && ( nContent == rPos.nContent ) ?
149             sal_True: sal_False);
150 }
151 
152 
153 sal_Bool SwPosition::operator!=(const SwPosition &rPos) const
154 {
155     if( nNode != rPos.nNode )
156         return sal_True;
157     return ( nContent != rPos.nContent );
158 }
159 
160 SwDoc * SwPosition::GetDoc() const
161 {
162     return nNode.GetNode().GetDoc();
163 }
164 
165 SwComparePosition ComparePosition(
166             const SwPosition& rStt1, const SwPosition& rEnd1,
167             const SwPosition& rStt2, const SwPosition& rEnd2 )
168 {
169     SwComparePosition nRet;
170     if( rStt1 < rStt2 )
171     {
172         if( rEnd1 > rStt2 )
173         {
174             if( rEnd1 >= rEnd2 )
175                 nRet = POS_OUTSIDE;
176             else
177                 nRet = POS_OVERLAP_BEFORE;
178 
179         }
180         else if( rEnd1 == rStt2 )
181             nRet = POS_COLLIDE_END;
182         else
183             nRet = POS_BEFORE;
184     }
185     else if( rEnd2 > rStt1 )
186     {
187         if( rEnd2 >= rEnd1 )
188         {
189             if( rEnd2 == rEnd1 && rStt2 == rStt1 )
190                 nRet = POS_EQUAL;
191             else
192                 nRet = POS_INSIDE;
193         }
194         else
195         {
196             if (rStt1 == rStt2)
197                 nRet = POS_OUTSIDE;
198             else
199                 nRet = POS_OVERLAP_BEHIND;
200         }
201     }
202     else if( rEnd2 == rStt1 )
203         nRet = POS_COLLIDE_START;
204     else
205         nRet = POS_BEHIND;
206     return nRet;
207 }
208 
209 SwComparePosition ComparePosition(
210             const unsigned long nStt1, const unsigned long nEnd1,
211             const unsigned long nStt2, const unsigned long nEnd2 )
212 {
213     SwComparePosition nRet;
214     if( nStt1 < nStt2 )
215     {
216         if( nEnd1 > nStt2 )
217         {
218             if( nEnd1 >= nEnd2 )
219                 nRet = POS_OUTSIDE;
220             else
221                 nRet = POS_OVERLAP_BEFORE;
222 
223         }
224         else if( nEnd1 == nStt2 )
225             nRet = POS_COLLIDE_END;
226         else
227             nRet = POS_BEFORE;
228     }
229     else if( nEnd2 > nStt1 )
230     {
231         if( nEnd2 >= nEnd1 )
232         {
233             if( nEnd2 == nEnd1 && nStt2 == nStt1 )
234                 nRet = POS_EQUAL;
235             else
236                 nRet = POS_INSIDE;
237         }
238         else
239         {
240             if (nStt1 == nStt2)
241                 nRet = POS_OUTSIDE;
242             else
243                 nRet = POS_OVERLAP_BEHIND;
244         }
245     }
246     else if( nEnd2 == nStt1 )
247         nRet = POS_COLLIDE_START;
248     else
249         nRet = POS_BEHIND;
250     return nRet;
251 }
252 
253 /*  */
254 
255 enum CHKSECTION { Chk_Both, Chk_One, Chk_None };
256 
257 
258 CHKSECTION lcl_TstIdx( sal_uLong nSttIdx, sal_uLong nEndIdx, const SwNode& rEndNd )
259 {
260     sal_uLong nStt = rEndNd.StartOfSectionIndex(), nEnd = rEndNd.GetIndex();
261     CHKSECTION eSec = nStt < nSttIdx && nEnd >= nSttIdx ? Chk_One : Chk_None;
262     if( nStt < nEndIdx && nEnd >= nEndIdx )
263         return( eSec == Chk_One ? Chk_Both : Chk_One );
264     return eSec;
265 }
266 
267 
268 sal_Bool lcl_ChkOneRange( CHKSECTION eSec, sal_Bool bChkSections,
269                     const SwNode& rBaseEnd, sal_uLong nStt, sal_uLong nEnd )
270 {
271     if( eSec != Chk_Both )
272         return sal_False;
273 
274     if( !bChkSections )
275         return sal_True;
276 
277     // suche die umspannende Section
278     const SwNodes& rNds = rBaseEnd.GetNodes();
279     const SwNode *pTmp, *pNd = rNds[ nStt ];
280     if( !pNd->IsStartNode() )
281         pNd = pNd->StartOfSectionNode();
282 
283     if( pNd == rNds[ nEnd ]->StartOfSectionNode() )
284         return sal_True;        // der gleiche StartNode, die selbe Section
285 
286     // steht schon auf einem GrundSection Node ? Fehler !!!
287     if( !pNd->StartOfSectionIndex() )
288         return sal_False;
289 
290     while( ( pTmp = pNd->StartOfSectionNode())->EndOfSectionNode() !=
291             &rBaseEnd )
292         pNd = pTmp;
293 
294     sal_uLong nSttIdx = pNd->GetIndex(), nEndIdx = pNd->EndOfSectionIndex();
295     return nSttIdx <= nStt && nStt <= nEndIdx &&
296            nSttIdx <= nEnd && nEnd <= nEndIdx ? sal_True : sal_False;
297 }
298 
299 
300 sal_Bool CheckNodesRange( const SwNodeIndex& rStt,
301                         const SwNodeIndex& rEnd, sal_Bool bChkSection )
302 {
303     const SwNodes& rNds = rStt.GetNodes();
304     sal_uLong nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex();
305     CHKSECTION eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfContent() );
306     if( Chk_None != eSec ) return eSec == Chk_Both ? sal_True : sal_False;
307 
308     eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfAutotext() );
309     if( Chk_None != eSec )
310         return lcl_ChkOneRange( eSec, bChkSection,
311                             rNds.GetEndOfAutotext(), nStt, nEnd );
312 
313     eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfPostIts() );
314     if( Chk_None != eSec )
315         return lcl_ChkOneRange( eSec, bChkSection,
316                             rNds.GetEndOfPostIts(), nStt, nEnd );
317 
318     eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfInserts() );
319     if( Chk_None != eSec )
320         return lcl_ChkOneRange( eSec, bChkSection,
321                             rNds.GetEndOfInserts(), nStt, nEnd );
322 
323     eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfRedlines() );
324     if( Chk_None != eSec )
325         return lcl_ChkOneRange( eSec, bChkSection,
326                             rNds.GetEndOfRedlines(), nStt, nEnd );
327 
328     return sal_False;       // liegt irgendwo dazwischen, FEHLER
329 }
330 
331 
332 sal_Bool GoNext(SwNode* pNd, SwIndex * pIdx, sal_uInt16 nMode )
333 {
334     if( pNd->IsCntntNode() )
335         return ((SwCntntNode*)pNd)->GoNext( pIdx, nMode );
336     return sal_False;
337 }
338 
339 
340 sal_Bool GoPrevious( SwNode* pNd, SwIndex * pIdx, sal_uInt16 nMode )
341 {
342     if( pNd->IsCntntNode() )
343         return ((SwCntntNode*)pNd)->GoPrevious( pIdx, nMode );
344     return sal_False;
345 }
346 
347 
348 SwCntntNode* GoNextNds( SwNodeIndex* pIdx, sal_Bool bChk )
349 {
350     SwNodeIndex aIdx( *pIdx );
351     SwCntntNode* pNd = aIdx.GetNodes().GoNext( &aIdx );
352     if( pNd )
353     {
354         if( bChk && 1 != aIdx.GetIndex() - pIdx->GetIndex() &&
355             !CheckNodesRange( *pIdx, aIdx, sal_True ) )
356                 pNd = 0;
357         else
358             *pIdx = aIdx;
359     }
360     return pNd;
361 }
362 
363 
364 SwCntntNode* GoPreviousNds( SwNodeIndex * pIdx, sal_Bool bChk )
365 {
366     SwNodeIndex aIdx( *pIdx );
367     SwCntntNode* pNd = aIdx.GetNodes().GoPrevious( &aIdx );
368     if( pNd )
369     {
370         if( bChk && 1 != pIdx->GetIndex() - aIdx.GetIndex() &&
371             !CheckNodesRange( *pIdx, aIdx, sal_True ) )
372                 pNd = 0;
373         else
374             *pIdx = aIdx;
375     }
376     return pNd;
377 }
378 
379 // ----------------------------------------------------------------------
380 
381 /*************************************************************************
382 |*
383 |*  SwPointAndMark
384 |*
385 |*  Beschreibung        PAM.DOC
386 |*  Ersterstellung      VB  4.3.91
387 |*  Letzte Aenderung    JP  6.5.91
388 |*
389 *************************************************************************/
390 
391 SwPaM::SwPaM( const SwPosition& rPos, SwPaM* pRing )
392     : Ring( pRing )
393     , m_Bound1( rPos )
394     , m_Bound2( rPos.nNode.GetNode().GetNodes() ) // default initialize
395     , m_pPoint( &m_Bound1 )
396     , m_pMark( m_pPoint )
397     , m_bIsInFrontOfLabel( false )
398 {
399 }
400 
401 SwPaM::SwPaM( const SwPosition& rMark, const SwPosition& rPoint, SwPaM* pRing )
402     : Ring( pRing )
403     , m_Bound1( rMark )
404     , m_Bound2( rPoint )
405     , m_pPoint( &m_Bound2 )
406     , m_pMark( &m_Bound1 )
407     , m_bIsInFrontOfLabel( false )
408 {
409 }
410 
411 SwPaM::SwPaM( const SwNodeIndex& rMark, const SwNodeIndex& rPoint,
412               long nMarkOffset, long nPointOffset, SwPaM* pRing )
413     : Ring( pRing )
414     , m_Bound1( rMark )
415     , m_Bound2( rPoint )
416     , m_pPoint( &m_Bound2 )
417     , m_pMark( &m_Bound1 )
418     , m_bIsInFrontOfLabel( false )
419 {
420     if ( nMarkOffset )
421     {
422         m_pMark->nNode += nMarkOffset;
423     }
424     if ( nPointOffset )
425     {
426         m_pPoint->nNode += nPointOffset;
427     }
428 
429     m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetCntntNode(), 0 );
430     m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetCntntNode(), 0 );
431 }
432 
433 SwPaM::SwPaM( const SwNode& rMark, const SwNode& rPoint,
434               long nMarkOffset, long nPointOffset, SwPaM* pRing )
435     : Ring( pRing )
436     , m_Bound1( rMark )
437     , m_Bound2( rPoint )
438     , m_pPoint( &m_Bound2 )
439     , m_pMark( &m_Bound1 )
440     , m_bIsInFrontOfLabel( false )
441 {
442     if ( nMarkOffset )
443     {
444         m_pMark->nNode += nMarkOffset;
445     }
446     if ( nPointOffset )
447     {
448         m_pPoint->nNode += nPointOffset;
449     }
450 
451     m_Bound1.nContent.Assign( m_Bound1.nNode.GetNode().GetCntntNode(), 0 );
452     m_Bound2.nContent.Assign( m_Bound2.nNode.GetNode().GetCntntNode(), 0 );
453 }
454 
455 SwPaM::SwPaM( const SwNodeIndex& rMark , xub_StrLen nMarkCntnt,
456               const SwNodeIndex& rPoint, xub_StrLen nPointCntnt, SwPaM* pRing )
457     : Ring( pRing )
458     , m_Bound1( rMark )
459     , m_Bound2( rPoint )
460     , m_pPoint( &m_Bound2 )
461     , m_pMark( &m_Bound1 )
462     , m_bIsInFrontOfLabel( false )
463 {
464     m_pPoint->nContent.Assign( rPoint.GetNode().GetCntntNode(), nPointCntnt);
465     m_pMark ->nContent.Assign( rMark .GetNode().GetCntntNode(), nMarkCntnt );
466 }
467 
468 SwPaM::SwPaM( const SwNode& rMark , xub_StrLen nMarkCntnt,
469               const SwNode& rPoint, xub_StrLen nPointCntnt, SwPaM* pRing )
470     : Ring( pRing )
471     , m_Bound1( rMark )
472     , m_Bound2( rPoint )
473     , m_pPoint( &m_Bound2 )
474     , m_pMark( &m_Bound1 )
475     , m_bIsInFrontOfLabel( false )
476 {
477     m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetCntntNode(),
478         nPointCntnt);
479     m_pMark ->nContent.Assign( m_pMark ->nNode.GetNode().GetCntntNode(),
480         nMarkCntnt );
481 }
482 
483 SwPaM::SwPaM( const SwNode& rNode, xub_StrLen nCntnt, SwPaM* pRing )
484     : Ring( pRing )
485     , m_Bound1( rNode )
486     , m_Bound2( m_Bound1.nNode.GetNode().GetNodes() ) // default initialize
487     , m_pPoint( &m_Bound1 )
488     , m_pMark( &m_Bound1 )
489     , m_bIsInFrontOfLabel( false )
490 {
491     m_pPoint->nContent.Assign( m_pPoint->nNode.GetNode().GetCntntNode(),
492         nCntnt );
493 }
494 
495 SwPaM::SwPaM( const SwNodeIndex& rNodeIdx, xub_StrLen nCntnt, SwPaM* pRing )
496     : Ring( pRing )
497     , m_Bound1( rNodeIdx )
498     , m_Bound2( rNodeIdx.GetNode().GetNodes() ) // default initialize
499     , m_pPoint( &m_Bound1 )
500     , m_pMark( &m_Bound1 )
501     , m_bIsInFrontOfLabel( false )
502 {
503     m_pPoint->nContent.Assign( rNodeIdx.GetNode().GetCntntNode(), nCntnt );
504 }
505 
506 SwPaM::~SwPaM() {}
507 
508 // @@@ semantic: no copy ctor.
509 SwPaM::SwPaM( SwPaM &rPam )
510     : Ring( &rPam )
511     , m_Bound1( *(rPam.m_pPoint) )
512     , m_Bound2( *(rPam.m_pMark)  )
513     , m_pPoint( &m_Bound1 ), m_pMark( rPam.HasMark() ? &m_Bound2 : m_pPoint )
514     , m_bIsInFrontOfLabel( false )
515 {
516 }
517 
518 // @@@ semantic: no copy assignment for super class Ring.
519 SwPaM &SwPaM::operator=( const SwPaM &rPam )
520 {
521     *m_pPoint = *( rPam.m_pPoint );
522     if ( rPam.HasMark() )
523     {
524         SetMark();
525         *m_pMark = *( rPam.m_pMark );
526     }
527     else
528     {
529         DeleteMark();
530     }
531     return *this;
532 }
533 
534 void SwPaM::SetMark()
535 {
536     if (m_pPoint == &m_Bound1)
537     {
538         m_pMark = &m_Bound2;
539     }
540     else
541     {
542         m_pMark = &m_Bound1;
543     }
544     (*m_pMark) = (*m_pPoint);
545 }
546 
547 #ifdef DBG_UTIL
548 
549 void SwPaM::Exchange()
550 {
551     if (m_pPoint != m_pMark)
552     {
553         SwPosition *pTmp = m_pPoint;
554         m_pPoint = m_pMark;
555         m_pMark = pTmp;
556     }
557 }
558 #endif
559 
560 // Bewegen des Cursors
561 
562 
563 sal_Bool SwPaM::Move( SwMoveFn fnMove, SwGoInDoc fnGo )
564 {
565     sal_Bool bRet = (*fnGo)( *this, fnMove );
566 
567     m_bIsInFrontOfLabel = false;
568 
569     return bRet;
570 }
571 
572 
573 /*************************************************************************
574 |*
575 |*    void SwPaM::MakeRegion( SwMoveFn, SwPaM*, const SwPaM* )
576 |*
577 |*    Beschreibung      Setzt den 1. SwPaM auf den uebergebenen SwPaM
578 |*                      oder setzt auf den Anfang oder Ende vom Document.
579 |*                      SPoint bleibt auf der Position stehen, GetMark aendert
580 |*                      sich entsprechend !
581 |*
582 |*    Parameter         SwDirection     gibt an, ob an Anfang / Ende
583 |*                      SwPaM *         der zu setzende Bereich
584 |*                      const SwPaM&    der enventuell vorgegeben Bereich
585 |*    Return-Werte      SwPaM*          der entsprehend neu gesetzte Bereich
586 |*
587 |*    Ersterstellung    JP 26.04.91
588 |*    Letzte Aenderung  JP 26.04.91
589 |*
590 *************************************************************************/
591 
592 
593 SwPaM* SwPaM::MakeRegion( SwMoveFn fnMove, const SwPaM * pOrigRg )
594 {
595     SwPaM* pPam;
596     if( pOrigRg == 0 )
597     {
598         pPam = new SwPaM( *m_pPoint );
599         pPam->SetMark();                    // setze Anfang fest
600         pPam->Move( fnMove, fnGoSection);       // an Anfang / Ende vom Node
601 
602         // stelle SPoint wieder auf alte Position, GetMark auf das "Ende"
603         pPam->Exchange();
604     }
605     else
606     {
607         pPam = new SwPaM( *(SwPaM*)pOrigRg );   // die Suchregion ist vorgegeben
608         // sorge dafuer, dass SPoint auf dem "echten" StartPunkt steht
609         // FORWARD  --> SPoint immer kleiner  als GetMark
610         // BACKWARD --> SPoint immer groesser als GetMark
611         if( (pPam->GetMark()->*fnMove->fnCmpOp)( *pPam->GetPoint() ) )
612             pPam->Exchange();
613     }
614     return pPam;
615 }
616 
617 SwPaM & SwPaM::Normalize(sal_Bool bPointFirst)
618 {
619     if (HasMark())
620         if ( ( bPointFirst && *m_pPoint > *m_pMark) ||
621              (!bPointFirst && *m_pPoint < *m_pMark) )
622         {
623             Exchange();
624         }
625 
626     return *this;
627 }
628 
629 sal_uInt16 SwPaM::GetPageNum( sal_Bool bAtPoint, const Point* pLayPos )
630 {
631     // return die Seitennummer am Cursor
632     // (fuer Reader + Seitengebundene Rahmen)
633     const SwCntntFrm* pCFrm;
634     const SwPageFrm *pPg;
635     const SwCntntNode *pNd ;
636     const SwPosition* pPos = bAtPoint ? m_pPoint : m_pMark;
637 
638     if( 0 != ( pNd = pPos->nNode.GetNode().GetCntntNode() ) &&
639         0 != ( pCFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout(), pLayPos, pPos, sal_False )) &&
640         0 != ( pPg = pCFrm->FindPageFrm() ))
641         return pPg->GetPhyPageNum();
642     return 0;
643 }
644 
645 // --> FME 2004-06-29 #114856# Formular view
646 // See also SwCrsrShell::IsCrsrReadonly()
647 const SwFrm* lcl_FindEditInReadonlyFrm( const SwFrm& rFrm )
648 {
649     const SwFrm* pRet = 0;
650 
651     const SwFlyFrm* pFly;
652     const SwSectionFrm* pSectionFrm;
653 
654     if( rFrm.IsInFly() &&
655        (pFly = rFrm.FindFlyFrm())->GetFmt()->GetEditInReadonly().GetValue() &&
656         pFly->Lower() &&
657        !pFly->Lower()->IsNoTxtFrm() )
658     {
659        pRet = pFly;
660     }
661     else if ( rFrm.IsInSct() &&
662               0 != ( pSectionFrm = rFrm.FindSctFrm() )->GetSection() &&
663               pSectionFrm->GetSection()->IsEditInReadonlyFlag() )
664     {
665         pRet = pSectionFrm;
666     }
667 
668     return pRet;
669 }
670 // <--
671 
672 // steht in etwas geschuetztem oder in die Selektion umspannt
673 // etwas geschuetztes.
674 sal_Bool SwPaM::HasReadonlySel( const bool bFormView ) const
675 {
676     sal_Bool bRet = sal_False;
677 
678     const SwCntntNode* pNd = GetPoint()->nNode.GetNode().GetCntntNode();
679     const SwCntntFrm *pFrm = NULL;
680     if ( pNd != NULL )
681     {
682         Point aTmpPt;
683         pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout(), &aTmpPt, GetPoint(), sal_False );
684     }
685 
686     // Will be set if point are inside edit-in-readonly environment
687     const SwFrm* pPointEditInReadonlyFrm = NULL;
688     if ( pFrm != NULL
689          && ( pFrm->IsProtected()
690               || ( bFormView
691                    && 0 == ( pPointEditInReadonlyFrm = lcl_FindEditInReadonlyFrm( *pFrm ) ) ) ) )
692     {
693         bRet = sal_True;
694     }
695     else if( pNd != NULL )
696     {
697         const SwSectionNode* pSNd = pNd->GetSectionNode();
698         if ( pSNd != NULL
699              && ( pSNd->GetSection().IsProtectFlag()
700                   || ( bFormView
701                        && !pSNd->GetSection().IsEditInReadonlyFlag()) ) )
702         {
703             bRet = sal_True;
704         }
705     }
706 
707     if ( !bRet
708          && HasMark()
709          && GetPoint()->nNode != GetMark()->nNode )
710     {
711         pNd = GetMark()->nNode.GetNode().GetCntntNode();
712         pFrm = NULL;
713         if ( pNd != NULL )
714         {
715             Point aTmpPt;
716             pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout(), &aTmpPt, GetMark(), sal_False );
717         }
718 
719         const SwFrm* pMarkEditInReadonlyFrm = NULL;
720         if ( pFrm != NULL
721              && ( pFrm->IsProtected()
722                   || ( bFormView
723                        && 0 == ( pMarkEditInReadonlyFrm = lcl_FindEditInReadonlyFrm( *pFrm ) ) ) ) )
724         {
725             bRet = sal_True;
726         }
727         else if( pNd != NULL )
728         {
729             const SwSectionNode* pSNd = pNd->GetSectionNode();
730             if ( pSNd != NULL
731                  && ( pSNd->GetSection().IsProtectFlag()
732                       || ( bFormView
733                            && !pSNd->GetSection().IsEditInReadonlyFlag()) ) )
734             {
735                 bRet = sal_True;
736             }
737         }
738 
739         if ( !bRet && bFormView )
740         {
741            // Check if start and end frame are inside the _same_
742            // edit-in-readonly-environment. Otherwise we better return 'true'
743            if ( pPointEditInReadonlyFrm != pMarkEditInReadonlyFrm )
744                 bRet = sal_True;
745         }
746 
747         // check for protected section inside the selection
748         if( !bRet )
749         {
750             sal_uLong nSttIdx = GetMark()->nNode.GetIndex(),
751                     nEndIdx = GetPoint()->nNode.GetIndex();
752             if( nEndIdx <= nSttIdx )
753             {
754                 sal_uLong nTmp = nSttIdx;
755                 nSttIdx = nEndIdx;
756                 nEndIdx = nTmp;
757             }
758 
759             // wenn ein geschuetzter Bereich zwischen den Nodes stehen soll,
760             // muss die Selektion selbst schon x Nodes umfassen.
761             // (TxtNd, SectNd, TxtNd, EndNd, TxtNd )
762             if( nSttIdx + 3 < nEndIdx )
763             {
764                 const SwSectionFmts& rFmts = GetDoc()->GetSections();
765                 for( sal_uInt16 n = rFmts.Count(); n;  )
766                 {
767                     const SwSectionFmt* pFmt = rFmts[ --n ];
768                     if( pFmt->GetProtect().IsCntntProtected() )
769                     {
770                         const SwFmtCntnt& rCntnt = pFmt->GetCntnt(sal_False);
771                         ASSERT( rCntnt.GetCntntIdx(), "wo ist der SectionNode?" );
772                         sal_uLong nIdx = rCntnt.GetCntntIdx()->GetIndex();
773                         if( nSttIdx <= nIdx && nEndIdx >= nIdx &&
774                             rCntnt.GetCntntIdx()->GetNode().GetNodes().IsDocNodes() )
775                         {
776                             bRet = sal_True;
777                             break;
778                         }
779                     }
780                 }
781 
782 #ifdef CHECK_CELL_READONLY
783 //JP 22.01.99: bisher wurden Tabelle, die in der Text-Selektion standen
784 //              nicht beachtet. Wollte man das haben, dann muss dieser
785 //              Code freigeschaltet werden
786 
787                 if( !bRet )
788                 {
789                     // dann noch ueber alle Tabellen
790                     const SwFrmFmts& rFmts = *GetDoc()->GetTblFrmFmts();
791                     for( n = rFmts.Count(); n ;  )
792                     {
793                         SwFrmFmt* pFmt = (SwFrmFmt*)rFmts[ --n ];
794                         const SwTable* pTbl = SwTable::FindTable( pFmt );
795                         sal_uLong nIdx = pTbl ? pTbl->GetTabSortBoxes()[0]->GetSttIdx()
796                                           : 0;
797                         if( nSttIdx <= nIdx && nEndIdx >= nIdx )
798                         {
799                             // dann teste mal alle Boxen
800                             const SwTableSortBoxes& rBoxes = pTbl->GetTabSortBoxes();
801 
802                             for( sal_uInt16 i =  rBoxes.Count(); i; )
803                                 if( rBoxes[ --i ]->GetFrmFmt()->GetProtect().
804                                     IsCntntProtected() )
805                                 {
806                                     bRet = sal_True;
807                                     break;
808                                 }
809 
810                             if( bRet )
811                                 break;
812                         }
813                     }
814                 }
815 #endif
816             }
817         }
818     }
819 
820     //FIXME FieldBk
821     // TODO: Form Protection when Enhanced Fields are enabled
822     if (!bRet)
823     {
824         const SwDoc *pDoc = GetDoc();
825         sw::mark::IMark* pA = NULL;
826         sw::mark::IMark* pB = NULL;
827         if ( pDoc )
828         {
829             const IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess( );
830             pA = GetPoint() ? pMarksAccess->getFieldmarkFor( *GetPoint( ) ) : NULL;
831             pB = GetMark( ) ? pMarksAccess->getFieldmarkFor( *GetMark( ) ) : pA;
832             bRet = ( pA != pB );
833         }
834         bool bProtectForm = pDoc->get( IDocumentSettingAccess::PROTECT_FORM );
835         if ( bProtectForm )
836             bRet |= ( pA == NULL || pB == NULL );
837     }
838 
839     return bRet;
840 }
841 
842 //--------------------  Suche nach Formaten( FormatNamen ) -----------------
843 
844 // die Funktion gibt in Suchrichtung den folgenden Node zurueck.
845 // Ist in der Richtung keiner mehr vorhanden oder ist dieser ausserhalb
846 // des Bereiches, wird ein 0 Pointer returnt.
847 // Das rbFirst gibt an, ob es man zu erstenmal einen Node holt. Ist das der
848 // Fall, darf die Position vom Pam nicht veraendert werden!
849 
850 
851 SwCntntNode* GetNode( SwPaM & rPam, sal_Bool& rbFirst, SwMoveFn fnMove,
852                         sal_Bool bInReadOnly )
853 {
854     SwCntntNode * pNd = 0;
855     SwCntntFrm* pFrm;
856     if( ((*rPam.GetPoint()).*fnMove->fnCmpOp)( *rPam.GetMark() ) ||
857         ( *rPam.GetPoint() == *rPam.GetMark() && rbFirst ) )
858     {
859         if( rbFirst )
860         {
861             rbFirst = sal_False;
862             pNd = rPam.GetCntntNode();
863             if( pNd )
864             {
865                 if(
866                     (
867                         0 == ( pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout() ) ) ||
868                         ( !bInReadOnly && pFrm->IsProtected() ) ||
869                         (pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow())
870                     ) ||
871                     ( !bInReadOnly && pNd->FindSectionNode() &&
872                         pNd->FindSectionNode()->GetSection().IsProtect()
873                     )
874                   )
875                     {
876                         pNd = 0;
877                     }
878             }
879         }
880 
881         if( !pNd )          // steht Cursor auf keinem ContentNode ?
882         {
883             SwPosition aPos( *rPam.GetPoint() );
884             sal_Bool bSrchForward = fnMove == fnMoveForward;
885             SwNodes& rNodes = aPos.nNode.GetNodes();
886 
887             // zum naechsten / vorherigen ContentNode
888 // Funktioniert noch alles, wenn die Uerbpruefung vom ueberspringen der
889 // Sektions herausgenommen wird ??
890 //          if( (*fnMove->fnNds)( rNodes, &aPos.nNode ) )
891             while( sal_True )
892             {
893                 pNd = bSrchForward
894                         ? rNodes.GoNextSection( &aPos.nNode, sal_True, !bInReadOnly )
895                         : rNodes.GoPrevSection( &aPos.nNode, sal_True, !bInReadOnly );
896                 if( pNd )
897                 {
898                     aPos.nContent.Assign( pNd, ::GetSttOrEnd( bSrchForward,*pNd ));
899                     // liegt Position immer noch im Bereich ?
900                     if( (aPos.*fnMove->fnCmpOp)( *rPam.GetMark() ) )
901                     {
902                         // nur in der AutoTextSection koennen Node stehen, die
903                         // nicht angezeigt werden !!
904                         if( 0 == ( pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout() ) ) ||
905                             ( !bInReadOnly && pFrm->IsProtected() ) ||
906                             ( pFrm->IsTxtFrm() &&
907                                 ((SwTxtFrm*)pFrm)->IsHiddenNow() ) )
908 
909 //                          rNodes[ rNodes.EndOfAutotext ]->StartOfSection().GetIndex()
910 //                          < aPos.nNode.GetIndex() && aPos.nNode.GetIndex()
911 //                          < rNodes.EndOfAutotext.GetIndex() &&
912 //                          0 == ( pFrm = pNd->GetFrm()) &&
913 //                          pFrm->IsProtected() )
914                         {
915                             pNd = 0;
916                             continue;       // suche weiter
917                         }
918                         *(SwPosition*)rPam.GetPoint() = aPos;
919                     }
920                     else
921                         pNd = 0;            // kein gueltiger Node
922                     break;
923                 }
924                 break;
925             }
926         }
927     }
928     return pNd;
929 }
930 
931 // ----------------------------------------------------------------------
932 
933 // hier folgen die Move-Methoden ( Foward, Backward; Content, Node, Doc )
934 
935 
936 void GoStartDoc( SwPosition * pPos )
937 {
938     SwNodes& rNodes = pPos->nNode.GetNodes();
939     pPos->nNode = *rNodes.GetEndOfContent().StartOfSectionNode();
940     // es muss immer ein ContentNode gefunden werden !!
941     SwCntntNode* pCNd = rNodes.GoNext( &pPos->nNode );
942     if( pCNd )
943         pCNd->MakeStartIndex( &pPos->nContent );
944 }
945 
946 
947 void GoEndDoc( SwPosition * pPos )
948 {
949     SwNodes& rNodes = pPos->nNode.GetNodes();
950     pPos->nNode = rNodes.GetEndOfContent();
951     SwCntntNode* pCNd = GoPreviousNds( &pPos->nNode, sal_True );
952     if( pCNd )
953         pCNd->MakeEndIndex( &pPos->nContent );
954 }
955 
956 
957 void GoStartSection( SwPosition * pPos )
958 {
959     // springe zum Anfang der Section
960     SwNodes& rNodes = pPos->nNode.GetNodes();
961     sal_uInt16 nLevel = rNodes.GetSectionLevel( pPos->nNode );
962     if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() )
963         nLevel--;
964     do { rNodes.GoStartOfSection( &pPos->nNode ); } while( nLevel-- );
965 
966     // steht jetzt schon auf einem CntntNode
967     pPos->nNode.GetNode().GetCntntNode()->MakeStartIndex( &pPos->nContent );
968 }
969 
970 // gehe an das Ende der akt. Grund-Section
971 
972 
973 void GoEndSection( SwPosition * pPos )
974 {
975     // springe zum Anfang/Ende der Section
976     SwNodes& rNodes = pPos->nNode.GetNodes();
977     sal_uInt16 nLevel = rNodes.GetSectionLevel( pPos->nNode );
978     if( pPos->nNode < rNodes.GetEndOfContent().StartOfSectionIndex() )
979         nLevel--;
980     do { rNodes.GoEndOfSection( &pPos->nNode ); } while( nLevel-- );
981 
982     // steht jetzt auf einem EndNode, also zum vorherigen CntntNode
983     if( GoPreviousNds( &pPos->nNode, sal_True ) )
984         pPos->nNode.GetNode().GetCntntNode()->MakeEndIndex( &pPos->nContent );
985 }
986 
987 
988 
989 sal_Bool GoInDoc( SwPaM & rPam, SwMoveFn fnMove )
990 {
991     (*fnMove->fnDoc)( rPam.GetPoint() );
992     return sal_True;
993 }
994 
995 
996 sal_Bool GoInSection( SwPaM & rPam, SwMoveFn fnMove )
997 {
998     (*fnMove->fnSections)( (SwPosition*)rPam.GetPoint() );
999     return sal_True;
1000 }
1001 
1002 
1003 sal_Bool GoInNode( SwPaM & rPam, SwMoveFn fnMove )
1004 {
1005     SwCntntNode *pNd = (*fnMove->fnNds)( &rPam.GetPoint()->nNode, sal_True );
1006     if( pNd )
1007         rPam.GetPoint()->nContent.Assign( pNd,
1008                         ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) );
1009     return 0 != pNd;
1010 }
1011 
1012 
1013 sal_Bool GoInCntnt( SwPaM & rPam, SwMoveFn fnMove )
1014 {
1015     if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
1016                         &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS ))
1017         return sal_True;
1018     return GoInNode( rPam, fnMove );
1019 }
1020 
1021 sal_Bool GoInCntntCells( SwPaM & rPam, SwMoveFn fnMove )
1022 {
1023     if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
1024                          &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS ))
1025         return sal_True;
1026     return GoInNode( rPam, fnMove );
1027 }
1028 
1029 sal_Bool GoInCntntSkipHidden( SwPaM & rPam, SwMoveFn fnMove )
1030 {
1031     if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
1032                         &rPam.GetPoint()->nContent, CRSR_SKIP_CHARS | CRSR_SKIP_HIDDEN ) )
1033         return sal_True;
1034     return GoInNode( rPam, fnMove );
1035 }
1036 
1037 sal_Bool GoInCntntCellsSkipHidden( SwPaM & rPam, SwMoveFn fnMove )
1038 {
1039     if( (*fnMove->fnNd)( &rPam.GetPoint()->nNode.GetNode(),
1040                          &rPam.GetPoint()->nContent, CRSR_SKIP_CELLS | CRSR_SKIP_HIDDEN ) )
1041         return sal_True;
1042     return GoInNode( rPam, fnMove );
1043 }
1044 
1045 
1046 
1047 // --------- Funktionsdefinitionen fuer die SwCrsrShell --------------
1048 
1049 
1050 sal_Bool GoPrevPara( SwPaM & rPam, SwPosPara aPosPara )
1051 {
1052     if( rPam.Move( fnMoveBackward, fnGoNode ) )
1053     {
1054         // steht immer auf einem ContentNode !
1055         SwPosition& rPos = *rPam.GetPoint();
1056         SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode();
1057         rPos.nContent.Assign( pNd,
1058                             ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ) );
1059         return sal_True;
1060     }
1061     return sal_False;
1062 }
1063 
1064 
1065 sal_Bool GoCurrPara( SwPaM & rPam, SwPosPara aPosPara )
1066 {
1067     SwPosition& rPos = *rPam.GetPoint();
1068     SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode();
1069     if( pNd )
1070     {
1071         xub_StrLen nOld = rPos.nContent.GetIndex(),
1072                    nNew = aPosPara == fnMoveForward ? 0 : pNd->Len();
1073         // stand er schon auf dem Anfang/Ende dann zum naechsten/vorherigen
1074         if( nOld != nNew )
1075         {
1076             rPos.nContent.Assign( pNd, nNew );
1077             return sal_True;
1078         }
1079     }
1080     // den Node noch etwas bewegen ( auf den naechsten/vorh. CntntNode)
1081     if( ( aPosPara==fnParaStart && 0 != ( pNd =
1082             GoPreviousNds( &rPos.nNode, sal_True ))) ||
1083         ( aPosPara==fnParaEnd && 0 != ( pNd =
1084             GoNextNds( &rPos.nNode, sal_True ))) )
1085     {
1086         rPos.nContent.Assign( pNd,
1087                         ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ));
1088         return sal_True;
1089     }
1090     return sal_False;
1091 }
1092 
1093 
1094 sal_Bool GoNextPara( SwPaM & rPam, SwPosPara aPosPara )
1095 {
1096     if( rPam.Move( fnMoveForward, fnGoNode ) )
1097     {
1098         // steht immer auf einem ContentNode !
1099         SwPosition& rPos = *rPam.GetPoint();
1100         SwCntntNode * pNd = rPos.nNode.GetNode().GetCntntNode();
1101         rPos.nContent.Assign( pNd,
1102                         ::GetSttOrEnd( aPosPara == fnMoveForward, *pNd ) );
1103         return sal_True;
1104     }
1105     return sal_False;
1106 }
1107 
1108 
1109 
1110 sal_Bool GoCurrSection( SwPaM & rPam, SwMoveFn fnMove )
1111 {
1112     SwPosition& rPos = *rPam.GetPoint();
1113     SwPosition aSavePos( rPos );        // eine Vergleichsposition
1114     SwNodes& rNds = aSavePos.nNode.GetNodes();
1115     (rNds.*fnMove->fnSection)( &rPos.nNode );
1116     SwCntntNode *pNd;
1117     if( 0 == ( pNd = rPos.nNode.GetNode().GetCntntNode()) &&
1118         0 == ( pNd = (*fnMove->fnNds)( &rPos.nNode, sal_True )) )
1119     {
1120         rPos = aSavePos;        // Cusror nicht veraendern
1121         return sal_False;
1122     }
1123 
1124     rPos.nContent.Assign( pNd,
1125                         ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) );
1126     return aSavePos != rPos;
1127 }
1128 
1129 
1130 sal_Bool GoNextSection( SwPaM & rPam, SwMoveFn fnMove )
1131 {
1132     SwPosition& rPos = *rPam.GetPoint();
1133     SwPosition aSavePos( rPos );        // eine Vergleichsposition
1134     SwNodes& rNds = aSavePos.nNode.GetNodes();
1135     rNds.GoEndOfSection( &rPos.nNode );
1136 
1137     // kein weiterer ContentNode vorhanden ?
1138     if( !GoInCntnt( rPam, fnMoveForward ) )
1139     {
1140         rPos = aSavePos;        // Cusror nicht veraendern
1141         return sal_False;
1142     }
1143     (rNds.*fnMove->fnSection)( &rPos.nNode );
1144     SwCntntNode *pNd = rPos.nNode.GetNode().GetCntntNode();
1145     rPos.nContent.Assign( pNd,
1146                         ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ) );
1147     return sal_True;
1148 }
1149 
1150 
1151 sal_Bool GoPrevSection( SwPaM & rPam, SwMoveFn fnMove )
1152 {
1153     SwPosition& rPos = *rPam.GetPoint();
1154     SwPosition aSavePos( rPos );        // eine Vergleichsposition
1155     SwNodes& rNds = aSavePos.nNode.GetNodes();
1156     rNds.GoStartOfSection( &rPos.nNode );
1157 
1158     // kein weiterer ContentNode vorhanden ?
1159     if( !GoInCntnt( rPam, fnMoveBackward ))
1160     {
1161         rPos = aSavePos;        // Cusror nicht veraendern
1162         return sal_False;
1163     }
1164     (rNds.*fnMove->fnSection)( &rPos.nNode );
1165     SwCntntNode *pNd = rPos.nNode.GetNode().GetCntntNode();
1166     rPos.nContent.Assign( pNd,
1167                             ::GetSttOrEnd( fnMove == fnMoveForward, *pNd ));
1168     return sal_True;
1169 }
1170 
1171 // #111827#
1172 String SwPaM::GetTxt() const
1173 {
1174     String aResult;
1175 
1176     SwNodeIndex aNodeIndex = Start()->nNode;
1177 
1178     /* The first node can be the end node. A first end node must be
1179        handled, too. There fore do ... while and no incrementing of
1180        aNodeIndex in the first pass.
1181      */
1182     bool bFirst = true;
1183     do
1184     {
1185         if (! bFirst)
1186         {
1187             aNodeIndex++;
1188         }
1189 
1190         bFirst = false;
1191 
1192         SwTxtNode * pTxtNode = aNodeIndex.GetNode().GetTxtNode();
1193 
1194         if (pTxtNode != NULL)
1195         {
1196             const String & aTmpStr = pTxtNode->GetTxt();
1197 
1198             if (aNodeIndex == Start()->nNode)
1199             {
1200                 xub_StrLen nEnd;
1201                 if (End()->nNode == aNodeIndex)
1202                     nEnd = End()->nContent.GetIndex();
1203                 else
1204                     nEnd = aTmpStr.Len();
1205 
1206                 aResult += aTmpStr.Copy(Start()->nContent.GetIndex(),
1207                                         nEnd - Start()->nContent.GetIndex()) ;
1208             }
1209             else if (aNodeIndex == End()->nNode)
1210                 aResult += aTmpStr.Copy(0, End()->nContent.GetIndex());
1211             else
1212                 aResult += aTmpStr;
1213         }
1214     }
1215     while (aNodeIndex != End()->nNode);
1216 
1217     return aResult;
1218 }
1219 
1220 sal_Bool SwPaM::Overlap(const SwPaM & a, const SwPaM & b)
1221 {
1222     return !(*b.End() <= *a.Start() || *a.End() <= *b.End());
1223 }
1224 
1225 void SwPaM::InvalidatePaM()
1226 {
1227     const SwNode *_pNd=this->GetNode();
1228     const SwTxtNode *_pTxtNd=(_pNd!=NULL?_pNd->GetTxtNode():NULL);
1229     if (_pTxtNd!=NULL)
1230     {
1231         // pretent that the PaM marks inserted text to recalc the portion...
1232         SwInsTxt aHint( Start()->nContent.GetIndex(),
1233                         End()->nContent.GetIndex() - Start()->nContent.GetIndex() + 1 );
1234         SwModify *_pModify=(SwModify*)_pTxtNd;
1235         _pModify->ModifyNotification( 0, &aHint);
1236     }
1237 }
1238 
1239 sal_Bool SwPaM::LessThan(const SwPaM & a, const SwPaM & b)
1240 {
1241     return (*a.Start() < *b.Start()) || (*a.Start() == *b.Start() && *a.End() < *b.End());
1242 }
1243