xref: /trunk/main/sw/source/core/crsr/trvltbl.cxx (revision cdf0e10c)
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