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