xref: /trunk/main/sw/source/core/crsr/trvltbl.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 #include <hintids.hxx>
31 
32 #include <vcl/svapp.hxx>
33 #include <editeng/protitem.hxx>
34 #include <crsrsh.hxx>
35 #include <doc.hxx>
36 #include <cntfrm.hxx>
37 #include <editsh.hxx>       //EndAllAction gibts nur an der EditShell
38 #include <pam.hxx>
39 #include <swtable.hxx>
40 #include <docary.hxx>
41 #include <frmatr.hxx>
42 #include <frmfmt.hxx>
43 #include <viscrs.hxx>
44 #include <callnk.hxx>
45 #include <tabfrm.hxx>
46 #include <ndtxt.hxx>
47 #include <shellres.hxx>
48 #include <cellatr.hxx>
49 #include <cellfrm.hxx>
50 #include <rowfrm.hxx>
51 
52 
53 // setze Crsr in die naechsten/vorherigen Celle
54 sal_Bool SwCrsrShell::GoNextCell( sal_Bool bAppendLine )
55 {
56     sal_Bool bRet = sal_False;
57     const SwTableNode* pTblNd = 0;
58 
59     if( IsTableMode() || 0 != ( pTblNd = IsCrsrInTbl() ))
60     {
61         SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
62         SwCallLink aLk( *this );        // Crsr-Moves ueberwachen,
63         bRet = sal_True;
64 
65         // Check if we have to move the cursor to a covered cell before
66         // proceeding:
67         const SwNode* pTableBoxStartNode = pCrsr->GetNode()->FindTableBoxStartNode();
68         const SwTableBox* pTableBox = 0;
69 
70         if ( pCrsr->GetCrsrRowSpanOffset() )
71         {
72             pTableBox = pTableBoxStartNode->GetTblBox();
73             if ( pTableBox->getRowSpan() > 1 )
74             {
75                 if ( !pTblNd )
76                     pTblNd = IsCrsrInTbl();
77                 pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(),
78                                                            (sal_uInt16)(pTableBox->getRowSpan() + pCrsr->GetCrsrRowSpanOffset() ) );
79                 pTableBoxStartNode = pTableBox->GetSttNd();
80             }
81         }
82 
83         SwNodeIndex  aCellStt( *pTableBoxStartNode->EndOfSectionNode(), 1 );
84 
85         // folgt nach dem EndNode der Cell ein weiterer StartNode, dann
86         // gibt es auch eine naechste Celle
87 
88         if( !aCellStt.GetNode().IsStartNode() )
89         {
90             if( pCrsr->HasMark() || !bAppendLine )
91                 bRet = sal_False;
92             else
93             {
94                 // auf besonderen Wunsch: keine Line mehr vorhanden, dann
95                 // mache doch eine neue:
96                 if ( !pTableBox )
97                     pTableBox = pTblNd->GetTable().GetTblBox(
98                                     pCrsr->GetPoint()->nNode.GetNode().
99                                     StartOfSectionIndex() );
100 
101                 ASSERT( pTableBox, "Box steht nicht in dieser Tabelle" );
102                 SwSelBoxes aBoxes;
103 
104                 //Das Dokument veraendert sich evtl. ohne Action wuerden die Sichten
105                 //nichts mitbekommen.
106                 ((SwEditShell*)this)->StartAllAction();
107                 bRet = pDoc->InsertRow( pTblNd->GetTable().
108                                     SelLineFromBox( pTableBox, aBoxes, sal_False ));
109                 ((SwEditShell*)this)->EndAllAction();
110             }
111         }
112         if( bRet && 0 != ( bRet = pCrsr->GoNextCell() ))
113             UpdateCrsr();                 // und den akt. Updaten
114     }
115     return bRet;
116 }
117 
118 
119 sal_Bool SwCrsrShell::GoPrevCell()
120 {
121     sal_Bool bRet = sal_False;
122     const SwTableNode* pTblNd;
123     if( IsTableMode() || 0 != ( pTblNd = IsCrsrInTbl() ))
124     {
125         SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
126         SwCallLink aLk( *this );        // Crsr-Moves ueberwachen,
127         bRet = pCrsr->GoPrevCell();
128         if( bRet )
129             UpdateCrsr();                 // und den akt. Updaten
130     }
131     return bRet;
132 }
133 
134 const SwFrm* lcl_FindMostUpperCellFrm( const SwFrm* pFrm )
135 {
136     while ( pFrm &&
137             ( !pFrm->IsCellFrm() ||
138               !pFrm->GetUpper()->GetUpper()->IsTabFrm() ||
139                pFrm->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) )
140     {
141         pFrm = pFrm->GetUpper();
142     }
143     return pFrm;
144 }
145 
146 sal_Bool SwCrsrShell::_SelTblRowOrCol( bool bRow, bool bRowSimple )
147 {
148     // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
149     SwFrm *pFrm = GetCurrFrm();
150     if( !pFrm->IsInTab() )
151         return sal_False;
152 
153     const SwTabFrm* pTabFrm = pFrm->FindTabFrm();
154     const SwTabFrm* pMasterTabFrm = pTabFrm->IsFollow() ? pTabFrm->FindMaster( true ) : pTabFrm;
155     const SwTable* pTable = pTabFrm->GetTable();
156 
157     SET_CURR_SHELL( this );
158 
159     const SwTableBox* pStt = 0;
160     const SwTableBox* pEnd = 0;
161 
162     // lasse ueber das Layout die Boxen suchen
163     SwSelBoxes aBoxes;
164     SwTblSearchType eType = bRow ? nsSwTblSearchType::TBLSEARCH_ROW : nsSwTblSearchType::TBLSEARCH_COL;
165     const bool bCheckProtected = !IsReadOnlyAvailable();
166 
167     if( bCheckProtected )
168         eType = (SwTblSearchType)(eType | nsSwTblSearchType::TBLSEARCH_PROTECT);
169 
170     if ( !bRowSimple )
171     {
172         GetTblSel( *this, aBoxes, eType );
173 
174         if( !aBoxes.Count() )
175             return sal_False;
176 
177         pStt = aBoxes[0];
178         pEnd = aBoxes[aBoxes.Count() - 1];
179     }
180     // --> FME 2004-07-30 #i32329# Enhanced table selection
181     else if ( pTable->IsNewModel() )
182     {
183         const SwShellCrsr *pCrsr = _GetCrsr();
184         SwTable::SearchType eSearchType = bRow ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL;
185         pTable->CreateSelection( *pCrsr, aBoxes, eSearchType, bCheckProtected );
186         if( !aBoxes.Count() )
187             return sal_False;
188 
189         pStt = aBoxes[0];
190         pEnd = aBoxes[aBoxes.Count() - 1];
191     }
192     else
193     {
194         const SwShellCrsr *pCrsr = _GetCrsr();
195         const SwFrm* pStartFrm = pFrm;
196         const SwCntntNode *pCNd = pCrsr->GetCntntNode( sal_False );
197         const SwFrm* pEndFrm   = pCNd ? pCNd->getLayoutFrm( GetLayout(), &pCrsr->GetMkPos() ) : 0;
198 
199         if ( bRow )
200         {
201             pStartFrm = lcl_FindMostUpperCellFrm( pStartFrm );
202             pEndFrm   = lcl_FindMostUpperCellFrm( pEndFrm   );
203         }
204 
205         if ( !pStartFrm || !pEndFrm )
206             return sal_False;
207 
208         const bool bVert = pFrm->ImplFindTabFrm()->IsVertical();
209 
210         // If we select upwards it is sufficient to set pStt and pEnd
211         // to the first resp. last box of the selection obtained from
212         // GetTblSel. However, selecting downwards requires the frames
213         // located at the corners of the selection. This does not work
214         // for column selections in vertical tables:
215         const bool bSelectUp = ( bVert && !bRow ) ||
216                                 *pCrsr->GetPoint() <= *pCrsr->GetMark();
217         SwCellFrms aCells;
218         GetTblSel( static_cast<const SwCellFrm*>(pStartFrm),
219                    static_cast<const SwCellFrm*>(pEndFrm),
220                    aBoxes, bSelectUp ? 0 : &aCells, eType );
221 
222         if( !aBoxes.Count() || ( !bSelectUp && 4 != aCells.Count() ) )
223             return sal_False;
224 
225         if ( bSelectUp )
226         {
227             pStt = aBoxes[0];
228             pEnd = aBoxes[aBoxes.Count() - 1];
229         }
230         else
231         {
232             pStt = aCells[ bVert ? (bRow ? 0 : 3) : (bRow ? 2 : 1) ]->GetTabBox();  // will become point of table cursor
233             pEnd = aCells[ bVert ? (bRow ? 3 : 0) : (bRow ? 1 : 2) ]->GetTabBox();  // will become mark of table cursor
234         }
235     }
236     // <--
237 
238     // noch kein Tabellen-Cursor vorhanden, dann erzeuge einen
239     if( !pTblCrsr )
240     {
241         pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
242         pCurCrsr->DeleteMark();
243         pCurCrsr->SwSelPaintRects::Hide();
244     }
245 
246     pTblCrsr->DeleteMark();
247 
248     // dann setze mal Anfang und Ende der Spalte
249     pTblCrsr->GetPoint()->nNode = *pEnd->GetSttNd();
250     pTblCrsr->Move( fnMoveForward, fnGoCntnt );
251     pTblCrsr->SetMark();
252     pTblCrsr->GetPoint()->nNode = *pStt->GetSttNd()->EndOfSectionNode();
253     pTblCrsr->Move( fnMoveBackward, fnGoCntnt );
254 
255     // set PtPos 'close' to the reference table, otherwise we might get problems with the
256     // repeated headlines check in UpdateCrsr():
257     if ( !bRow )
258         pTblCrsr->GetPtPos() = pMasterTabFrm->IsVertical() ? pMasterTabFrm->Frm().TopRight() : pMasterTabFrm->Frm().TopLeft();
259 
260     UpdateCrsr();                 // und den akt. Updaten
261     return sal_True;
262 }
263 
264 sal_Bool SwCrsrShell::SelTbl()
265 {
266     // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
267     SwFrm *pFrm = GetCurrFrm();
268     if( !pFrm->IsInTab() )
269         return sal_False;
270 
271     const SwTabFrm *pTblFrm = pFrm->ImplFindTabFrm();
272     const SwTabFrm* pMasterTabFrm = pTblFrm->IsFollow() ? pTblFrm->FindMaster( true ) : pTblFrm;
273     const SwTableNode* pTblNd = pTblFrm->GetTable()->GetTableNode();
274 
275     SET_CURR_SHELL( this );
276 
277     if( !pTblCrsr )
278     {
279         pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
280         pCurCrsr->DeleteMark();
281         pCurCrsr->SwSelPaintRects::Hide();
282     }
283 
284     pTblCrsr->DeleteMark();
285     pTblCrsr->GetPoint()->nNode = *pTblNd;
286     pTblCrsr->Move( fnMoveForward, fnGoCntnt );
287     pTblCrsr->SetMark();
288     // set MkPos 'close' to the master table, otherwise we might get problems with the
289     // repeated headlines check in UpdateCrsr():
290     pTblCrsr->GetMkPos() = pMasterTabFrm->IsVertical() ? pMasterTabFrm->Frm().TopRight() : pMasterTabFrm->Frm().TopLeft();
291     pTblCrsr->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
292     pTblCrsr->Move( fnMoveBackward, fnGoCntnt );
293     UpdateCrsr();                 // und den akt. Updaten
294     return sal_True;
295 }
296 
297 
298 sal_Bool SwCrsrShell::SelTblBox()
299 {
300     // if we're in a table, create a table cursor, and select the cell
301     // that the current cursor's point resides in
302 
303     // search for start node of our table box. If not found, exit realy
304     const SwStartNode* pStartNode =
305         pCurCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
306 
307 #ifdef DBG_UTIL
308     // the old code checks whether we're in a table by asking the
309     // frame. This should yield the same result as searching for the
310     // table box start node, right?
311     SwFrm *pFrm = GetCurrFrm();
312     DBG_ASSERT( !pFrm->IsInTab() == !(pStartNode != NULL),
313                 "Schroedinger's table: We're in a box, and also we aren't." );
314 #endif
315 
316     if( pStartNode == NULL )
317         return sal_False;
318 
319 
320     SET_CURR_SHELL( this );
321 
322     // create a table cursor, if there isn't one already
323     if( !pTblCrsr )
324     {
325         pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
326         pCurCrsr->DeleteMark();
327         pCurCrsr->SwSelPaintRects::Hide();
328     }
329 
330     // select the complete box with our shiny new pTblCrsr
331     // 1. delete mark, and move point to first content node in box
332     // 2. set mark, and move point to last content node in box
333     // 3. exchange
334 
335     pTblCrsr->DeleteMark();
336     *(pTblCrsr->GetPoint()) = SwPosition( *pStartNode );
337     pTblCrsr->Move( fnMoveForward, fnGoNode );
338 
339     pTblCrsr->SetMark();
340     *(pTblCrsr->GetPoint()) = SwPosition( *(pStartNode->EndOfSectionNode()) );
341     pTblCrsr->Move( fnMoveBackward, fnGoNode );
342 
343     pTblCrsr->Exchange();
344 
345     // with some luck, UpdateCrsr() will now update everything that
346     // needs updateing
347     UpdateCrsr();
348 
349     return sal_True;
350 }
351 
352 // return the next non-protected cell inside a table
353 //      rIdx    - is on a table node
354 //  return:
355 //      true  - Idx points to content in a suitable cell
356 //      false - could not find a suitable cell
357 bool lcl_FindNextCell( SwNodeIndex& rIdx, sal_Bool bInReadOnly )
358 {
359     // ueberpruefe geschuetzte Zellen
360     SwNodeIndex aTmp( rIdx, 2 );            // TableNode + StartNode
361 
362     // the resulting cell should be in that table:
363     const SwTableNode* pTblNd = rIdx.GetNode().GetTableNode();
364 
365     if ( !pTblNd )
366     {
367         ASSERT( false, "lcl_FindNextCell not celled with table start node!" )
368         return false;
369     }
370 
371     const SwNode* pTableEndNode = pTblNd->EndOfSectionNode();
372 
373     SwNodes& rNds = aTmp.GetNode().GetNodes();
374     SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode();
375 
376     // no content node => go to next content node
377     if( !pCNd )
378         pCNd = rNds.GoNext( &aTmp );
379 
380     // robust
381     if ( !pCNd )
382         return false;
383 
384     SwCntntFrm* pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
385 
386     if ( 0 == pFrm || pCNd->FindTableNode() != pTblNd ||
387         (!bInReadOnly && pFrm->IsProtected() ) )
388     {
389         // we are not located inside a 'valid' cell. We have to continue searching...
390 
391         // skip behind current section. This might be the end of the table cell
392         // or behind a inner section or or or...
393         aTmp.Assign( *pCNd->EndOfSectionNode(), 1 );
394 
395         // loop to find a suitable cell...
396         for( ;; )
397         {
398             SwNode* pNd = &aTmp.GetNode();
399 
400             // we break this loop if we reached the end of the table.
401             // to make this code even more robust, we also break if we are
402             // already behind the table end node:
403             if( pNd == pTableEndNode || /*robust: */ pNd->GetIndex() > pTableEndNode->GetIndex() )
404                 return false;
405 
406             // ok, get the next content node:
407             pCNd = aTmp.GetNode().GetCntntNode();
408             if( 0 == pCNd )
409                 pCNd = rNds.GoNext( &aTmp );
410 
411             // robust:
412             if ( !pCNd )
413                 return false;
414 
415             // check if we have found a suitable table cell:
416             pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
417 
418             if ( 0 != pFrm && pCNd->FindTableNode() == pTblNd &&
419                 (bInReadOnly || !pFrm->IsProtected() ) )
420             {
421                 // finally, we have found a suitable table cell => set index and return
422                 rIdx = *pCNd;
423                 return true;
424             }
425 
426             // continue behind the current section:
427             aTmp.Assign( *pCNd->EndOfSectionNode(), +1 );
428         }
429     }
430 
431     rIdx = *pCNd;
432     return true;
433 }
434 
435 // comments see lcl_FindNextCell
436 bool lcl_FindPrevCell( SwNodeIndex& rIdx, sal_Bool bInReadOnly  )
437 {
438     SwNodeIndex aTmp( rIdx, -2 );       // TableNode + EndNode
439 
440     const SwNode* pTableEndNode = &rIdx.GetNode();
441     const SwTableNode* pTblNd = pTableEndNode->StartOfSectionNode()->GetTableNode();
442 
443     if ( !pTblNd )
444     {
445         ASSERT( false, "lcl_FindPrevCell not celled with table start node!" )
446         return false;
447     }
448 
449     SwNodes& rNds = aTmp.GetNode().GetNodes();
450     SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode();
451 
452     if( !pCNd )
453         pCNd = rNds.GoPrevious( &aTmp );
454 
455     if ( !pCNd )
456         return false;
457 
458     SwCntntFrm* pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
459 
460     if( 0 == pFrm || pCNd->FindTableNode() != pTblNd ||
461         (!bInReadOnly && pFrm->IsProtected() ))
462     {
463         // skip before current section
464         aTmp.Assign( *pCNd->StartOfSectionNode(), -1 );
465         for( ;; )
466         {
467             SwNode* pNd = &aTmp.GetNode();
468 
469             if( pNd == pTblNd || pNd->GetIndex() < pTblNd->GetIndex() )
470                 return false;
471 
472             pCNd = aTmp.GetNode().GetCntntNode();
473             if( 0 == pCNd )
474                 pCNd = rNds.GoPrevious( &aTmp );
475 
476             if ( !pCNd )
477                 return false;
478 
479             pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
480 
481             if( 0 != pFrm && pCNd->FindTableNode() == pTblNd &&
482                 (bInReadOnly || !pFrm->IsProtected() ) )
483             {
484                 rIdx = *pCNd;
485                 return true;      // Ok, nicht geschuetzt
486             }
487             aTmp.Assign( *pCNd->StartOfSectionNode(), - 1 );
488         }
489     }
490 
491     rIdx = *pCNd;
492     return true;
493 }
494 
495 
496 sal_Bool GotoPrevTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl,
497                         sal_Bool bInReadOnly )
498 {
499     SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode );
500 
501     SwTableNode* pTblNd = aIdx.GetNode().FindTableNode();
502     if( pTblNd )
503     {
504         // #i26532#: If we are inside a table, we may not go backward
505         // to the table start node, because we would miss any tables
506         // inside this table.
507         SwTableNode* pInnerTblNd = 0;
508         SwNodeIndex aTmpIdx( aIdx );
509         while( aTmpIdx.GetIndex() &&
510                 0 == ( pInnerTblNd = aTmpIdx.GetNode().StartOfSectionNode()->GetTableNode()) )
511             aTmpIdx--;
512 
513         if( pInnerTblNd == pTblNd )
514             aIdx.Assign( *pTblNd, - 1 );
515     }
516 
517     do {
518         while( aIdx.GetIndex() &&
519             0 == ( pTblNd = aIdx.GetNode().StartOfSectionNode()->GetTableNode()) )
520             aIdx--;
521 
522         if( pTblNd )        // gibt einen weiteren TableNode ?
523         {
524             if( fnPosTbl == fnMoveForward )         // an Anfang ?
525             {
526                 aIdx = *aIdx.GetNode().StartOfSectionNode();
527                 if( !lcl_FindNextCell( aIdx, bInReadOnly ))
528                 {
529                     // Tabelle ueberspringen
530                     aIdx.Assign( *pTblNd, -1 );
531                     continue;
532                 }
533             }
534             else
535             {
536                 // ueberpruefe geschuetzte Zellen
537                 if( !lcl_FindNextCell( aIdx, bInReadOnly ))
538                 {
539                     // Tabelle ueberspringen
540                     aIdx.Assign( *pTblNd, -1 );
541                     continue;
542                 }
543             }
544 
545             SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode();
546             if ( pTxtNode )
547             {
548                 rCurCrsr.GetPoint()->nNode = *pTxtNode;
549                 rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ?
550                                                       pTxtNode->Len() :
551                                                       0 );
552             }
553             return sal_True;
554         }
555     } while( pTblNd );
556 
557     return sal_False;
558 }
559 
560 
561 sal_Bool GotoNextTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl,
562                         sal_Bool bInReadOnly )
563 {
564     SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode );
565     SwTableNode* pTblNd = aIdx.GetNode().FindTableNode();
566 
567     if( pTblNd )
568         aIdx.Assign( *pTblNd->EndOfSectionNode(), 1 );
569 
570     sal_uLong nLastNd = rCurCrsr.GetDoc()->GetNodes().Count() - 1;
571     do {
572         while( aIdx.GetIndex() < nLastNd &&
573                 0 == ( pTblNd = aIdx.GetNode().GetTableNode()) )
574             aIdx++;
575         if( pTblNd )        // gibt einen weiteren TableNode ?
576         {
577             if( fnPosTbl == fnMoveForward )         // an Anfang ?
578             {
579                 if( !lcl_FindNextCell( aIdx, bInReadOnly ))
580                 {
581                     // Tabelle ueberspringen
582                     aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 );
583                     continue;
584                 }
585             }
586             else
587             {
588                 aIdx = *aIdx.GetNode().EndOfSectionNode();
589                 // ueberpruefe geschuetzte Zellen
590                 if( !lcl_FindNextCell( aIdx, bInReadOnly ))
591                 {
592                     // Tabelle ueberspringen
593                     aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 );
594                     continue;
595                 }
596             }
597 
598             SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode();
599             if ( pTxtNode )
600             {
601                 rCurCrsr.GetPoint()->nNode = *pTxtNode;
602                 rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ?
603                                                       pTxtNode->Len() :
604                                                       0 );
605             }
606             return sal_True;
607         }
608     } while( pTblNd );
609 
610     return sal_False;
611 }
612 
613 
614 sal_Bool GotoCurrTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl,
615                         sal_Bool bInReadOnly )
616 {
617     SwTableNode* pTblNd = rCurCrsr.GetPoint()->nNode.GetNode().FindTableNode();
618     if( !pTblNd )
619         return sal_False;
620 
621     SwTxtNode* pTxtNode = 0;
622     if( fnPosTbl == fnMoveBackward )    // ans Ende der Tabelle
623     {
624         SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() );
625         if( !lcl_FindPrevCell( aIdx, bInReadOnly ))
626             return sal_False;
627         pTxtNode = aIdx.GetNode().GetTxtNode();
628     }
629     else
630     {
631         SwNodeIndex aIdx( *pTblNd );
632         if( !lcl_FindNextCell( aIdx, bInReadOnly ))
633             return sal_False;
634         pTxtNode = aIdx.GetNode().GetTxtNode();
635     }
636 
637     if ( pTxtNode )
638     {
639         rCurCrsr.GetPoint()->nNode = *pTxtNode;
640         rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ?
641                                                         pTxtNode->Len() :
642                                                         0 );
643     }
644 
645     return sal_True;
646 }
647 
648 
649 sal_Bool SwCursor::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl )
650 {
651     sal_Bool bRet = sal_False;
652     SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this);
653 
654     if( pTblCrsr || !HasMark() )    // nur wenn kein Mark oder ein TblCrsr
655     {
656         SwCrsrSaveState aSaveState( *this );
657         bRet = (*fnWhichTbl)( *this, fnPosTbl, IsReadOnlyAvailable() ) &&
658                 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION |
659                            nsSwCursorSelOverFlags::SELOVER_TOGGLE );
660     }
661     return bRet;
662 }
663 
664 sal_Bool SwCrsrShell::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl )
665 {
666     SwCallLink aLk( *this );        // Crsr-Moves ueberwachen, evt. Link callen
667 
668     SwShellCrsr* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
669     sal_Bool bCheckPos, bRet;
670     sal_uLong nPtNd = 0;
671     xub_StrLen nPtCnt = 0;
672 
673     if( !pTblCrsr && pCurCrsr->HasMark() )      // wenn Mark und kein TblCrsr,
674     {
675         // dann auf jedenfall in den Tabellen-Modus schalten
676         pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
677         pCurCrsr->DeleteMark();
678         pCurCrsr->SwSelPaintRects::Hide();
679         pTblCrsr->SetMark();
680         pCrsr = pTblCrsr;
681         bCheckPos = sal_False;
682     }
683     else
684     {
685         bCheckPos = sal_True;
686         nPtNd = pCrsr->GetPoint()->nNode.GetIndex();
687         nPtCnt = pCrsr->GetPoint()->nContent.GetIndex();
688     }
689 
690     bRet = pCrsr->MoveTable( fnWhichTbl, fnPosTbl );
691 
692     if( bRet )
693     {
694         //JP 28.10.97: Bug 45028 - die "oberste" Position setzen fuer
695         //              wiederholte Kopfzeilen
696         pCrsr->GetPtPos() = Point();
697 
698         UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY);
699 
700         if( bCheckPos &&
701             pCrsr->GetPoint()->nNode.GetIndex() == nPtNd &&
702             pCrsr->GetPoint()->nContent.GetIndex() == nPtCnt )
703             bRet = sal_False;
704     }
705     return bRet;
706 }
707 
708 
709 sal_Bool SwCrsrShell::IsTblComplex() const
710 {
711     SwFrm *pFrm = GetCurrFrm( sal_False );
712     if ( pFrm && pFrm->IsInTab() )
713         return pFrm->FindTabFrm()->GetTable()->IsTblComplex();
714     return sal_False;
715 }
716 
717 
718 sal_Bool SwCrsrShell::IsTblComplexForChart()
719 {
720     sal_Bool bRet = sal_False;
721 
722     StartAction();  // IsTblComplexForChart() may trigger table formatting
723                     // we better do that inside an action
724 
725     const SwTableNode* pTNd = pCurCrsr->GetPoint()->nNode.GetNode().FindTableNode();
726     if( pTNd )
727     {
728         // wir stehen in der Tabelle, dann teste mal, ob die Tabelle oder die
729         // Selektion ausgeglichen ist.
730         String sSel;
731         if( pTblCrsr )
732             sSel = GetBoxNms();
733         bRet = pTNd->GetTable().IsTblComplexForChart( sSel );
734     }
735 
736     EndAction();
737 
738     return bRet;
739 }
740 
741 String SwCrsrShell::GetBoxNms() const
742 {
743     String sNm;
744     const SwPosition* pPos;
745     SwFrm* pFrm;
746 
747     if( IsTableMode() )
748     {
749         SwCntntNode *pCNd = pTblCrsr->Start()->nNode.GetNode().GetCntntNode();
750         pFrm = pCNd ? pCNd->getLayoutFrm( GetLayout() ) : 0;
751         if( !pFrm )
752             return sNm;
753 
754         do {
755             pFrm = pFrm->GetUpper();
756         } while ( pFrm && !pFrm->IsCellFrm() );
757 
758         ASSERT( pFrm, "kein Frame zur Box" );
759         sNm = ((SwCellFrm*)pFrm)->GetTabBox()->GetName();
760         sNm += ':';
761         pPos = pTblCrsr->End();
762     }
763     else
764     {
765         const SwTableNode* pTblNd = IsCrsrInTbl();
766         if( !pTblNd )
767             return sNm;
768         pPos = GetCrsr()->GetPoint();
769     }
770 
771     SwCntntNode* pCNd = pPos->nNode.GetNode().GetCntntNode();
772     pFrm = pCNd ? pCNd->getLayoutFrm( GetLayout() ) : 0;
773 
774     if( pFrm )
775     {
776         do {
777             pFrm = pFrm->GetUpper();
778         } while ( pFrm && !pFrm->IsCellFrm() );
779 
780         if( pFrm )
781             sNm += ((SwCellFrm*)pFrm)->GetTabBox()->GetName();
782     }
783     return sNm;
784 }
785 
786 
787 sal_Bool SwCrsrShell::GotoTable( const String& rName )
788 {
789     SwCallLink aLk( *this );        // Crsr-Moves ueberwachen,
790     sal_Bool bRet = !pTblCrsr && pCurCrsr->GotoTable( rName );
791     if( bRet )
792     {
793         pCurCrsr->GetPtPos() = Point();
794         UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE |
795                     SwCrsrShell::READONLY ); // und den akt. Updaten
796     }
797     return bRet;
798 }
799 
800 
801 sal_Bool SwCrsrShell::CheckTblBoxCntnt( const SwPosition* pPos )
802 {
803     if( !pBoxIdx || !pBoxPtr || IsSelTblCells() || !IsAutoUpdateCells() )
804         return sal_False;
805 
806     // ueberpruefe, ob der Box Inhalt mit dem angegebenen Format der Box
807     // ueber einstimmt. Wenn nicht, setze neu
808     SwTableBox* pChkBox = 0;
809     SwStartNode* pSttNd = 0;
810     if( !pPos )
811     {
812         // gesicherte Position heraus holen.
813         if( pBoxIdx && pBoxPtr &&
814             0 != ( pSttNd = pBoxIdx->GetNode().GetStartNode() ) &&
815             SwTableBoxStartNode == pSttNd->GetStartNodeType() &&
816             pBoxPtr == pSttNd->FindTableNode()->GetTable().
817                         GetTblBox( pBoxIdx->GetIndex() ) )
818             pChkBox = pBoxPtr;
819     }
820     else if( 0 != ( pSttNd = pPos->nNode.GetNode().
821                                 FindSttNodeByType( SwTableBoxStartNode )) )
822     {
823         pChkBox = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() );
824     }
825 
826 
827     // Box mehr als 1 Absatz?
828     if( pChkBox && pSttNd->GetIndex() + 2 != pSttNd->EndOfSectionIndex() )
829         pChkBox = 0;
830 
831     // jetzt sollten wir mal die Pointer zerstoeren, bevor eine erneute
832     // Actionklammerung kommt.
833     if( !pPos && !pChkBox )
834         ClearTblBoxCntnt();
835 
836     // liegt der Cursor nicht mehr in dem Bereich ?
837     if( pChkBox && !pPos &&
838         ( pCurCrsr->HasMark() || pCurCrsr->GetNext() != pCurCrsr ||
839           pSttNd->GetIndex() + 1 == pCurCrsr->GetPoint()->nNode.GetIndex() ))
840         pChkBox = 0;
841 
842     //JP 12.01.99: hat sich der Inhalt der Box ueberhaupt veraendert?
843     // Ist wichtig, wenn z.B. Undo nicht den richtigen Inhalt wieder
844     // herstellen konnte.
845     if( pChkBox )
846     {
847         const SwTxtNode* pNd = GetDoc()->GetNodes()[
848                                     pSttNd->GetIndex() + 1 ]->GetTxtNode();
849         if( !pNd ||
850             ( pNd->GetTxt() == ViewShell::GetShellRes()->aCalc_Error &&
851               SFX_ITEM_SET == pChkBox->GetFrmFmt()->
852                             GetItemState( RES_BOXATR_FORMULA )) )
853             pChkBox = 0;
854     }
855 
856     if( pChkBox )
857     {
858         // jetzt sollten wir mal die Pointer zerstoeren, bevor ein weiterer
859         // aufruf kommt.
860         ClearTblBoxCntnt();
861         StartAction();
862         GetDoc()->ChkBoxNumFmt( *pChkBox, sal_True );
863         EndAction();
864     }
865 
866     return 0 != pChkBox;
867 }
868 
869 
870 void SwCrsrShell::SaveTblBoxCntnt( const SwPosition* pPos )
871 {
872     if( IsSelTblCells() || !IsAutoUpdateCells() )
873         return ;
874 
875     if( !pPos )
876         pPos = pCurCrsr->GetPoint();
877 
878     SwStartNode* pSttNd = pPos->nNode.GetNode().FindSttNodeByType( SwTableBoxStartNode );
879 
880     sal_Bool bCheckBox = sal_False;
881     if( pSttNd && pBoxIdx )
882     {
883         if( pSttNd == &pBoxIdx->GetNode() )
884             pSttNd = 0;     // die haben wir schon
885         else
886             bCheckBox = sal_True;
887     }
888     else
889         bCheckBox = 0 != pBoxIdx;
890 
891     if( bCheckBox )
892     {
893         // pBoxIdx Checken
894         SwPosition aPos( *pBoxIdx );
895         CheckTblBoxCntnt( &aPos );
896     }
897 
898     if( pSttNd )
899     {
900         pBoxPtr = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() );
901 
902         if( pBoxIdx )
903             *pBoxIdx = *pSttNd;
904         else
905             pBoxIdx = new SwNodeIndex( *pSttNd );
906     }
907 }
908 
909 
910 void SwCrsrShell::ClearTblBoxCntnt()
911 {
912     delete pBoxIdx, pBoxIdx = 0;
913     pBoxPtr = 0;
914 }
915 
916 sal_Bool SwCrsrShell::EndAllTblBoxEdit()
917 {
918     sal_Bool bRet = sal_False;
919     ViewShell *pSh = this;
920     do {
921         if( pSh->IsA( TYPE( SwCrsrShell ) ) )
922             bRet |= ((SwCrsrShell*)pSh)->CheckTblBoxCntnt(
923                         ((SwCrsrShell*)pSh)->pCurCrsr->GetPoint() );
924 
925     } while( this != (pSh = (ViewShell *)pSh->GetNext()) );
926     return bRet;
927 }
928 
929 
930 
931 
932