xref: /aoo42x/main/sw/source/core/frmedt/fetab.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 
27 
28 #include <hintids.hxx>
29 
30 #include <tools/errinf.hxx>
31 #include <vcl/svapp.hxx>
32 #include <basegfx/vector/b2dvector.hxx>
33 #ifndef _SVX_SVXIDS_HRC
34 #include <svx/svxids.hrc>
35 #endif
36 #include <editeng/protitem.hxx>
37 #include <editeng/brshitem.hxx>
38 #include <editeng/frmdiritem.hxx>
39 #include <svtools/ruler.hxx>
40 #include <swwait.hxx>
41 #include <fmtfsize.hxx>
42 #include <fmtornt.hxx>
43 #include <frmatr.hxx>
44 #include <docary.hxx>
45 #include <fesh.hxx>
46 #include <doc.hxx>
47 #include <cntfrm.hxx>
48 #include <rootfrm.hxx>
49 #include <pagefrm.hxx>
50 #include <tabfrm.hxx>
51 #include <rowfrm.hxx>
52 #include <cellfrm.hxx>
53 #include <flyfrm.hxx>
54 #include <dflyobj.hxx>
55 #include <swtable.hxx>
56 #include <swddetbl.hxx>
57 #include <ndtxt.hxx>
58 #include <calc.hxx>
59 #include <tabcol.hxx>
60 #include <cellatr.hxx>
61 #include <pam.hxx>
62 #include <viscrs.hxx>
63 #include <tblsel.hxx>
64 #include <swtblfmt.hxx>
65 #include <swerror.h>
66 #include <swundo.hxx>
67 #include <frmtool.hxx>
68 
69 #include <node.hxx> // #i23726#
70 // OD 2004-05-24 #i28701#
71 #include <sortedobjs.hxx>
72 
73 using namespace ::com::sun::star;
74 
75 
76 //siehe auch swtable.cxx
77 #define COLFUZZY 20L
78 
79 inline sal_Bool IsSame( long nA, long nB ) { return  Abs(nA-nB) <= COLFUZZY; }
80 inline sal_Bool IsNear( long nA, long nB, long nTolerance ) { return Abs( nA - nB ) <= nTolerance; }
81 
82 // table column cache
83 SwTabCols *pLastCols   = 0;
84 const SwTable   *pColumnCacheLastTable  = 0;
85 const SwTabFrm  *pColumnCacheLastTabFrm = 0;
86 const SwFrm     *pColumnCacheLastCellFrm = 0;
87 
88 // table row cache
89 SwTabCols *pLastRows   = 0;
90 const SwTable   *pRowCacheLastTable  = 0;
91 const SwTabFrm  *pRowCacheLastTabFrm = 0;
92 const SwFrm     *pRowCacheLastCellFrm = 0;
93 
94 
95 class TblWait
96 {
97 	SwWait *pWait;
98 public:
99 	TblWait( sal_uInt16 nCnt, SwFrm *pFrm, SwDocShell &rDocShell, sal_uInt16 nCnt2 = 0);
100 	~TblWait() { delete pWait; }
101 };
102 
103 TblWait::TblWait( sal_uInt16 nCnt, SwFrm *pFrm, SwDocShell &rDocShell, sal_uInt16 nCnt2):
104 	pWait( 0 )
105 {
106 	sal_Bool bWait = 20 < nCnt || 20 < nCnt2 || (pFrm &&
107 				 20 < pFrm->ImplFindTabFrm()->GetTable()->GetTabLines().Count());
108 	if( bWait )
109 		pWait = new SwWait( rDocShell, sal_True );
110 }
111 
112 
113 void SwFEShell::ParkCursorInTab()
114 {
115     SwCursor * pSwCrsr = GetSwCrsr();
116 
117     ASSERT(pSwCrsr, "no SwCursor");
118 
119     SwPosition aStartPos = *pSwCrsr->GetPoint(), aEndPos = aStartPos;
120 
121     SwCursor * pTmpCrsr = (SwCursor *) pSwCrsr;
122 
123     /* Search least and greatest position in current cursor ring.
124      */
125     do
126     {
127         const SwPosition * pPt = pTmpCrsr->GetPoint(),
128             * pMk = pTmpCrsr->GetMark();
129 
130         if (*pPt < aStartPos)
131             aStartPos = *pPt;
132 
133         if (*pPt > aEndPos)
134             aEndPos = *pPt;
135 
136         if (*pMk < aStartPos)
137             aStartPos = *pMk;
138 
139         if (*pMk > aEndPos)
140             aEndPos = *pMk;
141 
142         pTmpCrsr = (SwCursor *) pTmpCrsr->GetNext();
143     }
144     while (pTmpCrsr != pSwCrsr);
145 
146     KillPams();
147 
148 	/* @@@ semantic: SwCursor::operator=() is not implemented @@@ */
149 
150     /* Set cursor to end of selection to ensure IsLastCellInRow works
151        properly. */
152     {
153         SwCursor aTmpCrsr( aEndPos, 0, false );
154         *pSwCrsr = aTmpCrsr;
155     }
156 
157     /* Move the cursor out of the columns to delete and stay in the
158        same row. If the table has only one column the cursor will
159        stay in the row and the shell will take care of it. */
160     if (IsLastCellInRow())
161     {
162         /* If the cursor is in the last row of the table, first
163            try to move it to the previous cell. If that fails move
164            it to the next cell. */
165 
166         {
167             SwCursor aTmpCrsr( aStartPos, 0, false );
168             *pSwCrsr = aTmpCrsr;
169         }
170 
171         if (! pSwCrsr->GoPrevCell())
172         {
173             SwCursor aTmpCrsr( aEndPos, 0, false );
174             *pSwCrsr = aTmpCrsr;
175             pSwCrsr->GoNextCell();
176         }
177     }
178     else
179     {
180         /* If the cursor is not in the last row of the table, first
181            try to move it to the next cell. If that fails move it
182            to the previous cell. */
183 
184         {
185             SwCursor aTmpCrsr( aEndPos, 0, false );
186             *pSwCrsr = aTmpCrsr;
187         }
188 
189         if (! pSwCrsr->GoNextCell())
190         {
191             SwCursor aTmpCrsr( aStartPos, 0, false );
192             *pSwCrsr = aTmpCrsr;
193             pSwCrsr->GoPrevCell();
194         }
195     }
196 }
197 
198 /***********************************************************************
199 #*	Class	   :  SwFEShell
200 #*	Methoden   :  InsertRow(), InsertCol
201 #*	Datum	   :  MA 03. May. 93
202 #*	Update	   :  MA 19. Apr. 95
203 #***********************************************************************/
204 sal_Bool SwFEShell::InsertRow( sal_uInt16 nCnt, sal_Bool bBehind )
205 {
206 	// pruefe ob vom aktuellen Crsr der Point/Mark in einer Tabelle stehen
207 	SwFrm *pFrm = GetCurrFrm();
208 	if( !pFrm || !pFrm->IsInTab() )
209 		return sal_False;
210 
211 	if( pFrm->ImplFindTabFrm()->GetTable()->ISA( SwDDETable ))
212 	{
213 		ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
214 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
215 		return sal_False;
216 	}
217 
218 	SET_CURR_SHELL( this );
219 	StartAllAction();
220 
221 	// lasse ueber das Layout die Boxen suchen
222 	SwSelBoxes aBoxes;
223 	GetTblSel( *this, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
224 
225 	TblWait( nCnt, pFrm, *GetDoc()->GetDocShell(), aBoxes.Count() );
226 
227 	sal_Bool bRet = sal_False;
228 	if ( aBoxes.Count() )
229 		bRet = GetDoc()->InsertRow( aBoxes, nCnt, bBehind );
230 
231 	EndAllActionAndCall();
232 	return bRet;
233 }
234 
235 sal_Bool SwFEShell::InsertCol( sal_uInt16 nCnt, sal_Bool bBehind )
236 {
237 	// pruefe ob vom aktuellen Crsr der Point/Mark in einer Tabelle stehen
238 	SwFrm *pFrm = GetCurrFrm();
239 	if( !pFrm || !pFrm->IsInTab() )
240 		return sal_False;
241 
242 	if( pFrm->ImplFindTabFrm()->GetTable()->ISA( SwDDETable ))
243 	{
244 		ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
245 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
246 		return sal_False;
247 	}
248 
249 	SET_CURR_SHELL( this );
250 
251 	if( !CheckSplitCells( *this, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) )
252 	{
253 		ErrorHandler::HandleError( ERR_TBLINSCOL_ERROR,
254 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
255 		return sal_False;
256 	}
257 
258 	StartAllAction();
259 	// lasse ueber das Layout die Boxen suchen
260 	SwSelBoxes aBoxes;
261 	GetTblSel( *this, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
262 
263 	TblWait( nCnt, pFrm, *GetDoc()->GetDocShell(), aBoxes.Count() );
264 
265 	sal_Bool bRet = sal_False;
266 	if( aBoxes.Count() )
267 		bRet = GetDoc()->InsertCol( aBoxes, nCnt, bBehind );
268 
269 	EndAllActionAndCall();
270 	return bRet;
271 }
272 
273 /***********************************************************************
274 #*	Class	   :  SwFEShell
275 #*	Methoden   :  DeleteRow(), DeleteCol()
276 #*	Datum	   :  MA 03. May. 93
277 #*	Update	   :  MA 19. Apr. 95
278 #***********************************************************************/
279 
280 /**
281    Determines if the current cursor is in the last row of the table.
282 */
283 sal_Bool SwFEShell::IsLastCellInRow() const
284 {
285     SwTabCols aTabCols;
286     GetTabCols( aTabCols );
287     sal_Bool bResult = sal_False;
288 
289     if (IsTableRightToLeft())
290         /* If the table is right-to-left the last row is the most left one. */
291         bResult = 0 == GetCurTabColNum();
292     else
293         /* If the table is left-to-right the last row is the most right one. */
294         bResult = aTabCols.Count() == GetCurTabColNum();
295 
296     return bResult;
297 }
298 
299 sal_Bool SwFEShell::DeleteCol()
300 {
301 	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
302 	SwFrm *pFrm = GetCurrFrm();
303 	if( !pFrm || !pFrm->IsInTab() )
304 		return sal_False;
305 
306 	if( pFrm->ImplFindTabFrm()->GetTable()->ISA( SwDDETable ))
307 	{
308 		ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
309 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
310 		return sal_False;
311 	}
312 
313 	SET_CURR_SHELL( this );
314 	StartAllAction();
315 
316 	// lasse ueber das Layout die Boxen suchen
317 	sal_Bool bRet;
318 	SwSelBoxes aBoxes;
319 	GetTblSel( *this, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
320 	if ( aBoxes.Count() )
321 	{
322 		TblWait( aBoxes.Count(), pFrm, *GetDoc()->GetDocShell() );
323 
324 		// die Crsr muessen noch aus dem Loesch Bereich entfernt
325 		// werden. Setze sie immer hinter/auf die Tabelle; ueber die
326 		// Dokument-Position werden sie dann immer an die alte Position gesetzt.
327 		while( !pFrm->IsCellFrm() )
328 			pFrm = pFrm->GetUpper();
329 
330         ParkCursorInTab();
331 
332 		// dann loesche doch die Spalten
333         StartUndo(UNDO_COL_DELETE);
334 		bRet = GetDoc()->DeleteRowCol( aBoxes, true );
335         EndUndo(UNDO_COL_DELETE);
336 
337 	}
338 	else
339 		bRet = sal_False;
340 
341 	EndAllActionAndCall();
342 	return bRet;
343 }
344 
345 sal_Bool SwFEShell::DeleteRow()
346 {
347 	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
348 	SwFrm *pFrm = GetCurrFrm();
349 	if( !pFrm || !pFrm->IsInTab() )
350 		return sal_False;
351 
352 	if( pFrm->ImplFindTabFrm()->GetTable()->ISA( SwDDETable ))
353 	{
354 		ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
355 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
356 		return sal_False;
357 	}
358 
359 	SET_CURR_SHELL( this );
360 	StartAllAction();
361 
362 	// lasse ueber das Layout die Boxen suchen
363 	sal_Bool bRet;
364 	SwSelBoxes aBoxes;
365 	GetTblSel( *this, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
366 
367 	if( aBoxes.Count() )
368 	{
369 		TblWait( aBoxes.Count(), pFrm, *GetDoc()->GetDocShell() );
370 
371 		// die Crsr aus dem Loeschbereich entfernen.
372 		// Der Cursor steht danach:
373 		//	- es folgt noch eine Zeile, in dieser
374 		//	- vorher steht noch eine Zeile, in dieser
375 		//	- sonst immer dahinter
376 		{
377 			SwTableNode* pTblNd = ((SwCntntFrm*)pFrm)->GetNode()->FindTableNode();
378 
379 			// suche alle Boxen / Lines
380 			_FndBox aFndBox( 0, 0 );
381 			{
382 				_FndPara aPara( aBoxes, &aFndBox );
383 				pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
384 			}
385 
386 			if( !aFndBox.GetLines().Count() )
387 			{
388 				EndAllActionAndCall();
389 				return sal_False;
390 			}
391 
392 			KillPams();
393 
394 			_FndBox* pFndBox = &aFndBox;
395 			while( 1 == pFndBox->GetLines().Count() &&
396 					1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
397 			{
398 				_FndBox* pTmp = pFndBox->GetLines()[0]->GetBoxes()[0];
399 				if( pTmp->GetBox()->GetSttNd() )
400 					break;		// das ist sonst zu weit
401 				pFndBox = pTmp;
402 			}
403 
404 			SwTableLine* pDelLine = pFndBox->GetLines()[
405 							pFndBox->GetLines().Count()-1 ]->GetLine();
406 			SwTableBox* pDelBox = pDelLine->GetTabBoxes()[
407 								pDelLine->GetTabBoxes().Count() - 1 ];
408 			while( !pDelBox->GetSttNd() )
409 			{
410 				SwTableLine* pLn = pDelBox->GetTabLines()[
411 							pDelBox->GetTabLines().Count()-1 ];
412 				pDelBox = pLn->GetTabBoxes()[ pLn->GetTabBoxes().Count() - 1 ];
413 			}
414 			SwTableBox* pNextBox = pDelLine->FindNextBox( pTblNd->GetTable(),
415 															pDelBox, sal_True );
416 			while( pNextBox &&
417 					pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
418 				pNextBox = pNextBox->FindNextBox( pTblNd->GetTable(), pNextBox );
419 
420 			if( !pNextBox )			// keine nachfolgende? dann die vorhergehende
421 			{
422 				pDelLine = pFndBox->GetLines()[ 0 ]->GetLine();
423 				pDelBox = pDelLine->GetTabBoxes()[ 0 ];
424 				while( !pDelBox->GetSttNd() )
425 					pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
426 				pNextBox = pDelLine->FindPreviousBox( pTblNd->GetTable(),
427 															pDelBox, sal_True );
428 				while( pNextBox &&
429 						pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
430 					pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox );
431 			}
432 
433 			sal_uLong nIdx;
434 			if( pNextBox )		// dann den Cursor hier hinein
435 				nIdx = pNextBox->GetSttIdx() + 1;
436 			else				// ansonsten hinter die Tabelle
437 				nIdx = pTblNd->EndOfSectionIndex() + 1;
438 
439 			SwNodeIndex aIdx( GetDoc()->GetNodes(), nIdx );
440 			SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
441 			if( !pCNd )
442 				pCNd = GetDoc()->GetNodes().GoNext( &aIdx );
443 
444 			if( pCNd )
445 			{
446 				SwPaM* pPam = GetCrsr();
447 				pPam->GetPoint()->nNode = aIdx;
448 				pPam->GetPoint()->nContent.Assign( pCNd, 0 );
449 				pPam->SetMark();			// beide wollen etwas davon haben
450 				pPam->DeleteMark();
451 			}
452 		}
453 
454 		// dann loesche doch die Zeilen
455         StartUndo(UNDO_ROW_DELETE);
456 		bRet = GetDoc()->DeleteRowCol( aBoxes );
457         EndUndo(UNDO_ROW_DELETE);
458 	}
459 	else
460 		bRet = sal_False;
461 
462 	EndAllActionAndCall();
463 	return bRet;
464 }
465 
466 /***********************************************************************
467 #*	Class	   :  SwFEShell
468 #*	Methoden   :  MergeTab(), SplitTab()
469 #*	Datum	   :  MA 03. May. 93
470 #*	Update	   :  MA 19. Apr. 95
471 #***********************************************************************/
472 
473 sal_uInt16 SwFEShell::MergeTab()
474 {
475 	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
476 	sal_uInt16 nRet = TBLMERGE_NOSELECTION;
477 	if( IsTableMode() )
478 	{
479         SwShellTableCrsr* pTableCrsr = GetTableCrsr();
480         const SwTableNode* pTblNd = pTableCrsr->GetNode()->FindTableNode();
481 		if( pTblNd->GetTable().ISA( SwDDETable ))
482 		{
483 			ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
484 							ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
485 		}
486 		else
487 		{
488 			SET_CURR_SHELL( this );
489 			StartAllAction();
490 
491             TblWait( pTableCrsr->GetBoxesCount(), 0, *GetDoc()->GetDocShell(),
492 					 pTblNd->GetTable().GetTabLines().Count() );
493 
494             nRet = GetDoc()->MergeTbl( *pTableCrsr );
495 
496 			KillPams();
497 
498 			EndAllActionAndCall();
499 		}
500 	}
501 	return nRet;
502 }
503 
504 sal_Bool SwFEShell::SplitTab( sal_Bool bVert, sal_uInt16 nCnt, sal_Bool bSameHeight )
505 {
506 	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
507 	SwFrm *pFrm = GetCurrFrm();
508 	if( !pFrm || !pFrm->IsInTab() )
509 		return sal_False;
510 
511 	if( pFrm->ImplFindTabFrm()->GetTable()->ISA( SwDDETable ))
512 	{
513 		ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
514 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
515 		return sal_False;
516 	}
517 
518 	SET_CURR_SHELL( this );
519 
520 	if( bVert && !CheckSplitCells( *this, nCnt + 1 ) )
521 	{
522 		ErrorHandler::HandleError( ERR_TBLSPLIT_ERROR,
523 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
524 		return sal_False;
525 	}
526 	StartAllAction();
527 	// lasse ueber das Layout die Boxen suchen
528 	sal_Bool bRet;
529 	SwSelBoxes aBoxes;
530 	GetTblSel( *this, aBoxes );
531 	if( aBoxes.Count() )
532 	{
533 		TblWait( nCnt, pFrm, *GetDoc()->GetDocShell(), aBoxes.Count() );
534 
535 		// dann loesche doch die Spalten
536         bRet = GetDoc()->SplitTbl( aBoxes, bVert, nCnt, bSameHeight );
537 
538 		DELETEZ( pLastCols );
539         DELETEZ( pLastRows );
540 	}
541 	else
542 		bRet = sal_False;
543 	EndAllActionAndCall();
544 	return bRet;
545 }
546 
547 
548 /***********************************************************************
549 #*	Class	   :  SwFEShell
550 #*	Methoden   :  _GetTabCols
551 #*	Datum	   :  MA 30. Nov. 95
552 #*	Update	   :  MA 08. Jan. 97
553 #***********************************************************************/
554 void SwFEShell::_GetTabCols( SwTabCols &rToFill, const SwFrm *pBox ) const
555 {
556 	const SwTabFrm *pTab = pBox->FindTabFrm();
557 	if ( pLastCols )
558 	{
559 		//Paar Kleinigkeiten muessen wir schon noch sicherstellen
560 		sal_Bool bDel = sal_True;
561         if ( pColumnCacheLastTable == pTab->GetTable() )
562 		{
563 			bDel = sal_False;
564             SWRECTFN( pTab )
565 
566             const SwPageFrm* pPage = pTab->FindPageFrm();
567             const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
568                                    (pPage->Frm().*fnRect->fnGetLeft)();
569             const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
570                                     (pPage->Frm().*fnRect->fnGetLeft)();
571 
572             if ( pColumnCacheLastTabFrm != pTab )
573 			{
574 				//Wenn der TabFrm gewechselt hat, brauchen wir bei gleicher
575 				//Breite nur ein wenig shiften.
576                 SWRECTFNX( pColumnCacheLastTabFrm )
577                 if( (pColumnCacheLastTabFrm->Frm().*fnRectX->fnGetWidth)() ==
578                     (pTab->Frm().*fnRect->fnGetWidth)() )
579 				{
580                     pLastCols->SetLeftMin( nLeftMin );
581 
582                     //ASSERT( bVert ||
583                     //        pLastCols->GetLeftMin() == (pTab->Frm().*fnRect->fnGetLeft)(),
584                     //        "GetTabCols: wrong result" )
585 
586                     pColumnCacheLastTabFrm = pTab;
587 				}
588 				else
589 					bDel = sal_True;
590 			}
591 
592 			if ( !bDel &&
593                  pLastCols->GetLeftMin () == (sal_uInt16)nLeftMin &&
594                  pLastCols->GetLeft    () == (sal_uInt16)(pTab->Prt().*fnRect->fnGetLeft)() &&
595                  pLastCols->GetRight   () == (sal_uInt16)(pTab->Prt().*fnRect->fnGetRight)()&&
596                  pLastCols->GetRightMax() == (sal_uInt16)nRightMax - pLastCols->GetLeftMin() )
597 			{
598                 if ( pColumnCacheLastCellFrm != pBox )
599 				{
600 					pTab->GetTable()->GetTabCols( *pLastCols,
601 										((SwCellFrm*)pBox)->GetTabBox(), sal_True);
602                     pColumnCacheLastCellFrm = pBox;
603 				}
604 				rToFill = *pLastCols;
605 			}
606 			else
607 				bDel = sal_True;
608 		}
609 		if ( bDel )
610 			DELETEZ(pLastCols);
611 	}
612 	if ( !pLastCols )
613 	{
614 		GetDoc()->GetTabCols( rToFill, 0, (SwCellFrm*)pBox );
615 
616 		pLastCols   = new SwTabCols( rToFill );
617         pColumnCacheLastTable  = pTab->GetTable();
618         pColumnCacheLastTabFrm = pTab;
619         pColumnCacheLastCellFrm= pBox;
620 	}
621 
622 #if OSL_DEBUG_LEVEL > 1
623     SwTabColsEntry aEntry;
624     for ( sal_uInt16 i = 0; i < rToFill.Count(); ++i )
625     {
626         aEntry = rToFill.GetEntry( i );
627         (void)aEntry;
628     }
629 #endif
630 }
631 
632 /***********************************************************************
633 #*	Class	   :  SwFEShell
634 #*	Methoden   :  _GetTabRows
635 #*	Datum	   :  FME 2004-01-14
636 #*	Update	   :
637 #***********************************************************************/
638 void SwFEShell::_GetTabRows( SwTabCols &rToFill, const SwFrm *pBox ) const
639 {
640 	const SwTabFrm *pTab = pBox->FindTabFrm();
641 	if ( pLastRows )
642 	{
643 		//Paar Kleinigkeiten muessen wir schon noch sicherstellen
644 		sal_Bool bDel = sal_True;
645         if ( pRowCacheLastTable == pTab->GetTable() )
646 		{
647 			bDel = sal_False;
648             SWRECTFN( pTab )
649             const SwPageFrm* pPage = pTab->FindPageFrm();
650             const long nLeftMin  = ( bVert ?
651                                      pTab->GetPrtLeft() - pPage->Frm().Left() :
652                                      pTab->GetPrtTop() - pPage->Frm().Top() );
653             const long nLeft     = bVert ? LONG_MAX : 0;
654             const long nRight    = (pTab->Prt().*fnRect->fnGetHeight)();
655             const long nRightMax = bVert ? nRight : LONG_MAX;
656 
657             if ( pRowCacheLastTabFrm != pTab ||
658                  pRowCacheLastCellFrm != pBox )
659                 bDel = sal_True;
660 
661             if ( !bDel &&
662                  pLastRows->GetLeftMin () == nLeftMin &&
663                  pLastRows->GetLeft    () == nLeft &&
664                  pLastRows->GetRight   () == nRight &&
665                  pLastRows->GetRightMax() == nRightMax )
666             {
667                 rToFill = *pLastRows;
668             }
669             else
670                 bDel = sal_True;
671         }
672 		if ( bDel )
673 			DELETEZ(pLastRows);
674 	}
675 	if ( !pLastRows )
676 	{
677         GetDoc()->GetTabRows( rToFill, 0, (SwCellFrm*)pBox );
678 
679         pLastRows   = new SwTabCols( rToFill );
680         pRowCacheLastTable  = pTab->GetTable();
681         pRowCacheLastTabFrm = pTab;
682         pRowCacheLastCellFrm= pBox;
683 	}
684 }
685 
686 /***********************************************************************
687 #*	Class	   :  SwFEShell
688 #*	Methoden   :  SetTabCols(), GetTabCols()
689 #*	Datum	   :  MA 03. May. 93
690 #*	Update	   :  MA 18. May. 93
691 #***********************************************************************/
692 void SwFEShell::SetTabCols( const SwTabCols &rNew, sal_Bool bCurRowOnly )
693 {
694 	SwFrm *pBox = GetCurrFrm();
695 	if( !pBox || !pBox->IsInTab() )
696 		return;
697 
698 	SET_CURR_SHELL( this );
699 	StartAllAction();
700 
701 	do {
702 		pBox = pBox->GetUpper();
703 	} while ( !pBox->IsCellFrm() );
704 
705 	GetDoc()->SetTabCols( rNew, bCurRowOnly, 0, (SwCellFrm*)pBox );
706 	EndAllActionAndCall();
707 }
708 
709 void SwFEShell::GetTabCols( SwTabCols &rToFill ) const
710 {
711 	const SwFrm *pFrm = GetCurrFrm();
712 	if( !pFrm || !pFrm->IsInTab() )
713 		return;
714 	do
715 	{	pFrm = pFrm->GetUpper();
716 	} while ( !pFrm->IsCellFrm() );
717 
718 	_GetTabCols( rToFill, pFrm );
719 }
720 
721 /*-- 19.01.2004 08:56:42---------------------------------------------------
722 
723   -----------------------------------------------------------------------*/
724 void SwFEShell::GetTabRows( SwTabCols &rToFill ) const
725 {
726 	const SwFrm *pFrm = GetCurrFrm();
727 	if( !pFrm || !pFrm->IsInTab() )
728 		return;
729 	do
730 	{	pFrm = pFrm->GetUpper();
731 	} while ( !pFrm->IsCellFrm() );
732 
733 	_GetTabRows( rToFill, pFrm );
734 }
735 /*-- 19.01.2004 08:56:44---------------------------------------------------
736 
737   -----------------------------------------------------------------------*/
738 void SwFEShell::SetTabRows( const SwTabCols &rNew, sal_Bool bCurColOnly )
739 {
740 	SwFrm *pBox = GetCurrFrm();
741 	if( !pBox || !pBox->IsInTab() )
742 		return;
743 
744 	SET_CURR_SHELL( this );
745 	StartAllAction();
746 
747 	do {
748 		pBox = pBox->GetUpper();
749 	} while ( !pBox->IsCellFrm() );
750 
751     GetDoc()->SetTabRows( rNew, bCurColOnly, 0, (SwCellFrm*)pBox );
752 	EndAllActionAndCall();
753 }
754 /*-- 19.01.2004 08:59:45---------------------------------------------------
755 
756   -----------------------------------------------------------------------*/
757 void SwFEShell::GetMouseTabRows( SwTabCols &rToFill, const Point &rPt ) const
758 {
759     const SwFrm *pBox = GetBox( rPt );
760 	if ( pBox )
761 		_GetTabRows( rToFill, pBox );
762 }
763 /*-- 19.01.2004 08:59:45---------------------------------------------------
764 
765   -----------------------------------------------------------------------*/
766 void SwFEShell::SetMouseTabRows( const SwTabCols &rNew, sal_Bool bCurColOnly, const Point &rPt )
767 {
768 	const SwFrm *pBox = GetBox( rPt );
769 	if( pBox )
770 	{
771 		SET_CURR_SHELL( this );
772 		StartAllAction();
773         GetDoc()->SetTabRows( rNew, bCurColOnly, 0, (SwCellFrm*)pBox );
774 		EndAllActionAndCall();
775 	}
776 }
777 
778 /***********************************************************************
779  *  Class      :  SwFEShell
780  *  Methoden   :  SetRowSplit(), GetRowSplit()
781  *  Datum      :  FME 13.11.2003
782  ***********************************************************************/
783 
784 void SwFEShell::SetRowSplit( const SwFmtRowSplit& rNew )
785 {
786     SET_CURR_SHELL( this );
787     StartAllAction();
788     GetDoc()->SetRowSplit( *getShellCrsr( false ), rNew );
789     EndAllActionAndCall();
790 }
791 
792 void SwFEShell::GetRowSplit( SwFmtRowSplit*& rpSz ) const
793 {
794     GetDoc()->GetRowSplit( *getShellCrsr( false ), rpSz );
795 }
796 
797 
798 /***********************************************************************
799 #*	Class	   :  SwFEShell
800 #*	Methoden   :  SetRowHeight(), GetRowHeight()
801 #*	Datum	   :  MA 17. May. 93
802 #*	Update	   :  JP 29.04.98
803 #***********************************************************************/
804 
805 void SwFEShell::SetRowHeight( const SwFmtFrmSize &rNew )
806 {
807 	SET_CURR_SHELL( this );
808 	StartAllAction();
809     GetDoc()->SetRowHeight( *getShellCrsr( false ), rNew );
810 	EndAllActionAndCall();
811 }
812 
813 /******************************************************************************
814  *				 SwTwips SwFEShell::GetRowHeight() const
815  ******************************************************************************/
816 void SwFEShell::GetRowHeight( SwFmtFrmSize *& rpSz ) const
817 {
818     GetDoc()->GetRowHeight( *getShellCrsr( false ), rpSz );
819 }
820 
821 sal_Bool SwFEShell::BalanceRowHeight( sal_Bool bTstOnly )
822 {
823 	SET_CURR_SHELL( this );
824 	if( !bTstOnly )
825 		StartAllAction();
826     sal_Bool bRet = GetDoc()->BalanceRowHeight( *getShellCrsr( false ), bTstOnly );
827 	if( !bTstOnly )
828 		EndAllActionAndCall();
829 	return bRet;
830 }
831 
832 /******************************************************************************
833  *				void SwFEShell::SetRowBackground()
834  ******************************************************************************/
835 void SwFEShell::SetRowBackground( const SvxBrushItem &rNew )
836 {
837 	SET_CURR_SHELL( this );
838 	StartAllAction();
839     GetDoc()->SetRowBackground( *getShellCrsr( false ), rNew );
840 	EndAllActionAndCall();
841 }
842 
843 /******************************************************************************
844  *				 SwTwips SwFEShell::GetRowBackground() const
845  ******************************************************************************/
846 sal_Bool SwFEShell::GetRowBackground( SvxBrushItem &rToFill ) const
847 {
848     return GetDoc()->GetRowBackground( *getShellCrsr( false ), rToFill );
849 }
850 
851 /***********************************************************************
852 #*	Class	   :  SwFEShell
853 #*	Methoden   :  SetTabBorders(), GetTabBorders()
854 #*	Datum	   :  MA 18. May. 93
855 #*	Update	   :  JP 29.04.98
856 #***********************************************************************/
857 
858 void SwFEShell::SetTabBorders( const SfxItemSet& rSet )
859 {
860 	SET_CURR_SHELL( this );
861 	StartAllAction();
862     GetDoc()->SetTabBorders( *getShellCrsr( false ), rSet );
863 	EndAllActionAndCall();
864 }
865 
866 void SwFEShell::SetTabLineStyle( const Color* pColor, sal_Bool bSetLine,
867 								 const SvxBorderLine* pBorderLine )
868 {
869 	SET_CURR_SHELL( this );
870 	StartAllAction();
871     GetDoc()->SetTabLineStyle( *getShellCrsr( false ),
872 								pColor, bSetLine, pBorderLine );
873 	EndAllActionAndCall();
874 }
875 
876 void SwFEShell::GetTabBorders( SfxItemSet& rSet ) const
877 {
878     GetDoc()->GetTabBorders( *getShellCrsr( false ), rSet );
879 }
880 
881 
882 /***********************************************************************
883 #*	Class	   :  SwFEShell
884 #*	Methoden   :  SetBoxBackground(), GetBoxBackground()
885 #*	Datum	   :  MA 01. Jun. 93
886 #*	Update	   :  MA 03. Jul. 96
887 #***********************************************************************/
888 void SwFEShell::SetBoxBackground( const SvxBrushItem &rNew )
889 {
890 	SET_CURR_SHELL( this );
891 	StartAllAction();
892     GetDoc()->SetBoxAttr( *getShellCrsr( false ), rNew );
893 	EndAllActionAndCall();
894 }
895 
896 sal_Bool SwFEShell::GetBoxBackground( SvxBrushItem &rToFill ) const
897 {
898     return GetDoc()->GetBoxAttr( *getShellCrsr( false ), rToFill );
899 }
900 
901 /***********************************************************************
902 #*	Class	   :  SwFEShell
903 #*	Methoden   :  SetBoxDirection(), GetBoxDirection()
904 #*  Datum      :  FME 2004-02-03
905 #*  Update     :  FME 2004-02-03
906 #***********************************************************************/
907 void SwFEShell::SetBoxDirection( const SvxFrameDirectionItem& rNew )
908 {
909 	SET_CURR_SHELL( this );
910 	StartAllAction();
911     GetDoc()->SetBoxAttr( *getShellCrsr( false ), rNew );
912 	EndAllActionAndCall();
913 }
914 
915 sal_Bool SwFEShell::GetBoxDirection( SvxFrameDirectionItem&  rToFill ) const
916 {
917     return GetDoc()->GetBoxAttr( *getShellCrsr( false ), rToFill );
918 }
919 
920 /***********************************************************************
921 #*	Class	   :  SwFEShell
922 #*	Methoden   :  SetBoxAlign, SetBoxAlign
923 #*	Datum	   :  MA 18. Dec. 96
924 #*	Update	   :  JP 29.04.98
925 #***********************************************************************/
926 void SwFEShell::SetBoxAlign( sal_uInt16 nAlign )
927 {
928 	SET_CURR_SHELL( this );
929 	StartAllAction();
930     GetDoc()->SetBoxAlign( *getShellCrsr( false ), nAlign );
931 	EndAllActionAndCall();
932 }
933 
934 sal_uInt16 SwFEShell::GetBoxAlign() const
935 {
936     return GetDoc()->GetBoxAlign( *getShellCrsr( false ) );
937 }
938 
939 /***********************************************************************
940 #*	Class	   :  SwFEShell
941 #*	Methoden   :  SetTabBackground(), GetTabBackground()
942 #*	Datum	   :  MA 08. Jul. 96
943 #*	Update	   :  MA 08. Jul. 96
944 #***********************************************************************/
945 void SwFEShell::SetTabBackground( const SvxBrushItem &rNew )
946 {
947 	SwFrm *pFrm = GetCurrFrm();
948 	if( !pFrm || !pFrm->IsInTab() )
949 		return;
950 
951 	SET_CURR_SHELL( this );
952 	StartAllAction();
953 	GetDoc()->SetAttr( rNew, *pFrm->ImplFindTabFrm()->GetFmt() );
954 	EndAllAction();	//Kein Call, denn es veraendert sich nichts!
955 	GetDoc()->SetModified();
956 }
957 
958 void SwFEShell::GetTabBackground( SvxBrushItem &rToFill ) const
959 {
960 	SwFrm *pFrm = GetCurrFrm();
961 	if( pFrm && pFrm->IsInTab() )
962 		rToFill = pFrm->ImplFindTabFrm()->GetFmt()->GetBackground();
963 }
964 
965 
966 /***********************************************************************
967 #*	Class	   :  SwFEShell
968 #*	Methoden   :  HasWholeTabSelection()
969 #*	Datum	   :  MA 18. May. 93
970 #*	Update	   :  MA 20. Jul. 93
971 #***********************************************************************/
972 sal_Bool SwFEShell::HasWholeTabSelection() const
973 {
974 	//Ist die ganze Tabelle Selektiert?
975 	if ( IsTableMode() )
976 	{
977 		SwSelBoxes aBoxes;
978 		::GetTblSelCrs( *this, aBoxes );
979 		if( aBoxes.Count() )
980 		{
981 			const SwTableNode *pTblNd = IsCrsrInTbl();
982 			return ( pTblNd && aBoxes[0]->GetSttIdx()-1 == pTblNd->
983 				EndOfSectionNode()->StartOfSectionIndex() &&
984 				aBoxes[aBoxes.Count()-1]->GetSttNd()->EndOfSectionIndex()+1
985 				==  pTblNd->EndOfSectionIndex() );
986 		}
987 	}
988 	return sal_False;
989 }
990 
991 sal_Bool SwFEShell::HasBoxSelection() const
992 {
993 	if(!IsCrsrInTbl())
994 		return sal_False;
995 	//Ist die ganze Tabelle Selektiert?
996 	if( IsTableMode() )
997 		return sal_True;
998 	SwPaM* pPam = GetCrsr();
999 		// leere Boxen gelten auch ohne Selektion als selektiert
1000 //	if( !pPam->HasMark() )
1001 //		return sal_False;
1002 	sal_Bool bChg = sal_False;
1003 	if( pPam->GetPoint() == pPam->End())
1004 	{
1005 		bChg = sal_True;
1006 		pPam->Exchange();
1007 	}
1008 	SwNode* pNd;
1009 	if( pPam->GetPoint()->nNode.GetIndex() -1 ==
1010 		( pNd = pPam->GetNode())->StartOfSectionIndex() &&
1011 		!pPam->GetPoint()->nContent.GetIndex() &&
1012 		pPam->GetMark()->nNode.GetIndex() + 1 ==
1013 		pNd->EndOfSectionIndex())
1014 	{
1015 			SwNodeIndex aIdx( *pNd->EndOfSectionNode(), -1 );
1016 			SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
1017 			if( !pCNd )
1018 			{
1019 				pCNd = GetDoc()->GetNodes().GoPrevious( &aIdx );
1020 				ASSERT( pCNd, "kein ContentNode in der Box ??" );
1021 			}
1022 			if( pPam->GetMark()->nContent == pCNd->Len() )
1023 			{
1024 				if( bChg )
1025 					pPam->Exchange();
1026 				return sal_True;
1027 			}
1028 	}
1029 	if( bChg )
1030 		pPam->Exchange();
1031 	return sal_False;
1032 }
1033 
1034 /***********************************************************************
1035 #*	Class	   :  SwFEShell
1036 #*	Methoden   :  ProtectCells(), UnProtectCells()
1037 #*	Datum	   :  MA 20. Jul. 93
1038 #*	Update	   :  JP 25. Sep. 93
1039 #***********************************************************************/
1040 void SwFEShell::ProtectCells()
1041 {
1042     SvxProtectItem aProt( RES_PROTECT );
1043 	aProt.SetCntntProtect( sal_True );
1044 
1045 	SET_CURR_SHELL( this );
1046 	StartAllAction();
1047 
1048     GetDoc()->SetBoxAttr( *getShellCrsr( false ), aProt );
1049 
1050 	if( !IsCrsrReadonly() )
1051 	{
1052 		if( IsTableMode() )
1053 			ClearMark();
1054 		ParkCursorInTab();
1055 	}
1056 	EndAllActionAndCall();
1057 }
1058 
1059 // die Tabellenselektion aufheben
1060 void SwFEShell::UnProtectCells()
1061 {
1062 	SET_CURR_SHELL( this );
1063 	StartAllAction();
1064 
1065 	SwSelBoxes aBoxes;
1066 	if( IsTableMode() )
1067 		::GetTblSelCrs( *this, aBoxes );
1068 	else
1069 	{
1070 		SwFrm *pFrm = GetCurrFrm();
1071 		do {
1072 			pFrm = pFrm->GetUpper();
1073 		} while ( pFrm && !pFrm->IsCellFrm() );
1074 		if( pFrm )
1075 		{
1076 			SwTableBox *pBox = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
1077 			aBoxes.Insert( pBox );
1078 		}
1079 	}
1080 
1081 	if( aBoxes.Count() )
1082 		GetDoc()->UnProtectCells( aBoxes );
1083 
1084 	EndAllActionAndCall();
1085 }
1086 
1087 void SwFEShell::UnProtectTbls()
1088 {
1089 	SET_CURR_SHELL( this );
1090 	StartAllAction();
1091 	GetDoc()->UnProtectTbls( *GetCrsr() );
1092 	EndAllActionAndCall();
1093 }
1094 
1095 sal_Bool SwFEShell::HasTblAnyProtection( const String* pTblName,
1096 									sal_Bool* pFullTblProtection )
1097 {
1098 	return GetDoc()->HasTblAnyProtection( GetCrsr()->GetPoint(), pTblName,
1099 										pFullTblProtection );
1100 }
1101 
1102 sal_Bool SwFEShell::CanUnProtectCells() const
1103 {
1104 	sal_Bool bUnProtectAvailable = sal_False;
1105 	const SwTableNode *pTblNd = IsCrsrInTbl();
1106 	if( pTblNd && !pTblNd->IsProtect() )
1107 	{
1108 		SwSelBoxes aBoxes;
1109 		if( IsTableMode() )
1110 			::GetTblSelCrs( *this, aBoxes );
1111 		else
1112 		{
1113 			SwFrm *pFrm = GetCurrFrm();
1114 			do {
1115 				pFrm = pFrm->GetUpper();
1116 			} while ( pFrm && !pFrm->IsCellFrm() );
1117 			if( pFrm )
1118 			{
1119 				SwTableBox *pBox = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
1120 				aBoxes.Insert( pBox );
1121 			}
1122 		}
1123 		if( aBoxes.Count() )
1124 			bUnProtectAvailable = ::HasProtectedCells( aBoxes );
1125 	}
1126 	return bUnProtectAvailable;
1127 }
1128 
1129 /***********************************************************************
1130 #*  Class      :  SwFEShell
1131 #*  Methoden   :  GetRowsToRepeat(), SetRowsToRepeat()
1132 #***********************************************************************/
1133 sal_uInt16 SwFEShell::GetRowsToRepeat() const
1134 {
1135     const SwFrm *pFrm = GetCurrFrm();
1136     const SwTabFrm *pTab = pFrm ? pFrm->FindTabFrm() : 0;
1137     if( pTab )
1138         return pTab->GetTable()->GetRowsToRepeat();
1139     return 0;
1140 }
1141 
1142 void SwFEShell::SetRowsToRepeat( sal_uInt16 nSet )
1143 {
1144     SwFrm    *pFrm = GetCurrFrm();
1145     SwTabFrm *pTab = pFrm ? pFrm->FindTabFrm() : 0;
1146     if( pTab && pTab->GetTable()->GetRowsToRepeat() != nSet )
1147     {
1148         SwWait aWait( *GetDoc()->GetDocShell(), sal_True );
1149         SET_CURR_SHELL( this );
1150         StartAllAction();
1151         GetDoc()->SetRowsToRepeat( *pTab->GetTable(), nSet );
1152         EndAllActionAndCall();
1153     }
1154 }
1155 /*-- 30.06.2004 08:46:35---------------------------------------------------
1156     returns the number of rows consecutively selected from top
1157   -----------------------------------------------------------------------*/
1158 sal_uInt16 lcl_GetRowNumber( const SwPosition& rPos )
1159 {
1160     sal_uInt16 nRet = USHRT_MAX;
1161     Point aTmpPt;
1162     const SwCntntNode *pNd;
1163     const SwCntntFrm *pFrm;
1164 
1165     if( 0 != ( pNd = rPos.nNode.GetNode().GetCntntNode() ))
1166         pFrm = pNd->getLayoutFrm( pNd->GetDoc()->GetCurrentLayout(), &aTmpPt, &rPos, sal_False );
1167     else
1168         pFrm = 0;
1169 
1170     if ( pFrm && pFrm->IsInTab() )
1171     {
1172         const SwFrm* pRow = pFrm->GetUpper();
1173         while ( !pRow->GetUpper()->IsTabFrm() )
1174             pRow = pRow->GetUpper();
1175 
1176         const SwTabFrm* pTabFrm = (const SwTabFrm*)pRow->GetUpper();
1177         const SwTableLine* pTabLine = static_cast<const SwRowFrm*>(pRow)->GetTabLine();
1178 
1179         sal_uInt16 nI = 0;
1180         while ( nI < pTabFrm->GetTable()->GetTabLines().Count() )
1181         {
1182             if ( pTabFrm->GetTable()->GetTabLines()[ nI ] == pTabLine )
1183             {
1184                 nRet = nI;
1185                 break;
1186             }
1187             ++nI;
1188         }
1189     }
1190 
1191     return nRet;
1192 }
1193 sal_uInt16 SwFEShell::GetRowSelectionFromTop() const
1194 {
1195     sal_uInt16 nRet = 0;
1196     const SwPaM* pPaM = IsTableMode() ? GetTableCrsr() : _GetCrsr();
1197     const sal_uInt16 nPtLine = lcl_GetRowNumber( *pPaM->GetPoint() );
1198 
1199     if ( !IsTableMode() )
1200     {
1201         nRet = 0 == nPtLine ? 1 : 0;
1202     }
1203     else
1204     {
1205         const sal_uInt16 nMkLine = lcl_GetRowNumber( *pPaM->GetMark() );
1206 
1207         if ( ( nPtLine == 0 && nMkLine != USHRT_MAX ) ||
1208              ( nMkLine == 0 && nPtLine != USHRT_MAX ) )
1209         {
1210             nRet = Max( nPtLine, nMkLine ) + 1;
1211         }
1212     }
1213 
1214     return nRet;
1215 }
1216 
1217 /*
1218  * 1. case: bRepeat = true
1219  * returns true if the current frame is located inside a table headline in
1220  * a follow frame
1221  *
1222  * 2. case: bRepeat = false
1223  * returns true if the current frame is localed inside a table headline OR
1224  * inside the first line of a table!!!
1225  */
1226 sal_Bool SwFEShell::CheckHeadline( bool bRepeat ) const
1227 {
1228 	sal_Bool bRet = sal_False;
1229 	if ( !IsTableMode() )
1230 	{
1231         SwFrm *pFrm = GetCurrFrm();  // DONE MULTIIHEADER
1232         if ( pFrm && pFrm->IsInTab() )
1233         {
1234             SwTabFrm* pTab = pFrm->FindTabFrm();
1235             if ( bRepeat )
1236             {
1237                 bRet = pTab->IsFollow() && pTab->IsInHeadline( *pFrm );
1238             }
1239             else
1240             {
1241                 bRet =  ((SwLayoutFrm*)pTab->Lower())->IsAnLower( pFrm ) ||
1242                         pTab->IsInHeadline( *pFrm );
1243             }
1244         }
1245 	}
1246 	return bRet;
1247 }
1248 
1249 /***********************************************************************
1250 #*	Class	   :  SwFEShell
1251 #*	Methoden   :  AdjustCellWidth()
1252 #*	Datum	   :  MA 20. Feb. 95
1253 #*	Update	   :  MA 27. Jul. 95
1254 #***********************************************************************/
1255 
1256 void SwFEShell::AdjustCellWidth( sal_Bool bBalance )
1257 {
1258 	SET_CURR_SHELL( this );
1259 	StartAllAction();
1260 
1261 	//WarteCrsr immer einschalten, weil sich im vorraus nicht so recht
1262 	//ermitteln laesst wieviel Inhalt betroffen ist.
1263 	TblWait aWait( USHRT_MAX, 0, *GetDoc()->GetDocShell() );
1264 
1265     GetDoc()->AdjustCellWidth( *getShellCrsr( false ), bBalance );
1266 	EndAllActionAndCall();
1267 }
1268 
1269 sal_Bool SwFEShell::IsAdjustCellWidthAllowed( sal_Bool bBalance ) const
1270 {
1271 	//Es muss mindestens eine Zelle mit Inhalt in der Selektion enthalten
1272 	//sein.
1273 
1274 	SwFrm *pFrm = GetCurrFrm();
1275 	if( !pFrm || !pFrm->IsInTab() )
1276 		return sal_False;
1277 
1278 	SwSelBoxes aBoxes;
1279 	::GetTblSelCrs( *this, aBoxes );
1280 
1281 	if ( bBalance )
1282 		return aBoxes.Count() > 1;
1283 
1284 	if ( !aBoxes.Count() )
1285 	{
1286 		do
1287 		{	pFrm = pFrm->GetUpper();
1288 		} while ( !pFrm->IsCellFrm() );
1289 		SwTableBox *pBox = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
1290 		aBoxes.Insert( pBox );
1291 	}
1292 
1293 	for ( sal_uInt16 i = 0; i < aBoxes.Count(); ++i )
1294 	{
1295 		SwTableBox *pBox = aBoxes[i];
1296 		if ( pBox->GetSttNd() )
1297 		{
1298 			SwNodeIndex aIdx( *pBox->GetSttNd(), 1 );
1299 			SwTxtNode* pCNd = aIdx.GetNode().GetTxtNode();
1300 			if( !pCNd )
1301 				pCNd = (SwTxtNode*)GetDoc()->GetNodes().GoNext( &aIdx );
1302 
1303 			while ( pCNd )
1304 			{
1305 				if ( pCNd->GetTxt().Len() )
1306 					return sal_True;
1307 				++aIdx;
1308                 pCNd = aIdx.GetNode().GetTxtNode();
1309             }
1310         }
1311     }
1312 	return sal_False;
1313 }
1314 
1315 	// AutoFormat fuer die Tabelle/TabellenSelection
1316 sal_Bool SwFEShell::SetTableAutoFmt( const SwTableAutoFmt& rNew )
1317 {
1318 	SwTableNode *pTblNd = (SwTableNode*)IsCrsrInTbl();
1319 	if( !pTblNd || pTblNd->GetTable().IsTblComplex() )
1320 		return sal_False;
1321 
1322 	SwSelBoxes aBoxes;
1323 
1324 	if ( !IsTableMode() )		// falls Crsr noch nicht akt. sind
1325 		GetCrsr();
1326 
1327 	// gesamte Tabelle oder nur auf die akt. Selektion
1328 	if( IsTableMode() )
1329 		::GetTblSelCrs( *this, aBoxes );
1330 	else
1331 	{
1332 		const SwTableSortBoxes& rTBoxes = pTblNd->GetTable().GetTabSortBoxes();
1333 		for( sal_uInt16 n = 0; n < rTBoxes.Count(); ++n )
1334 		{
1335 			SwTableBox* pBox = rTBoxes[ n ];
1336 			aBoxes.Insert( pBox );
1337 		}
1338 	}
1339 
1340 	sal_Bool bRet;
1341 	if( aBoxes.Count() )
1342 	{
1343 		SET_CURR_SHELL( this );
1344 		StartAllAction();
1345 		bRet = GetDoc()->SetTableAutoFmt( aBoxes, rNew );
1346 		DELETEZ( pLastCols );
1347         DELETEZ( pLastRows );
1348         EndAllActionAndCall();
1349 	}
1350 	else
1351 		bRet = sal_False;
1352 	return bRet;
1353 }
1354 
1355 sal_Bool SwFEShell::GetTableAutoFmt( SwTableAutoFmt& rGet )
1356 {
1357 	const SwTableNode *pTblNd = IsCrsrInTbl();
1358 	if( !pTblNd || pTblNd->GetTable().IsTblComplex() )
1359 		return sal_False;
1360 
1361 	SwSelBoxes aBoxes;
1362 
1363 	if ( !IsTableMode() )		// falls Crsr noch nicht akt. sind
1364 		GetCrsr();
1365 
1366 	// gesamte Tabelle oder nur auf die akt. Selektion
1367 	if( IsTableMode() )
1368 		::GetTblSelCrs( *this, aBoxes );
1369 	else
1370 	{
1371 		const SwTableSortBoxes& rTBoxes = pTblNd->GetTable().GetTabSortBoxes();
1372 		for( sal_uInt16 n = 0; n < rTBoxes.Count(); ++n )
1373 		{
1374 			SwTableBox* pBox = rTBoxes[ n ];
1375 			aBoxes.Insert( pBox );
1376 		}
1377 	}
1378 
1379 	return GetDoc()->GetTableAutoFmt( aBoxes, rGet );
1380 }
1381 
1382 /***********************************************************************
1383 #*	Class	   :  SwFEShell
1384 #*	Methoden   :  DeleteTblSel()
1385 #*	Datum	   :  MA 03. May. 93
1386 #*	Update	   :  MA 19. Apr. 95
1387 #***********************************************************************/
1388 sal_Bool SwFEShell::DeleteTblSel()
1389 {
1390 	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
1391 	SwFrm *pFrm = GetCurrFrm();
1392 	if( !pFrm || !pFrm->IsInTab() )
1393 		return sal_False;
1394 
1395 	if( pFrm->ImplFindTabFrm()->GetTable()->ISA( SwDDETable ))
1396 	{
1397 		ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
1398 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
1399 		return sal_False;
1400 	}
1401 
1402 	SET_CURR_SHELL( this );
1403 	StartAllAction();
1404 
1405 	// lasse ueber das Layout die Boxen suchen
1406 	sal_Bool bRet;
1407 	SwSelBoxes aBoxes;
1408 	GetTblSelCrs( *this, aBoxes );
1409 	if( aBoxes.Count() )
1410 	{
1411 		TblWait( aBoxes.Count(), pFrm, *GetDoc()->GetDocShell() );
1412 
1413 		// die Crsr muessen noch aus dem Loesch Bereich entfernt
1414 		// werden. Setze sie immer hinter/auf die Tabelle; ueber die
1415 		// Dokument-Position werden sie dann immer an die alte Position gesetzt.
1416 		while( !pFrm->IsCellFrm() )
1417 			pFrm = pFrm->GetUpper();
1418 		ParkCrsr( SwNodeIndex( *((SwCellFrm*)pFrm)->GetTabBox()->GetSttNd() ));
1419 
1420 		bRet = GetDoc()->DeleteRowCol( aBoxes );
1421 
1422 		DELETEZ( pLastCols );
1423         DELETEZ( pLastRows );
1424     }
1425 	else
1426 		bRet = sal_False;
1427 	EndAllActionAndCall();
1428 	return bRet;
1429 }
1430 
1431 /*************************************************************************
1432 |*
1433 |*	SwFEShell::GetCurTabColNum()
1434 |*
1435 |*	Ersterstellung		MA 03. Feb. 95
1436 |*	Letzte Aenderung	MA 21. May. 95
1437 |
1438 |*************************************************************************/
1439 sal_uInt16 SwFEShell::GetCurTabColNum() const
1440 {
1441 	//!!!GetCurMouseTabColNum() mitpflegen!!!!
1442 	sal_uInt16 nRet = 0;
1443 
1444 	SwFrm *pFrm = GetCurrFrm();
1445 	ASSERT( pFrm, "Crsr geparkt?" );
1446 
1447 	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
1448 	if( pFrm && pFrm->IsInTab() )
1449 	{
1450 		do {			// JP 26.09.95: warum mit dem CntntFrame und nicht mit
1451 						// 				dem CellFrame vergleichen????
1452 			pFrm = pFrm->GetUpper();
1453 		} while ( !pFrm->IsCellFrm() );
1454         SWRECTFN( pFrm )
1455 
1456         const SwPageFrm* pPage = pFrm->FindPageFrm();
1457 
1458 		//TabCols besorgen, den nur ueber diese erreichen wir die Position.
1459 		SwTabCols aTabCols;
1460 		GetTabCols( aTabCols );
1461 
1462         if( pFrm->FindTabFrm()->IsRightToLeft() )
1463 		{
1464             long nX = (pFrm->Frm().*fnRect->fnGetRight)() - (pPage->Frm().*fnRect->fnGetLeft)();
1465 
1466 			const long nRight = aTabCols.GetLeftMin() + aTabCols.GetRight();;
1467 
1468             if ( !::IsSame( nX, nRight ) )
1469 			{
1470                 nX = nRight - nX + aTabCols.GetLeft();
1471 				for ( sal_uInt16 i = 0; i < aTabCols.Count(); ++i )
1472                     if ( ::IsSame( nX, aTabCols[i] ) )
1473 					{
1474 						nRet = i + 1;
1475 						break;
1476 					}
1477 			}
1478 		}
1479 		else
1480 		{
1481             const long nX = (pFrm->Frm().*fnRect->fnGetLeft)() -
1482                             (pPage->Frm().*fnRect->fnGetLeft)();
1483 
1484             const long nLeft = aTabCols.GetLeftMin();
1485 
1486 			if ( !::IsSame( nX, nLeft + aTabCols.GetLeft() ) )
1487 			{
1488 				for ( sal_uInt16 i = 0; i < aTabCols.Count(); ++i )
1489 					if ( ::IsSame( nX, nLeft + aTabCols[i] ) )
1490 					{
1491 						nRet = i + 1;
1492 						break;
1493 					}
1494 			}
1495 		}
1496 	}
1497 	return nRet;
1498 }
1499 
1500 /*************************************************************************
1501 |*
1502 |*	SwFEShell::GetBox()
1503 |*
1504 |*	Ersterstellung		MA 22. Jun. 95
1505 |*	Letzte Aenderung	MA 21. Nov. 96
1506 |*
1507 |*************************************************************************/
1508 
1509 const SwFrm *lcl_FindFrmInTab( const SwLayoutFrm *pLay, const Point &rPt, SwTwips nFuzzy )
1510 {
1511 	const SwFrm *pFrm = pLay->Lower();
1512 
1513     while( pFrm && pLay->IsAnLower( pFrm ) )
1514 	{
1515         if ( pFrm->Frm().IsNear( rPt, nFuzzy ) )
1516 		{
1517 			if ( pFrm->IsLayoutFrm() )
1518 			{
1519 				const SwFrm *pTmp = ::lcl_FindFrmInTab( (SwLayoutFrm*)pFrm, rPt, nFuzzy );
1520 				if ( pTmp )
1521 					return pTmp;
1522 			}
1523 
1524             return pFrm;
1525         }
1526 
1527 		pFrm = pFrm->FindNext();
1528     }
1529 
1530 	return 0;
1531 }
1532 
1533 const SwCellFrm *lcl_FindFrm( const SwLayoutFrm *pLay, const Point &rPt,
1534                               SwTwips nFuzzy, bool* pbRow, bool* pbCol )
1535 {
1536     // bMouseMoveRowCols :
1537     // Method is called for
1538     // - Moving columns/rows with the mouse or
1539     // - Enhanced table selection
1540     const bool bMouseMoveRowCols = 0 == pbCol;
1541 
1542     bool bCloseToRow = false;
1543     bool bCloseToCol = false;
1544 
1545     const SwFrm *pFrm = pLay->ContainsCntnt();
1546     const SwFrm* pRet = 0;
1547 
1548     if ( pFrm )
1549 	{
1550 		do
1551 		{
1552 			if ( pFrm->IsInTab() )
1553 				pFrm = ((SwFrm*)pFrm)->ImplFindTabFrm();
1554 
1555             if ( pFrm->IsTabFrm() )
1556 			{
1557                 Point aPt( rPt );
1558                 bool bSearchForFrmInTab = true;
1559                 SwTwips nTmpFuzzy = nFuzzy;
1560 
1561                 if ( !bMouseMoveRowCols )
1562                 {
1563                     // We ignore nested tables for the enhanced table selection:
1564                     while ( pFrm->GetUpper()->IsInTab() )
1565                         pFrm = pFrm->GetUpper()->FindTabFrm();
1566 
1567                     // We first check if the given point is 'close' to the left or top
1568                     // border of the table frame:
1569                     ASSERT( pFrm, "Nested table frame without outer table" )
1570                     SWRECTFN( pFrm )
1571                     const bool bRTL = pFrm->IsRightToLeft();
1572 
1573                     SwRect aTabRect = pFrm->Prt();
1574                     aTabRect.Pos() += pFrm->Frm().Pos();
1575 
1576                     const SwTwips nLeft = bRTL ?
1577                                           (aTabRect.*fnRect->fnGetRight)() :
1578                                           (aTabRect.*fnRect->fnGetLeft)();
1579                     const SwTwips nTop  = (aTabRect.*fnRect->fnGetTop)();
1580 
1581                     SwTwips& rPointX = bVert ? aPt.Y() : aPt.X();
1582                     SwTwips& rPointY = bVert ? aPt.X() : aPt.Y();
1583 
1584                     const SwTwips nXDiff = (*fnRect->fnXDiff)( nLeft, rPointX ) * ( bRTL ? (-1) : 1 );
1585                     const SwTwips nYDiff = (*fnRect->fnYDiff)( nTop, rPointY );
1586 
1587                     bCloseToRow = nXDiff >= 0 && nXDiff < nFuzzy;
1588                     bCloseToCol = nYDiff >= 0 && nYDiff < nFuzzy;
1589 
1590                     if ( bCloseToCol && 2 * nYDiff > nFuzzy )
1591                     {
1592                         const SwFrm* pPrev = pFrm->GetPrev();
1593                         if ( pPrev )
1594                         {
1595                             SwRect aPrevRect = pPrev->Prt();
1596                             aPrevRect.Pos() += pPrev->Frm().Pos();
1597 
1598                             if( aPrevRect.IsInside( rPt ) )
1599                             {
1600                                 bCloseToCol = false;
1601                             }
1602                         }
1603 
1604                     }
1605 
1606                     // If we found the point to be 'close' to the left or top border
1607                     // of the table frame, we adjust the point to be on that border:
1608                     if ( bCloseToRow && bCloseToCol )
1609                         aPt = bRTL ? aTabRect.TopRight() : (aTabRect.*fnRect->fnGetPos)();
1610                     else if ( bCloseToRow )
1611                         rPointX = nLeft;
1612                     else if ( bCloseToCol )
1613                         rPointY = nTop;
1614 
1615                     if ( !bCloseToRow && !bCloseToCol )
1616                         bSearchForFrmInTab = false;
1617 
1618                     // Since the point has been adjusted, we call lcl_FindFrmInTab()
1619                     // with a fuzzy value of 1:
1620                     nTmpFuzzy = 1;
1621                 }
1622 
1623                 const SwFrm* pTmp = bSearchForFrmInTab ?
1624                                     ::lcl_FindFrmInTab( (SwLayoutFrm*)pFrm, aPt, nTmpFuzzy ) :
1625                                     0;
1626 
1627                 if ( pTmp )
1628                 {
1629                     pFrm = pTmp;
1630                     break;
1631                 }
1632 			}
1633 			pFrm = pFrm->FindNextCnt();
1634 
1635 		} while ( pFrm && pLay->IsAnLower( pFrm ) );
1636 	}
1637 
1638     if ( pFrm && pFrm->IsInTab() && pLay->IsAnLower( pFrm ) )
1639 	{
1640 		do
1641         {
1642             // We allow mouse drag of table borders within nested tables,
1643             // but disallow hotspot selection of nested tables.
1644             if ( bMouseMoveRowCols )
1645             {
1646                 // find the next cell frame
1647                 while ( pFrm && !pFrm->IsCellFrm() )
1648                     pFrm = pFrm->GetUpper();
1649             }
1650             else
1651             {
1652                 // find the most upper cell frame:
1653                 while ( pFrm &&
1654                         ( !pFrm->IsCellFrm() ||
1655                           !pFrm->GetUpper()->GetUpper()->IsTabFrm() ||
1656                            pFrm->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) )
1657                     pFrm = pFrm->GetUpper();
1658             }
1659 
1660             if ( pFrm ) // Note: this condition should be the same like the while condition!!!
1661 			{
1662                 // --> FME 2004-07-30 #i32329# Enhanced table selection
1663                 // used for hotspot selection of tab/cols/rows
1664                 if ( !bMouseMoveRowCols )
1665                 {
1666 
1667                     ASSERT( pbCol && pbRow, "pbCol or pbRow missing" )
1668 
1669                     if ( bCloseToRow || bCloseToCol )
1670                     {
1671                         *pbRow = bCloseToRow;
1672                         *pbCol = bCloseToCol;
1673                         pRet = pFrm;
1674                         break;
1675                     }
1676                 }
1677                 // <--
1678                 else
1679                 {
1680                     // used for mouse move of columns/rows
1681                     const SwTabFrm* pTabFrm = pFrm->FindTabFrm();
1682                     SwRect aTabRect = pTabFrm->Prt();
1683                     aTabRect.Pos() += pTabFrm->Frm().Pos();
1684 
1685                     SWRECTFN( pTabFrm )
1686 
1687                     const SwTwips nTabTop  = (aTabRect.*fnRect->fnGetTop)();
1688                     const SwTwips nMouseTop  = bVert ? rPt.X() : rPt.Y();
1689 
1690                     // Do not allow to drag upper table border:
1691                     if ( !::IsSame( nTabTop, nMouseTop ) )
1692                     {
1693                         if ( ::IsSame( pFrm->Frm().Left(), rPt.X() ) ||
1694                              ::IsSame( pFrm->Frm().Right(),rPt.X() ) )
1695                         {
1696                             if ( pbRow ) *pbRow = false;
1697                             pRet = pFrm;
1698                             break;
1699                         }
1700                         if ( ::IsSame( pFrm->Frm().Top(), rPt.Y() ) ||
1701                              ::IsSame( pFrm->Frm().Bottom(),rPt.Y() ) )
1702                         {
1703                             if ( pbRow ) *pbRow = true;
1704                             pRet = pFrm;
1705                             break;
1706                         }
1707                     }
1708                 }
1709 
1710                 pFrm = pFrm->GetUpper();
1711 			}
1712 		} while ( pFrm );
1713 	}
1714 
1715     // robust:
1716     ASSERT( !pRet || pRet->IsCellFrm(), "lcl_FindFrm() is supposed to find a cell frame!" )
1717     return pRet && pRet->IsCellFrm() ? static_cast<const SwCellFrm*>(pRet) : 0;
1718 }
1719 
1720 //
1721 // pbCol  = 0 => Used for moving table rows/cols with mouse
1722 // pbCol != 0 => Used for selecting table/rows/cols
1723 //
1724 #define ENHANCED_TABLE_SELECTION_FUZZY 10
1725 
1726 const SwFrm* SwFEShell::GetBox( const Point &rPt, bool* pbRow, bool* pbCol ) const
1727 {
1728 	const SwPageFrm *pPage = (SwPageFrm*)GetLayout()->Lower();
1729 	Window* pOutWin = GetWin();
1730     SwTwips nFuzzy = COLFUZZY;
1731 	if( pOutWin )
1732 	{
1733         // --> FME 2004-07-30 #i32329# Enhanced table selection
1734         SwTwips nSize = pbCol ? ENHANCED_TABLE_SELECTION_FUZZY : RULER_MOUSE_MARGINWIDTH;
1735         // <--
1736         Size aTmp( nSize, nSize );
1737         aTmp = pOutWin->PixelToLogic( aTmp );
1738         nFuzzy = aTmp.Width();
1739 	}
1740 
1741     while ( pPage && !pPage->Frm().IsNear( rPt, nFuzzy ) )
1742 		pPage = (SwPageFrm*)pPage->GetNext();
1743 
1744     const SwCellFrm *pFrm = 0;
1745 	if ( pPage )
1746 	{
1747 		//Per GetCrsrOfst oder GetCntntPos koennen wir hier die Box leider
1748 		//nicht suchen. Das wuerde zu einem Performance-Zusammenbruch bei
1749 		//Dokumenten mit vielen Absaetzen/Tabellen auf einer Seite fuehren
1750 		//(BrowseMode!)
1751 
1752 		//Erst die Flys checken.
1753 		if ( pPage->GetSortedObjs() )
1754 		{
1755 			for ( sal_uInt16 i = 0; !pFrm && i < pPage->GetSortedObjs()->Count(); ++i )
1756 			{
1757                 SwAnchoredObject* pObj = (*pPage->GetSortedObjs())[i];
1758                 if ( pObj->ISA(SwFlyFrm) )
1759 				{
1760                     pFrm = lcl_FindFrm( static_cast<SwFlyFrm*>(pObj),
1761                                         rPt, nFuzzy, pbRow, pbCol );
1762 				}
1763             }
1764 		}
1765 		const SwLayoutFrm *pLay = (SwLayoutFrm*)pPage->Lower();
1766 		while ( pLay && !pFrm )
1767 		{
1768             pFrm = lcl_FindFrm( pLay, rPt, nFuzzy, pbRow, pbCol );
1769             pLay = (SwLayoutFrm*)pLay->GetNext();
1770 		}
1771 	}
1772 	return pFrm;
1773 }
1774 
1775 /* Helper function*/
1776 /* calculated the distance between Point rC and Line Segment (rA, rB) */
1777 double lcl_DistancePoint2Segment( const Point& rA, const Point& rB, const Point& rC )
1778 {
1779     double nRet = 0;
1780 
1781     const basegfx::B2DVector aBC( rC.X() - rB.X(), rC.Y() - rB.Y() );
1782     const basegfx::B2DVector aAB( rB.X() - rA.X(), rB.Y() - rA.Y() );
1783     const double nDot1 = aBC.scalar( aAB );
1784 
1785     if ( nDot1 > 0 ) // check outside case 1
1786         nRet = aBC.getLength();
1787     else
1788     {
1789         const basegfx::B2DVector aAC( rC.X() - rA.X(), rC.Y() - rA.Y() );
1790         const basegfx::B2DVector aBA( rA.X() - rB.X(), rA.Y() - rB.Y() );
1791         const double nDot2 = aAC.scalar( aBA );
1792 
1793         if ( nDot2 > 0 ) // check outside case 2
1794             nRet = aAC.getLength();
1795         else
1796         {
1797             const double nDiv = aAB.getLength();
1798             nRet = nDiv ? aAB.cross( aAC ) / nDiv : 0;
1799         }
1800     }
1801 
1802     return Abs(nRet);
1803 }
1804 
1805 /* Helper function*/
1806 Point lcl_ProjectOntoClosestTableFrm( const SwTabFrm& rTab, const Point& rPoint, bool bRowDrag )
1807 {
1808     Point aRet( rPoint );
1809     const SwTabFrm* pCurrentTab = &rTab;
1810     const bool bVert = pCurrentTab->IsVertical();
1811     const bool bRTL = pCurrentTab->IsRightToLeft();
1812 
1813     // Western Layout:
1814     // bRowDrag = true => compare to left border of table
1815     // bRowDrag = false => compare to top border of table
1816 
1817     // Asian Layout:
1818     // bRowDrag = true => compare to right border of table
1819     // bRowDrag = false => compare to top border of table
1820 
1821     // RTL Layout:
1822     // bRowDrag = true => compare to right border of table
1823     // bRowDrag = false => compare to top border of table
1824     bool bLeft = false;
1825     bool bRight = false;
1826 
1827     if ( bRowDrag )
1828     {
1829         if ( bVert || bRTL )
1830             bRight = true;
1831         else
1832             bLeft = true;
1833     }
1834 
1835     // used to find the minimal distance
1836     double nMin = -1;
1837     Point aMin1;
1838     Point aMin2;
1839 
1840     Point aS1;
1841     Point aS2;
1842 
1843     while ( pCurrentTab )
1844     {
1845         SwRect aTabRect( pCurrentTab->Prt() );
1846         aTabRect += pCurrentTab->Frm().Pos();
1847 
1848         if ( bLeft )
1849         {
1850             // distance to left table border
1851             aS1 = aTabRect.TopLeft();
1852             aS2 = aTabRect.BottomLeft();
1853         }
1854         else if ( bRight )
1855         {
1856             // distance to right table border
1857             aS1 = aTabRect.TopRight();
1858             aS2 = aTabRect.BottomRight();
1859         }
1860         else //if ( bTop )
1861         {
1862             // distance to top table border
1863             aS1 = aTabRect.TopLeft();
1864             aS2 = aTabRect.TopRight();
1865         }
1866 
1867         const double nDist = lcl_DistancePoint2Segment( aS1, aS2, rPoint );
1868 
1869         if ( nDist < nMin || -1 == nMin )
1870         {
1871             aMin1 = aS1;
1872             aMin2 = aS2;
1873             nMin = nDist;
1874         }
1875 
1876         pCurrentTab = pCurrentTab->GetFollow();
1877     }
1878 
1879     // project onto closest line:
1880     if ( bLeft || bRight )
1881     {
1882         aRet.X() = aMin1.X();
1883         if ( aRet.Y() > aMin2.Y() )
1884             aRet.Y() = aMin2.Y();
1885         else if ( aRet.Y() < aMin1.Y() )
1886             aRet.Y() = aMin1.Y();
1887     }
1888     else //if ( bTop )
1889     {
1890         aRet.Y() = aMin1.Y();
1891         if ( aRet.X() > aMin2.X() )
1892             aRet.X() = aMin2.X();
1893         else if ( aRet.X() < aMin1.X() )
1894             aRet.X() = aMin1.X();
1895     }
1896 
1897     return aRet;
1898 }
1899 
1900 // --> FME 2004-07-30 #i32329# Enhanced table selection
1901 bool SwFEShell::SelTblRowCol( const Point& rPt, const Point* pEnd, bool bRowDrag )
1902 {
1903     bool bRet = false;
1904     Point aEndPt;
1905     if ( pEnd )
1906         aEndPt = *pEnd;
1907 
1908     SwPosition*  ppPos[2] = { 0, 0 };
1909     Point        paPt [2] = { rPt, aEndPt };
1910     bool         pbRow[2] = { 0, 0 };
1911     bool         pbCol[2] = { 0, 0 };
1912 
1913     // pEnd is set during dragging.
1914     for ( sal_uInt16 i = 0; i < ( pEnd ? 2 : 1 ); ++i )
1915     {
1916         const SwCellFrm* pFrm =
1917              static_cast<const SwCellFrm*>(GetBox( paPt[i], &pbRow[i], &pbCol[i] ) );
1918 
1919         if( pFrm )
1920         {
1921             while( pFrm->Lower() && pFrm->Lower()->IsRowFrm() )
1922                 pFrm = static_cast<const SwCellFrm*>( static_cast<const SwLayoutFrm*>( pFrm->Lower() )->Lower() );
1923             if( pFrm && pFrm->GetTabBox()->GetSttNd() &&
1924                 pFrm->GetTabBox()->GetSttNd()->IsInProtectSect() )
1925                 pFrm = 0;
1926         }
1927 
1928         if ( pFrm )
1929         {
1930             const SwCntntFrm* pCntnt = ::GetCellCntnt( *pFrm );
1931 
1932             if ( pCntnt && pCntnt->IsTxtFrm() )
1933             {
1934                 ppPos[i] = new SwPosition( *pCntnt->GetNode() );
1935                 ppPos[i]->nContent.Assign( const_cast<SwCntntNode*>(pCntnt->GetNode()), 0 );
1936 
1937                 // paPt[i] will not be used any longer, now we use it to store
1938                 // a position inside the content frame
1939                 paPt[i] = pCntnt->Frm().Center();
1940             }
1941         }
1942 
1943         // no calculation of end frame if start frame has not been found.
1944         if ( 1 == i || !ppPos[0] || !pEnd )
1945             break;
1946 
1947         // find 'closest' table frame to pEnd:
1948         const SwTabFrm* pCurrentTab = pFrm->FindTabFrm();
1949         if ( pCurrentTab->IsFollow() )
1950             pCurrentTab = pCurrentTab->FindMaster( true );
1951 
1952         const Point aProjection = lcl_ProjectOntoClosestTableFrm( *pCurrentTab, *pEnd, bRowDrag );
1953         paPt[1] = aProjection;
1954     }
1955 
1956     if ( ppPos[0] )
1957     {
1958         SwShellCrsr* pCrsr = _GetCrsr();
1959         SwCrsrSaveState aSaveState( *pCrsr );
1960         SwPosition aOldPos( *pCrsr->GetPoint() );
1961 
1962         pCrsr->DeleteMark();
1963         *pCrsr->GetPoint() = *ppPos[0];
1964         pCrsr->GetPtPos() = paPt[0];
1965 
1966         if ( !pCrsr->IsInProtectTable( sal_False, sal_True ) )
1967         {
1968             bool bNewSelection = true;
1969 
1970             if ( ppPos[1] )
1971             {
1972                 if ( ppPos[1]->nNode.GetNode().StartOfSectionNode() !=
1973                      aOldPos.nNode.GetNode().StartOfSectionNode() )
1974                 {
1975                     pCrsr->SetMark();
1976                     SwCrsrSaveState aSaveState2( *pCrsr );
1977                     *pCrsr->GetPoint() = *ppPos[1];
1978                     pCrsr->GetPtPos() = paPt[1];
1979 
1980                     if ( pCrsr->IsInProtectTable( sal_False, sal_False ) )
1981                     {
1982                         pCrsr->RestoreSavePos();
1983                         bNewSelection = false;
1984                     }
1985                 }
1986                 else
1987                 {
1988                     pCrsr->RestoreSavePos();
1989                     bNewSelection = false;
1990                 }
1991             }
1992 
1993             if ( bNewSelection )
1994             {
1995                 // --> FME 2004-10-20 #i35543# SelTblRowCol should remove any existing
1996                 // table cursor:
1997                 if ( IsTableMode() )
1998                     TblCrsrToCursor();
1999                 // <--
2000 
2001                 if ( pbRow[0] && pbCol[0] )
2002                     bRet = SwCrsrShell::SelTbl();
2003                 else if ( pbRow[0] )
2004                     bRet = SwCrsrShell::_SelTblRowOrCol( true, true );
2005                 else if ( pbCol[0] )
2006                     bRet = SwCrsrShell::_SelTblRowOrCol( false, true );
2007             }
2008             else
2009                 bRet = true;
2010         }
2011 
2012         delete ppPos[0];
2013         delete ppPos[1];
2014     }
2015 
2016     return bRet;
2017 }
2018 // <--
2019 
2020 
2021 /*************************************************************************
2022 |*
2023 |*  SwFEShell::WhichMouseTabCol()
2024 |*
2025 |*	Ersterstellung		MA 22. Jun. 95
2026 |*  Last change         AMA 12. Jun. 02
2027 |
2028 |*************************************************************************/
2029 sal_uInt8 SwFEShell::WhichMouseTabCol( const Point &rPt ) const
2030 {
2031     sal_uInt8 nRet = SW_TABCOL_NONE;
2032     bool bRow = false;
2033     bool bCol = false;
2034     bool bSelect = false;
2035 
2036     // First try: Do we get the row/col move cursor?
2037     SwCellFrm* pFrm = (SwCellFrm*)GetBox( rPt, &bRow, 0 );
2038 
2039     if ( !pFrm )
2040     {
2041         // Second try: Do we get the row/col/tab selection cursor?
2042         pFrm = (SwCellFrm*)GetBox( rPt, &bRow, &bCol );
2043         bSelect = true;
2044     }
2045 
2046     if( pFrm )
2047 	{
2048 		while( pFrm->Lower() && pFrm->Lower()->IsRowFrm() )
2049 			pFrm = (SwCellFrm*)((SwLayoutFrm*)pFrm->Lower())->Lower();
2050 		if( pFrm && pFrm->GetTabBox()->GetSttNd() &&
2051 			pFrm->GetTabBox()->GetSttNd()->IsInProtectSect() )
2052 			pFrm = 0;
2053 	}
2054 
2055     if( pFrm )
2056     {
2057         if ( !bSelect )
2058         {
2059             if ( pFrm->IsVertical() )
2060                 nRet = bRow ? SW_TABCOL_VERT : SW_TABROW_VERT;
2061             else
2062                 nRet = bRow ? SW_TABROW_HORI : SW_TABCOL_HORI;
2063         }
2064         else
2065         {
2066             const SwTabFrm* pTabFrm = pFrm->FindTabFrm();
2067             if ( pTabFrm->IsVertical() )
2068             {
2069                 if ( bRow && bCol )
2070                 {
2071                     nRet = SW_TABSEL_VERT;
2072                 }
2073                 else if ( bRow )
2074                 {
2075                     nRet = SW_TABROWSEL_VERT;
2076                 }
2077                 else if ( bCol )
2078                 {
2079                     nRet = SW_TABCOLSEL_VERT;
2080                 }
2081             }
2082             else
2083             {
2084                 if ( bRow && bCol )
2085                 {
2086                     nRet =  pTabFrm->IsRightToLeft() ?
2087                             SW_TABSEL_HORI_RTL :
2088                             SW_TABSEL_HORI;
2089                 }
2090                 else if ( bRow )
2091                 {
2092                     nRet = pTabFrm->IsRightToLeft() ?
2093                            SW_TABROWSEL_HORI_RTL :
2094                            SW_TABROWSEL_HORI;
2095                 }
2096                 else if ( bCol )
2097                 {
2098                     nRet = SW_TABCOLSEL_HORI;
2099                 }
2100             }
2101         }
2102     }
2103 
2104     return nRet;
2105 }
2106 
2107 // -> #i23726#
2108 SwTxtNode * SwFEShell::GetNumRuleNodeAtPos( const Point &rPt)
2109 {
2110     SwTxtNode * pResult = NULL;
2111 
2112     SwContentAtPos aCntntAtPos
2113         (SwContentAtPos::SW_NUMLABEL);
2114 
2115     if( GetContentAtPos(rPt, aCntntAtPos) && aCntntAtPos.aFnd.pNode)
2116         pResult = aCntntAtPos.aFnd.pNode->GetTxtNode();
2117 
2118     return pResult;
2119 }
2120 
2121 sal_Bool SwFEShell::IsNumLabel( const Point &rPt, int nMaxOffset )
2122 {
2123     sal_Bool bResult = sal_False;
2124 
2125     SwContentAtPos aCntntAtPos
2126         (SwContentAtPos::SW_NUMLABEL);
2127 
2128     if( GetContentAtPos(rPt, aCntntAtPos))
2129     {
2130         if ((nMaxOffset >= 0 && aCntntAtPos.nDist <= nMaxOffset) ||
2131             (nMaxOffset < 0))
2132             bResult = sal_True;
2133     }
2134 
2135     return bResult;
2136 }
2137 // <- #i23726#
2138 
2139 // --> OD 2005-02-21 #i42921#
2140 bool SwFEShell::IsVerticalModeAtNdAndPos( const SwTxtNode& _rTxtNode,
2141                                           const Point& _rDocPos ) const
2142 {
2143     bool bRet( false );
2144 
2145     const short nTextDir =
2146         _rTxtNode.GetTextDirection( SwPosition(_rTxtNode), &_rDocPos );
2147     switch ( nTextDir )
2148     {
2149         case -1:
2150         case FRMDIR_HORI_RIGHT_TOP:
2151         case FRMDIR_HORI_LEFT_TOP:
2152         {
2153             bRet = false;
2154         }
2155         break;
2156         case FRMDIR_VERT_TOP_LEFT:
2157         case FRMDIR_VERT_TOP_RIGHT:
2158         {
2159             bRet = true;
2160         }
2161         break;
2162     }
2163 
2164     return bRet;
2165 }
2166 // <--
2167 
2168 /*************************************************************************
2169 |*
2170 |*	SwFEShell::GetMouseTabCols()
2171 |*
2172 |*	Ersterstellung		MA 22. Jun. 95
2173 |*	Letzte Aenderung	MA 27. Aug. 96
2174 |
2175 |*************************************************************************/
2176 void SwFEShell::GetMouseTabCols( SwTabCols &rToFill, const Point &rPt ) const
2177 {
2178 	const SwFrm *pBox = GetBox( rPt );
2179 	if ( pBox )
2180 		_GetTabCols( rToFill, pBox );
2181 }
2182 
2183 void SwFEShell::SetMouseTabCols( const SwTabCols &rNew, sal_Bool bCurRowOnly,
2184 								 const Point &rPt )
2185 {
2186 	const SwFrm *pBox = GetBox( rPt );
2187 	if( pBox )
2188 	{
2189 		SET_CURR_SHELL( this );
2190 		StartAllAction();
2191 		GetDoc()->SetTabCols( rNew, bCurRowOnly, 0, (SwCellFrm*)pBox );
2192 		EndAllActionAndCall();
2193 	}
2194 }
2195 
2196 /*************************************************************************
2197 |*
2198 |*	SwFEShell::GetMouseColNum(), GetMouseTabColNum()
2199 |*
2200 |*	Ersterstellung		MA 04. Jul. 95
2201 |*	Letzte Aenderung	MA 04. Jul. 95
2202 |
2203 |*************************************************************************/
2204 sal_uInt16 SwFEShell::GetCurMouseColNum( const Point &rPt,
2205 									SwGetCurColNumPara* pPara ) const
2206 {
2207 	return _GetCurColNum( GetBox( rPt ), pPara );
2208 }
2209 
2210 sal_uInt16 SwFEShell::GetCurMouseTabColNum( const Point &rPt ) const
2211 {
2212 	//!!!GetCurTabColNum() mitpflegen!!!!
2213 	sal_uInt16 nRet = 0;
2214 
2215 	const SwFrm *pFrm = GetBox( rPt );
2216 	ASSERT( pFrm, "Table not found" );
2217 	if( pFrm )
2218 	{
2219 		const long nX = pFrm->Frm().Left();
2220 
2221 		//TabCols besorgen, den nur ueber diese erreichen wir die Position.
2222 		SwTabCols aTabCols;
2223 		GetMouseTabCols( aTabCols, rPt );
2224 
2225 		const long nLeft = aTabCols.GetLeftMin();
2226 
2227 		if ( !::IsSame( nX, nLeft + aTabCols.GetLeft() ) )
2228 		{
2229 			for ( sal_uInt16 i = 0; i < aTabCols.Count(); ++i )
2230 				if ( ::IsSame( nX, nLeft + aTabCols[i] ) )
2231 				{
2232 					nRet = i + 1;
2233 					break;
2234 				}
2235 		}
2236 	}
2237 	return nRet;
2238 }
2239 
2240 void ClearFEShellTabCols()
2241 {
2242 	DELETEZ( pLastCols );
2243     DELETEZ( pLastRows );
2244 }
2245 
2246 /*************************************************************************
2247 |*
2248 |*	SwFEShell::GetTblAttr(), SetTblAttr()
2249 |*
2250 |*	Ersterstellung		MA 09. Dec. 96
2251 |*	Letzte Aenderung	MA 09. Dec. 96
2252 |
2253 |*************************************************************************/
2254 void SwFEShell::GetTblAttr( SfxItemSet &rSet ) const
2255 {
2256 	SwFrm *pFrm = GetCurrFrm();
2257 	if( pFrm && pFrm->IsInTab() )
2258 		rSet.Put( pFrm->ImplFindTabFrm()->GetFmt()->GetAttrSet() );
2259 }
2260 
2261 void SwFEShell::SetTblAttr( const SfxItemSet &rNew )
2262 {
2263 	SwFrm *pFrm = GetCurrFrm();
2264 	if( pFrm && pFrm->IsInTab() )
2265 	{
2266 		SET_CURR_SHELL( this );
2267 		StartAllAction();
2268 		SwTabFrm *pTab = pFrm->FindTabFrm();
2269 		pTab->GetTable()->SetHTMLTableLayout( 0 );
2270 		GetDoc()->SetAttr( rNew, *pTab->GetFmt() );
2271 		GetDoc()->SetModified();
2272 		EndAllActionAndCall();
2273 	}
2274 }
2275 
2276 /** move cursor within a table into previous/next row (same column)
2277  * @param pShell cursor shell whose cursor is to be moved
2278  * @param bUp true: move up, false: move down
2279  * @returns true if successful
2280  */
2281 bool lcl_GoTableRow( SwCrsrShell* pShell, bool bUp )
2282 {
2283     ASSERT( pShell != NULL, "need shell" );
2284 
2285     bool bRet = false;
2286 
2287     SwPaM* pPam = pShell->GetCrsr();
2288     const SwStartNode* pTableBox = pPam->GetNode()->FindTableBoxStartNode();
2289     ASSERT( pTableBox != NULL, "I'm living in a box... NOT!" );
2290 
2291     // move cursor to start node of table box
2292     pPam->GetPoint()->nNode = pTableBox->GetIndex();
2293     pPam->GetPoint()->nContent.Assign( NULL, 0 );
2294     GoInCntnt( *pPam, fnMoveForward );
2295 
2296     // go to beginning end of table box
2297     SwPosSection fnPosSect = bUp ? fnSectionStart : fnSectionEnd;
2298     pShell->MoveSection( fnSectionCurr, fnPosSect );
2299 
2300     // and go up/down into next content
2301     bRet = bUp ? pShell->Up() : pShell->Down();
2302 
2303     return bRet;
2304 }
2305 
2306 	// aender eine  Zellenbreite/-Hoehe/Spaltenbreite/Zeilenhoehe
2307 sal_Bool SwFEShell::SetColRowWidthHeight( sal_uInt16 eType, sal_uInt16 nDiff )
2308 {
2309 	SwFrm *pFrm = GetCurrFrm();
2310 	if( !pFrm || !pFrm->IsInTab() )
2311 		return sal_False;
2312 
2313 	if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType &&
2314 		pFrm->ImplFindTabFrm()->GetTable()->ISA( SwDDETable ))
2315 	{
2316 		ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR,
2317 						ERRCODE_MSG_INFO | ERRCODE_BUTTON_DEF_OK );
2318 		return sal_False;
2319 	}
2320 
2321 	SET_CURR_SHELL( this );
2322 	StartAllAction();
2323 
2324 	do {
2325 		pFrm = pFrm->GetUpper();
2326 	} while( !pFrm->IsCellFrm() );
2327 
2328 	SwTabFrm *pTab = pFrm->ImplFindTabFrm();
2329 
2330 	// sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
2331 	// dann muss es jetzt auf absolute umgerechnet werden.
2332 	const SwFmtFrmSize& rTblFrmSz = pTab->GetFmt()->GetFrmSize();
2333     SWRECTFN( pTab )
2334     long nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
2335 	if( TBLVAR_CHGABS == pTab->GetTable()->GetTblChgMode() &&
2336 		( eType & nsTblChgWidthHeightType::WH_COL_LEFT || eType & nsTblChgWidthHeightType::WH_COL_RIGHT ) &&
2337         text::HoriOrientation::NONE == pTab->GetFmt()->GetHoriOrient().GetHoriOrient() &&
2338         nPrtWidth != rTblFrmSz.GetWidth() )
2339     {
2340         SwFmtFrmSize aSz( rTblFrmSz );
2341         aSz.SetWidth( pTab->Prt().Width() );
2342         pTab->GetFmt()->SetFmtAttr( aSz );
2343 	}
2344 
2345 	if( (eType & (nsTblChgWidthHeightType::WH_FLAG_BIGGER | nsTblChgWidthHeightType::WH_FLAG_INSDEL)) ==
2346 		(nsTblChgWidthHeightType::WH_FLAG_BIGGER | nsTblChgWidthHeightType::WH_FLAG_INSDEL) )
2347     {
2348         nDiff = sal_uInt16((pFrm->Frm().*fnRect->fnGetWidth)());
2349 
2350         // we must move the cursor outside the current cell before
2351         // deleting the cells.
2352         TblChgWidthHeightType eTmp =
2353             static_cast<TblChgWidthHeightType>( eType & 0xfff );
2354         switch( eTmp )
2355         {
2356         case nsTblChgWidthHeightType::WH_ROW_TOP:
2357             lcl_GoTableRow( this, true );
2358             break;
2359         case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
2360             lcl_GoTableRow( this, false );
2361             break;
2362         case nsTblChgWidthHeightType::WH_COL_LEFT:
2363             GoPrevCell();
2364             break;
2365         case nsTblChgWidthHeightType::WH_COL_RIGHT:
2366             GoNextCell();
2367             break;
2368         default:
2369             break;
2370         }
2371     }
2372 
2373 	SwTwips nLogDiff = nDiff;
2374 	nLogDiff *= pTab->GetFmt()->GetFrmSize().GetWidth();
2375     nLogDiff /= nPrtWidth;
2376 
2377     /** The cells are destroyed in here */
2378 	sal_Bool bRet = GetDoc()->SetColRowWidthHeight(
2379 					*(SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox(),
2380 					eType, nDiff, nLogDiff );
2381 
2382 	delete pLastCols, pLastCols = 0;
2383 	EndAllActionAndCall();
2384 
2385 	if( bRet && (eType & (nsTblChgWidthHeightType::WH_FLAG_BIGGER | nsTblChgWidthHeightType::WH_FLAG_INSDEL)) == nsTblChgWidthHeightType::WH_FLAG_INSDEL )
2386 	{
2387 		switch(eType & ~(nsTblChgWidthHeightType::WH_FLAG_BIGGER | nsTblChgWidthHeightType::WH_FLAG_INSDEL))
2388 		{
2389 		case nsTblChgWidthHeightType::WH_CELL_LEFT:
2390 		case nsTblChgWidthHeightType::WH_COL_LEFT:
2391 				GoPrevCell();
2392 				break;
2393 
2394 		case nsTblChgWidthHeightType::WH_CELL_RIGHT:
2395 		case nsTblChgWidthHeightType::WH_COL_RIGHT:
2396 				GoNextCell();
2397 				break;
2398 
2399 		case nsTblChgWidthHeightType::WH_CELL_TOP:
2400 		case nsTblChgWidthHeightType::WH_ROW_TOP:
2401                 lcl_GoTableRow( this, true );
2402 				break;
2403 
2404 		case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
2405 		case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
2406                 lcl_GoTableRow( this, false );
2407 				break;
2408 		}
2409 	}
2410 
2411 	return bRet;
2412 }
2413 
2414 sal_Bool lcl_IsFormulaSelBoxes( const SwTable& rTbl, const SwTblBoxFormula& rFml,
2415 							SwCellFrms& rCells )
2416 {
2417 	SwTblBoxFormula aTmp( rFml );
2418 	SwSelBoxes aBoxes;
2419 	for( sal_uInt16 nSelBoxes = aTmp.GetBoxesOfFormula( rTbl,aBoxes ); nSelBoxes; )
2420 	{
2421 		SwTableBox* pBox = aBoxes[ --nSelBoxes ];
2422 		sal_uInt16 i;
2423 		for( i = 0; i < rCells.Count(); ++i )
2424 			if( rCells[ i ]->GetTabBox() == pBox )
2425 				break;		// gefunden
2426 
2427 		if( i == rCells.Count() )
2428 			return sal_False;
2429 	}
2430 
2431 	return sal_True;
2432 }
2433 
2434 	// erfrage die Formel fuer die Autosumme
2435 sal_Bool SwFEShell::GetAutoSum( String& rFml ) const
2436 {
2437 	SwFrm *pFrm = GetCurrFrm();
2438 	SwTabFrm *pTab = pFrm ? pFrm->ImplFindTabFrm() : 0;
2439 	if( !pTab )
2440 		return sal_False;
2441 
2442 	rFml = String::CreateFromAscii( sCalc_Sum );
2443 
2444 	SwCellFrms aCells;
2445 	if( ::GetAutoSumSel( *this, aCells ))
2446 	{
2447 		sal_uInt16 nW = 0, nInsPos = 0;
2448 		for( sal_uInt16 n = aCells.Count(); n; )
2449 		{
2450 			SwCellFrm* pCFrm = aCells[ --n ];
2451 			sal_uInt16 nBoxW = pCFrm->GetTabBox()->IsFormulaOrValueBox();
2452 			if( !nBoxW )
2453 				break;
2454 
2455 			if( !nW )
2456 			{
2457 				if( USHRT_MAX == nBoxW )
2458 					continue;		// leere am Anfang ueberspringen
2459 
2460 				rFml += '(';
2461 				nInsPos = rFml.Len();
2462 
2463 				// Formeln nur wenn diese Boxen enthalten
2464 				if( RES_BOXATR_FORMULA == nBoxW &&
2465 					!::lcl_IsFormulaSelBoxes( *pTab->GetTable(), pCFrm->
2466 					GetTabBox()->GetFrmFmt()->GetTblBoxFormula(), aCells))
2467 				{
2468 					nW = RES_BOXATR_VALUE;
2469 					// alle vorhierigen Leere wieder mit aufnehmen !
2470 					for( sal_uInt16 i = aCells.Count(); n+1 < i; )
2471 					{
2472 						String sTmp( String::CreateFromAscii(
2473 								RTL_CONSTASCII_STRINGPARAM( "|<" )) );
2474 						sTmp += aCells[ --i ]->GetTabBox()->GetName();
2475 						sTmp += '>';
2476 						rFml.Insert( sTmp, nInsPos );
2477 					}
2478 				}
2479 				else
2480 					nW = nBoxW;
2481 			}
2482 			else if( RES_BOXATR_VALUE == nW )
2483 			{
2484 				// values werden gesucht, Value/Formel/Text gefunden -> aufn.
2485 				if( RES_BOXATR_FORMULA == nBoxW &&
2486 					::lcl_IsFormulaSelBoxes( *pTab->GetTable(), pCFrm->
2487 						GetTabBox()->GetFrmFmt()->GetTblBoxFormula(), aCells ))
2488 					break;
2489 				else if( USHRT_MAX != nBoxW )
2490 					rFml.Insert( cListDelim, nInsPos );
2491 				else
2492 					break;
2493 			}
2494 			else if( RES_BOXATR_FORMULA == nW )
2495 			{
2496 				// bei Formeln nur weiter suchen, wenn die akt. Formel auf
2497 				// alle Boxen verweist, die sich in der Selektion befinden
2498 				if( RES_BOXATR_FORMULA == nBoxW )
2499 				{
2500 					if( !::lcl_IsFormulaSelBoxes( *pTab->GetTable(), pCFrm->
2501 						GetTabBox()->GetFrmFmt()->GetTblBoxFormula(), aCells ))
2502 					{
2503 						// dann noch mal von vorne und nur die Values!
2504 
2505 						nW = RES_BOXATR_VALUE;
2506 						rFml.Erase( nInsPos );
2507 						// alle vorhierigen Leere wieder mit aufnehmen !
2508 						for( sal_uInt16 i = aCells.Count(); n+1 < i; )
2509 						{
2510 							String sTmp( String::CreateFromAscii(
2511 									RTL_CONSTASCII_STRINGPARAM( "|<" )) );
2512 							sTmp += aCells[ --i ]->GetTabBox()->GetName();
2513 							sTmp += '>';
2514 							rFml.Insert( sTmp, nInsPos );
2515 						}
2516 					}
2517 					else
2518 						rFml.Insert( cListDelim, nInsPos );
2519 				}
2520 				else if( USHRT_MAX == nBoxW )
2521 					break;
2522 				else
2523 					continue;		// diese Boxen ignorieren
2524 			}
2525 			else
2526 				// alles andere beendet die Schleife
2527 // evt. Texte noch zu lassen??
2528 				break;
2529 
2530 			String sTmp( '<' );
2531 			sTmp += pCFrm->GetTabBox()->GetName();
2532 			sTmp += '>';
2533 			rFml.Insert( sTmp, nInsPos );
2534 		}
2535 		if( nW )
2536 		{
2537 			rFml += ')';
2538 
2539 /*
2540 			// TabellenSelektion erzeugen??
2541 			SwTblBoxFormula aTmp( rFml );
2542 			SwSelBoxes aBoxes;
2543 			for( sal_uInt16 nSelBoxes = aTmp.GetBoxesOfFormula( rTbl,aBoxes );
2544 					nSelBoxes; )
2545 			{
2546 			}
2547 */
2548 		}
2549 	}
2550 
2551 	return sal_True;
2552 }
2553 /* -----------------------------22.08.2002 12:50------------------------------
2554 
2555  ---------------------------------------------------------------------------*/
2556 sal_Bool SwFEShell::IsTableRightToLeft() const
2557 {
2558 	SwFrm *pFrm = GetCurrFrm();
2559 	if( !pFrm || !pFrm->IsInTab() )
2560 		return sal_False;
2561 
2562     return pFrm->ImplFindTabFrm()->IsRightToLeft();
2563 }
2564 
2565 /* -----------------------------22.08.2002 12:50------------------------------
2566 
2567  ---------------------------------------------------------------------------*/
2568 sal_Bool SwFEShell::IsMouseTableRightToLeft(const Point &rPt) const
2569 {
2570     SwFrm *pFrm = (SwFrm *)GetBox( rPt );
2571     const SwTabFrm*  pTabFrm = pFrm ? pFrm->ImplFindTabFrm() : 0;
2572     ASSERT( pTabFrm, "Table not found" );
2573     return pTabFrm ? pTabFrm->IsRightToLeft() : sal_False;
2574 }
2575 
2576 /* -----------------------------11.02.2004 12:50------------------------------
2577 
2578  ---------------------------------------------------------------------------*/
2579 sal_Bool SwFEShell::IsTableVertical() const
2580 {
2581     SwFrm *pFrm = GetCurrFrm();
2582     if( !pFrm || !pFrm->IsInTab() )
2583         return sal_False;
2584 
2585     return pFrm->ImplFindTabFrm()->IsVertical();
2586 }
2587 
2588 
2589 
2590