xref: /trunk/main/sw/source/core/docnode/ndtbl.cxx (revision 870262e3)
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 
25 // MARKER(update_precomp.py): autogen include statement, do not remove
26 #include "precompiled_sw.hxx"
27 
28 #include <com/sun/star/chart2/XChartDocument.hpp>
29 #include <hintids.hxx>
30 #include <editeng/lrspitem.hxx>
31 #include <editeng/brkitem.hxx>
32 #include <editeng/protitem.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/shaditem.hxx>
35 #include <fmtfsize.hxx>
36 #include <fmtornt.hxx>
37 #include <fmtfordr.hxx>
38 #include <fmtpdsc.hxx>
39 #include <fmtanchr.hxx>
40 #include <fmtlsplt.hxx>
41 #include <frmatr.hxx>
42 #include <charatr.hxx>
43 #include <cellfrm.hxx>
44 #include <pagefrm.hxx>
45 #include <tabcol.hxx>
46 #include <doc.hxx>
47 #include <IDocumentUndoRedo.hxx>
48 #include <UndoManager.hxx>
49 #include <cntfrm.hxx>
50 #include <pam.hxx>
51 #include <swcrsr.hxx>
52 #include <viscrs.hxx>
53 #include <swtable.hxx>
54 #include <ndtxt.hxx>
55 #include <swundo.hxx>
56 #include <tblsel.hxx>
57 #include <fldbas.hxx>
58 #include <poolfmt.hxx>
59 #include <tabfrm.hxx>
60 #include <UndoCore.hxx>
61 #include <UndoRedline.hxx>
62 #include <UndoDelete.hxx>
63 #include <UndoTable.hxx>
64 #include <hints.hxx>
65 #include <tblafmt.hxx>
66 #include <swcache.hxx>
67 #include <ddefld.hxx>
68 #include <frminf.hxx>
69 #include <cellatr.hxx>
70 #include <swtblfmt.hxx>
71 #include <swddetbl.hxx>
72 #include <mvsave.hxx>
73 #include <docary.hxx>
74 #include <redline.hxx>
75 #include <rolbck.hxx>
76 #include <tblrwcl.hxx>
77 #include <editsh.hxx>
78 #include <txtfrm.hxx>
79 #include <ftnfrm.hxx>
80 #include <section.hxx>
81 #include <frmtool.hxx>
82 #include <node2lay.hxx>
83 #include <comcore.hrc>
84 #include "docsh.hxx"
85 #include <tabcol.hxx>
86 #include <unochart.hxx>
87 #include <node.hxx>
88 #include <ndtxt.hxx>
89 #include <map>
90 #include <algorithm>
91 #include <rootfrm.hxx>
92 #include <fldupde.hxx>
93 #include <switerator.hxx>
94 
95 #ifndef DBG_UTIL
96 #define CHECK_TABLE(t)
97 #else
98 #ifdef DEBUG
99 #define CHECK_TABLE(t) (t).CheckConsistency();
100 #else
101 #define CHECK_TABLE(t)
102 #endif
103 #endif
104 
105 
106 using namespace ::com::sun::star;
107 
108 // #i17764# delete table redlines when modifying the table structure?
109 // #define DEL_TABLE_REDLINES 1
110 
111 const sal_Unicode T2T_PARA = 0x0a;
112 
113 extern void ClearFEShellTabCols();
114 
115 // steht im gctable.cxx
116 extern sal_Bool lcl_GC_Line_Border( const SwTableLine*& , void* pPara );
117 
118 #ifdef DEL_TABLE_REDLINES
119 class lcl_DelRedlines
120 {
121 	SwDoc* pDoc;
122 public:
123 	lcl_DelRedlines( const SwTableNode& rNd, sal_Bool bCheckForOwnRedline );
124 	lcl_DelRedlines( SwPaM& rPam );
125 
~lcl_DelRedlines()126     ~lcl_DelRedlines() { pDoc->EndUndo(UNDO_EMPTY, NULL); }
127 };
128 
lcl_DelRedlines(SwPaM & rPam)129 lcl_DelRedlines::lcl_DelRedlines( SwPaM & rPam) : pDoc( rPam.GetDoc() )
130 {
131     pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
132 	if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
133 		pDoc->AcceptRedline( rPam, true );
134 }
135 #endif
136 
lcl_SetDfltBoxAttr(SwFrmFmt & rFmt,sal_uInt8 nId)137 void lcl_SetDfltBoxAttr( SwFrmFmt& rFmt, sal_uInt8 nId )
138 {
139 	sal_Bool bTop = sal_False, bBottom = sal_False, bLeft = sal_False, bRight = sal_False;
140 	switch ( nId )
141 	{
142 	case 0:	bTop = bBottom = bLeft = sal_True; 			break;
143 	case 1:	bTop = bBottom = bLeft = bRight = sal_True;	break;
144 	case 2:	bBottom = bLeft = sal_True; 				break;
145 	case 3: bBottom = bLeft = bRight = sal_True; 		break;
146 	}
147 
148     const sal_Bool bHTML = rFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE);
149 	Color aCol( bHTML ? COL_GRAY : COL_BLACK );
150 	SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
151 	if ( bHTML )
152 	{
153 		aLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
154 		aLine.SetInWidth ( DEF_DOUBLE_LINE7_IN  );
155 		aLine.SetDistance( DEF_DOUBLE_LINE7_DIST);
156 	}
157     SvxBoxItem aBox(RES_BOX); aBox.SetDistance( 55 );
158 	if ( bTop )
159 		aBox.SetLine( &aLine, BOX_LINE_TOP );
160 	if ( bBottom )
161 		aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
162 	if ( bLeft )
163 		aBox.SetLine( &aLine, BOX_LINE_LEFT );
164 	if ( bRight )
165 		aBox.SetLine( &aLine, BOX_LINE_RIGHT );
166     rFmt.SetFmtAttr( aBox );
167 }
168 
lcl_SetDfltBoxAttr(SwTableBox & rBox,SvPtrarr & rBoxFmtArr,sal_uInt8 nId,const SwTableAutoFmt * pAutoFmt=0)169 void lcl_SetDfltBoxAttr( SwTableBox& rBox, SvPtrarr &rBoxFmtArr, sal_uInt8 nId,
170 							const SwTableAutoFmt* pAutoFmt = 0 )
171 {
172 	SvPtrarr* pArr = (SvPtrarr*)rBoxFmtArr[ nId ];
173 	if( !pArr )
174 	{
175 		pArr = new SvPtrarr;
176 		rBoxFmtArr.Replace( pArr, nId );
177 	}
178 
179 	SwTableBoxFmt* pNewBoxFmt = 0;
180 	SwFrmFmt* pBoxFmt = rBox.GetFrmFmt();
181 	for( sal_uInt16 n = 0; n < pArr->Count(); n += 2 )
182 		if( pArr->GetObject( n ) == pBoxFmt )
183 		{
184 			pNewBoxFmt = (SwTableBoxFmt*)pArr->GetObject( n + 1 );
185 			break;
186 		}
187 
188 	if( !pNewBoxFmt )
189 	{
190 		SwDoc* pDoc = pBoxFmt->GetDoc();
191 		// das Format ist also nicht vorhanden, also neu erzeugen
192 		pNewBoxFmt = pDoc->MakeTableBoxFmt();
193         pNewBoxFmt->SetFmtAttr( pBoxFmt->GetAttrSet().Get( RES_FRM_SIZE ) );
194 
195 		if( pAutoFmt )
196 			pAutoFmt->UpdateToSet( nId, (SfxItemSet&)pNewBoxFmt->GetAttrSet(),
197 									SwTableAutoFmt::UPDATE_BOX,
198 									pDoc->GetNumberFormatter( sal_True ) );
199 		else
200 			::lcl_SetDfltBoxAttr( *pNewBoxFmt, nId );
201 
202 		void* p = pBoxFmt;
203 		pArr->Insert( p, pArr->Count() );
204 		p = pNewBoxFmt;
205 		pArr->Insert( p, pArr->Count() );
206 	}
207 	rBox.ChgFrmFmt( pNewBoxFmt );
208 }
209 
lcl_CreateDfltBoxFmt(SwDoc & rDoc,SvPtrarr & rBoxFmtArr,sal_uInt16 nCols,sal_uInt8 nId)210 SwTableBoxFmt *lcl_CreateDfltBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
211 									sal_uInt16 nCols, sal_uInt8 nId )
212 {
213 	if ( !rBoxFmtArr[nId] )
214 	{
215 		SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
216 		if( USHRT_MAX != nCols )
217             pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
218 											USHRT_MAX / nCols, 0 ));
219 		::lcl_SetDfltBoxAttr( *pBoxFmt, nId );
220 		rBoxFmtArr.Replace( pBoxFmt, nId );
221 	}
222 	return (SwTableBoxFmt*)rBoxFmtArr[nId];
223 }
224 
lcl_CreateAFmtBoxFmt(SwDoc & rDoc,SvPtrarr & rBoxFmtArr,const SwTableAutoFmt & rAutoFmt,sal_uInt16 nCols,sal_uInt8 nId)225 SwTableBoxFmt *lcl_CreateAFmtBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
226 									const SwTableAutoFmt& rAutoFmt,
227 									sal_uInt16 nCols, sal_uInt8 nId )
228 {
229 	if( !rBoxFmtArr[nId] )
230 	{
231 		SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
232 		rAutoFmt.UpdateToSet( nId, (SfxItemSet&)pBoxFmt->GetAttrSet(),
233 								SwTableAutoFmt::UPDATE_BOX,
234 								rDoc.GetNumberFormatter( sal_True ) );
235 		if( USHRT_MAX != nCols )
236             pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
237 											USHRT_MAX / nCols, 0 ));
238 		rBoxFmtArr.Replace( pBoxFmt, nId );
239 	}
240 	return (SwTableBoxFmt*)rBoxFmtArr[nId];
241 }
242 
IsIdxInTbl(const SwNodeIndex & rIdx)243 SwTableNode* SwDoc::IsIdxInTbl(const SwNodeIndex& rIdx)
244 {
245 	SwTableNode* pTableNd = 0;
246 	sal_uLong nIndex = rIdx.GetIndex();
247 	do {
248 		SwNode* pNd = (SwNode*)GetNodes()[ nIndex ]->StartOfSectionNode();
249 		if( 0 != ( pTableNd = pNd->GetTableNode() ) )
250 			break;
251 
252 		nIndex = pNd->GetIndex();
253 	} while ( nIndex );
254 	return pTableNd;
255 }
256 
257 
258 // --------------- einfuegen einer neuen Box --------------
259 
260 	// fuege in der Line, vor der InsPos eine neue Box ein.
261 
InsBoxen(SwTableNode * pTblNd,SwTableLine * pLine,SwTableBoxFmt * pBoxFmt,SwTxtFmtColl * pTxtColl,const SfxItemSet * pAutoAttr,sal_uInt16 nInsPos,sal_uInt16 nCnt)262 sal_Bool SwNodes::InsBoxen( SwTableNode* pTblNd,
263 						SwTableLine* pLine,
264 						SwTableBoxFmt* pBoxFmt,
265 						SwTxtFmtColl* pTxtColl,
266                         const SfxItemSet* pAutoAttr,
267 						sal_uInt16 nInsPos,
268 						sal_uInt16 nCnt )
269 {
270     if( !nCnt )
271 		return sal_False;
272 	ASSERT( pLine, "keine gueltige Zeile" );
273 
274 	// Index hinter die letzte Box der Line
275 	sal_uLong nIdxPos = 0;
276 	SwTableBox *pPrvBox = 0, *pNxtBox = 0;
277 	if( pLine->GetTabBoxes().Count() )
278 	{
279 		if( nInsPos < pLine->GetTabBoxes().Count() )
280 		{
281 			if( 0 == (pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable(),
282 							pLine->GetTabBoxes()[ nInsPos ] )))
283 				pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
284 		}
285 		else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable(),
286 							pLine->GetTabBoxes()[ nInsPos-1 ] )))
287 				pNxtBox = pLine->FindNextBox( pTblNd->GetTable() );
288 	}
289 	else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable() )))
290 		pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
291 
292 	if( !pPrvBox && !pNxtBox )
293 	{
294 		sal_Bool bSetIdxPos = sal_True;
295 		if( pTblNd->GetTable().GetTabLines().Count() && !nInsPos )
296 		{
297 			const SwTableLine* pTblLn = pLine;
298 			while( pTblLn->GetUpper() )
299 				pTblLn = pTblLn->GetUpper()->GetUpper();
300 
301 			if( pTblNd->GetTable().GetTabLines()[ 0 ] == pTblLn )
302 			{
303 				// also vor die erste Box der Tabelle
304 				while( ( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().Count() )
305 					pLine = pNxtBox->GetTabLines()[0];
306 				nIdxPos = pNxtBox->GetSttIdx();
307 				bSetIdxPos = sal_False;
308 			}
309 		}
310 		if( bSetIdxPos )
311 			// Tabelle ohne irgendeinen Inhalt oder am Ende, also vors Ende
312 			nIdxPos = pTblNd->EndOfSectionIndex();
313 	}
314 	else if( pNxtBox )			// es gibt einen Nachfolger
315 		nIdxPos = pNxtBox->GetSttIdx();
316 	else						// es gibt einen Vorgaenger
317 		nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1;
318 
319 	SwNodeIndex aEndIdx( *this, nIdxPos );
320 	for( sal_uInt16 n = 0; n < nCnt; ++n )
321 	{
322 		SwStartNode* pSttNd = new SwStartNode( aEndIdx, ND_STARTNODE,
323 												SwTableBoxStartNode );
324 		pSttNd->pStartOfSection = pTblNd;
325 		new SwEndNode( aEndIdx, *pSttNd );
326 
327 		pPrvBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
328 
329         SwTableBoxes & rTabBoxes = pLine->GetTabBoxes();
330         sal_uInt16 nRealInsPos = nInsPos + n;
331         if (nRealInsPos > rTabBoxes.Count())
332             nRealInsPos = rTabBoxes.Count();
333 
334         rTabBoxes.C40_INSERT( SwTableBox, pPrvBox, nRealInsPos );
335 
336 		//if( NO_NUMBERING == pTxtColl->GetOutlineLevel()//#outline level,zhaojianwei
337 		if( ! pTxtColl->IsAssignedToListLevelOfOutlineStyle()//<-end,zhaojianwei
338 //FEATURE::CONDCOLL
339 			&& RES_CONDTXTFMTCOLL != pTxtColl->Which()
340 //FEATURE::CONDCOLL
341 		)
342 			new SwTxtNode( SwNodeIndex( *pSttNd->EndOfSectionNode() ),
343 								pTxtColl, pAutoAttr );
344 		else
345 		{
346 			// Outline-Numerierung richtig behandeln !!!
347 			SwTxtNode* pTNd = new SwTxtNode(
348 							SwNodeIndex( *pSttNd->EndOfSectionNode() ),
349 							(SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl(),
350 							pAutoAttr );
351 			pTNd->ChgFmtColl( pTxtColl );
352 		}
353 	}
354 	return sal_True;
355 }
356 
357 // --------------- einfuegen einer neuen Tabelle --------------
358 
InsertTable(const SwInsertTableOptions & rInsTblOpts,const SwPosition & rPos,sal_uInt16 nRows,sal_uInt16 nCols,sal_Int16 eAdjust,const SwTableAutoFmt * pTAFmt,const SvUShorts * pColArr,sal_Bool bCalledFromShell,sal_Bool bNewModel)359 const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTblOpts,
360                                    const SwPosition& rPos, sal_uInt16 nRows,
361                                    sal_uInt16 nCols, sal_Int16 eAdjust,
362                                    const SwTableAutoFmt* pTAFmt,
363                                    const SvUShorts* pColArr,
364                                    sal_Bool bCalledFromShell,
365                                    sal_Bool bNewModel )
366 {
367     ASSERT( nRows, "Tabelle ohne Zeile?" );
368     ASSERT( nCols, "Tabelle ohne Spalten?" );
369 
370     {
371         // nicht in Fussnoten kopieren !!
372         if( rPos.nNode < GetNodes().GetEndOfInserts().GetIndex() &&
373             rPos.nNode >= GetNodes().GetEndOfInserts().StartOfSectionIndex() )
374             return 0;
375 
376         // sollte das ColumnArray die falsche Anzahl haben wird es ignoriert!
377         if( pColArr &&
378             (nCols + ( text::HoriOrientation::NONE == eAdjust ? 2 : 1 )) != pColArr->Count() )
379             pColArr = 0;
380     }
381 
382     String aTblName = GetUniqueTblName();
383 
384     if( GetIDocumentUndoRedo().DoesUndo() )
385     {
386         GetIDocumentUndoRedo().AppendUndo(
387             new SwUndoInsTbl( rPos, nCols, nRows, static_cast<sal_uInt16>(eAdjust),
388                                       rInsTblOpts, pTAFmt, pColArr,
389                                       aTblName));
390     }
391 
392     // fuege erstmal die Nodes ein
393     // hole das Auto-Format fuer die Tabelle
394     SwTxtFmtColl *pBodyColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE ),
395                  *pHeadColl = pBodyColl;
396 
397     sal_Bool bDfltBorders = 0 != ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER );
398 
399     if( (rInsTblOpts.mnInsMode & tabopts::HEADLINE) && (1 != nRows || !bDfltBorders) )
400         pHeadColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN );
401 
402     const sal_uInt16 nRowsToRepeat =
403             tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
404             rInsTblOpts.mnRowsToRepeat :
405             0;
406 
407     /* #106283# Save content node to extract FRAMEDIR from. */
408     const SwCntntNode * pCntntNd = rPos.nNode.GetNode().GetCntntNode();
409 
410     /* #109161# If we are called from a shell pass the attrset from
411         pCntntNd (aka the node the table is inserted at) thus causing
412         SwNodes::InsertTable to propagate an adjust item if
413         necessary. */
414     SwTableNode *pTblNd = GetNodes().InsertTable(
415         rPos.nNode,
416         nCols,
417         pBodyColl,
418         nRows,
419         nRowsToRepeat,
420         pHeadColl,
421         bCalledFromShell ? &pCntntNd->GetSwAttrSet() : 0 );
422 
423     // dann erstelle die Box/Line/Table-Struktur
424     SwTableLineFmt* pLineFmt = MakeTableLineFmt();
425     SwTableFmt* pTableFmt = MakeTblFrmFmt( aTblName, GetDfltFrmFmt() );
426 
427     /* #106283# If the node to insert the table at is a context node and has a
428        non-default FRAMEDIR propagate it to the table. */
429     if (pCntntNd)
430     {
431         const SwAttrSet & aNdSet = pCntntNd->GetSwAttrSet();
432         const SfxPoolItem *pItem = NULL;
433 
434         if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
435             && pItem != NULL)
436         {
437             pTableFmt->SetFmtAttr( *pItem );
438         }
439     }
440 
441     //Orientation am Fmt der Table setzen
442     pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
443     // alle Zeilen haben die Fill-Order von links nach rechts !
444     pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
445 
446     // die Tabelle bekommt USHRT_MAX als default SSize
447     SwTwips nWidth = USHRT_MAX;
448     if( pColArr )
449     {
450         sal_uInt16 nSttPos = (*pColArr)[ 0 ];
451         sal_uInt16 nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-1)];
452         if( text::HoriOrientation::NONE == eAdjust )
453         {
454             sal_uInt16 nFrmWidth = nLastPos;
455             nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-2)];
456             pTableFmt->SetFmtAttr( SvxLRSpaceItem( nSttPos, nFrmWidth - nLastPos, 0, 0, RES_LR_SPACE ) );
457         }
458         nWidth = nLastPos - nSttPos;
459     }
460     else if( nCols )
461     {
462         nWidth /= nCols;
463         nWidth *= nCols; // to avoid rounding problems
464     }
465     pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
466     if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
467         pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
468 
469     // verschiebe ggfs. die harten PageDesc/PageBreak Attribute:
470     SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]
471                             ->GetCntntNode();
472     if( pNextNd && pNextNd->HasSwAttrSet() )
473     {
474         const SfxItemSet* pNdSet = pNextNd->GetpSwAttrSet();
475         const SfxPoolItem *pItem;
476         if( SFX_ITEM_SET == pNdSet->GetItemState( RES_PAGEDESC, sal_False,
477             &pItem ) )
478         {
479             pTableFmt->SetFmtAttr( *pItem );
480             pNextNd->ResetAttr( RES_PAGEDESC );
481             pNdSet = pNextNd->GetpSwAttrSet();
482         }
483         if( pNdSet && SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, sal_False,
484              &pItem ) )
485         {
486             pTableFmt->SetFmtAttr( *pItem );
487             pNextNd->ResetAttr( RES_BREAK );
488         }
489     }
490 
491     SwTable * pNdTbl = &pTblNd->GetTable();
492     pNdTbl->RegisterToFormat( *pTableFmt );
493 
494     pNdTbl->SetRowsToRepeat( nRowsToRepeat );
495     pNdTbl->SetTableModel( bNewModel );
496 
497     SvPtrarr aBoxFmtArr( 0, 16 );
498     SwTableBoxFmt* pBoxFmt = 0;
499     if( !bDfltBorders && !pTAFmt )
500     {
501         pBoxFmt = MakeTableBoxFmt();
502         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nCols, 0 ));
503     }
504     else
505     {
506         const sal_uInt16 nBoxArrLen = pTAFmt ? 16 : 4;
507         for( sal_uInt16 i = 0; i < nBoxArrLen; ++i )
508             aBoxFmtArr.Insert( (void*)0, i );
509     }
510     // --> OD 2008-02-25 #refactorlists#
511 //    SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
512     SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
513     // <--
514 
515     SwNodeIndex aNdIdx( *pTblNd, 1 );   // auf den ersten Box-StartNode
516     SwTableLines& rLines = pNdTbl->GetTabLines();
517     for( sal_uInt16 n = 0; n < nRows; ++n )
518     {
519         SwTableLine* pLine = new SwTableLine( pLineFmt, nCols, 0 );
520         rLines.C40_INSERT( SwTableLine, pLine, n );
521         SwTableBoxes& rBoxes = pLine->GetTabBoxes();
522         for( sal_uInt16 i = 0; i < nCols; ++i )
523         {
524             SwTableBoxFmt *pBoxF;
525             if( pTAFmt )
526             {
527                 sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
528                                         ? 12 : (4 * (1 + ((n-1) & 1 )))));
529                 nId = nId + static_cast<sal_uInt8>( !i ? 0 :
530                             ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
531                 pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr, *pTAFmt,
532                                                 nCols, nId );
533 
534                 // ggfs. noch die Absatz/ZeichenAttribute setzen
535                 if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
536                 {
537                     aCharSet.ClearItem();
538                     pTAFmt->UpdateToSet( nId, aCharSet,
539                                         SwTableAutoFmt::UPDATE_CHAR, 0 );
540                     if( aCharSet.Count() )
541                         GetNodes()[ aNdIdx.GetIndex()+1 ]->GetCntntNode()->
542                             SetAttr( aCharSet );
543                 }
544             }
545             else if( bDfltBorders )
546             {
547                 sal_uInt8 nBoxId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
548                 pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr, nCols, nBoxId);
549             }
550             else
551                 pBoxF = pBoxFmt;
552 
553             // fuer AutoFormat bei der Eingabe: beim Einfuegen der Tabelle
554             // werden gleich die Spalten gesetzt. Im Array stehen die
555             // Positionen der Spalten!! (nicht deren Breite!)
556             if( pColArr )
557             {
558                 nWidth = (*pColArr)[ sal_uInt16(i + 1) ] - (*pColArr)[ i ];
559                 if( pBoxF->GetFrmSize().GetWidth() != nWidth )
560                 {
561                     if( pBoxF->GetDepends() )       // neues Format erzeugen!
562                     {
563                         SwTableBoxFmt *pNewFmt = MakeTableBoxFmt();
564                         *pNewFmt = *pBoxF;
565                         pBoxF = pNewFmt;
566                     }
567                     pBoxF->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
568                 }
569             }
570 
571             SwTableBox *pBox = new SwTableBox( pBoxF, aNdIdx, pLine);
572             rBoxes.C40_INSERT( SwTableBox, pBox, i );
573             aNdIdx += 3;        // StartNode, TextNode, EndNode  == 3 Nodes
574         }
575     }
576     // und Frms einfuegen.
577     GetNodes().GoNext( &aNdIdx );      // zum naechsten ContentNode
578     pTblNd->MakeFrms( &aNdIdx );
579 
580     if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
581     {
582         SwPaM aPam( *pTblNd->EndOfSectionNode(), *pTblNd, 1 );
583         if( IsRedlineOn() )
584             AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
585         else
586             SplitRedline( aPam );
587     }
588 
589     SetModified();
590     CHECK_TABLE( *pNdTbl );
591     return pNdTbl;
592 }
593 
InsertTable(const SwNodeIndex & rNdIdx,sal_uInt16 nBoxes,SwTxtFmtColl * pCntntTxtColl,sal_uInt16 nLines,sal_uInt16 nRepeat,SwTxtFmtColl * pHeadlineTxtColl,const SwAttrSet * pAttrSet)594 SwTableNode* SwNodes::InsertTable( const SwNodeIndex& rNdIdx,
595                                    sal_uInt16 nBoxes,
596                                    SwTxtFmtColl* pCntntTxtColl,
597                                    sal_uInt16 nLines,
598                                    sal_uInt16 nRepeat,
599 								   SwTxtFmtColl* pHeadlineTxtColl,
600                                    const SwAttrSet * pAttrSet)
601 {
602 	if( !nBoxes )
603 		return 0;
604 
605 	// wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
606 	if( !pHeadlineTxtColl || !nLines )
607 		pHeadlineTxtColl = pCntntTxtColl;
608 
609 	SwTableNode * pTblNd = new SwTableNode( rNdIdx );
610 	SwEndNode* pEndNd = new SwEndNode( rNdIdx, *pTblNd );
611 
612 	if( !nLines )		// fuer die FOR-Schleife
613 		++nLines;
614 
615 	SwNodeIndex aIdx( *pEndNd );
616 	SwTxtFmtColl* pTxtColl = pHeadlineTxtColl;
617 	for( sal_uInt16 nL = 0; nL < nLines; ++nL )
618 	{
619 		for( sal_uInt16 nB = 0; nB < nBoxes; ++nB )
620 		{
621 			SwStartNode* pSttNd = new SwStartNode( aIdx, ND_STARTNODE,
622 													SwTableBoxStartNode );
623 			pSttNd->pStartOfSection = pTblNd;
624 
625 			SwTxtNode * pTmpNd = new SwTxtNode( aIdx, pTxtColl );
626 
627             // --> FME 2006-04-13 #i60422# Propagate some more attributes.
628             // Adjustment was done for #109161#
629             const SfxPoolItem* pItem = NULL;
630             if ( NULL != pAttrSet )
631             {
632                 static const sal_uInt16 aPropagateItems[] = {
633                     RES_PARATR_ADJUST,
634                     RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
635                     RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE,
636                     RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, 0 };
637 
638                 const sal_uInt16* pIdx = aPropagateItems;
639                 while ( *pIdx != 0 )
640                 {
641                     if ( SFX_ITEM_SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) &&
642                          SFX_ITEM_SET == pAttrSet->GetItemState( *pIdx, sal_True, &pItem ) )
643                         static_cast<SwCntntNode *>(pTmpNd)->SetAttr(*pItem);
644                     ++pIdx;
645                 }
646             }
647             // <--
648 
649 			new SwEndNode( aIdx, *pSttNd );
650 		}
651 		if ( nL + 1 >= nRepeat )
652             pTxtColl = pCntntTxtColl;
653 	}
654 	return pTblNd;
655 }
656 
657 
658 //---------------- Text -> Tabelle -----------------------
659 
TextToTable(const SwInsertTableOptions & rInsTblOpts,const SwPaM & rRange,sal_Unicode cCh,sal_Int16 eAdjust,const SwTableAutoFmt * pTAFmt)660 const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTblOpts,
661                                    const SwPaM& rRange, sal_Unicode cCh,
662                                    sal_Int16 eAdjust,
663                                    const SwTableAutoFmt* pTAFmt )
664 {
665 	// pruefe ob in der Selection eine Tabelle liegt
666 	const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
667 	{
668 		sal_uLong nCnt = pStt->nNode.GetIndex();
669 		for( ; nCnt <= pEnd->nNode.GetIndex(); ++nCnt )
670 			if( !GetNodes()[ nCnt ]->IsTxtNode() )
671 				return 0;
672 	}
673 
674 	/* #106283# Save first node in the selection if it is a context node. */
675 	SwCntntNode * pSttCntntNd = pStt->nNode.GetNode().GetCntntNode();
676 
677 	SwPaM aOriginal( *pStt, *pEnd );
678 	pStt = aOriginal.GetMark();
679 	pEnd = aOriginal.GetPoint();
680 
681 #ifdef DEL_TABLE_REDLINES
682 	lcl_DelRedlines aDelRedl( aOriginal );
683 #endif
684 
685 	SwUndoTxtToTbl* pUndo = 0;
686     if( GetIDocumentUndoRedo().DoesUndo() )
687     {
688         GetIDocumentUndoRedo().StartUndo( UNDO_TEXTTOTABLE, NULL );
689         pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh,
690                     static_cast<sal_uInt16>(eAdjust), pTAFmt );
691         GetIDocumentUndoRedo().AppendUndo( pUndo );
692 
693 		// das Splitten vom TextNode nicht in die Undohistory aufnehmen
694         GetIDocumentUndoRedo().DoUndo( false );
695     }
696 
697 	::PaMCorrAbs( aOriginal, *pEnd );
698 
699 	// sorge dafuer, das der Bereich auf Node-Grenzen liegt
700 	SwNodeRange aRg( pStt->nNode, pEnd->nNode );
701 	if( pStt->nContent.GetIndex() )
702 		SplitNode( *pStt, false );
703 
704 	sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
705 	// nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
706 	if( bEndCntnt )
707 	{
708 		if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
709 			|| pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
710 		{
711 			SplitNode( *pEnd, false );
712 			((SwNodeIndex&)pEnd->nNode)--;
713 			((SwIndex&)pEnd->nContent).Assign(
714 								pEnd->nNode.GetNode().GetCntntNode(), 0 );
715 			// ein Node und am Ende ??
716 			if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
717 				aRg.aStart--;
718 		}
719 		else
720 			aRg.aEnd++;
721 	}
722 
723 
724 	if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
725 	{
726 		ASSERT( sal_False, "Kein Bereich" );
727 		aRg.aEnd++;
728 	}
729 
730 	// Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
731 	SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
732 
733     GetIDocumentUndoRedo().DoUndo( 0 != pUndo );
734 
735 	// dann erstelle die Box/Line/Table-Struktur
736 	SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
737 	SwTableLineFmt* pLineFmt = MakeTableLineFmt();
738 	SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
739 
740 	// alle Zeilen haben die Fill-Order von links nach rechts !
741     pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
742 	// die Tabelle bekommt USHRT_MAX als default SSize
743     pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
744     if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
745         pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
746 
747 	/* #106283# If the first node in the selection is a context node and if it
748        has an item FRAMEDIR set (no default) propagate the item to the
749        replacing table. */
750 	if (pSttCntntNd)
751 	{
752 		const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
753 		const SfxPoolItem *pItem = NULL;
754 
755 		if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
756 			&& pItem != NULL)
757 		{
758             pTableFmt->SetFmtAttr( *pItem );
759 		}
760 	}
761 
762     SwTableNode* pTblNd = GetNodes().TextToTable(
763             aRg, cCh, pTableFmt, pLineFmt, pBoxFmt,
764             GetTxtCollFromPool( RES_POOLCOLL_STANDARD ), pUndo );
765 
766 	SwTable * pNdTbl = &pTblNd->GetTable();
767 	ASSERT( pNdTbl, "kein Tabellen-Node angelegt."  )
768 
769     const sal_uInt16 nRowsToRepeat =
770             tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
771             rInsTblOpts.mnRowsToRepeat :
772             0;
773     pNdTbl->SetRowsToRepeat( nRowsToRepeat );
774 
775 	sal_Bool bUseBoxFmt = sal_False;
776 	if( !pBoxFmt->GetDepends() )
777 	{
778 		// die Formate an den Boxen haben schon die richtige Size, es darf
779 		// also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
780 		bUseBoxFmt = sal_True;
781         pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
782 		delete pBoxFmt;
783         eAdjust = text::HoriOrientation::NONE;
784 	}
785 
786 	//Orientation am Fmt der Table setzen
787     pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
788     pNdTbl->RegisterToFormat( *pTableFmt );
789 
790     if( pTAFmt || ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER) )
791 	{
792 		sal_uInt8 nBoxArrLen = pTAFmt ? 16 : 4;
793 		SvPtrarr aBoxFmtArr( nBoxArrLen, 0 );
794 		{
795 			for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
796 				aBoxFmtArr.Insert( (void*)0, i );
797 		}
798 
799         // --> OD 2008-02-25 #refactorlists#
800 //        SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
801         SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
802         // <--
803 		SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
804 
805         SwTableBoxFmt *pBoxF = 0;
806 		SwTableLines& rLines = pNdTbl->GetTabLines();
807 		sal_uInt16 nRows = rLines.Count();
808 		for( sal_uInt16 n = 0; n < nRows; ++n )
809 		{
810 			SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes();
811 			sal_uInt16 nCols = rBoxes.Count();
812 			for( sal_uInt16 i = 0; i < nCols; ++i )
813 			{
814 				SwTableBox* pBox = rBoxes[ i ];
815 				sal_Bool bChgSz = sal_False;
816 
817 				if( pTAFmt )
818 				{
819 					sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
820 											? 12 : (4 * (1 + ((n-1) & 1 )))));
821 					nId = nId + static_cast<sal_uInt8>(!i ? 0 :
822                                 ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
823 					if( bUseBoxFmt )
824 						::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId, pTAFmt );
825 					else
826 					{
827 						bChgSz = 0 == aBoxFmtArr[ nId ];
828 						pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr,
829 												*pTAFmt, USHRT_MAX, nId );
830 					}
831 
832 					// ggfs. noch die Absatz/ZeichenAttribute setzen
833 					if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
834 					{
835 						aCharSet.ClearItem();
836 						pTAFmt->UpdateToSet( nId, aCharSet,
837 											SwTableAutoFmt::UPDATE_CHAR, 0 );
838 						if( aCharSet.Count() )
839 						{
840 							sal_uLong nSttNd = pBox->GetSttIdx()+1;
841 							sal_uLong nEndNd = pBox->GetSttNd()->EndOfSectionIndex();
842 							for( ; nSttNd < nEndNd; ++nSttNd )
843 							{
844 								SwCntntNode* pNd = GetNodes()[ nSttNd ]->GetCntntNode();
845 								if( pNd )
846 								{
847 									if( pHistory )
848 									{
849 										SwRegHistory aReg( pNd, *pNd, pHistory );
850 										pNd->SetAttr( aCharSet );
851 									}
852 									else
853 										pNd->SetAttr( aCharSet );
854 								}
855 							}
856 						}
857 					}
858 				}
859 				else
860 				{
861 					sal_uInt8 nId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
862 					if( bUseBoxFmt )
863 						::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId );
864 					else
865 					{
866 						bChgSz = 0 == aBoxFmtArr[ nId ];
867 						pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr,
868 														USHRT_MAX, nId );
869 					}
870 				}
871 
872 				if( !bUseBoxFmt )
873 				{
874 					if( bChgSz )
875                         pBoxF->SetFmtAttr( pBox->GetFrmFmt()->GetFrmSize() );
876 					pBox->ChgFrmFmt( pBoxF );
877 				}
878 			}
879 		}
880 
881 		if( bUseBoxFmt )
882 		{
883 			for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
884 			{
885 				SvPtrarr* pArr = (SvPtrarr*)aBoxFmtArr[ i ];
886 				delete pArr;
887 			}
888 		}
889 	}
890 
891 	// JP 03.04.97: Inhalt der Boxen auf Zahlen abpruefen
892 	if( IsInsTblFormatNum() )
893 	{
894 		for( sal_uInt16 nBoxes = pNdTbl->GetTabSortBoxes().Count(); nBoxes; )
895 			ChkBoxNumFmt( *pNdTbl->GetTabSortBoxes()[ --nBoxes ], sal_False );
896 	}
897 
898 	sal_uLong nIdx = pTblNd->GetIndex();
899 	aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
900 
901 	{
902 		SwPaM& rTmp = (SwPaM&)rRange;	// Point immer an den Anfang
903 		rTmp.DeleteMark();
904 		rTmp.GetPoint()->nNode = *pTblNd;
905 		SwCntntNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode );
906 		rTmp.GetPoint()->nContent.Assign( pCNd, 0 );
907 	}
908 
909 	if( pUndo )
910     {
911         GetIDocumentUndoRedo().EndUndo( UNDO_TEXTTOTABLE, NULL );
912     }
913 
914 	SetModified();
915 	SetFieldsDirty(true, NULL, 0);
916 	return pNdTbl;
917 }
918 
TextToTable(const SwNodeRange & rRange,sal_Unicode cCh,SwTableFmt * pTblFmt,SwTableLineFmt * pLineFmt,SwTableBoxFmt * pBoxFmt,SwTxtFmtColl * pTxtColl,SwUndoTxtToTbl * pUndo)919 SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
920 									SwTableFmt* pTblFmt,
921 									SwTableLineFmt* pLineFmt,
922 									SwTableBoxFmt* pBoxFmt,
923 									SwTxtFmtColl* pTxtColl,
924 									SwUndoTxtToTbl* pUndo )
925 {
926 	if( rRange.aStart >= rRange.aEnd )
927 		return 0;
928 
929 	SwTableNode * pTblNd = new SwTableNode( rRange.aStart );
930 	new SwEndNode( rRange.aEnd, *pTblNd );
931 
932 	SwDoc* pDoc = GetDoc();
933 	SvUShorts aPosArr( 0, 16 );
934 	SwTable * pTable = &pTblNd->GetTable();
935 	SwTableLine* pLine;
936 	SwTableBox* pBox;
937 	sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
938 
939 	SwNodeIndex aSttIdx( *pTblNd, 1 );
940 	SwNodeIndex aEndIdx( rRange.aEnd, -1 );
941 	for( nLines = 0, nBoxes = 0;
942 		aSttIdx.GetIndex() < aEndIdx.GetIndex();
943 		aSttIdx += 2, nLines++, nBoxes = 0 )
944 	{
945 		SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
946 		ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
947 
948 		if( !nLines && 0x0b == cCh )
949 		{
950 			cCh = 0x09;
951 
952 			// JP 28.10.96: vom 1. Node die Positionen des Trenners besorgen,
953 			//				damit die Boxen entsprechend eingestellt werden
954 			SwTxtFrmInfo aFInfo( (SwTxtFrm*)pTxtNd->getLayoutFrm( pTxtNd->GetDoc()->GetCurrentLayout() ) );
955 			if( aFInfo.IsOneLine() )		// nur dann sinnvoll!
956 			{
957 				const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
958 				for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
959                 {
960 					if( *pTxt == cCh )
961 					{
962 						aPosArr.Insert( static_cast<sal_uInt16>(
963                                         aFInfo.GetCharPos( nChPos+1, sal_False )),
964 										aPosArr.Count() );
965 					}
966                 }
967 
968 				aPosArr.Insert( /*aFInfo.GetFrm()->Frm().Left() +*/
969                                 static_cast<sal_uInt16>(aFInfo.GetFrm()->IsVertical() ?
970                                 aFInfo.GetFrm()->Prt().Bottom() :
971                                 aFInfo.GetFrm()->Prt().Right()),
972 								aPosArr.Count() );
973 			}
974 		}
975 
976 		// die alten Frames loeschen, es werden neue erzeugt
977 		pTxtNd->DelFrms();
978 
979 		// PageBreaks/PageDesc/ColBreak rausschmeissen.
980         const SfxItemSet* pSet = pTxtNd->GetpSwAttrSet();
981 		if( pSet )
982 		{
983 // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
984 // erfolgen, denn sonst stehen sie falsch in der History !!!
985 //			SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
986 			const SfxPoolItem* pItem;
987 			if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
988 			{
989 				if( !nLines )
990                     pTblFmt->SetFmtAttr( *pItem );
991                 pTxtNd->ResetAttr( RES_BREAK );
992                 pSet = pTxtNd->GetpSwAttrSet();
993 			}
994 
995 			if( pSet && SFX_ITEM_SET == pSet->GetItemState(
996 				RES_PAGEDESC, sal_False, &pItem ) &&
997 				((SwFmtPageDesc*)pItem)->GetPageDesc() )
998 			{
999 				if( !nLines )
1000                     pTblFmt->SetFmtAttr( *pItem );
1001                 pTxtNd->ResetAttr( RES_PAGEDESC );
1002 			}
1003 		}
1004 
1005 		// setze den bei allen TextNode in der Tabelle den TableNode
1006 		// als StartNode
1007 		pTxtNd->pStartOfSection = pTblNd;
1008 
1009 		pLine = new SwTableLine( pLineFmt, 1, 0 );
1010 		pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
1011 
1012 		SwStartNode* pSttNd;
1013 		SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
1014 
1015 		SvULongs aBkmkArr( 15, 15 );
1016 		_SaveCntntIdx( pDoc, aSttIdx.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
1017 
1018 		const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
1019 
1020 		if( T2T_PARA != cCh )
1021 			for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
1022 				if( *pTxt == cCh )
1023 				{
1024 					aCntPos.nContent = nChPos;
1025                     SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( aCntPos );
1026 
1027 					if( aBkmkArr.Count() )
1028 						_RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
1029 											nChPos + 1 );
1030 
1031 					// Trennzeichen loeschen und SuchString korrigieren
1032                     pTxtNd->EraseText( aCntPos.nContent, 1 );
1033 					pTxt = pTxtNd->GetTxt().GetBuffer();
1034 					nChPos = 0;
1035 					--nChPos, --pTxt;           // for the ++ in the for loop !!!
1036 
1037 					// setze bei allen TextNodes in der Tabelle den TableNode
1038 					// als StartNode
1039 					const SwNodeIndex aTmpIdx( aCntPos.nNode, -1 );
1040 					pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
1041 												SwTableBoxStartNode );
1042 					new SwEndNode( aCntPos.nNode, *pSttNd );
1043 					pNewNd->pStartOfSection = pSttNd;
1044 
1045 					// Section der Box zuweisen
1046 					pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1047 					pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1048 				}
1049 
1050 		// und jetzt den letzten Teil-String
1051 		if( aBkmkArr.Count() )
1052 			_RestoreCntntIdx( aBkmkArr, *pTxtNd, pTxtNd->GetTxt().Len(),
1053 								pTxtNd->GetTxt().Len()+1 );
1054 
1055 		pSttNd = new SwStartNode( aCntPos.nNode, ND_STARTNODE, SwTableBoxStartNode );
1056 		const SwNodeIndex aTmpIdx( aCntPos.nNode, 1 );
1057 		new SwEndNode( aTmpIdx, *pSttNd  );
1058 		pTxtNd->pStartOfSection = pSttNd;
1059 
1060 		pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1061 		pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1062 		if( nMaxBoxes < nBoxes )
1063 			nMaxBoxes = nBoxes;
1064 	}
1065 
1066 	// die Tabelle ausgleichen, leere Sections einfuegen
1067 	sal_uInt16 n;
1068 
1069 	for( n = 0; n < pTable->GetTabLines().Count(); ++n )
1070 	{
1071 		SwTableLine* pCurrLine = pTable->GetTabLines()[ n ];
1072 		if( nMaxBoxes != ( nBoxes = pCurrLine->GetTabBoxes().Count() ))
1073 		{
1074 			InsBoxen( pTblNd, pCurrLine, pBoxFmt, pTxtColl, 0,
1075 						nBoxes, nMaxBoxes - nBoxes );
1076 
1077 			if( pUndo )
1078 				for( sal_uInt16 i = nBoxes; i < nMaxBoxes; ++i )
1079 					pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[ i ] );
1080 
1081 			// fehlen der 1. Line Boxen, dann kann man das Breiten Array
1082 			// vergessen!
1083 			if( !n )
1084 				aPosArr.Remove( 0, aPosArr.Count() );
1085 		}
1086 	}
1087 
1088 	if( aPosArr.Count() )
1089 	{
1090 		SwTableLines& rLns = pTable->GetTabLines();
1091 		sal_uInt16 nLastPos = 0;
1092 		for( n = 0; n < aPosArr.Count(); ++n )
1093 		{
1094 			SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
1095             pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1096 												aPosArr[ n ] - nLastPos ));
1097 			for( sal_uInt16 nTmpLine = 0; nTmpLine < rLns.Count(); ++nTmpLine )
1098 				//JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
1099 				//				von der rufenden Methode noch gebraucht wird!
1100 				pNewFmt->Add( rLns[ nTmpLine ]->GetTabBoxes()[ n ] );
1101 
1102 			nLastPos = aPosArr[ n ];
1103 		}
1104 
1105 		// damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
1106 		// Groesse nach "oben" transportieren.
1107 		ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
1108         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
1109 	}
1110 	else
1111         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
1112 
1113 	// das wars doch wohl ??
1114 	return pTblNd;
1115 }
1116 /*-- 18.05.2006 10:30:29---------------------------------------------------
1117 
1118   -----------------------------------------------------------------------*/
TextToTable(const std::vector<std::vector<SwNodeRange>> & rTableNodes)1119 const SwTable* SwDoc::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes )
1120 {
1121     /* #106283# Save first node in the selection if it is a content node. */
1122     SwCntntNode * pSttCntntNd = rTableNodes.begin()->begin()->aStart.GetNode().GetCntntNode();
1123 
1124     /**debug**/
1125 #if OSL_DEBUG_LEVEL > 1
1126     const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
1127     const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
1128     (void) rStartRange;
1129     (void) rEndRange;
1130 #endif
1131     /**debug**/
1132 
1133     //!!! not necessarily TextNodes !!!
1134     SwPaM aOriginal( rTableNodes.begin()->begin()->aStart, rTableNodes.rbegin()->rbegin()->aEnd );
1135     const SwPosition *pStt = aOriginal.GetMark();
1136     const SwPosition *pEnd = aOriginal.GetPoint();
1137 
1138 #ifdef DEL_TABLE_REDLINES
1139     lcl_DelRedlines aDelRedl( aOriginal );
1140 #endif
1141 
1142 //    SwUndoTxtToTbl* pUndo = 0;
1143     bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
1144     if (bUndo)
1145     {
1146         // das Splitten vom TextNode nicht in die Undohistory aufnehmen
1147         GetIDocumentUndoRedo().DoUndo(false);
1148     }
1149 
1150     ::PaMCorrAbs( aOriginal, *pEnd );
1151 
1152     // sorge dafuer, das der Bereich auf Node-Grenzen liegt
1153     SwNodeRange aRg( pStt->nNode, pEnd->nNode );
1154     if( pStt->nContent.GetIndex() )
1155         SplitNode( *pStt, false );
1156 
1157     sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
1158     // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
1159     if( bEndCntnt )
1160     {
1161         if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
1162             || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
1163         {
1164             SplitNode( *pEnd, false );
1165             ((SwNodeIndex&)pEnd->nNode)--;
1166             ((SwIndex&)pEnd->nContent).Assign(
1167                                 pEnd->nNode.GetNode().GetCntntNode(), 0 );
1168             // ein Node und am Ende ??
1169             if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
1170                 aRg.aStart--;
1171         }
1172         else
1173             aRg.aEnd++;
1174     }
1175 
1176 
1177     if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
1178     {
1179         ASSERT( sal_False, "Kein Bereich" );
1180         aRg.aEnd++;
1181     }
1182 
1183     // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
1184     SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
1185 
1186     GetIDocumentUndoRedo().DoUndo(bUndo);
1187 
1188     // dann erstelle die Box/Line/Table-Struktur
1189     SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
1190     SwTableLineFmt* pLineFmt = MakeTableLineFmt();
1191     SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
1192 
1193     // alle Zeilen haben die Fill-Order von links nach rechts !
1194     pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
1195     // die Tabelle bekommt USHRT_MAX als default SSize
1196     pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
1197 
1198     /* #106283# If the first node in the selection is a context node and if it
1199        has an item FRAMEDIR set (no default) propagate the item to the
1200        replacing table. */
1201     if (pSttCntntNd)
1202     {
1203         const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
1204         const SfxPoolItem *pItem = NULL;
1205 
1206         if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
1207             && pItem != NULL)
1208         {
1209             pTableFmt->SetFmtAttr( *pItem );
1210         }
1211     }
1212 
1213     SwTableNode* pTblNd = GetNodes().TextToTable(
1214             rTableNodes, pTableFmt, pLineFmt, pBoxFmt,
1215             GetTxtCollFromPool( RES_POOLCOLL_STANDARD )/*, pUndo*/ );
1216 
1217     SwTable * pNdTbl = &pTblNd->GetTable();
1218     ASSERT( pNdTbl, "kein Tabellen-Node angelegt."  )
1219     pNdTbl->RegisterToFormat( *pTableFmt );
1220 
1221     sal_Bool bUseBoxFmt = sal_False;
1222     if( !pBoxFmt->GetDepends() )
1223     {
1224         // die Formate an den Boxen haben schon die richtige Size, es darf
1225         // also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
1226         bUseBoxFmt = sal_True;
1227         pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
1228         delete pBoxFmt;
1229     }
1230 
1231     sal_uLong nIdx = pTblNd->GetIndex();
1232     aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
1233 
1234     SetModified();
1235     SetFieldsDirty( true, NULL, 0 );
1236     return pNdTbl;
1237 }
1238 
ExpandRangeForTableBox(const SwNodeRange & rRange)1239 SwNodeRange * SwNodes::ExpandRangeForTableBox(const SwNodeRange & rRange)
1240 {
1241     SwNodeRange * pResult = NULL;
1242     bool bChanged = false;
1243 
1244 	SwNodeIndex aNewStart = rRange.aStart;
1245 	SwNodeIndex aNewEnd = rRange.aEnd;
1246 
1247 	SwNodeIndex aEndIndex = rRange.aEnd;
1248 	SwNodeIndex aIndex = rRange.aStart;
1249 
1250 	while (aIndex < aEndIndex)
1251 	{
1252 		SwNode& rNode = aIndex.GetNode();
1253 
1254 		if (rNode.IsStartNode())
1255 		{
1256             // advance aIndex to the end node of this start node
1257             SwNode * pEndNode = rNode.EndOfSectionNode();
1258             aIndex = *pEndNode;
1259 
1260             if (aIndex > aNewEnd)
1261             {
1262                 aNewEnd = aIndex;
1263                 bChanged = true;
1264             }
1265 		}
1266 		else if (rNode.IsEndNode())
1267 		{
1268             SwNode * pStartNode = rNode.StartOfSectionNode();
1269 			SwNodeIndex aStartIndex = *pStartNode;
1270 
1271 			if (aStartIndex < aNewStart)
1272             {
1273 				aNewStart = aStartIndex;
1274                 bChanged = true;
1275             }
1276 		}
1277 
1278 		if (aIndex < aEndIndex)
1279 			++aIndex;
1280 	}
1281 
1282     SwNode * pNode = &aIndex.GetNode();
1283     while (pNode->IsEndNode())
1284     {
1285         SwNode * pStartNode = pNode->StartOfSectionNode();
1286         SwNodeIndex aStartIndex(*pStartNode);
1287         aNewStart = aStartIndex;
1288         aNewEnd = aIndex;
1289         bChanged = true;
1290 
1291         ++aIndex;
1292         pNode = &aIndex.GetNode();
1293     }
1294 
1295     if (bChanged)
1296         pResult = new SwNodeRange(aNewStart, aNewEnd);
1297 
1298     return pResult;
1299 }
1300 
1301 /*-- 18.05.2006 08:23:28---------------------------------------------------
1302 
1303   -----------------------------------------------------------------------*/
TextToTable(const SwNodes::TableRanges_t & rTableNodes,SwTableFmt * pTblFmt,SwTableLineFmt * pLineFmt,SwTableBoxFmt * pBoxFmt,SwTxtFmtColl *)1304 SwTableNode* SwNodes::TextToTable( const SwNodes::TableRanges_t & rTableNodes,
1305                                     SwTableFmt* pTblFmt,
1306                                     SwTableLineFmt* pLineFmt,
1307                                     SwTableBoxFmt* pBoxFmt,
1308                                     SwTxtFmtColl* /*pTxtColl*/  /*, SwUndo... pUndo*/  )
1309 {
1310     if( !rTableNodes.size() )
1311         return 0;
1312 
1313     SwTableNode * pTblNd = new SwTableNode( rTableNodes.begin()->begin()->aStart );
1314     //insert the end node after the last text node
1315    SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd );
1316    ++aInsertIndex;
1317 
1318    //!! owner ship will be transferred in c-tor to SwNodes array.
1319    //!! Thus no real problem here...
1320    new SwEndNode( aInsertIndex, *pTblNd );
1321 
1322 #if OSL_DEBUG_LEVEL > 1
1323     /**debug**/
1324     const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
1325     const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
1326     (void) rStartRange;
1327     (void) rEndRange;
1328     /**debug**/
1329 #endif
1330 
1331     SwDoc* pDoc = GetDoc();
1332     SvUShorts aPosArr( 0, 16 );
1333     SwTable * pTable = &pTblNd->GetTable();
1334     SwTableLine* pLine;
1335     SwTableBox* pBox;
1336     sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
1337 
1338 //    SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
1339 
1340 
1341     SwNodeIndex aNodeIndex = rTableNodes.begin()->begin()->aStart;
1342     // delete frames of all contained content nodes
1343     for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines )
1344     {
1345         SwNode& rNode = aNodeIndex.GetNode();
1346         if( rNode.IsCntntNode() )
1347         {
1348             static_cast<SwCntntNode&>(rNode).DelFrms();
1349             if(rNode.IsTxtNode())
1350             {
1351                 SwTxtNode& rTxtNode = static_cast<SwTxtNode&>(rNode);
1352                 // setze den bei allen TextNode in der Tabelle den TableNode
1353                 // als StartNode
1354 // FIXME: this is setting wrong node StartOfSections in nested tables.
1355 //                rTxtNode.pStartOfSection = pTblNd;
1356                 // remove PageBreaks/PageDesc/ColBreak
1357                 const SwAttrSet* pSet = rTxtNode.GetpSwAttrSet();
1358                 if( pSet )
1359                 {
1360         // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
1361         // erfolgen, denn sonst stehen sie falsch in der History !!!
1362         //          SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
1363                     const SfxPoolItem* pItem;
1364                     if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
1365                     {
1366                         if( !nLines )
1367                             pTblFmt->SetFmtAttr( *pItem );
1368                         rTxtNode.ResetAttr( RES_BREAK );
1369                         pSet = rTxtNode.GetpSwAttrSet();
1370                     }
1371 
1372                     if( pSet && SFX_ITEM_SET == pSet->GetItemState(
1373                         RES_PAGEDESC, sal_False, &pItem ) &&
1374                         ((SwFmtPageDesc*)pItem)->GetPageDesc() )
1375                     {
1376                         if( !nLines )
1377                             pTblFmt->SetFmtAttr( *pItem );
1378                         rTxtNode.ResetAttr( RES_PAGEDESC );
1379                     }
1380                 }
1381             }
1382         }
1383     }
1384 
1385 //    SwNodeIndex aSttIdx( *pTblNd, 1 );
1386 //    SwNodeIndex aEndIdx( rlNodes.rbegin()->aEnd, -1 );
1387     std::vector<std::vector < SwNodeRange > >::const_iterator aRowIter = rTableNodes.begin();
1388     for( nLines = 0, nBoxes = 0;
1389         aRowIter != rTableNodes.end();
1390         ++aRowIter, /*aSttIdx += 2, */nLines++, nBoxes = 0 )
1391     {
1392 //        SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
1393 //        ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
1394 
1395         pLine = new SwTableLine( pLineFmt, 1, 0 );
1396         pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
1397 
1398 //        SwStartNode* pSttNd;
1399 //        SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
1400 
1401         std::vector< SwNodeRange >::const_iterator aCellIter = aRowIter->begin();
1402 //        SvULongs aBkmkArr( 15, 15 );
1403 //        _SaveCntntIdx( pDoc, aCellIter->aStart.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
1404 //        const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
1405 
1406         for( ; aCellIter != aRowIter->end(); ++aCellIter )
1407         {
1408 //            aCellIter->aStart aCellIter->aEnd
1409 //                aCntPos.nContent = nChPos;
1410 //                SwCntntNode* pNewNd = pTxtNd->SplitNode( aCntPos );
1411 
1412 //        auch f?rs undo?
1413 //                if( aBkmkArr.Count() )
1414 //                    _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
1415 //                                        nChPos + 1 );
1416 
1417                 const SwNodeIndex aTmpIdx( aCellIter->aStart, 0 );
1418 
1419                SwNodeIndex aCellEndIdx(aCellIter->aEnd);
1420                ++aCellEndIdx;
1421                SwStartNode* pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
1422                                             SwTableBoxStartNode );
1423                 new SwEndNode( aCellEndIdx, *pSttNd );
1424                 //set the start node on all node of the current cell
1425                 SwNodeIndex aCellNodeIdx = aCellIter->aStart;
1426                 for(;aCellNodeIdx <= aCellIter->aEnd; ++aCellNodeIdx )
1427                 {
1428                     aCellNodeIdx.GetNode().pStartOfSection = pSttNd;
1429                     //skip start/end node pairs
1430                     if( aCellNodeIdx.GetNode().IsStartNode() )
1431                         aCellNodeIdx = SwNodeIndex( *aCellNodeIdx.GetNode().EndOfSectionNode() );
1432                 }
1433 
1434                 // Section der Box zuweisen
1435                 pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1436                 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1437         }
1438         if( nMaxBoxes < nBoxes )
1439             nMaxBoxes = nBoxes;
1440     }
1441 
1442     // die Tabelle ausgleichen, leere Sections einfuegen
1443     sal_uInt16 n;
1444 
1445     if( aPosArr.Count() )
1446     {
1447         SwTableLines& rLns = pTable->GetTabLines();
1448         sal_uInt16 nLastPos = 0;
1449         for( n = 0; n < aPosArr.Count(); ++n )
1450         {
1451             SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
1452             pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1453                                                 aPosArr[ n ] - nLastPos ));
1454             for( sal_uInt16 nLines2 = 0; nLines2 < rLns.Count(); ++nLines2 )
1455                 //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
1456                 //              von der rufenden Methode noch gebraucht wird!
1457                 pNewFmt->Add( rLns[ nLines2 ]->GetTabBoxes()[ n ] );
1458 
1459             nLastPos = aPosArr[ n ];
1460         }
1461 
1462         // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
1463         // Groesse nach "oben" transportieren.
1464         ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
1465         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
1466     }
1467     else
1468         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
1469 
1470     // das wars doch wohl ??
1471     return pTblNd;
1472 }
1473 
1474 
1475 //---------------- Tabelle -> Text -----------------------
1476 
1477 
TableToText(const SwTableNode * pTblNd,sal_Unicode cCh)1478 sal_Bool SwDoc::TableToText( const SwTableNode* pTblNd, sal_Unicode cCh )
1479 {
1480 	if( !pTblNd )
1481 		return sal_False;
1482 
1483     // --> FME 2004-09-28 #i34471#
1484     // If this is trigged by SwUndoTblToTxt::Repeat() nobody ever deleted
1485     // the table cursor.
1486     SwEditShell* pESh = GetEditShell();
1487     if( pESh && pESh->IsTableMode() )
1488         pESh->ClearMark();
1489     // <--
1490 
1491 #ifdef DEL_TABLE_REDLINES
1492     lcl_DelRedlines aDelRedl( *pTblNd, sal_False );
1493 #endif
1494 
1495 	SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode() );
1496 	SwUndoTblToTxt* pUndo = 0;
1497 	SwNodeRange* pUndoRg = 0;
1498     if (GetIDocumentUndoRedo().DoesUndo())
1499     {
1500         GetIDocumentUndoRedo().ClearRedo();
1501 		pUndoRg = new SwNodeRange( aRg.aStart, -1, aRg.aEnd, +1 );
1502 		pUndo = new SwUndoTblToTxt( pTblNd->GetTable(), cCh );
1503 	}
1504 
1505 	SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1506 	aMsgHnt.eFlags = TBL_BOXNAME;
1507 	UpdateTblFlds( &aMsgHnt );
1508 
1509 	sal_Bool bRet = GetNodes().TableToText( aRg, cCh, pUndo );
1510 	if( pUndoRg )
1511 	{
1512 		pUndoRg->aStart++;
1513 		pUndoRg->aEnd--;
1514 		pUndo->SetRange( *pUndoRg );
1515         GetIDocumentUndoRedo().AppendUndo(pUndo);
1516 		delete pUndoRg;
1517 	}
1518 
1519 	if( bRet )
1520 		SetModified();
1521 
1522 	return bRet;
1523 }
1524 
1525 // -- benutze die ForEach Methode vom PtrArray um aus einer Tabelle wieder
1526 //		Text zuerzeugen. (Die Boxen koennen auch noch Lines enthalten !!)
1527 struct _DelTabPara
1528 {
1529 	SwTxtNode* pLastNd;
1530 	SwNodes& rNds;
1531 	SwUndoTblToTxt* pUndo;
1532 	sal_Unicode cCh;
1533 
_DelTabPara_DelTabPara1534 	_DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTblToTxt* pU ) :
1535 		pLastNd(0), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {}
_DelTabPara_DelTabPara1536 	_DelTabPara( const _DelTabPara& rPara ) :
1537 		pLastNd(rPara.pLastNd), rNds( rPara.rNds ),
1538 		pUndo( rPara.pUndo ), cCh( rPara.cCh ) {}
1539 };
1540 
1541 // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
1542 // koennen.
1543 sal_Bool lcl_DelBox( const SwTableBox*&, void *pPara );
1544 
lcl_DelLine(const SwTableLine * & rpLine,void * pPara)1545 sal_Bool lcl_DelLine( const SwTableLine*& rpLine, void* pPara )
1546 {
1547 	ASSERT( pPara, "die Parameter fehlen" );
1548 	_DelTabPara aPara( *(_DelTabPara*)pPara );
1549 	((SwTableLine*&)rpLine)->GetTabBoxes().ForEach( &lcl_DelBox, &aPara );
1550 	if( rpLine->GetUpper() )		// gibt es noch eine uebergeordnete Box ??
1551 		// dann gebe den letzten TextNode zurueck
1552 		((_DelTabPara*)pPara)->pLastNd = aPara.pLastNd;
1553 	return sal_True;
1554 }
1555 
1556 
lcl_DelBox(const SwTableBox * & rpBox,void * pPara)1557 sal_Bool lcl_DelBox( const SwTableBox*& rpBox, void* pPara )
1558 {
1559 	ASSERT( pPara, "die Parameter fehlen" );
1560 
1561 	// loesche erstmal die Lines der Box
1562 	_DelTabPara* pDelPara = (_DelTabPara*)pPara;
1563 	if( rpBox->GetTabLines().Count() )
1564 		((SwTableBox*&)rpBox)->GetTabLines().ForEach( &lcl_DelLine, pDelPara );
1565 	else
1566 	{
1567 		SwDoc* pDoc = pDelPara->rNds.GetDoc();
1568 		SwNodeRange aDelRg( *rpBox->GetSttNd(), 0,
1569 							*rpBox->GetSttNd()->EndOfSectionNode() );
1570 		// loesche die Section
1571 		pDelPara->rNds.SectionUp( &aDelRg );
1572 		const SwTxtNode* pCurTxtNd;
1573 		if( T2T_PARA != pDelPara->cCh && pDelPara->pLastNd &&
1574 			0 != ( pCurTxtNd = aDelRg.aStart.GetNode().GetTxtNode() ))
1575 		{
1576 			// Join the current text node with the last from the previous box if possible
1577 			sal_uLong nNdIdx = aDelRg.aStart.GetIndex();
1578 			aDelRg.aStart--;
1579 			if( pDelPara->pLastNd == &aDelRg.aStart.GetNode() )
1580 			{
1581                 // Inserting the seperator
1582                 SwIndex aCntIdx( pDelPara->pLastNd, pDelPara->pLastNd->GetTxt().Len());
1583                 pDelPara->pLastNd->InsertText( pDelPara->cCh, aCntIdx,
1584                     IDocumentContentOperations::INS_EMPTYEXPAND );
1585 				if( pDelPara->pUndo )
1586 					pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex(),
1587 												aCntIdx.GetIndex() );
1588 
1589 				SvULongs aBkmkArr( 4, 4 );
1590 				xub_StrLen nOldTxtLen = aCntIdx.GetIndex();
1591 				_SaveCntntIdx( pDoc, nNdIdx, pCurTxtNd->GetTxt().Len(),
1592 								aBkmkArr );
1593 
1594 				pDelPara->pLastNd->JoinNext();
1595 
1596 				if( aBkmkArr.Count() )
1597 					_RestoreCntntIdx( pDoc, aBkmkArr,
1598 										pDelPara->pLastNd->GetIndex(),
1599 										nOldTxtLen );
1600 			}
1601 			else if( pDelPara->pUndo )
1602             {
1603                 aDelRg.aStart++;
1604 				pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex() );
1605             }
1606 		}
1607 		else if( pDelPara->pUndo )
1608 			pDelPara->pUndo->AddBoxPos( *pDoc, aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1609 		aDelRg.aEnd--;
1610 		pDelPara->pLastNd = aDelRg.aEnd.GetNode().GetTxtNode();
1611 
1612 		//JP 03.04.97: die Ausrichtung der ZahlenFormatierung auf
1613 		//				keinen Fall uebernehmen
1614         if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() )
1615 			pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST );
1616 	}
1617 	return sal_True;
1618 }
1619 
1620 
TableToText(const SwNodeRange & rRange,sal_Unicode cCh,SwUndoTblToTxt * pUndo)1621 sal_Bool SwNodes::TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
1622 							SwUndoTblToTxt* pUndo )
1623 {
1624 	// ist eine Tabelle selektiert ?
1625 	SwTableNode* pTblNd;
1626 	if( rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex() ||
1627         0 == ( pTblNd = rRange.aStart.GetNode().GetTableNode()) ||
1628 		&rRange.aEnd.GetNode() != pTblNd->EndOfSectionNode() )
1629 		return sal_False;
1630 
1631 	// stand die Tabelle ganz alleine in einer Section ?
1632 	// dann ueber den Upper der Tabelle die Frames anlegen
1633 	SwNode2Layout* pNode2Layout = 0;
1634 	SwNodeIndex aFrmIdx( rRange.aStart );
1635 	SwNode* pFrmNd = FindPrvNxtFrmNode( aFrmIdx, &rRange.aEnd.GetNode() );
1636 	if( !pFrmNd )
1637 		// dann sammel mal alle Uppers ein
1638 		pNode2Layout = new SwNode2Layout( *pTblNd );
1639 
1640 	// loesche schon mal die Frames
1641 	pTblNd->DelFrms();
1642 
1643 	// dann "loeschen" die Tabellen und fasse alle Lines/Boxen zusammen
1644 	_DelTabPara aDelPara( *this, cCh, pUndo );
1645 	pTblNd->pTable->GetTabLines().ForEach( &lcl_DelLine, &aDelPara );
1646 
1647 	// jetzt ist aus jeder TableLine ein TextNode mit dem entsprechenden
1648 	// Trenner erzeugt worden. Es braucht nur noch die Table-Section
1649 	// geloescht und fuer die neuen TextNode die Frames erzeugt werden.
1650 	SwNodeRange aDelRg( rRange.aStart, rRange.aEnd );
1651 
1652 	// JP 14.01.97: hat die Tabelle PageDesc-/Break-Attribute? Dann in den
1653 	//				ersten TextNode uebernehmen
1654 	{
1655 // was ist mit UNDO???
1656 		const SfxItemSet& rTblSet = pTblNd->pTable->GetFrmFmt()->GetAttrSet();
1657 		const SfxPoolItem *pBreak, *pDesc;
1658 		if( SFX_ITEM_SET != rTblSet.GetItemState( RES_PAGEDESC, sal_False, &pDesc ))
1659 			pDesc = 0;
1660 		if( SFX_ITEM_SET != rTblSet.GetItemState( RES_BREAK, sal_False, &pBreak ))
1661 			pBreak = 0;
1662 
1663 		if( pBreak || pDesc )
1664 		{
1665 			SwNodeIndex aIdx( *pTblNd  );
1666 			SwCntntNode* pCNd = GoNext( &aIdx );
1667 			if( pBreak )
1668 				pCNd->SetAttr( *pBreak );
1669 			if( pDesc )
1670 				pCNd->SetAttr( *pDesc );
1671 		}
1672 	}
1673 
1674 	SectionUp( &aDelRg );		// loesche die Section und damit die Tabelle
1675     // #i28006#
1676     sal_uLong nStt = aDelRg.aStart.GetIndex(), nEnd = aDelRg.aEnd.GetIndex();
1677 	if( !pFrmNd )
1678 	{
1679 		pNode2Layout->RestoreUpperFrms( *this,
1680 						aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1681 		delete pNode2Layout;
1682 	}
1683 	else
1684 	{
1685 		SwCntntNode *pCNd;
1686 		SwSectionNode *pSNd;
1687 		while( aDelRg.aStart.GetIndex() < nEnd )
1688 		{
1689 			if( 0 != ( pCNd = aDelRg.aStart.GetNode().GetCntntNode()))
1690 			{
1691 				if( pFrmNd->IsCntntNode() )
1692 					((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd );
1693 				else if( pFrmNd->IsTableNode() )
1694 					((SwTableNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
1695 				else if( pFrmNd->IsSectionNode() )
1696 					((SwSectionNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
1697 				pFrmNd = pCNd;
1698 			}
1699 			else if( 0 != ( pSNd = aDelRg.aStart.GetNode().GetSectionNode()))
1700 			{
1701 				if( !pSNd->GetSection().IsHidden() && !pSNd->IsCntntHidden() )
1702 				{
1703 					pSNd->MakeFrms( &aFrmIdx, &aDelRg.aEnd );
1704 					pFrmNd = pSNd;
1705 					break;
1706 				}
1707 				aDelRg.aStart = *pSNd->EndOfSectionNode();
1708 			}
1709 			aDelRg.aStart++;
1710 		}
1711     }
1712 
1713     // #i28006# Fly frames have to be restored even if the table was
1714     // #alone in the section
1715     const SwSpzFrmFmts& rFlyArr = *GetDoc()->GetSpzFrmFmts();
1716     for( sal_uInt16 n = 0; n < rFlyArr.Count(); ++n )
1717     {
1718         SwFrmFmt *const pFmt = (SwFrmFmt*)rFlyArr[n];
1719         const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
1720         SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
1721         if (pAPos &&
1722             ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
1723              (FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
1724             nStt <= pAPos->nNode.GetIndex() &&
1725             pAPos->nNode.GetIndex() < nEnd )
1726         {
1727             pFmt->MakeFrms();
1728         }
1729 	}
1730 
1731 	return sal_True;
1732 }
1733 
1734 
1735 // ----- einfuegen von Spalten/Zeilen ------------------------
1736 
InsertCol(const SwCursor & rCursor,sal_uInt16 nCnt,sal_Bool bBehind)1737 sal_Bool SwDoc::InsertCol( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
1738 {
1739 	if( !::CheckSplitCells( rCursor, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) )
1740 		return sal_False;
1741 
1742 	// lasse ueber das Layout die Boxen suchen
1743 	SwSelBoxes aBoxes;
1744 	::GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
1745 
1746 	sal_Bool bRet = sal_False;
1747 	if( aBoxes.Count() )
1748 		bRet = InsertCol( aBoxes, nCnt, bBehind );
1749 	return bRet;
1750 }
1751 
InsertCol(const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bBehind)1752 sal_Bool SwDoc::InsertCol( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
1753 {
1754 	// uebers SwDoc fuer Undo !!
1755 	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
1756 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1757 	if( !pTblNd )
1758 		return sal_False;
1759 
1760 	SwTable& rTbl = pTblNd->GetTable();
1761 	if( rTbl.ISA( SwDDETable ))
1762 		return sal_False;
1763 
1764 #ifdef DEL_TABLE_REDLINES
1765 	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
1766 #endif
1767 
1768 	SwTableSortBoxes aTmpLst( 0, 5 );
1769 	SwUndoTblNdsChg* pUndo = 0;
1770     if (GetIDocumentUndoRedo().DoesUndo())
1771     {
1772 		pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSCOL, rBoxes, *pTblNd,
1773                                      0, 0, nCnt, bBehind, sal_False );
1774 		aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
1775 	}
1776 
1777     bool bRet(false);
1778     {
1779         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1780 
1781         SwTableFmlUpdate aMsgHnt( &rTbl );
1782         aMsgHnt.eFlags = TBL_BOXPTR;
1783         UpdateTblFlds( &aMsgHnt );
1784 
1785         bRet = rTbl.InsertCol( this, rBoxes, nCnt, bBehind );
1786         if (bRet)
1787         {
1788             SetModified();
1789             ::ClearFEShellTabCols();
1790             SetFieldsDirty( true, NULL, 0 );
1791         }
1792     }
1793 
1794 	if( pUndo )
1795     {
1796 		if( bRet )
1797         {
1798 			pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
1799             GetIDocumentUndoRedo().AppendUndo( pUndo );
1800         }
1801         else
1802 			delete pUndo;
1803 	}
1804 	return bRet;
1805 }
1806 
InsertRow(const SwCursor & rCursor,sal_uInt16 nCnt,sal_Bool bBehind)1807 sal_Bool SwDoc::InsertRow( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
1808 {
1809 	// lasse ueber das Layout die Boxen suchen
1810 	SwSelBoxes aBoxes;
1811 	GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
1812 
1813 	sal_Bool bRet = sal_False;
1814 	if( aBoxes.Count() )
1815 		bRet = InsertRow( aBoxes, nCnt, bBehind );
1816 	return bRet;
1817 }
1818 
InsertRow(const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bBehind)1819 sal_Bool SwDoc::InsertRow( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
1820 {
1821 	// uebers SwDoc fuer Undo !!
1822 	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
1823 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1824 	if( !pTblNd )
1825 		return sal_False;
1826 
1827 	SwTable& rTbl = pTblNd->GetTable();
1828 	if( rTbl.ISA( SwDDETable ))
1829 		return sal_False;
1830 
1831 #ifdef DEL_TABLE_REDLINES
1832 	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
1833 #endif
1834 
1835 	SwTableSortBoxes aTmpLst( 0, 5 );
1836 	SwUndoTblNdsChg* pUndo = 0;
1837     if (GetIDocumentUndoRedo().DoesUndo())
1838     {
1839 		pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW,rBoxes, *pTblNd,
1840 									 0, 0, nCnt, bBehind, sal_False );
1841 		aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
1842 	}
1843 
1844     bool bRet(false);
1845     {
1846         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1847 
1848         SwTableFmlUpdate aMsgHnt( &rTbl );
1849         aMsgHnt.eFlags = TBL_BOXPTR;
1850         UpdateTblFlds( &aMsgHnt );
1851 
1852         bRet = rTbl.InsertRow( this, rBoxes, nCnt, bBehind );
1853         if (bRet)
1854         {
1855             SetModified();
1856             ::ClearFEShellTabCols();
1857             SetFieldsDirty( true, NULL, 0 );
1858         }
1859     }
1860 
1861 	if( pUndo )
1862     {
1863 		if( bRet )
1864         {
1865 			pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
1866             GetIDocumentUndoRedo().AppendUndo( pUndo );
1867         }
1868         else
1869 			delete pUndo;
1870 	}
1871 	return bRet;
1872 
1873 }
1874 
1875 // ----- loeschen von Spalten/Zeilen ------------------------
1876 
DeleteRow(const SwCursor & rCursor)1877 sal_Bool SwDoc::DeleteRow( const SwCursor& rCursor )
1878 {
1879 	// lasse ueber das Layout die Boxen suchen
1880 	SwSelBoxes aBoxes;
1881 	GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
1882 	if( ::HasProtectedCells( aBoxes ))
1883 		return sal_False;
1884 
1885 	// die Crsr aus dem Loeschbereich entfernen.
1886 	// Der Cursor steht danach:
1887 	//	- es folgt noch eine Zeile, in dieser
1888 	//	- vorher steht noch eine Zeile, in dieser
1889 	//	- sonst immer dahinter
1890 	{
1891 		SwTableNode* pTblNd = rCursor.GetNode()->FindTableNode();
1892 
1893 		if( pTblNd->GetTable().ISA( SwDDETable ))
1894 			return sal_False;
1895 
1896 		// suche alle Boxen / Lines
1897 		_FndBox aFndBox( 0, 0 );
1898 		{
1899 			_FndPara aPara( aBoxes, &aFndBox );
1900 			pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
1901 		}
1902 
1903 		if( !aFndBox.GetLines().Count() )
1904 			return sal_False;
1905 
1906 		SwEditShell* pESh = GetEditShell();
1907 		if( pESh )
1908 		{
1909 			pESh->KillPams();
1910 			// JP: eigentlich sollte man ueber alle Shells iterieren!!
1911 		}
1912 
1913 		_FndBox* pFndBox = &aFndBox;
1914 		while( 1 == pFndBox->GetLines().Count() &&
1915 				1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
1916 		{
1917 			_FndBox* pTmp = pFndBox->GetLines()[0]->GetBoxes()[0];
1918 			if( pTmp->GetBox()->GetSttNd() )
1919 				break;		// das ist sonst zu weit
1920 			pFndBox = pTmp;
1921 		}
1922 
1923 		SwTableLine* pDelLine = pFndBox->GetLines()[
1924 						pFndBox->GetLines().Count()-1 ]->GetLine();
1925 		SwTableBox* pDelBox = pDelLine->GetTabBoxes()[
1926 							pDelLine->GetTabBoxes().Count() - 1 ];
1927 		while( !pDelBox->GetSttNd() )
1928 		{
1929 			SwTableLine* pLn = pDelBox->GetTabLines()[
1930 						pDelBox->GetTabLines().Count()-1 ];
1931 			pDelBox = pLn->GetTabBoxes()[ pLn->GetTabBoxes().Count() - 1 ];
1932 		}
1933 		SwTableBox* pNextBox = pDelLine->FindNextBox( pTblNd->GetTable(),
1934 														pDelBox, sal_True );
1935 		while( pNextBox &&
1936 				pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
1937 			pNextBox = pNextBox->FindNextBox( pTblNd->GetTable(), pNextBox );
1938 
1939 		if( !pNextBox )			// keine nachfolgende? dann die vorhergehende
1940 		{
1941 			pDelLine = pFndBox->GetLines()[ 0 ]->GetLine();
1942 			pDelBox = pDelLine->GetTabBoxes()[ 0 ];
1943 			while( !pDelBox->GetSttNd() )
1944 				pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
1945 			pNextBox = pDelLine->FindPreviousBox( pTblNd->GetTable(),
1946 														pDelBox, sal_True );
1947 			while( pNextBox &&
1948 					pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
1949 				pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox );
1950 		}
1951 
1952 		sal_uLong nIdx;
1953 		if( pNextBox )		// dann den Cursor hier hinein
1954 			nIdx = pNextBox->GetSttIdx() + 1;
1955 		else				// ansonsten hinter die Tabelle
1956 			nIdx = pTblNd->EndOfSectionIndex() + 1;
1957 
1958 		SwNodeIndex aIdx( GetNodes(), nIdx );
1959 		SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
1960 		if( !pCNd )
1961 			pCNd = GetNodes().GoNext( &aIdx );
1962 
1963 		if( pCNd )
1964 		{
1965 			// die Cursor von der Shell oder den uebergebenen Cursor aendern?
1966 			SwPaM* pPam = (SwPaM*)&rCursor;
1967 			pPam->GetPoint()->nNode = aIdx;
1968 			pPam->GetPoint()->nContent.Assign( pCNd, 0 );
1969 			pPam->SetMark();			// beide wollen etwas davon haben
1970 			pPam->DeleteMark();
1971 		}
1972 	}
1973 
1974 	// dann loesche doch die Zeilen
1975 
1976     GetIDocumentUndoRedo().StartUndo(UNDO_ROW_DELETE, NULL);
1977     sal_Bool bResult = DeleteRowCol( aBoxes );
1978     GetIDocumentUndoRedo().EndUndo(UNDO_ROW_DELETE, NULL);
1979 
1980 	return bResult;
1981 }
1982 
DeleteCol(const SwCursor & rCursor)1983 sal_Bool SwDoc::DeleteCol( const SwCursor& rCursor )
1984 {
1985 	// lasse ueber das Layout die Boxen suchen
1986 	SwSelBoxes aBoxes;
1987 	GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
1988 	if( ::HasProtectedCells( aBoxes ))
1989 		return sal_False;
1990 
1991 	// die Crsr muessen noch aus dem Loesch Bereich entfernt
1992 	// werden. Setze sie immer hinter/auf die Tabelle; ueber die
1993 	// Dokument-Position werden sie dann immer an die alte Position gesetzt.
1994 	SwEditShell* pESh = GetEditShell();
1995 	if( pESh )
1996 	{
1997 		const SwNode* pNd = rCursor.GetNode()->FindTableBoxStartNode();
1998 		pESh->ParkCrsr( SwNodeIndex( *pNd ) );
1999 	}
2000 
2001 	// dann loesche doch die Spalten
2002     GetIDocumentUndoRedo().StartUndo(UNDO_COL_DELETE, NULL);
2003     sal_Bool bResult = DeleteRowCol( aBoxes, true );
2004     GetIDocumentUndoRedo().EndUndo(UNDO_COL_DELETE, NULL);
2005 
2006 	return bResult;
2007 }
2008 
DeleteRowCol(const SwSelBoxes & rBoxes,bool bColumn)2009 sal_Bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn )
2010 {
2011 	if( ::HasProtectedCells( rBoxes ))
2012 		return sal_False;
2013 
2014 	// uebers SwDoc fuer Undo !!
2015 	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
2016 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
2017 	if( !pTblNd )
2018 		return sal_False;
2019 
2020 	if( pTblNd->GetTable().ISA( SwDDETable ))
2021 		return sal_False;
2022 
2023 	::ClearFEShellTabCols();
2024     SwSelBoxes aSelBoxes;
2025     aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count());
2026     SwTable &rTable = pTblNd->GetTable();
2027     long nMin = 0;
2028     long nMax = 0;
2029     if( rTable.IsNewModel() )
2030 	{
2031 		if( bColumn )
2032 			rTable.ExpandColumnSelection( aSelBoxes, nMin, nMax );
2033 		else
2034 			rTable.FindSuperfluousRows( aSelBoxes );
2035 	}
2036 
2037 #ifdef DEL_TABLE_REDLINES
2038 	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
2039 #endif
2040 
2041 	// soll die gesamte Tabelle geloescht werden ??
2042 	const sal_uLong nTmpIdx1 = pTblNd->GetIndex();
2043 	const sal_uLong nTmpIdx2 = aSelBoxes[ aSelBoxes.Count()-1 ]->GetSttNd()->
2044 								EndOfSectionIndex()+1;
2045 	if( pTblNd->GetTable().GetTabSortBoxes().Count() == aSelBoxes.Count() &&
2046 		aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 &&
2047 		nTmpIdx2 == pTblNd->EndOfSectionIndex() )
2048 	{
2049 		sal_Bool bNewTxtNd = sal_False;
2050 		// steht diese auch noch alleine in einem FlyFrame ?
2051 		SwNodeIndex aIdx( *pTblNd, -1 );
2052 		const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode();
2053 		if( pSttNd )
2054 		{
2055 			const sal_uLong nTblEnd = pTblNd->EndOfSectionIndex() + 1;
2056 			const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex();
2057 			if( nTblEnd == nSectEnd )
2058 			{
2059 				if( SwFlyStartNode == pSttNd->GetStartNodeType() )
2060 				{
2061 					SwFrmFmt* pFmt = pSttNd->GetFlyFmt();
2062 					if( pFmt )
2063 					{
2064 						// Ok, das ist das gesuchte FlyFormat
2065 						DelLayoutFmt( pFmt );
2066 						return sal_True;
2067 					}
2068 				}
2069 				// kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
2070 				// TextNode ueberig lassen.
2071 				// Undo koennen wir dann vergessen !!
2072 				bNewTxtNd = sal_True;
2073 			}
2074 		}
2075 
2076 		// kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
2077 		// TextNode ueberig lassen.
2078 		aIdx++;
2079         if (GetIDocumentUndoRedo().DoesUndo())
2080         {
2081             GetIDocumentUndoRedo().ClearRedo();
2082 			SwPaM aPaM( *pTblNd->EndOfSectionNode(), aIdx.GetNode() );
2083 
2084 			if( bNewTxtNd )
2085 			{
2086 				const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
2087 				GetNodes().MakeTxtNode( aTmpIdx,
2088 							GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
2089 			}
2090 
2091             // save the cursors (UNO and otherwise)
2092             SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
2093             if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
2094             {
2095                 *aSavePaM.GetMark() = SwPosition( *pTblNd );
2096                 aSavePaM.Move( fnMoveBackward, fnGoNode );
2097             }
2098             {
2099                 SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
2100                 ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
2101             }
2102 
2103 			// harte SeitenUmbrueche am nachfolgenden Node verschieben
2104 			sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
2105 			sal_uLong nNextNd = pTblNd->EndOfSectionIndex()+1;
2106 			SwCntntNode* pNextNd = GetNodes()[ nNextNd ]->GetCntntNode();
2107 			if( pNextNd )
2108 			{
2109 //JP 24.08.98: will man wirklich den PageDesc/Break vom
2110 //				nachfolgen Absatz ueberbuegeln?
2111 //				const SwAttrSet& rAttrSet = pNextNd->GetSwAttrSet();
2112 //				if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
2113 //					SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
2114 				{
2115 					SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2116 					const SfxPoolItem *pItem;
2117 					if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2118 						sal_False, &pItem ) )
2119 					{
2120 						pNextNd->SetAttr( *pItem );
2121 						bSavePageDesc = sal_True;
2122 					}
2123 
2124 					if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2125 						sal_False, &pItem ) )
2126 					{
2127 						pNextNd->SetAttr( *pItem );
2128 						bSavePageBreak = sal_True;
2129 					}
2130 				}
2131 			}
2132 			SwUndoDelete* pUndo = new SwUndoDelete( aPaM );
2133 			if( bNewTxtNd )
2134 				pUndo->SetTblDelLastNd();
2135 			pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2136             pUndo->SetTableName(pTblNd->GetTable().GetFrmFmt()->GetName());
2137             GetIDocumentUndoRedo().AppendUndo( pUndo );
2138         }
2139         else
2140         {
2141 			if( bNewTxtNd )
2142 			{
2143 				const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
2144 				GetNodes().MakeTxtNode( aTmpIdx,
2145 							GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
2146 			}
2147 
2148             // save the cursors (UNO and otherwise)
2149             SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
2150             if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
2151             {
2152                 *aSavePaM.GetMark() = SwPosition( *pTblNd );
2153                 aSavePaM.Move( fnMoveBackward, fnGoNode );
2154             }
2155             {
2156                 SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
2157                 ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
2158             }
2159 
2160 			// harte SeitenUmbrueche am nachfolgenden Node verschieben
2161 			SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
2162 			if( pNextNd )
2163 			{
2164 				SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2165 				const SfxPoolItem *pItem;
2166 				if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2167 					sal_False, &pItem ) )
2168 					pNextNd->SetAttr( *pItem );
2169 
2170 				if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2171 					sal_False, &pItem ) )
2172 					pNextNd->SetAttr( *pItem );
2173 			}
2174 
2175 			pTblNd->DelFrms();
2176 			DeleteSection( pTblNd );
2177 		}
2178 		SetModified();
2179 		SetFieldsDirty( true, NULL, 0 );
2180 		return sal_True;
2181 	}
2182 
2183 	SwUndoTblNdsChg* pUndo = 0;
2184     if (GetIDocumentUndoRedo().DoesUndo())
2185     {
2186 		pUndo = new SwUndoTblNdsChg( UNDO_TABLE_DELBOX, aSelBoxes, *pTblNd,
2187                                      nMin, nMax, 0, sal_False, sal_False );
2188 	}
2189 
2190     bool bRet(false);
2191     {
2192         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2193 
2194         SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2195         aMsgHnt.eFlags = TBL_BOXPTR;
2196         UpdateTblFlds( &aMsgHnt );
2197 
2198         if (rTable.IsNewModel())
2199         {
2200             if (bColumn)
2201                 rTable.PrepareDeleteCol( nMin, nMax );
2202             rTable.FindSuperfluousRows( aSelBoxes );
2203             if (pUndo)
2204                 pUndo->ReNewBoxes( aSelBoxes );
2205         }
2206         bRet = rTable.DeleteSel( this, aSelBoxes, 0, pUndo, sal_True, sal_True );
2207         if (bRet)
2208         {
2209             SetModified();
2210             SetFieldsDirty( true, NULL, 0 );
2211         }
2212     }
2213 
2214 	if( pUndo )
2215     {
2216 		if( bRet )
2217         {
2218             GetIDocumentUndoRedo().AppendUndo( pUndo );
2219         }
2220         else
2221 			delete pUndo;
2222 	}
2223 
2224 	return bRet;
2225 }
2226 
2227 
2228 // ---------- teilen / zusammenfassen von Boxen in der Tabelle --------
2229 
SplitTbl(const SwSelBoxes & rBoxes,sal_Bool bVert,sal_uInt16 nCnt,sal_Bool bSameHeight)2230 sal_Bool SwDoc::SplitTbl( const SwSelBoxes& rBoxes, sal_Bool bVert, sal_uInt16 nCnt,
2231                       sal_Bool bSameHeight )
2232 {
2233 	// uebers SwDoc fuer Undo !!
2234 	ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" );
2235 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
2236 	if( !pTblNd )
2237 		return sal_False;
2238 
2239 	SwTable& rTbl = pTblNd->GetTable();
2240 	if( rTbl.ISA( SwDDETable ))
2241 		return sal_False;
2242 
2243 #ifdef DEL_TABLE_REDLINES
2244 	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
2245 #endif
2246 
2247 	SvULongs aNdsCnts;
2248 	SwTableSortBoxes aTmpLst( 0, 5 );
2249 	SwUndoTblNdsChg* pUndo = 0;
2250     if (GetIDocumentUndoRedo().DoesUndo())
2251     {
2252         pUndo = new SwUndoTblNdsChg( UNDO_TABLE_SPLIT, rBoxes, *pTblNd, 0, 0,
2253                                      nCnt, bVert, bSameHeight );
2254 
2255 		aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
2256 		if( !bVert )
2257 		{
2258 			for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
2259 			{
2260 				const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd();
2261 				aNdsCnts.Insert( pSttNd->EndOfSectionIndex() -
2262 								 pSttNd->GetIndex(), n );
2263 			}
2264 		}
2265 	}
2266 
2267     bool bRet(false);
2268     {
2269         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2270 
2271         SwTableFmlUpdate aMsgHnt( &rTbl );
2272         aMsgHnt.eFlags = TBL_BOXPTR;
2273         UpdateTblFlds( &aMsgHnt );
2274 
2275         if (bVert)
2276             bRet = rTbl.SplitCol( this, rBoxes, nCnt );
2277         else
2278             bRet = rTbl.SplitRow( this, rBoxes, nCnt, bSameHeight );
2279 
2280         if (bRet)
2281         {
2282             SetModified();
2283             SetFieldsDirty( true, NULL, 0 );
2284         }
2285     }
2286 
2287 	if( pUndo )
2288 	{
2289 		if( bRet )
2290 		{
2291 			if( bVert )
2292 				pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
2293 			else
2294 				pUndo->SaveNewBoxes( *pTblNd, aTmpLst, rBoxes, aNdsCnts );
2295             GetIDocumentUndoRedo().AppendUndo( pUndo );
2296         }
2297         else
2298 			delete pUndo;
2299 	}
2300 
2301 	return bRet;
2302 }
2303 
2304 
MergeTbl(SwPaM & rPam)2305 sal_uInt16 SwDoc::MergeTbl( SwPaM& rPam )
2306 {
2307 	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
2308 	SwTableNode* pTblNd = rPam.GetNode()->FindTableNode();
2309 	if( !pTblNd )
2310 		return TBLMERGE_NOSELECTION;
2311     SwTable& rTable = pTblNd->GetTable();
2312     if( rTable.ISA(SwDDETable) )
2313 		return TBLMERGE_NOSELECTION;
2314 	sal_uInt16 nRet = TBLMERGE_NOSELECTION;
2315     if( !rTable.IsNewModel() )
2316     {
2317         nRet =::CheckMergeSel( rPam );
2318         if( TBLMERGE_OK != nRet )
2319             return nRet;
2320         nRet = TBLMERGE_NOSELECTION;
2321     }
2322 
2323     // --> FME 2004-10-08 #i33394#
2324     GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_MERGE, NULL );
2325     // <--
2326 
2327 #ifdef DEL_TABLE_REDLINES
2328 	if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
2329 		DeleteRedline( *pTblNd, true, USHRT_MAX );
2330 #endif
2331 	RedlineMode_t eOld = GetRedlineMode();
2332 	SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
2333 
2334     SwUndoTblMerge *const pUndo( (GetIDocumentUndoRedo().DoesUndo())
2335         ?   new SwUndoTblMerge( rPam )
2336         :   0 );
2337 
2338 	// lasse ueber das Layout die Boxen suchen
2339 	SwSelBoxes aBoxes;
2340     SwSelBoxes aMerged;
2341 	SwTableBox* pMergeBox;
2342 
2343 	if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo ) )
2344 	{   // no cells found to merge
2345 		SetRedlineMode_intern( eOld );
2346 		if( pUndo )
2347 		{
2348 			delete pUndo;
2349             SwUndoId nLastUndoId(UNDO_EMPTY);
2350             if (GetIDocumentUndoRedo().GetLastUndoInfo(0, & nLastUndoId)
2351                 && (UNDO_REDLINE == nLastUndoId))
2352             {
2353                 // FIXME: why is this horrible cleanup necessary?
2354                 SwUndoRedline *const pU = dynamic_cast<SwUndoRedline*>(
2355                         GetUndoManager().RemoveLastUndo());
2356 				if( pU->GetRedlSaveCount() )
2357                 {
2358                     SwEditShell *const pEditShell(GetEditShell(0));
2359                     OSL_ASSERT(pEditShell);
2360                     ::sw::UndoRedoContext context(*this, *pEditShell);
2361                     static_cast<SfxUndoAction *>(pU)->UndoWithContext(context);
2362                 }
2363 				delete pU;
2364 			}
2365 		}
2366 	}
2367 	else
2368 	{
2369 		// die PaMs muessen noch aus dem Loesch Bereich entfernt
2370 		// werden. Setze sie immer hinter/auf die Tabelle; ueber die
2371 		// Dokument-Position werden sie dann immer an die alte Position gesetzt.
2372 		// Erstmal einen Index auf die Parkposition merken, denn nach GetMergeSel
2373 		// komme ich nicht mehr dran.
2374 		{
2375 			rPam.DeleteMark();
2376 			rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2377 			rPam.GetPoint()->nContent.Assign( 0, 0 );
2378 			rPam.SetMark();
2379 			rPam.DeleteMark();
2380 
2381 			SwPaM* pTmp = &rPam;
2382 			while( &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ))
2383 				for( int i = 0; i < 2; ++i )
2384 					pTmp->GetBound( (sal_Bool)i ) = *rPam.GetPoint();
2385 		}
2386 
2387 		// dann fuege sie zusammen
2388 		SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2389 		aMsgHnt.eFlags = TBL_BOXPTR;
2390 		UpdateTblFlds( &aMsgHnt );
2391 
2392 		if( pTblNd->GetTable().Merge( this, aBoxes, aMerged, pMergeBox, pUndo ))
2393 		{
2394 			nRet = TBLMERGE_OK;
2395 			SetModified();
2396 			SetFieldsDirty( true, NULL, 0 );
2397 			if( pUndo )
2398             {
2399                 GetIDocumentUndoRedo().AppendUndo( pUndo );
2400             }
2401         }
2402 		else if( pUndo )
2403 			delete pUndo;
2404 
2405 		rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2406 		rPam.Move();
2407 
2408 		::ClearFEShellTabCols();
2409 		SetRedlineMode_intern( eOld );
2410 	}
2411     GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_MERGE, NULL );
2412 	return nRet;
2413 }
2414 
2415 
2416 
2417 // -------------------------------------------------------
2418 
2419 //---------
2420 // SwTableNode
2421 //---------
2422 
SwTableNode(const SwNodeIndex & rIdx)2423 SwTableNode::SwTableNode( const SwNodeIndex& rIdx )
2424 	: SwStartNode( rIdx, ND_TABLENODE )
2425 {
2426 	pTable = new SwTable( 0 );
2427 }
2428 
~SwTableNode()2429 SwTableNode::~SwTableNode()
2430 {
2431 	//don't forget to notify uno wrappers
2432 	SwFrmFmt* pTblFmt = GetTable().GetFrmFmt();
2433 	SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
2434 								pTblFmt );
2435 	pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint );
2436 	DelFrms();
2437 	delete pTable;
2438 }
2439 
MakeFrm(SwFrm * pSib)2440 SwTabFrm *SwTableNode::MakeFrm( SwFrm* pSib )
2441 {
2442 	return new SwTabFrm( *pTable, pSib );
2443 }
2444 
2445 //Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom
2446 //Dokument. Die erzeugten Contentframes werden in das entsprechende
2447 //Layout gehaengt.
MakeFrms(const SwNodeIndex & rIdx)2448 void SwTableNode::MakeFrms(const SwNodeIndex & rIdx )
2449 {
2450 	if( !GetTable().GetFrmFmt()->GetDepends())//gibt es ueberhaupt Frames ??
2451 		return;
2452 
2453 	SwFrm *pFrm, *pNew;
2454 	SwCntntNode * pNode = rIdx.GetNode().GetCntntNode();
2455 
2456 	ASSERT( pNode, "Kein Contentnode oder Copy-Node und neuer Node identisch.");
2457 
2458 	sal_Bool bBefore = rIdx < GetIndex();
2459 
2460 	SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
2461 
2462 	while( 0 != (pFrm = aNode2Layout.NextFrm()) )
2463 	{
2464 		pNew = pNode->MakeFrm( pFrm );
2465 		// wird ein Node vorher oder nachher mit Frames versehen
2466 		if ( bBefore )
2467 			// der neue liegt vor mir
2468 			pNew->Paste( pFrm->GetUpper(), pFrm );
2469 		else
2470 			// der neue liegt hinter mir
2471 			pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() );
2472 	}
2473 }
2474 
2475 //Fuer jede Shell einen TblFrm anlegen und vor den entsprechenden
2476 //CntntFrm pasten.
2477 
MakeFrms(SwNodeIndex * pIdxBehind)2478 void SwTableNode::MakeFrms( SwNodeIndex* pIdxBehind )
2479 {
2480 	ASSERT( pIdxBehind, "kein Index" );
2481 	*pIdxBehind = *this;
2482 	SwNode *pNd = GetNodes().FindPrvNxtFrmNode( *pIdxBehind, EndOfSectionNode() );
2483 	if( !pNd )
2484 		return ;
2485 
2486     SwFrm *pFrm( 0L );
2487 	SwLayoutFrm *pUpper( 0L );
2488 	SwNode2Layout aNode2Layout( *pNd, GetIndex() );
2489 	while( 0 != (pUpper = aNode2Layout.UpperFrm( pFrm, *this )) )
2490 	{
2491         SwTabFrm* pNew = MakeFrm( pUpper );
2492 		pNew->Paste( pUpper, pFrm );
2493         // --> OD 2005-12-01 #i27138#
2494         // notify accessibility paragraphs objects about changed
2495         // CONTENT_FLOWS_FROM/_TO relation.
2496         // Relation CONTENT_FLOWS_FROM for next paragraph will change
2497         // and relation CONTENT_FLOWS_TO for previous paragraph will change.
2498         {
2499             ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
2500             if ( pViewShell && pViewShell->GetLayout() &&
2501                  pViewShell->GetLayout()->IsAnyShellAccessible() )
2502             {
2503                 pViewShell->InvalidateAccessibleParaFlowRelation(
2504                             dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
2505                             dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) );
2506             }
2507         }
2508         // <--
2509         ((SwTabFrm*)pNew)->RegistFlys();
2510 	}
2511 }
2512 
DelFrms()2513 void SwTableNode::DelFrms()
2514 {
2515 	//Erstmal die TabFrms ausschneiden und deleten, die Columns und Rows
2516 	//nehmen sie mit in's Grab.
2517 	//Die TabFrms haengen am FrmFmt des SwTable.
2518 	//Sie muessen etwas umstaendlich zerstort werden, damit die Master
2519 	//die Follows mit in's Grab nehmen.
2520 
2521 	SwIterator<SwTabFrm,SwFmt> aIter( *(pTable->GetFrmFmt()) );
2522 	SwTabFrm *pFrm = aIter.First();
2523 	while ( pFrm )
2524 	{
2525 		sal_Bool bAgain = sal_False;
2526 		{
2527 			if ( !pFrm->IsFollow() )
2528 			{
2529 				while ( pFrm->HasFollow() )
2530 					pFrm->JoinAndDelFollows();
2531                 // --> OD 2005-12-01 #i27138#
2532                 // notify accessibility paragraphs objects about changed
2533                 // CONTENT_FLOWS_FROM/_TO relation.
2534                 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
2535                 // and relation CONTENT_FLOWS_TO for current previous paragraph will change.
2536                 {
2537                     ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() );
2538                     if ( pViewShell && pViewShell->GetLayout() &&
2539                          pViewShell->GetLayout()->IsAnyShellAccessible() )
2540                     {
2541                         pViewShell->InvalidateAccessibleParaFlowRelation(
2542                             dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
2543                             dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
2544                     }
2545                 }
2546                 // <--
2547                 pFrm->Cut();
2548 				delete pFrm;
2549 				bAgain = sal_True;
2550 			}
2551 		}
2552 		pFrm = bAgain ? aIter.First() : aIter.Next();
2553 	}
2554 }
2555 
2556 
SetNewTable(SwTable * pNewTable,sal_Bool bNewFrames)2557 void SwTableNode::SetNewTable( SwTable* pNewTable, sal_Bool bNewFrames )
2558 {
2559 	DelFrms();
2560 	delete pTable;
2561 	pTable = pNewTable;
2562 	if( bNewFrames )
2563 	{
2564 		SwNodeIndex aIdx( *EndOfSectionNode());
2565 		GetNodes().GoNext( &aIdx );
2566 		MakeFrms( &aIdx );
2567 	}
2568 }
2569 
GetTabCols(SwTabCols & rFill,const SwCursor * pCrsr,const SwCellFrm * pBoxFrm) const2570 void SwDoc::GetTabCols( SwTabCols &rFill, const SwCursor* pCrsr,
2571 						const SwCellFrm* pBoxFrm ) const
2572 {
2573 	const SwTableBox* pBox = 0;
2574 	SwTabFrm *pTab = 0;
2575 
2576 	if( pBoxFrm )
2577 	{
2578 		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2579 		pBox = pBoxFrm->GetTabBox();
2580 	}
2581 	else if( pCrsr )
2582 	{
2583 		const SwCntntNode* pCNd = pCrsr->GetCntntNode();
2584 		if( !pCNd )
2585 			return ;
2586 
2587 		Point aPt;
2588         const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
2589 		if( pShCrsr )
2590 			aPt = pShCrsr->GetPtPos();
2591 
2592 		const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
2593 		do {
2594 			pTmpFrm = pTmpFrm->GetUpper();
2595 		} while ( !pTmpFrm->IsCellFrm() );
2596 
2597 		pBoxFrm = (SwCellFrm*)pTmpFrm;
2598 		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2599 		pBox = pBoxFrm->GetTabBox();
2600 	}
2601 	else if( !pCrsr && !pBoxFrm )
2602 	{
2603 		ASSERT( sal_False, "one of them must be indicated!" );
2604 		return ;
2605 	}
2606 
2607 	//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2608     SWRECTFN( pTab )
2609     const SwPageFrm* pPage = pTab->FindPageFrm();
2610     const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
2611                            (pPage->Frm().*fnRect->fnGetLeft)();
2612     const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
2613                             (pPage->Frm().*fnRect->fnGetLeft)();
2614 
2615     rFill.SetLeftMin ( nLeftMin );
2616     rFill.SetLeft    ( (pTab->Prt().*fnRect->fnGetLeft)() );
2617     rFill.SetRight   ( (pTab->Prt().*fnRect->fnGetRight)());
2618     rFill.SetRightMax( nRightMax - nLeftMin );
2619 
2620 	pTab->GetTable()->GetTabCols( rFill, pBox );
2621 }
2622 
2623 //
2624 // Here are some little helpers used in SwDoc::GetTabRows
2625 //
2626 
2627 #define ROWFUZZY 25
2628 
2629 struct FuzzyCompare
2630 {
2631     bool operator() ( long s1, long s2 ) const;
2632 };
2633 
operator ()(long s1,long s2) const2634 bool FuzzyCompare::operator() ( long s1, long s2 ) const
2635 {
2636     return ( s1 < s2 && abs( s1 - s2 ) > ROWFUZZY );
2637 }
2638 
lcl_IsFrmInColumn(const SwCellFrm & rFrm,SwSelBoxes & rBoxes)2639 bool lcl_IsFrmInColumn( const SwCellFrm& rFrm, SwSelBoxes& rBoxes )
2640 {
2641     for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
2642     {
2643         if ( rFrm.GetTabBox() == rBoxes[ i ] )
2644             return true;
2645     }
2646 
2647     return false;
2648 }
2649 
2650 //
2651 // SwDoc::GetTabRows()
2652 //
2653 
GetTabRows(SwTabCols & rFill,const SwCursor *,const SwCellFrm * pBoxFrm) const2654 void SwDoc::GetTabRows( SwTabCols &rFill, const SwCursor* ,
2655 						const SwCellFrm* pBoxFrm ) const
2656 {
2657     ASSERT( pBoxFrm, "GetTabRows called without pBoxFrm" )
2658 
2659     // --> FME 2005-09-12 #121591# Make code robust:
2660     if ( !pBoxFrm )
2661         return;
2662     // <--
2663 
2664     // --> FME 2005-01-06 #i39552# Collection of the boxes of the current
2665     // column has to be done at the beginning of this function, because
2666     // the table may be formatted in ::GetTblSel.
2667     SwDeletionChecker aDelCheck( pBoxFrm );
2668 
2669     SwSelBoxes aBoxes;
2670     const SwCntntFrm* pCntnt = ::GetCellCntnt( *pBoxFrm );
2671     if ( pCntnt && pCntnt->IsTxtFrm() )
2672     {
2673         const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
2674         const SwCursor aTmpCrsr( aPos, 0, false );
2675         ::GetTblSel( aTmpCrsr, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
2676     }
2677     // <--
2678 
2679     // --> FME 2005-09-12 #121591# Make code robust:
2680     if ( aDelCheck.HasBeenDeleted() )
2681     {
2682         ASSERT( false, "Current box has been deleted during GetTabRows()" )
2683         return;
2684     }
2685     // <--
2686 
2687     // --> FME 2005-09-12 #121591# Make code robust:
2688     const SwTabFrm* pTab = pBoxFrm->FindTabFrm();
2689     ASSERT( pTab, "GetTabRows called without a table" )
2690     if ( !pTab )
2691         return;
2692     // <--
2693 
2694     const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
2695 
2696 	//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2697     SWRECTFN( pTab )
2698     const SwPageFrm* pPage = pTab->FindPageFrm();
2699     const long nLeftMin  = ( bVert ?
2700                              pTab->GetPrtLeft() - pPage->Frm().Left() :
2701                              pTab->GetPrtTop() - pPage->Frm().Top() );
2702     const long nLeft     = bVert ? LONG_MAX : 0;
2703     const long nRight    = (pTab->Prt().*fnRect->fnGetHeight)();
2704     const long nRightMax = bVert ? nRight : LONG_MAX;
2705 
2706     rFill.SetLeftMin( nLeftMin );
2707     rFill.SetLeft( nLeft );
2708     rFill.SetRight( nRight );
2709     rFill.SetRightMax( nRightMax );
2710 
2711     typedef std::map< long, std::pair< long, long >, FuzzyCompare > BoundaryMap;
2712     BoundaryMap aBoundaries;
2713     BoundaryMap::iterator aIter;
2714     std::pair< long, long > aPair;
2715 
2716     typedef std::map< long, bool > HiddenMap;
2717     HiddenMap aHidden;
2718     HiddenMap::iterator aHiddenIter;
2719 
2720     while ( pFrm && pTab->IsAnLower( pFrm ) )
2721     {
2722         if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
2723         {
2724             // upper and lower borders of current cell frame:
2725             long nUpperBorder = (pFrm->Frm().*fnRect->fnGetTop)();
2726             long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
2727 
2728             // get boundaries for nUpperBorder:
2729             aIter = aBoundaries.find( nUpperBorder );
2730             if ( aIter == aBoundaries.end() )
2731             {
2732                 aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2733                 aBoundaries[ nUpperBorder ] = aPair;
2734             }
2735 
2736             // get boundaries for nLowerBorder:
2737             aIter = aBoundaries.find( nLowerBorder );
2738             if ( aIter == aBoundaries.end() )
2739             {
2740                 aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2741             }
2742             else
2743             {
2744                 nLowerBorder = (*aIter).first;
2745                 long nNewLowerBorderUpperBoundary = Max( (*aIter).second.first, nUpperBorder );
2746                 aPair.first = nNewLowerBorderUpperBoundary; aPair.second = LONG_MAX;
2747             }
2748             aBoundaries[ nLowerBorder ] = aPair;
2749 
2750             // calculate hidden flags for entry nUpperBorder/nLowerBorder:
2751             long nTmpVal = nUpperBorder;
2752             for ( sal_uInt8 i = 0; i < 2; ++i )
2753             {
2754                 aHiddenIter = aHidden.find( nTmpVal );
2755                 if ( aHiddenIter == aHidden.end() )
2756                     aHidden[ nTmpVal ] = !lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes );
2757                 else
2758                 {
2759                     if ( aHidden[ nTmpVal ] &&
2760                          lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes ) )
2761                         aHidden[ nTmpVal ] = false;
2762                 }
2763                 nTmpVal = nLowerBorder;
2764             }
2765         }
2766 
2767         pFrm = pFrm->GetNextLayoutLeaf();
2768     }
2769 
2770     // transfer calculated values from BoundaryMap and HiddenMap into rFill:
2771     sal_uInt16 nIdx = 0;
2772     for ( aIter = aBoundaries.begin(); aIter != aBoundaries.end(); ++aIter )
2773     {
2774         const long nTabTop = (pTab->*fnRect->fnGetPrtTop)();
2775         const long nKey = (*fnRect->fnYDiff)( (*aIter).first, nTabTop );
2776         const std::pair< long, long > aTmpPair = (*aIter).second;
2777         const long nFirst = (*fnRect->fnYDiff)( aTmpPair.first, nTabTop );
2778         const long nSecond = aTmpPair.second;
2779 
2780         aHiddenIter = aHidden.find( (*aIter).first );
2781         const bool bHidden = aHiddenIter != aHidden.end() && (*aHiddenIter).second;
2782         rFill.Insert( nKey, nFirst, nSecond, bHidden, nIdx++ );
2783     }
2784 
2785     // delete first and last entry
2786     ASSERT( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" )
2787     // --> FME 2006-01-19 #i60818# There may be only one entry in rFill. Make
2788     // code robust by checking count of rFill.
2789     if ( rFill.Count() ) rFill.Remove( 0, 1 );
2790     if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 , 1 );
2791     // <--
2792     rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() );
2793 }
2794 
SetTabCols(const SwTabCols & rNew,sal_Bool bCurRowOnly,const SwCursor * pCrsr,const SwCellFrm * pBoxFrm)2795 void SwDoc::SetTabCols( const SwTabCols &rNew, sal_Bool bCurRowOnly,
2796 						const SwCursor* pCrsr, const SwCellFrm* pBoxFrm )
2797 {
2798 	const SwTableBox* pBox = 0;
2799 	SwTabFrm *pTab = 0;
2800 
2801 	if( pBoxFrm )
2802 	{
2803 		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2804 		pBox = pBoxFrm->GetTabBox();
2805 	}
2806 	else if( pCrsr )
2807 	{
2808 		const SwCntntNode* pCNd = pCrsr->GetCntntNode();
2809 		if( !pCNd )
2810 			return ;
2811 
2812 		Point aPt;
2813         const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
2814 		if( pShCrsr )
2815 			aPt = pShCrsr->GetPtPos();
2816 
2817 		const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
2818 		do {
2819 			pTmpFrm = pTmpFrm->GetUpper();
2820 		} while ( !pTmpFrm->IsCellFrm() );
2821 
2822 		pBoxFrm = (SwCellFrm*)pTmpFrm;
2823 		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2824 		pBox = pBoxFrm->GetTabBox();
2825 	}
2826 	else if( !pCrsr && !pBoxFrm )
2827 	{
2828 		ASSERT( sal_False, "one of them must be indicated!" );
2829 		return ;
2830 	}
2831 
2832 	// sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
2833 	// dann muss es jetzt auf absolute umgerechnet werden.
2834 	SwTable& rTab = *pTab->GetTable();
2835 	const SwFmtFrmSize& rTblFrmSz = rTab.GetFrmFmt()->GetFrmSize();
2836     SWRECTFN( pTab )
2837     // OD 06.08.2003 #i17174# - With fix for #i9040# the shadow size is taken
2838     // from the table width. Thus, add its left and right size to current table
2839     // printing area width in order to get the correct table size attribute.
2840     SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
2841     {
2842         SvxShadowItem aShadow( rTab.GetFrmFmt()->GetShadow() );
2843         nPrtWidth += aShadow.CalcShadowSpace( SHADOW_LEFT ) +
2844                      aShadow.CalcShadowSpace( SHADOW_RIGHT );
2845     }
2846     if( nPrtWidth != rTblFrmSz.GetWidth() )
2847 	{
2848 		SwFmtFrmSize aSz( rTblFrmSz );
2849         aSz.SetWidth( nPrtWidth );
2850         rTab.GetFrmFmt()->SetFmtAttr( aSz );
2851 	}
2852 
2853     SwTabCols aOld( rNew.Count() );
2854 
2855     const SwPageFrm* pPage = pTab->FindPageFrm();
2856     const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
2857                            (pPage->Frm().*fnRect->fnGetLeft)();
2858     const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
2859                             (pPage->Frm().*fnRect->fnGetLeft)();
2860 
2861     //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2862     aOld.SetLeftMin ( nLeftMin );
2863     aOld.SetLeft    ( (pTab->Prt().*fnRect->fnGetLeft)() );
2864     aOld.SetRight   ( (pTab->Prt().*fnRect->fnGetRight)());
2865     aOld.SetRightMax( nRightMax - nLeftMin );
2866 
2867     rTab.GetTabCols( aOld, pBox );
2868     SetTabCols(rTab, rNew, aOld, pBox, bCurRowOnly );
2869 }
2870 
SetTabRows(const SwTabCols & rNew,sal_Bool bCurColOnly,const SwCursor *,const SwCellFrm * pBoxFrm)2871 void SwDoc::SetTabRows( const SwTabCols &rNew, sal_Bool bCurColOnly, const SwCursor*,
2872                         const SwCellFrm* pBoxFrm )
2873 {
2874 	const SwTableBox* pBox;
2875 	SwTabFrm *pTab;
2876 
2877     ASSERT( pBoxFrm, "SetTabRows called without pBoxFrm" )
2878 
2879 	pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2880 	pBox = pBoxFrm->GetTabBox();
2881 
2882 	// sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
2883 	// dann muss es jetzt auf absolute umgerechnet werden.
2884     SWRECTFN( pTab )
2885 	SwTabCols aOld( rNew.Count() );
2886 
2887     //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2888     const SwPageFrm* pPage = pTab->FindPageFrm();
2889 
2890     aOld.SetRight( (pTab->Prt().*fnRect->fnGetHeight)() );
2891     long nLeftMin;
2892     if ( bVert )
2893     {
2894         nLeftMin = pTab->GetPrtLeft() - pPage->Frm().Left();
2895         aOld.SetLeft    ( LONG_MAX );
2896         aOld.SetRightMax( aOld.GetRight() );
2897 
2898     }
2899     else
2900     {
2901         nLeftMin = pTab->GetPrtTop() - pPage->Frm().Top();
2902         aOld.SetLeft    ( 0 );
2903         aOld.SetRightMax( LONG_MAX );
2904     }
2905     aOld.SetLeftMin ( nLeftMin );
2906 
2907     GetTabRows( aOld, 0, pBoxFrm );
2908 
2909     GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_ATTR, NULL );
2910 
2911     // check for differences between aOld and rNew:
2912     const sal_uInt16 nCount = rNew.Count();
2913     const SwTable* pTable = pTab->GetTable();
2914     ASSERT( pTable, "My colleague told me, this couldn't happen" );
2915 
2916     for ( sal_uInt16 i = 0; i <= nCount; ++i )
2917     {
2918         const sal_uInt16 nIdxStt = bVert ? nCount - i : i - 1;
2919         const sal_uInt16 nIdxEnd = bVert ? nCount - i - 1 : i;
2920 
2921         const long nOldRowStart = i == 0  ? 0 : aOld[ nIdxStt ];
2922         const long nOldRowEnd =   i == nCount ? aOld.GetRight() : aOld[ nIdxEnd ];
2923         const long nOldRowHeight = nOldRowEnd - nOldRowStart;
2924 
2925         const long nNewRowStart = i == 0  ? 0 : rNew[ nIdxStt ];
2926         const long nNewRowEnd =   i == nCount ? rNew.GetRight() : rNew[ nIdxEnd ];
2927         const long nNewRowHeight = nNewRowEnd - nNewRowStart;
2928 
2929         const long nDiff = nNewRowHeight - nOldRowHeight;
2930         if ( abs( nDiff ) >= ROWFUZZY )
2931         {
2932             // For the old table model pTxtFrm and pLine will be set for every box.
2933             // For the new table model pTxtFrm will be set if the box is not covered,
2934             // but the pLine will be set if the box is not an overlapping box
2935             // In the new table model the row height can be adjusted,
2936             // when both variables are set.
2937             SwTxtFrm* pTxtFrm = 0;
2938             const SwTableLine* pLine = 0;
2939 
2940             // Iterate over all SwCellFrms with Bottom = nOldPos
2941             const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
2942             while ( pFrm && pTab->IsAnLower( pFrm ) )
2943             {
2944                 if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
2945                 {
2946                     const long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
2947                     const sal_uLong nTabTop = (pTab->*fnRect->fnGetPrtTop)();
2948                     if ( abs( (*fnRect->fnYInc)( nTabTop, nOldRowEnd ) - nLowerBorder ) <= ROWFUZZY )
2949                     {
2950                         if ( !bCurColOnly || pFrm == pBoxFrm )
2951                         {
2952                             const SwFrm* pCntnt = ::GetCellCntnt( static_cast<const SwCellFrm&>(*pFrm) );
2953 
2954                             if ( pCntnt && pCntnt->IsTxtFrm() )
2955                             {
2956                                 pBox = ((SwCellFrm*)pFrm)->GetTabBox();
2957                                 const long nRowSpan = pBox->getRowSpan();
2958                                 if( nRowSpan > 0 ) // Not overlapped
2959                                     pTxtFrm = (SwTxtFrm*)pCntnt;
2960                                 if( nRowSpan < 2 ) // Not overlapping for row height
2961                                     pLine = pBox->GetUpper();
2962                                 if( pLine && pTxtFrm ) // always for old table model
2963                                 {
2964                                     // The new row height must not to be calculated from a overlapping box
2965                                     SwFmtFrmSize aNew( pLine->GetFrmFmt()->GetFrmSize() );
2966                                     const long nNewSize = (pFrm->Frm().*fnRect->fnGetHeight)() + nDiff;
2967                                     if( nNewSize != aNew.GetHeight() )
2968                                     {
2969                                         aNew.SetHeight( nNewSize );
2970                                         if ( ATT_VAR_SIZE == aNew.GetHeightSizeType() )
2971                                             aNew.SetHeightSizeType( ATT_MIN_SIZE );
2972                                         // This position must not be in an overlapped box
2973                                         const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
2974                                         const SwCursor aTmpCrsr( aPos, 0, false );
2975                                         SetRowHeight( aTmpCrsr, aNew );
2976                                         // For the new table model we're done, for the old one
2977                                         // there might be another (sub)row to adjust...
2978                                         if( pTable->IsNewModel() )
2979                                             break;
2980                                     }
2981                                     pLine = 0;
2982                                 }
2983                             }
2984                         }
2985                     }
2986                 }
2987                 pFrm = pFrm->GetNextLayoutLeaf();
2988             }
2989         }
2990     }
2991 
2992     GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_ATTR, NULL );
2993 
2994 	::ClearFEShellTabCols();
2995 }
2996 
2997 /* -----------------18.07.98 11:45-------------------
2998  *  Direktzugriff fuer UNO
2999  * --------------------------------------------------*/
SetTabCols(SwTable & rTab,const SwTabCols & rNew,const SwTabCols & rOld,const SwTableBox * pStart,sal_Bool bCurRowOnly)3000 void SwDoc::SetTabCols(SwTable& rTab, const SwTabCols &rNew, const SwTabCols &rOld,
3001 								const SwTableBox *pStart, sal_Bool bCurRowOnly )
3002 {
3003     if (GetIDocumentUndoRedo().DoesUndo())
3004     {
3005         GetIDocumentUndoRedo().AppendUndo(
3006             new SwUndoAttrTbl( *rTab.GetTableNode(), sal_True ));
3007 	}
3008 	rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly );
3009   	::ClearFEShellTabCols();
3010 	SetModified();
3011 }
3012 
SetRowsToRepeat(SwTable & rTable,sal_uInt16 nSet)3013 void SwDoc::SetRowsToRepeat( SwTable &rTable, sal_uInt16 nSet )
3014 {
3015     if( nSet == rTable.GetRowsToRepeat() )
3016         return;
3017 
3018     if (GetIDocumentUndoRedo().DoesUndo())
3019     {
3020         GetIDocumentUndoRedo().AppendUndo(
3021             new SwUndoTblHeadline(rTable, rTable.GetRowsToRepeat(), nSet) );
3022     }
3023 
3024     SwMsgPoolItem aChg( RES_TBLHEADLINECHG );
3025     rTable.SetRowsToRepeat( nSet );
3026     rTable.GetFrmFmt()->ModifyNotification( &aChg, &aChg );
3027     SetModified();
3028 }
3029 
3030 
3031 
3032 
3033 // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
3034 // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
3035 // Ist das Flag bCalcNewSize auf sal_True, wird fuer beide neuen Tabellen
3036 // die neue Size aus dem Max der Boxen errechnet; vorrausgesetzt,
3037 // die Size ist "absolut" gesetzt (USHRT_MAX)
3038 
AddToUndoHistory(const SwCntntNode & rNd)3039 void SwCollectTblLineBoxes::AddToUndoHistory( const SwCntntNode& rNd )
3040 {
3041 	if( pHst )
3042 		pHst->Add( rNd.GetFmtColl(), rNd.GetIndex(), ND_TEXTNODE );
3043 }
3044 
AddBox(const SwTableBox & rBox)3045 void SwCollectTblLineBoxes::AddBox( const SwTableBox& rBox )
3046 {
3047 	aPosArr.Insert( nWidth, aPosArr.Count() );
3048 	SwTableBox* p = (SwTableBox*)&rBox;
3049 	aBoxes.Insert( p, aBoxes.Count() );
3050 	nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
3051 }
3052 
GetBoxOfPos(const SwTableBox & rBox)3053 const SwTableBox* SwCollectTblLineBoxes::GetBoxOfPos( const SwTableBox& rBox )
3054 {
3055 	const SwTableBox* pRet = 0;
3056 	sal_uInt16 n;
3057 
3058 	if( aPosArr.Count() )
3059 	{
3060 		for( n = 0; n < aPosArr.Count(); ++n )
3061 			if( aPosArr[ n ] == nWidth )
3062 				break;
3063 			else if( aPosArr[ n ] > nWidth )
3064 			{
3065 				if( n )
3066 					--n;
3067 				break;
3068 			}
3069 
3070 		if( n >= aPosArr.Count() )
3071 			--n;
3072 
3073 		nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
3074 		pRet = aBoxes[ n ];
3075 	}
3076 	return pRet;
3077 }
3078 
Resize(sal_uInt16 nOffset,sal_uInt16 nOldWidth)3079 sal_Bool SwCollectTblLineBoxes::Resize( sal_uInt16 nOffset, sal_uInt16 nOldWidth )
3080 {
3081 	sal_uInt16 n;
3082 
3083 	if( aPosArr.Count() )
3084 	{
3085 		for( n = 0; n < aPosArr.Count(); ++n )
3086 			if( aPosArr[ n ] == nOffset )
3087 				break;
3088 			else if( aPosArr[ n ] > nOffset )
3089 			{
3090 				if( n )
3091 					--n;
3092 				break;
3093 			}
3094 
3095 		aPosArr.Remove( 0, n );
3096 		aBoxes.Remove( 0, n );
3097 
3098 		// dann die Positionen der neuen Size anpassen
3099 		for( n = 0; n < aPosArr.Count(); ++n )
3100 		{
3101 			sal_uLong nSize = nWidth;
3102 			nSize *= ( aPosArr[ n ] - nOffset );
3103 			nSize /= nOldWidth;
3104 			aPosArr[ n ] = sal_uInt16( nSize );
3105 		}
3106 	}
3107 	return 0 != aPosArr.Count();
3108 }
3109 
lcl_Line_CollectBox(const SwTableLine * & rpLine,void * pPara)3110 sal_Bool lcl_Line_CollectBox( const SwTableLine*& rpLine, void* pPara )
3111 {
3112 	SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3113 	if( pSplPara->IsGetValues() )
3114 		((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_Box_CollectBox, pPara );
3115 	else
3116 		((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, pPara );
3117 	return sal_True;
3118 }
3119 
lcl_Box_CollectBox(const SwTableBox * & rpBox,void * pPara)3120 sal_Bool lcl_Box_CollectBox( const SwTableBox*& rpBox, void* pPara )
3121 {
3122 	SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3123 	sal_uInt16 nLen = rpBox->GetTabLines().Count();
3124 	if( nLen )
3125 	{
3126 		// dann mit der richtigen Line weitermachen
3127 		if( pSplPara->IsGetFromTop() )
3128 			nLen = 0;
3129 		else
3130 			--nLen;
3131 
3132 		const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
3133 		lcl_Line_CollectBox( pLn, pPara );
3134 	}
3135 	else
3136 		pSplPara->AddBox( *rpBox );
3137 	return sal_True;
3138 }
3139 
lcl_BoxSetSplitBoxFmts(const SwTableBox * & rpBox,void * pPara)3140 sal_Bool lcl_BoxSetSplitBoxFmts( const SwTableBox*& rpBox, void* pPara )
3141 {
3142 	SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3143 	sal_uInt16 nLen = rpBox->GetTabLines().Count();
3144 	if( nLen )
3145 	{
3146 		// dann mit der richtigen Line weitermachen
3147 		if( pSplPara->IsGetFromTop() )
3148 			nLen = 0;
3149 		else
3150 			--nLen;
3151 
3152 		const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
3153 		lcl_Line_CollectBox( pLn, pPara );
3154 	}
3155 	else
3156 	{
3157 		const SwTableBox* pSrcBox = pSplPara->GetBoxOfPos( *rpBox );
3158 		SwFrmFmt* pFmt = pSrcBox->GetFrmFmt();
3159 		SwTableBox* pBox = (SwTableBox*)rpBox;
3160 
3161 		if( HEADLINE_BORDERCOPY == pSplPara->GetMode() )
3162 		{
3163 			const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
3164 			if( !rBoxItem.GetTop() )
3165 			{
3166 				SvxBoxItem aNew( rBoxItem );
3167 				aNew.SetLine( pFmt->GetBox().GetBottom(), BOX_LINE_TOP );
3168 				if( aNew != rBoxItem )
3169                     pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
3170 			}
3171 		}
3172 		else
3173 		{
3174 sal_uInt16 __FAR_DATA aTableSplitBoxSetRange[] = {
3175 	RES_LR_SPACE, 		RES_UL_SPACE,
3176 	RES_BACKGROUND, 	RES_SHADOW,
3177 	RES_PROTECT, 		RES_PROTECT,
3178 	RES_VERT_ORIENT,	RES_VERT_ORIENT,
3179 	0 };
3180 			SfxItemSet aTmpSet( pFmt->GetDoc()->GetAttrPool(),
3181 								aTableSplitBoxSetRange );
3182 			aTmpSet.Put( pFmt->GetAttrSet() );
3183 			if( aTmpSet.Count() )
3184                 pBox->ClaimFrmFmt()->SetFmtAttr( aTmpSet );
3185 
3186 			if( HEADLINE_BOXATRCOLLCOPY == pSplPara->GetMode() )
3187 			{
3188 				SwNodeIndex aIdx( *pSrcBox->GetSttNd(), 1 );
3189 				SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
3190 				if( !pCNd )
3191 					pCNd = aIdx.GetNodes().GoNext( &aIdx );
3192 				aIdx = *pBox->GetSttNd();
3193 				SwCntntNode* pDNd = aIdx.GetNodes().GoNext( &aIdx );
3194 
3195 				// nur wenn der Node alleine in der Section steht
3196 				if( 2 == pDNd->EndOfSectionIndex() -
3197 						pDNd->StartOfSectionIndex() )
3198 				{
3199 					pSplPara->AddToUndoHistory( *pDNd );
3200 					pDNd->ChgFmtColl( pCNd->GetFmtColl() );
3201 				}
3202 			}
3203 
3204 			// bedingte Vorlage beachten
3205 			pBox->GetSttNd()->CheckSectionCondColl();
3206 		}
3207 	}
3208 	return sal_True;
3209 }
3210 
3211 
SplitTable(const SwPosition & rPos,sal_uInt16 eHdlnMode,sal_Bool bCalcNewSize)3212 sal_Bool SwDoc::SplitTable( const SwPosition& rPos, sal_uInt16 eHdlnMode,
3213 						sal_Bool bCalcNewSize )
3214 {
3215 	SwNode* pNd = &rPos.nNode.GetNode();
3216 	SwTableNode* pTNd = pNd->FindTableNode();
3217 	if( !pTNd || pNd->IsTableNode() )
3218 		return 0;
3219 
3220 	if( pTNd->GetTable().ISA( SwDDETable ))
3221 		return sal_False;
3222 
3223 	SwTable& rTbl = pTNd->GetTable();
3224 	rTbl.SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
3225 
3226 	SwTableFmlUpdate aMsgHnt( &rTbl );
3227 
3228 	SwHistory aHistory;
3229     if (GetIDocumentUndoRedo().DoesUndo())
3230     {
3231 		aMsgHnt.pHistory = &aHistory;
3232     }
3233 
3234 	{
3235 		sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3236 
3237 		// Suche die Grund-Line dieser Box:
3238 		SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
3239 		if( pBox )
3240 		{
3241 			SwTableLine* pLine = pBox->GetUpper();
3242 			while( pLine->GetUpper() )
3243 				pLine = pLine->GetUpper()->GetUpper();
3244 
3245 			// in pLine steht jetzt die GrundLine.
3246 			aMsgHnt.nSplitLine = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
3247 		}
3248 
3249 		String sNewTblNm( GetUniqueTblName() );
3250 		aMsgHnt.DATA.pNewTblNm = &sNewTblNm;
3251 		aMsgHnt.eFlags = TBL_SPLITTBL;
3252 		UpdateTblFlds( &aMsgHnt );
3253 	}
3254 
3255 	//Lines fuer das Layout-Update heraussuchen.
3256 	_FndBox aFndBox( 0, 0 );
3257     aFndBox.SetTableLines( rTbl );
3258     aFndBox.DelFrms( rTbl );
3259 
3260     // TL_CHART2: need to inform chart of probably changed cell names
3261     //pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3262 
3263 	SwTableNode* pNew = GetNodes().SplitTable( rPos.nNode, sal_False, bCalcNewSize );
3264 
3265 	if( pNew )
3266 	{
3267         SwSaveRowSpan* pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTbl.GetTabLines().Count() );
3268 		SwUndoSplitTbl* pUndo = 0;
3269         if (GetIDocumentUndoRedo().DoesUndo())
3270         {
3271             pUndo = new SwUndoSplitTbl(
3272                         *pNew, pSaveRowSp, eHdlnMode, bCalcNewSize);
3273             GetIDocumentUndoRedo().AppendUndo(pUndo);
3274 			if( aHistory.Count() )
3275 				pUndo->SaveFormula( aHistory );
3276 		}
3277 
3278 		switch( eHdlnMode )
3279 		{
3280 			// setze die untere Border der vorherige Line,
3281 			// an der aktuellen als obere
3282 		case HEADLINE_BORDERCOPY:
3283 			{
3284 				SwCollectTblLineBoxes aPara( sal_False, eHdlnMode );
3285 				SwTableLine* pLn = rTbl.GetTabLines()[
3286 							rTbl.GetTabLines().Count() - 1 ];
3287 				pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
3288 
3289 				aPara.SetValues( sal_True );
3290 				pLn = pNew->GetTable().GetTabLines()[ 0 ];
3291 				pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
3292 
3293 				// Kopfzeile wiederholen abschalten
3294                 pNew->GetTable().SetRowsToRepeat( 0 );
3295 			}
3296 			break;
3297 
3298 			// setze die Attributierung der ersten Line an der neuen ersten
3299 		case HEADLINE_BOXATTRCOPY:
3300 		case HEADLINE_BOXATRCOLLCOPY:
3301 			{
3302 				SwHistory* pHst = 0;
3303 				if( HEADLINE_BOXATRCOLLCOPY == eHdlnMode && pUndo )
3304 					pHst = pUndo->GetHistory();
3305 
3306 				SwCollectTblLineBoxes aPara( sal_True, eHdlnMode, pHst );
3307 				SwTableLine* pLn = rTbl.GetTabLines()[ 0 ];
3308 				pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
3309 
3310 				aPara.SetValues( sal_True );
3311 				pLn = pNew->GetTable().GetTabLines()[ 0 ];
3312 				pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
3313 			}
3314 			break;
3315 
3316 		case HEADLINE_CNTNTCOPY:
3317 			rTbl.CopyHeadlineIntoTable( *pNew );
3318 			if( pUndo )
3319 				pUndo->SetTblNodeOffset( pNew->GetIndex() );
3320 			break;
3321 
3322 		case HEADLINE_NONE:
3323 			// Kopfzeile wiederholen abschalten
3324             pNew->GetTable().SetRowsToRepeat( 0 );
3325 			break;
3326 		}
3327 
3328 		// und Frms einfuegen.
3329 		SwNodeIndex aNdIdx( *pNew->EndOfSectionNode() );
3330 		GetNodes().GoNext( &aNdIdx );      // zum naechsten ContentNode
3331 		pNew->MakeFrms( &aNdIdx );
3332 
3333 		//Zwischen die Tabellen wird ein Absatz geschoben
3334 		GetNodes().MakeTxtNode( SwNodeIndex( *pNew ),
3335 								GetTxtCollFromPool( RES_POOLCOLL_TEXT ) );
3336 	}
3337 
3338 	//Layout updaten
3339     aFndBox.MakeFrms( rTbl );
3340 
3341     // TL_CHART2: need to inform chart of probably changed cell names
3342     UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3343 
3344     SetFieldsDirty( true, NULL, 0 );
3345 
3346 	return 0 != pNew;
3347 }
3348 
lcl_ChgTblSize(SwTable & rTbl)3349 sal_Bool lcl_ChgTblSize( SwTable& rTbl )
3350 {
3351 	// das Attribut darf nicht ueber das Modify an der
3352 	// Tabelle gesetzt werden, denn sonst werden alle
3353 	// Boxen wieder auf 0 zurueck gesetzt. Also locke das Format
3354 	SwFrmFmt* pFmt = rTbl.GetFrmFmt();
3355 	SwFmtFrmSize aTblMaxSz( pFmt->GetFrmSize() );
3356 
3357 	if( USHRT_MAX == aTblMaxSz.GetWidth() )
3358 		return sal_False;
3359 
3360 	sal_Bool bLocked = pFmt->IsModifyLocked();
3361 	pFmt->LockModify();
3362 
3363 	aTblMaxSz.SetWidth( 0 );
3364 
3365 	SwTableLines& rLns = rTbl.GetTabLines();
3366 	for( sal_uInt16 nLns = 0; nLns < rLns.Count(); ++nLns )
3367 	{
3368 		SwTwips nMaxLnWidth = 0;
3369 		SwTableBoxes& rBoxes = rLns[ nLns ]->GetTabBoxes();
3370 		for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox )
3371 			nMaxLnWidth += rBoxes[nBox]->GetFrmFmt()->GetFrmSize().GetWidth();
3372 
3373 		if( nMaxLnWidth > aTblMaxSz.GetWidth() )
3374 			aTblMaxSz.SetWidth( nMaxLnWidth );
3375 	}
3376     pFmt->SetFmtAttr( aTblMaxSz );
3377 	if( !bLocked )			// und gegebenenfalls Lock wieder freigeben
3378 		pFmt->UnlockModify();
3379 
3380 	return sal_True;
3381 }
3382 
3383 class _SplitTable_Para
3384 {
3385 	SvPtrarr aSrc, aDest;
3386 	SwTableNode* pNewTblNd;
3387 	SwTable& rOldTbl;
3388 
3389 public:
_SplitTable_Para(SwTableNode * pNew,SwTable & rOld)3390 	_SplitTable_Para( SwTableNode* pNew, SwTable& rOld )
3391 		: aSrc( 16, 16 ), aDest( 16, 16 ), pNewTblNd( pNew ), rOldTbl( rOld )
3392 	{}
SrcFmt_GetPos(void * pFmt) const3393 	sal_uInt16 SrcFmt_GetPos( void* pFmt ) const
3394 			{ return aSrc.GetPos( pFmt ); }
3395 
DestFmt_Insert(void * pFmt)3396 	void DestFmt_Insert( void* pFmt )
3397 			{ aDest.Insert( pFmt, aDest.Count() ); }
3398 
SrcFmt_Insert(void * pFmt)3399 	void SrcFmt_Insert( void* pFmt )
3400 			{ aSrc.Insert( pFmt, aSrc.Count() ); }
3401 
DestFmt_Get(sal_uInt16 nPos) const3402 	SwFrmFmt* DestFmt_Get( sal_uInt16 nPos ) const
3403 			{ return (SwFrmFmt*)aDest[ nPos ]; }
3404 
ChgBox(SwTableBox * pBox)3405 	void ChgBox( SwTableBox* pBox )
3406 	{
3407 		rOldTbl.GetTabSortBoxes().Remove( pBox );
3408 		pNewTblNd->GetTable().GetTabSortBoxes().Insert( pBox );
3409 	}
3410 };
3411 
3412 
3413 sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara );
3414 
lcl_SplitTable_CpyLine(const SwTableLine * & rpLine,void * pPara)3415 sal_Bool lcl_SplitTable_CpyLine( const SwTableLine*& rpLine, void* pPara )
3416 {
3417 	SwTableLine* pLn = (SwTableLine*)rpLine;
3418 	_SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
3419 
3420 	SwFrmFmt *pSrcFmt = pLn->GetFrmFmt();
3421 	sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
3422 	if( USHRT_MAX == nPos )
3423 	{
3424 		rPara.DestFmt_Insert( pLn->ClaimFrmFmt() );
3425 		rPara.SrcFmt_Insert( pSrcFmt );
3426 	}
3427 	else
3428 		pLn->ChgFrmFmt( (SwTableLineFmt*)rPara.DestFmt_Get( nPos ) );
3429 
3430 	pLn->GetTabBoxes().ForEach( &lcl_SplitTable_CpyBox, pPara );
3431 	return sal_True;
3432 }
3433 
lcl_SplitTable_CpyBox(const SwTableBox * & rpBox,void * pPara)3434 sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara )
3435 {
3436 	SwTableBox* pBox = (SwTableBox*)rpBox;
3437 	_SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
3438 
3439 	SwFrmFmt *pSrcFmt = pBox->GetFrmFmt();
3440 	sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
3441 	if( USHRT_MAX == nPos )
3442 	{
3443 		rPara.DestFmt_Insert( pBox->ClaimFrmFmt() );
3444 		rPara.SrcFmt_Insert( pSrcFmt );
3445 	}
3446 	else
3447 		pBox->ChgFrmFmt( (SwTableBoxFmt*)rPara.DestFmt_Get( nPos ) );
3448 
3449 	if( pBox->GetSttNd() )
3450 		rPara.ChgBox( pBox );
3451 	else
3452 		pBox->GetTabLines().ForEach( &lcl_SplitTable_CpyLine, pPara );
3453 	return sal_True;
3454 }
3455 
SplitTable(const SwNodeIndex & rPos,sal_Bool bAfter,sal_Bool bCalcNewSize)3456 SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, sal_Bool bAfter,
3457 									sal_Bool bCalcNewSize )
3458 {
3459 	SwNode* pNd = &rPos.GetNode();
3460 	SwTableNode* pTNd = pNd->FindTableNode();
3461 	if( !pTNd || pNd->IsTableNode() )
3462 		return 0;
3463 
3464 	sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3465 
3466 	// Suche die Grund-Line dieser Box:
3467 	SwTable& rTbl = pTNd->GetTable();
3468 	SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
3469 	if( !pBox )
3470 		return 0;
3471 
3472 	SwTableLine* pLine = pBox->GetUpper();
3473 	while( pLine->GetUpper() )
3474 		pLine = pLine->GetUpper()->GetUpper();
3475 
3476 	// in pLine steht jetzt die GrundLine.
3477 	sal_uInt16 nLinePos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
3478 	if( USHRT_MAX == nLinePos ||
3479 		( bAfter ? ++nLinePos >= rTbl.GetTabLines().Count() : !nLinePos ))
3480 		return 0;		// nicht gefunden oder letze Line !!
3481 
3482 	// Suche jetzt die 1. Box der nachfolgenden Line
3483 	SwTableLine* pNextLine = rTbl.GetTabLines()[ nLinePos ];
3484 	pBox = pNextLine->GetTabBoxes()[0];
3485 	while( !pBox->GetSttNd() )
3486 		pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
3487 
3488 	// dann fuege mal einen End- und TabelleNode ins Nodes-Array ein.
3489 	SwTableNode * pNewTblNd;
3490 	{
3491 		SwEndNode* pOldTblEndNd = (SwEndNode*)pTNd->EndOfSectionNode()->GetEndNode();
3492 		ASSERT( pOldTblEndNd, "wo ist der EndNode?" )
3493 
3494 		SwNodeIndex aIdx( *pBox->GetSttNd() );
3495 		new SwEndNode( aIdx, *pTNd );
3496 		pNewTblNd = new SwTableNode( aIdx );
3497         pNewTblNd->GetTable().SetTableModel( rTbl.IsNewModel() );
3498 
3499 		pOldTblEndNd->pStartOfSection = pNewTblNd;
3500 		pNewTblNd->pEndOfSection = pOldTblEndNd;
3501 
3502 		SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3503 		do {
3504 			ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
3505 			pBoxNd->pStartOfSection = pNewTblNd;
3506 			pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3507 		} while( pBoxNd != pOldTblEndNd );
3508 	}
3509 
3510 	{
3511         // die Lines ruebermoven...
3512 		SwTable& rNewTbl = pNewTblNd->GetTable();
3513 		rNewTbl.GetTabLines().Insert( &rTbl.GetTabLines(), 0, nLinePos );
3514         //
3515         // von hinten (unten-rechts) nach vorn (oben-links) alle Boxen
3516         // beim chart data provider austragen (das modified event wird dann
3517         // in der aufrufenden Funktion getriggert.
3518         // TL_CHART2:
3519         SwChartDataProvider *pPCD = rTbl.GetFrmFmt()->getIDocumentChartDataProviderAccess()->GetChartDataProvider();
3520         if( pPCD )
3521         {
3522             for (sal_uInt16 k = nLinePos;  k < rTbl.GetTabLines().Count();  ++k)
3523             {
3524                 sal_uInt16 nLineIdx = (rTbl.GetTabLines().Count() - 1) - k + nLinePos;
3525                 sal_uInt16 nBoxCnt = rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes().Count();
3526                 for (sal_uInt16 j = 0;  j < nBoxCnt;  ++j)
3527                 {
3528                     sal_uInt16 nIdx = nBoxCnt - 1 - j;
3529                     pPCD->DeleteBox( &rTbl, *rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] );
3530                 }
3531             }
3532         }
3533         //
3534         // ...und loeschen
3535         sal_uInt16 nDeleted = rTbl.GetTabLines().Count() - nLinePos;
3536 		rTbl.GetTabLines().Remove( nLinePos, nDeleted );
3537 
3538 		// und die betr. Boxen verschieben. Dabei die Formate eindeutig
3539 		// machen und die StartNodes korrigieren
3540 		_SplitTable_Para aPara( pNewTblNd, rTbl );
3541 		rNewTbl.GetTabLines().ForEach( &lcl_SplitTable_CpyLine, &aPara );
3542         rTbl.CleanUpBottomRowSpan( nDeleted );
3543 	}
3544 
3545 	{
3546 		// Das Tabellen-FrmFormat kopieren
3547 		SwFrmFmt* pOldTblFmt = rTbl.GetFrmFmt();
3548 		SwFrmFmt* pNewTblFmt = pOldTblFmt->GetDoc()->MakeTblFrmFmt(
3549 								pOldTblFmt->GetDoc()->GetUniqueTblName(),
3550 								pOldTblFmt->GetDoc()->GetDfltFrmFmt() );
3551 
3552 		*pNewTblFmt = *pOldTblFmt;
3553         pNewTblNd->GetTable().RegisterToFormat( *pNewTblFmt );
3554 
3555 		// neue Size errechnen ? (lcl_ChgTblSize nur das 2. aufrufen, wenn es
3556 		// beim 1. schon geklappt hat; also absolute Groesse hat)
3557 		if( bCalcNewSize && lcl_ChgTblSize( rTbl ) )
3558 			lcl_ChgTblSize( pNewTblNd->GetTable() );
3559 	}
3560 
3561     // TL_CHART2: need to inform chart of probably changed cell names
3562     rTbl.UpdateCharts();
3563 
3564 	return pNewTblNd;		// das wars
3565 }
3566 
3567 // und die Umkehrung davon. rPos muss in der Tabelle stehen, die bestehen
3568 // bleibt. Das Flag besagt ob die aktuelle mit der davor oder dahinter
3569 // stehenden vereint wird.
MergeTable(const SwPosition & rPos,sal_Bool bWithPrev,sal_uInt16 nMode)3570 sal_Bool SwDoc::MergeTable( const SwPosition& rPos, sal_Bool bWithPrev, sal_uInt16 nMode )
3571 {
3572 	SwTableNode* pTblNd = rPos.nNode.GetNode().FindTableNode(), *pDelTblNd;
3573 	if( !pTblNd )
3574 		return sal_False;
3575 
3576 	SwNodes& rNds = GetNodes();
3577 	if( bWithPrev )
3578 		pDelTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode();
3579 	else
3580 		pDelTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode();
3581 	if( !pDelTblNd )
3582 		return sal_False;
3583 
3584 	if( pTblNd->GetTable().ISA( SwDDETable ) ||
3585 		pDelTblNd->GetTable().ISA( SwDDETable ))
3586 		return sal_False;
3587 
3588 	// MIB 9.7.97: HTML-Layout loeschen
3589 	pTblNd->GetTable().SetHTMLTableLayout( 0 );
3590 	pDelTblNd->GetTable().SetHTMLTableLayout( 0 );
3591 
3592 	// beide Tabellen vorhanden, also kanns losgehen
3593 	SwUndoMergeTbl* pUndo = 0;
3594 	SwHistory* pHistory = 0;
3595     if (GetIDocumentUndoRedo().DoesUndo())
3596     {
3597         pUndo = new SwUndoMergeTbl( *pTblNd, *pDelTblNd, bWithPrev, nMode );
3598         GetIDocumentUndoRedo().AppendUndo(pUndo);
3599 		pHistory = new SwHistory;
3600 	}
3601 
3602 	// alle "Tabellenformeln" anpassen
3603 	SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
3604 	aMsgHnt.DATA.pDelTbl = &pDelTblNd->GetTable();
3605 	aMsgHnt.eFlags = TBL_MERGETBL;
3606 	aMsgHnt.pHistory = pHistory;
3607 	UpdateTblFlds( &aMsgHnt );
3608 
3609 	// das eigentliche Mergen
3610 	SwNodeIndex aIdx( bWithPrev ? *pTblNd : *pDelTblNd );
3611 	sal_Bool bRet = rNds.MergeTable( aIdx, !bWithPrev, nMode, pHistory );
3612 
3613 	if( pHistory )
3614 	{
3615 		if( pHistory->Count() )
3616 			pUndo->SaveFormula( *pHistory );
3617 		delete pHistory;
3618 	}
3619 	if( bRet )
3620 	{
3621 		SetModified();
3622 		SetFieldsDirty( true, NULL, 0 );
3623 	}
3624 	return bRet;
3625 }
3626 
MergeTable(const SwNodeIndex & rPos,sal_Bool bWithPrev,sal_uInt16 nMode,SwHistory *)3627 sal_Bool SwNodes::MergeTable( const SwNodeIndex& rPos, sal_Bool bWithPrev,
3628 							sal_uInt16 nMode, SwHistory* )
3629 {
3630 	SwTableNode* pDelTblNd = rPos.GetNode().GetTableNode();
3631 	ASSERT( pDelTblNd, "wo ist der TableNode geblieben?" );
3632 
3633 	SwTableNode* pTblNd = (*this)[ rPos.GetIndex() - 1]->FindTableNode();
3634 	ASSERT( pTblNd, "wo ist der TableNode geblieben?" );
3635 
3636 	if( !pDelTblNd || !pTblNd )
3637 		return sal_False;
3638 
3639 	pDelTblNd->DelFrms();
3640 
3641 	SwTable& rDelTbl = pDelTblNd->GetTable();
3642 	SwTable& rTbl = pTblNd->GetTable();
3643 
3644 	//Lines fuer das Layout-Update herausuchen.
3645 	_FndBox aFndBox( 0, 0 );
3646     aFndBox.SetTableLines( rTbl );
3647     aFndBox.DelFrms( rTbl );
3648 
3649     // TL_CHART2: since chart currently does not want to get informed about
3650     // additional rows/cols there is no need for a modified event in the
3651     // remaining first table. Also, if it is required it  should be done
3652     // after the merging and not here...
3653     // pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3654 
3655 
3656     // TL_CHART2:
3657     // tell the charts about the table to be deleted and have them use their own data
3658     GetDoc()->CreateChartInternalDataProviders( &rDelTbl );
3659 
3660 	// die Breite der TabellenFormate abgleichen:
3661 	{
3662 		const SwFmtFrmSize& rTblSz = rTbl.GetFrmFmt()->GetFrmSize();
3663 		const SwFmtFrmSize& rDelTblSz = rDelTbl.GetFrmFmt()->GetFrmSize();
3664 		if( rTblSz != rDelTblSz )
3665 		{
3666 			// dann sollten die mal schleunigst korrigiert werden
3667 			if( bWithPrev )
3668                 rDelTbl.GetFrmFmt()->SetFmtAttr( rTblSz );
3669 			else
3670                 rTbl.GetFrmFmt()->SetFmtAttr( rDelTblSz );
3671 		}
3672 	}
3673 
3674 	if( !bWithPrev )
3675 	{
3676 		// dann mussen alle Attruibute der hinteren Tabelle auf die
3677 		// vordere uebertragen werden, weil die hintere ueber das loeschen
3678 		// des Node geloescht wird.
3679         rTbl.SetRowsToRepeat( rDelTbl.GetRowsToRepeat() );
3680 		rTbl.SetTblChgMode( rDelTbl.GetTblChgMode() );
3681 
3682 		rTbl.GetFrmFmt()->LockModify();
3683 		*rTbl.GetFrmFmt() = *rDelTbl.GetFrmFmt();
3684 		// auch den Namen umsetzen!
3685 		rTbl.GetFrmFmt()->SetName( rDelTbl.GetFrmFmt()->GetName() );
3686 		rTbl.GetFrmFmt()->UnlockModify();
3687 	}
3688 
3689 	// die Lines und Boxen ruebermoven
3690 	sal_uInt16 nOldSize = rTbl.GetTabLines().Count();
3691 	rTbl.GetTabLines().Insert( &rDelTbl.GetTabLines(), nOldSize );
3692 	rDelTbl.GetTabLines().Remove( 0, rDelTbl.GetTabLines().Count() );
3693 
3694 	rTbl.GetTabSortBoxes().Insert( &rDelTbl.GetTabSortBoxes() );
3695 	rDelTbl.GetTabSortBoxes().Remove( (sal_uInt16)0, rDelTbl.GetTabSortBoxes().Count() );
3696 
3697 	// die vordere Tabelle bleibt immer stehen, die hintere wird geloescht
3698 	SwEndNode* pTblEndNd = pDelTblNd->EndOfSectionNode();
3699 	pTblNd->pEndOfSection = pTblEndNd;
3700 
3701 	SwNodeIndex aIdx( *pDelTblNd, 1 );
3702 
3703 	SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3704 	do {
3705 		ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
3706 		pBoxNd->pStartOfSection = pTblNd;
3707 		pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3708 	} while( pBoxNd != pTblEndNd );
3709 	pBoxNd->pStartOfSection = pTblNd;
3710 
3711 	aIdx -= 2;
3712 	DelNodes( aIdx, 2 );
3713 
3714 	// jetzt an der 1. eingefuegten Line die bedingten Vorlagen umschubsen
3715 	const SwTableLine* pFirstLn = rTbl.GetTabLines()[ nOldSize ];
3716 	if( 1 == nMode )		//
3717 	{
3718 		// Header-Vorlagen in der Zeile setzen
3719 		// und ggfs. in der History speichern fuers Undo!!!
3720 	}
3721 	lcl_LineSetHeadCondColl( pFirstLn, 0 );
3722 
3723 	// und die Borders "aufrauemen"
3724 	if( nOldSize )
3725 	{
3726 		_SwGCLineBorder aPara( rTbl );
3727 		aPara.nLinePos = --nOldSize;
3728 		pFirstLn = rTbl.GetTabLines()[ nOldSize ];
3729 		lcl_GC_Line_Border( pFirstLn, &aPara );
3730 	}
3731 
3732 	//Layout updaten
3733     aFndBox.MakeFrms( rTbl );
3734 
3735     return sal_True;
3736 }
3737 
3738 // -------------------------------------------------------------------
3739 
3740 
3741 // -- benutze die ForEach Methode vom PtrArray
3742 struct _SetAFmtTabPara
3743 {
3744 	SwTableAutoFmt& rTblFmt;
3745 	SwUndoTblAutoFmt* pUndo;
3746 	sal_uInt16 nEndBox, nCurBox;
3747 	sal_uInt8 nAFmtLine, nAFmtBox;
3748 
_SetAFmtTabPara_SetAFmtTabPara3749 	_SetAFmtTabPara( const SwTableAutoFmt& rNew )
3750 		: rTblFmt( (SwTableAutoFmt&)rNew ), pUndo( 0 ),
3751 		nEndBox( 0 ), nCurBox( 0 ), nAFmtLine( 0 ), nAFmtBox( 0 )
3752 	{}
3753 };
3754 
3755 // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
3756 // koennen.
3757 sal_Bool lcl_SetAFmtBox( const _FndBox*&, void *pPara );
3758 sal_Bool lcl_SetAFmtLine( const _FndLine*&, void *pPara );
3759 
lcl_SetAFmtLine(const _FndLine * & rpLine,void * pPara)3760 sal_Bool lcl_SetAFmtLine( const _FndLine*& rpLine, void *pPara )
3761 {
3762 	((_FndLine*&)rpLine)->GetBoxes().ForEach( &lcl_SetAFmtBox, pPara );
3763 	return sal_True;
3764 }
3765 
lcl_SetAFmtBox(const _FndBox * & rpBox,void * pPara)3766 sal_Bool lcl_SetAFmtBox( const _FndBox*& rpBox, void *pPara )
3767 {
3768 	_SetAFmtTabPara* pSetPara = (_SetAFmtTabPara*)pPara;
3769 
3770 	if( !rpBox->GetUpper()->GetUpper() )	// Box auf 1. Ebene ?
3771 	{
3772 		if( !pSetPara->nCurBox )
3773 			pSetPara->nAFmtBox = 0;
3774 		else if( pSetPara->nCurBox == pSetPara->nEndBox )
3775 			pSetPara->nAFmtBox = 3;
3776 		else
3777 			pSetPara->nAFmtBox = (sal_uInt8)(1 + ((pSetPara->nCurBox-1) & 1));
3778 	}
3779 
3780 	if( rpBox->GetBox()->GetSttNd() )
3781 	{
3782 		SwTableBox* pSetBox = (SwTableBox*)rpBox->GetBox();
3783 		SwDoc* pDoc = pSetBox->GetFrmFmt()->GetDoc();
3784         // --> OD 2008-02-25 #refactorlists#
3785 //        SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
3786         SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
3787         // <--
3788 		SfxItemSet aBoxSet( pDoc->GetAttrPool(), aTableBoxSetRange );
3789 		sal_uInt8 nPos = pSetPara->nAFmtLine * 4 + pSetPara->nAFmtBox;
3790 		pSetPara->rTblFmt.UpdateToSet( nPos, aCharSet,
3791 										SwTableAutoFmt::UPDATE_CHAR, 0 );
3792 		pSetPara->rTblFmt.UpdateToSet( nPos, aBoxSet,
3793 										SwTableAutoFmt::UPDATE_BOX,
3794 										pDoc->GetNumberFormatter( sal_True ) );
3795 		if( aCharSet.Count() )
3796 		{
3797 			sal_uLong nSttNd = pSetBox->GetSttIdx()+1;
3798 			sal_uLong nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex();
3799 			for( ; nSttNd < nEndNd; ++nSttNd )
3800 			{
3801 				SwCntntNode* pNd = pDoc->GetNodes()[ nSttNd ]->GetCntntNode();
3802 				if( pNd )
3803 					pNd->SetAttr( aCharSet );
3804 			}
3805 		}
3806 
3807 		if( aBoxSet.Count() )
3808 		{
3809 			if( pSetPara->pUndo &&
3810 				SFX_ITEM_SET == aBoxSet.GetItemState( RES_BOXATR_FORMAT ))
3811 				pSetPara->pUndo->SaveBoxCntnt( *pSetBox );
3812 
3813             pSetBox->ClaimFrmFmt()->SetFmtAttr( aBoxSet );
3814 		}
3815 	}
3816 	else
3817 		((_FndBox*&)rpBox)->GetLines().ForEach( &lcl_SetAFmtLine, pPara );
3818 
3819 	if( !rpBox->GetUpper()->GetUpper() )		// eine BaseLine
3820 		++pSetPara->nCurBox;
3821 	return sal_True;
3822 }
3823 
3824 
3825 		// AutoFormat fuer die Tabelle/TabellenSelection
SetTableAutoFmt(const SwSelBoxes & rBoxes,const SwTableAutoFmt & rNew)3826 sal_Bool SwDoc::SetTableAutoFmt( const SwSelBoxes& rBoxes, const SwTableAutoFmt& rNew )
3827 {
3828 	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
3829 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
3830 	if( !pTblNd )
3831 		return sal_False;
3832 
3833 	// suche alle Boxen / Lines
3834 	_FndBox aFndBox( 0, 0 );
3835 	{
3836 		_FndPara aPara( rBoxes, &aFndBox );
3837 		pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
3838 	}
3839 	if( !aFndBox.GetLines().Count() )
3840 		return sal_False;
3841 
3842 	pTblNd->GetTable().SetHTMLTableLayout( 0 );
3843 
3844 	_FndBox* pFndBox = &aFndBox;
3845 	while( 1 == pFndBox->GetLines().Count() &&
3846 			1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
3847 		pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
3848 
3849 	if( !pFndBox->GetLines().Count() )		// eine zu weit? (nur 1 sel.Box)
3850 		pFndBox = pFndBox->GetUpper()->GetUpper();
3851 
3852 
3853 	// Undo abschalten, Attribute werden sich vorher gemerkt
3854 	SwUndoTblAutoFmt* pUndo = 0;
3855     bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
3856     if (bUndo)
3857     {
3858         pUndo = new SwUndoTblAutoFmt( *pTblNd, rNew );
3859         GetIDocumentUndoRedo().AppendUndo(pUndo);
3860         GetIDocumentUndoRedo().DoUndo(false);
3861     }
3862 
3863 	_SetAFmtTabPara aPara( rNew );
3864 	_FndLines& rFLns = pFndBox->GetLines();
3865 	_FndLine* pLine;
3866 
3867 	for( sal_uInt16 n = 0; n < rFLns.Count(); ++n )
3868 	{
3869 		pLine = rFLns[n];
3870 
3871 		// Upper auf 0 setzen (Base-Line simulieren!)
3872 		_FndBox* pSaveBox = pLine->GetUpper();
3873 		pLine->SetUpper( 0 );
3874 
3875 		if( !n )
3876 			aPara.nAFmtLine = 0;
3877 		else if( n+1 == rFLns.Count() )
3878 			aPara.nAFmtLine = 3;
3879 		else
3880 			aPara.nAFmtLine = (sal_uInt8)(1 + ((n-1) & 1 ));
3881 
3882 		aPara.nAFmtBox = 0;
3883 		aPara.nCurBox = 0;
3884 		aPara.nEndBox = pLine->GetBoxes().Count()-1;
3885 		aPara.pUndo = pUndo;
3886 		pLine->GetBoxes().ForEach( &lcl_SetAFmtBox, &aPara );
3887 
3888 		pLine->SetUpper( pSaveBox );
3889 	}
3890 
3891 	if( pUndo )
3892     {
3893         GetIDocumentUndoRedo().DoUndo(bUndo);
3894     }
3895 
3896 	SetModified();
3897 	SetFieldsDirty( true, NULL, 0 );
3898 
3899 	return sal_True;
3900 }
3901 
3902 
3903 		// Erfrage wie attributiert ist
GetTableAutoFmt(const SwSelBoxes & rBoxes,SwTableAutoFmt & rGet)3904 sal_Bool SwDoc::GetTableAutoFmt( const SwSelBoxes& rBoxes, SwTableAutoFmt& rGet )
3905 {
3906 	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
3907 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
3908 	if( !pTblNd )
3909 		return sal_False;
3910 
3911 	// suche alle Boxen / Lines
3912 	_FndBox aFndBox( 0, 0 );
3913 	{
3914 		_FndPara aPara( rBoxes, &aFndBox );
3915 		pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
3916 	}
3917 	if( !aFndBox.GetLines().Count() )
3918 		return sal_False;
3919 
3920 	_FndBox* pFndBox = &aFndBox;
3921 	while( 1 == pFndBox->GetLines().Count() &&
3922 			1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
3923 		pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
3924 
3925 	if( !pFndBox->GetLines().Count() )		// eine zu weit? (nur 1 sel.Box)
3926 		pFndBox = pFndBox->GetUpper()->GetUpper();
3927 
3928 	_FndLines& rFLns = pFndBox->GetLines();
3929 
3930 	sal_uInt16 aLnArr[4];
3931 	aLnArr[0] = 0;
3932 	aLnArr[1] = 1 < rFLns.Count() ? 1 : 0;
3933 	aLnArr[2] = 2 < rFLns.Count() ? 2 : aLnArr[1];
3934 	aLnArr[3] = rFLns.Count() - 1;
3935 
3936 	for( sal_uInt8 nLine = 0; nLine < 4; ++nLine )
3937 	{
3938 		_FndLine& rLine = *rFLns[ aLnArr[ nLine ] ];
3939 
3940 		sal_uInt16 aBoxArr[4];
3941 		aBoxArr[0] = 0;
3942 		aBoxArr[1] = 1 < rLine.GetBoxes().Count() ? 1 : 0;
3943 		aBoxArr[2] = 2 < rLine.GetBoxes().Count() ? 2 : aBoxArr[1];
3944 		aBoxArr[3] = rLine.GetBoxes().Count() - 1;
3945 
3946 		for( sal_uInt8 nBox = 0; nBox < 4; ++nBox )
3947 		{
3948 			SwTableBox* pFBox = rLine.GetBoxes()[ aBoxArr[ nBox ] ]->GetBox();
3949 			// immer auf die 1. runterfallen
3950 			while( !pFBox->GetSttNd() )
3951 				pFBox = pFBox->GetTabLines()[0]->GetTabBoxes()[0];
3952 
3953 			sal_uInt8 nPos = nLine * 4 + nBox;
3954 			SwNodeIndex aIdx( *pFBox->GetSttNd(), 1 );
3955 			SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
3956 			if( !pCNd )
3957 				pCNd = GetNodes().GoNext( &aIdx );
3958 
3959 			if( pCNd )
3960 				rGet.UpdateFromSet( nPos, pCNd->GetSwAttrSet(),
3961 									SwTableAutoFmt::UPDATE_CHAR, 0 );
3962 			rGet.UpdateFromSet( nPos, pFBox->GetFrmFmt()->GetAttrSet(),
3963 								SwTableAutoFmt::UPDATE_BOX,
3964 								GetNumberFormatter( sal_True ) );
3965 		}
3966 	}
3967 
3968 	return sal_True;
3969 }
3970 
GetUniqueTblName() const3971 String SwDoc::GetUniqueTblName() const
3972 {
3973 	ResId aId( STR_TABLE_DEFNAME, *pSwResMgr );
3974 	String aName( aId );
3975 	xub_StrLen nNmLen = aName.Len();
3976 
3977 	sal_uInt16 nNum, nTmp, nFlagSize = ( pTblFrmFmtTbl->Count() / 8 ) +2;
3978 	sal_uInt16 n;
3979 
3980 	sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ];
3981 	memset( pSetFlags, 0, nFlagSize );
3982 
3983 	for( n = 0; n < pTblFrmFmtTbl->Count(); ++n )
3984 	{
3985 		const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
3986 		if( !pFmt->IsDefault() && IsUsed( *pFmt )  &&
3987 			pFmt->GetName().Match( aName ) == nNmLen )
3988 		{
3989 			// Nummer bestimmen und das Flag setzen
3990 			nNum = static_cast<sal_uInt16>(pFmt->GetName().Copy( nNmLen ).ToInt32());
3991 			if( nNum-- && nNum < pTblFrmFmtTbl->Count() )
3992 				pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
3993 		}
3994 	}
3995 
3996 	// alle Nummern entsprechend geflag, also bestimme die richtige Nummer
3997 	nNum = pTblFrmFmtTbl->Count();
3998 	for( n = 0; n < nFlagSize; ++n )
3999 		if( 0xff != ( nTmp = pSetFlags[ n ] ))
4000 		{
4001 			// also die Nummer bestimmen
4002 			nNum = n * 8;
4003 			while( nTmp & 1 )
4004 				++nNum, nTmp >>= 1;
4005 			break;
4006 		}
4007 
4008 	delete [] pSetFlags;
4009 	return aName += String::CreateFromInt32( ++nNum );
4010 }
4011 
FindTblFmtByName(const String & rName,sal_Bool bAll) const4012 SwTableFmt* SwDoc::FindTblFmtByName( const String& rName, sal_Bool bAll ) const
4013 {
4014 	const SwFmt* pRet = 0;
4015 	if( bAll )
4016 		pRet = FindFmtByName( (SvPtrarr&)*pTblFrmFmtTbl, rName );
4017 	else
4018 	{
4019 		// dann nur die, die im Doc gesetzt sind
4020 		for( sal_uInt16 n = 0; n < pTblFrmFmtTbl->Count(); ++n )
4021 		{
4022 			const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
4023 			if( !pFmt->IsDefault() && IsUsed( *pFmt ) &&
4024 				pFmt->GetName() == rName )
4025 			{
4026 				pRet = pFmt;
4027 				break;
4028 			}
4029 		}
4030 	}
4031 	return (SwTableFmt*)pRet;
4032 }
4033 
SetColRowWidthHeight(SwTableBox & rAktBox,sal_uInt16 eType,SwTwips nAbsDiff,SwTwips nRelDiff)4034 sal_Bool SwDoc::SetColRowWidthHeight( SwTableBox& rAktBox, sal_uInt16 eType,
4035 									SwTwips nAbsDiff, SwTwips nRelDiff )
4036 {
4037 	SwTableNode* pTblNd = (SwTableNode*)rAktBox.GetSttNd()->FindTableNode();
4038 	SwUndo* pUndo = 0;
4039 
4040 	if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType && pTblNd->GetTable().ISA( SwDDETable ))
4041 		return sal_False;
4042 
4043 	SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
4044 	aMsgHnt.eFlags = TBL_BOXPTR;
4045 	UpdateTblFlds( &aMsgHnt );
4046 
4047     bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
4048 	sal_Bool bRet = sal_False;
4049 	switch( eType & 0xff )
4050 	{
4051 	case nsTblChgWidthHeightType::WH_COL_LEFT:
4052 	case nsTblChgWidthHeightType::WH_COL_RIGHT:
4053 	case nsTblChgWidthHeightType::WH_CELL_LEFT:
4054 	case nsTblChgWidthHeightType::WH_CELL_RIGHT:
4055 		{
4056 			 bRet = pTblNd->GetTable().SetColWidth( rAktBox,
4057 								eType, nAbsDiff, nRelDiff,
4058                                 (bUndo) ? &pUndo : 0 );
4059         }
4060 		break;
4061 	case nsTblChgWidthHeightType::WH_ROW_TOP:
4062 	case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
4063 	case nsTblChgWidthHeightType::WH_CELL_TOP:
4064 	case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
4065 		bRet = pTblNd->GetTable().SetRowHeight( rAktBox,
4066 							eType, nAbsDiff, nRelDiff,
4067                             (bUndo) ? &pUndo : 0 );
4068 		break;
4069 	}
4070 
4071     GetIDocumentUndoRedo().DoUndo(bUndo); // SetColWidth can turn it off
4072 	if( pUndo )
4073     {
4074         GetIDocumentUndoRedo().AppendUndo( pUndo );
4075     }
4076 
4077 	if( bRet )
4078 	{
4079 		SetModified();
4080 		if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType )
4081 			SetFieldsDirty( true, NULL, 0 );
4082 	}
4083 	return bRet;
4084 }
4085 
4086 
ChkBoxNumFmt(SwTableBox & rBox,sal_Bool bCallUpdate)4087 void SwDoc::ChkBoxNumFmt( SwTableBox& rBox, sal_Bool bCallUpdate )
4088 {
4089 	//JP 09.07.97: Optimierung: wenn die Box schon sagt, das es Text
4090 	//							sein soll, dann bleibt das auch Text!
4091 	const SfxPoolItem* pNumFmtItem = 0;
4092 	if( SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
4093 		sal_False, &pNumFmtItem ) && GetNumberFormatter()->IsTextFormat(
4094 			((SwTblBoxNumFormat*)pNumFmtItem)->GetValue() ))
4095 		return ;
4096 
4097 	SwUndoTblNumFmt* pUndo = 0;
4098 
4099 	sal_Bool bIsEmptyTxtNd, bChgd = sal_True;
4100 	sal_uInt32 nFmtIdx;
4101 	double fNumber;
4102 	if( rBox.HasNumCntnt( fNumber, nFmtIdx, bIsEmptyTxtNd ) )
4103 	{
4104 		if( !rBox.IsNumberChanged() )
4105 			bChgd = sal_False;
4106 		else
4107 		{
4108             if (GetIDocumentUndoRedo().DoesUndo())
4109             {
4110                 GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
4111 				pUndo = new SwUndoTblNumFmt( rBox );
4112 				pUndo->SetNumFmt( nFmtIdx, fNumber );
4113 			}
4114 
4115 			SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
4116 			SfxItemSet aBoxSet( GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
4117 
4118 			sal_Bool bSetNumFmt = IsInsTblFormatNum(), bLockModify = sal_True;
4119 			if( bSetNumFmt )
4120 			{
4121 				if( !IsInsTblChangeNumFormat() )
4122 				{
4123 					if( !pNumFmtItem )
4124 						bSetNumFmt = sal_False;
4125 					else
4126 					{
4127 						sal_uLong nOldNumFmt = ((SwTblBoxNumFormat*)pNumFmtItem)->
4128 											GetValue();
4129 						SvNumberFormatter* pNumFmtr = GetNumberFormatter();
4130 
4131 						short nFmtType = pNumFmtr->GetType( nFmtIdx );
4132 						if( nFmtType == pNumFmtr->GetType( nOldNumFmt ) ||
4133 							NUMBERFORMAT_NUMBER == nFmtType )
4134 							// eingstelltes und vorgegebenes NumFormat
4135 							// stimmen ueberein -> altes Format beibehalten
4136 							nFmtIdx = nOldNumFmt;
4137 						else
4138 							// eingstelltes und vorgegebenes NumFormat
4139 							// stimmen nicht ueberein -> als Text einfuegen
4140 							bLockModify = bSetNumFmt = sal_False;
4141 					}
4142 				}
4143 
4144 				if( bSetNumFmt )
4145 				{
4146 					pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
4147 
4148 					aBoxSet.Put( SwTblBoxValue( fNumber ));
4149 					aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
4150 				}
4151 			}
4152 
4153 			// JP 28.04.98: Nur Formel zuruecksetzen reicht nicht.
4154 			//				Sorge dafuer, das der Text auch entsprechend
4155 			//				formatiert wird!
4156 
4157 			if( !bSetNumFmt && !bIsEmptyTxtNd && pNumFmtItem )
4158 			{
4159 				// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4160 				//				Sorge dafuer, das der Text auch entsprechend
4161 				//				formatiert wird!
4162                 pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4163 			}
4164 
4165 			if( bLockModify ) pBoxFmt->LockModify();
4166             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
4167 			if( bLockModify ) pBoxFmt->UnlockModify();
4168 
4169 			if( bSetNumFmt )
4170                 pBoxFmt->SetFmtAttr( aBoxSet );
4171 		}
4172 	}
4173 	else
4174 	{
4175 		// es ist keine Zahl
4176 		const SfxPoolItem* pValueItem = 0, *pFmtItem = 0;
4177 		SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
4178 		if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMAT,
4179 				sal_False, &pFmtItem ) ||
4180 			SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_VALUE,
4181 				sal_False, &pValueItem ))
4182 		{
4183             if (GetIDocumentUndoRedo().DoesUndo())
4184             {
4185                 GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
4186 				pUndo = new SwUndoTblNumFmt( rBox );
4187 			}
4188 
4189 			pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
4190 
4191 			// alle Zahlenformate entfernen
4192 			sal_uInt16 nWhich1 = RES_BOXATR_FORMULA;
4193 			if( !bIsEmptyTxtNd )
4194 				//JP 15.01.99: dieser Teil wurde doch schon oben abgeprueft!
4195 				/* && pFmtItem && !GetNumberFormatter()->
4196 				IsTextFormat( ((SwTblBoxNumFormat*)pFmtItem)->GetValue() ) )*/
4197 			{
4198 				nWhich1 = RES_BOXATR_FORMAT;
4199 
4200 				// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4201 				//				Sorge dafuer, das der Text auch entsprechend
4202 				//				formatiert wird!
4203                 pBoxFmt->SetFmtAttr( *GetDfltAttr( nWhich1 ));
4204 			}
4205             pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
4206 		}
4207 		else
4208 			bChgd = sal_False;
4209 	}
4210 
4211 	if( bChgd )
4212 	{
4213 		if( pUndo )
4214 		{
4215 			pUndo->SetBox( rBox );
4216             GetIDocumentUndoRedo().AppendUndo(pUndo);
4217             GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
4218         }
4219 
4220 		const SwTableNode* pTblNd = rBox.GetSttNd()->FindTableNode();
4221 		if( bCallUpdate )
4222 		{
4223 			SwTableFmlUpdate aTblUpdate( &pTblNd->GetTable() );
4224 			UpdateTblFlds( &aTblUpdate );
4225 
4226 			// TL_CHART2: update charts (when cursor leaves cell and
4227 			// automatic update is enabled)
4228 			if (AUTOUPD_FIELD_AND_CHARTS == getFieldUpdateFlags(true))
4229 				pTblNd->GetTable().UpdateCharts();
4230 		}
4231 		SetModified();
4232 	}
4233 }
4234 
SetTblBoxFormulaAttrs(SwTableBox & rBox,const SfxItemSet & rSet)4235 void SwDoc::SetTblBoxFormulaAttrs( SwTableBox& rBox, const SfxItemSet& rSet )
4236 {
4237     if (GetIDocumentUndoRedo().DoesUndo())
4238     {
4239         GetIDocumentUndoRedo().AppendUndo( new SwUndoTblNumFmt(rBox, &rSet) );
4240     }
4241 
4242 	SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
4243 	if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
4244 	{
4245 		pBoxFmt->LockModify();
4246         pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
4247 		pBoxFmt->UnlockModify();
4248 	}
4249 	else if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE ))
4250 	{
4251 		pBoxFmt->LockModify();
4252         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
4253 		pBoxFmt->UnlockModify();
4254 	}
4255     pBoxFmt->SetFmtAttr( rSet );
4256 	SetModified();
4257 }
4258 
ClearBoxNumAttrs(const SwNodeIndex & rNode)4259 void SwDoc::ClearBoxNumAttrs( const SwNodeIndex& rNode )
4260 {
4261 	SwStartNode* pSttNd;
4262     if( 0 != ( pSttNd = rNode.GetNode().
4263 								FindSttNodeByType( SwTableBoxStartNode )) &&
4264 		2 == pSttNd->EndOfSectionIndex() - pSttNd->GetIndex() )
4265 	{
4266 		SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().
4267 							GetTblBox( pSttNd->GetIndex() );
4268 
4269 		const SfxPoolItem* pFmtItem = 0;
4270 		const SfxItemSet& rSet = pBox->GetFrmFmt()->GetAttrSet();
4271 		if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pFmtItem ) ||
4272 			SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA, sal_False ) ||
4273 			SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, sal_False ))
4274 		{
4275             if (GetIDocumentUndoRedo().DoesUndo())
4276             {
4277                 GetIDocumentUndoRedo().AppendUndo(new SwUndoTblNumFmt(*pBox));
4278             }
4279 
4280 			SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
4281 
4282 			//JP 01.09.97: TextFormate bleiben erhalten!
4283 			sal_uInt16 nWhich1 = RES_BOXATR_FORMAT;
4284 			if( pFmtItem && GetNumberFormatter()->IsTextFormat(
4285 					((SwTblBoxNumFormat*)pFmtItem)->GetValue() ))
4286 				nWhich1 = RES_BOXATR_FORMULA;
4287 			else
4288 				// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4289 				//				Sorge dafuer, das der Text auch entsprechend
4290 				//				formatiert wird!
4291                 pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4292 
4293             pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
4294 			SetModified();
4295 		}
4296 	}
4297 }
4298 
4299 // kopiert eine Tabelle aus dem selben oder einem anderen Doc in sich
4300 // selbst. Dabei wird eine neue Tabelle angelegt oder eine bestehende
4301 // mit dem Inhalt gefuellt; wobei entweder der Inhalt ab einer Box oder
4302 // in eine bestehende TblSelektion gefuellt wird.
4303 // Gerufen wird es von: edglss.cxx/fecopy.cxx
4304 
InsCopyOfTbl(SwPosition & rInsPos,const SwSelBoxes & rBoxes,const SwTable * pCpyTbl,sal_Bool bCpyName,sal_Bool bCorrPos)4305 sal_Bool SwDoc::InsCopyOfTbl( SwPosition& rInsPos, const SwSelBoxes& rBoxes,
4306 						const SwTable* pCpyTbl, sal_Bool bCpyName, sal_Bool bCorrPos )
4307 {
4308 	sal_Bool bRet;
4309 
4310 	const SwTableNode* pSrcTblNd = pCpyTbl
4311 			? pCpyTbl->GetTableNode()
4312 			: rBoxes[ 0 ]->GetSttNd()->FindTableNode();
4313 
4314     SwTableNode * pInsTblNd = rInsPos.nNode.GetNode().FindTableNode();
4315 
4316     bool const bUndo( GetIDocumentUndoRedo().DoesUndo() );
4317 	if( !pCpyTbl && !pInsTblNd )
4318 	{
4319 		SwUndoCpyTbl* pUndo = 0;
4320         if (bUndo)
4321         {
4322             GetIDocumentUndoRedo().ClearRedo();
4323 			pUndo = new SwUndoCpyTbl;
4324         }
4325 
4326         {
4327             ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
4328             bRet = pSrcTblNd->GetTable().MakeCopy( this, rInsPos, rBoxes,
4329 												sal_True, bCpyName );
4330         }
4331 
4332 		if( pUndo )
4333 		{
4334 			if( !bRet )
4335             {
4336 				delete pUndo;
4337                 pUndo = 0;
4338             }
4339 			else
4340 			{
4341 				pInsTblNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode();
4342 
4343 				pUndo->SetTableSttIdx( pInsTblNd->GetIndex() );
4344                 GetIDocumentUndoRedo().AppendUndo( pUndo );
4345             }
4346 		}
4347 	}
4348 	else
4349 	{
4350         RedlineMode_t eOld = GetRedlineMode();
4351         if( IsRedlineOn() )
4352 	  SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON |
4353 								  nsRedlineMode_t::REDLINE_SHOW_INSERT |
4354 								  nsRedlineMode_t::REDLINE_SHOW_DELETE));
4355 
4356 		SwUndoTblCpyTbl* pUndo = 0;
4357         if (bUndo)
4358         {
4359             GetIDocumentUndoRedo().ClearRedo();
4360 			pUndo = new SwUndoTblCpyTbl;
4361             GetIDocumentUndoRedo().DoUndo(false);
4362         }
4363 
4364 		SwDoc* pCpyDoc = (SwDoc*)pSrcTblNd->GetDoc();
4365 		sal_Bool bDelCpyDoc = pCpyDoc == this;
4366 
4367 		if( bDelCpyDoc )
4368 		{
4369 			// kopiere die Tabelle erstmal in ein temp. Doc
4370 			pCpyDoc = new SwDoc;
4371             pCpyDoc->acquire();
4372 
4373 			SwPosition aPos( SwNodeIndex( pCpyDoc->GetNodes().GetEndOfContent() ));
4374 			if( !pSrcTblNd->GetTable().MakeCopy( pCpyDoc, aPos, rBoxes, sal_True, sal_True ))
4375 			{
4376                 if( pCpyDoc->release() == 0 )
4377                     delete pCpyDoc;
4378 
4379 				if( pUndo )
4380                 {
4381                     GetIDocumentUndoRedo().DoUndo(bUndo);
4382 					delete pUndo;
4383                     pUndo = 0;
4384 				}
4385 				return sal_False;
4386 			}
4387 			aPos.nNode -= 1;		// auf den EndNode der Tabelle
4388 			pSrcTblNd = aPos.nNode.GetNode().FindTableNode();
4389 		}
4390 
4391 		const SwStartNode* pSttNd = rInsPos.nNode.GetNode().FindTableBoxStartNode();
4392 
4393 		rInsPos.nContent.Assign( 0, 0 );
4394 
4395 		// no complex into complex, but copy into or from new model is welcome
4396 		if( ( !pSrcTblNd->GetTable().IsTblComplex() || pInsTblNd->GetTable().IsNewModel() )
4397             && ( bDelCpyDoc || rBoxes.Count() ) )
4398 		{
4399 			// dann die Tabelle "relativ" kopieren
4400 			const SwSelBoxes* pBoxes;
4401 			SwSelBoxes aBoxes;
4402 
4403 			if( bDelCpyDoc )
4404 			{
4405 				SwTableBox* pBox = pInsTblNd->GetTable().GetTblBox(
4406 										pSttNd->GetIndex() );
4407 				ASSERT( pBox, "Box steht nicht in dieser Tabelle" );
4408 				aBoxes.Insert( pBox );
4409 				pBoxes = &aBoxes;
4410 			}
4411 			else
4412 				pBoxes = &rBoxes;
4413 
4414 			// kopiere die Tabelle in die selktierten Zellen.
4415 			bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
4416 														*pBoxes, pUndo );
4417 		}
4418 		else
4419 		{
4420 			SwNodeIndex aNdIdx( *pSttNd, 1 );
4421 			bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
4422 													aNdIdx, pUndo );
4423 		}
4424 
4425 		if( bDelCpyDoc )
4426         {
4427             if( pCpyDoc->release() == 0 )
4428                 delete pCpyDoc;
4429         }
4430 
4431 		if( pUndo )
4432 		{
4433 			// falls die Tabelle nicht kopiert werden konnte, das Undo-Object
4434 			// wieder loeschen
4435             GetIDocumentUndoRedo().DoUndo(bUndo);
4436 			if( !bRet && pUndo->IsEmpty() )
4437 				delete pUndo;
4438             else
4439             {
4440                 GetIDocumentUndoRedo().AppendUndo(pUndo);
4441             }
4442         }
4443 
4444 		if( bCorrPos )
4445 		{
4446 			rInsPos.nNode = *pSttNd;
4447 			rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 );
4448 		}
4449         SetRedlineMode( eOld );
4450 	}
4451 
4452 	if( bRet )
4453 	{
4454 		SetModified();
4455 		SetFieldsDirty( true, NULL, 0 );
4456 	}
4457 	return bRet;
4458 }
4459 
4460 
4461 
_UnProtectTblCells(SwTable & rTbl)4462 sal_Bool SwDoc::_UnProtectTblCells( SwTable& rTbl )
4463 {
4464 	sal_Bool bChgd = sal_False;
4465     SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
4466         ?   new SwUndoAttrTbl( *rTbl.GetTableNode() )
4467         :   0;
4468 
4469 	SwTableSortBoxes& rSrtBox = rTbl.GetTabSortBoxes();
4470 	for( sal_uInt16 i = rSrtBox.Count(); i; )
4471 	{
4472 		SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
4473 		if( pBoxFmt->GetProtect().IsCntntProtected() )
4474 		{
4475             pBoxFmt->ResetFmtAttr( RES_PROTECT );
4476 			bChgd = sal_True;
4477 		}
4478 	}
4479 
4480 	if( pUndo )
4481 	{
4482 		if( bChgd )
4483         {
4484             GetIDocumentUndoRedo().AppendUndo( pUndo );
4485         }
4486         else
4487 			delete pUndo;
4488 	}
4489 	return bChgd;
4490 }
4491 
4492 
UnProtectCells(const String & rName)4493 sal_Bool SwDoc::UnProtectCells( const String& rName )
4494 {
4495 	sal_Bool bChgd = sal_False;
4496 	SwTableFmt* pFmt = FindTblFmtByName( rName );
4497 	if( pFmt )
4498 	{
4499 		bChgd = _UnProtectTblCells( *SwTable::FindTable( pFmt ) );
4500 		if( bChgd )
4501 			SetModified();
4502 	}
4503 
4504 	return bChgd;
4505 }
4506 
UnProtectCells(const SwSelBoxes & rBoxes)4507 sal_Bool SwDoc::UnProtectCells( const SwSelBoxes& rBoxes )
4508 {
4509 	sal_Bool bChgd = sal_False;
4510 	if( rBoxes.Count() )
4511     {
4512         SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
4513 				? new SwUndoAttrTbl( *rBoxes[0]->GetSttNd()->FindTableNode() )
4514 				: 0;
4515 
4516 		SvPtrarr aFmts( 16 ), aNewFmts( 16 );
4517 		for( sal_uInt16 i = rBoxes.Count(); i; )
4518 		{
4519 			SwTableBox* pBox = rBoxes[ --i ];
4520 			SwFrmFmt* pBoxFmt = pBox->GetFrmFmt();
4521 			if( pBoxFmt->GetProtect().IsCntntProtected() )
4522 			{
4523 				sal_uInt16 nFnd = aFmts.GetPos( pBoxFmt );
4524 				if( USHRT_MAX != nFnd )
4525 					pBox->ChgFrmFmt( (SwTableBoxFmt*)aNewFmts[ nFnd ] );
4526 				else
4527 				{
4528 					aFmts.Insert( pBoxFmt, aFmts.Count() );
4529 					pBoxFmt = pBox->ClaimFrmFmt();
4530                     pBoxFmt->ResetFmtAttr( RES_PROTECT );
4531 					aNewFmts.Insert( pBoxFmt, aNewFmts.Count() );
4532 				}
4533 				bChgd = sal_True;
4534 			}
4535 		}
4536 
4537 		if( pUndo )
4538 		{
4539 			if( bChgd )
4540             {
4541                 GetIDocumentUndoRedo().AppendUndo( pUndo );
4542             }
4543             else
4544 				delete pUndo;
4545 		}
4546 	}
4547 	return bChgd;
4548 }
4549 
UnProtectTbls(const SwPaM & rPam)4550 sal_Bool SwDoc::UnProtectTbls( const SwPaM& rPam )
4551 {
4552     GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
4553 
4554 	sal_Bool bChgd = sal_False, bHasSel = rPam.HasMark() ||
4555 									rPam.GetNext() != (SwPaM*)&rPam;
4556 	SwFrmFmts& rFmts = *GetTblFrmFmts();
4557 	SwTable* pTbl;
4558 	const SwTableNode* pTblNd;
4559 	for( sal_uInt16 n = rFmts.Count(); n ; )
4560 		if( 0 != (pTbl = SwTable::FindTable( rFmts[ --n ] )) &&
4561 			0 != (pTblNd = pTbl->GetTableNode() ) &&
4562 			pTblNd->GetNodes().IsDocNodes() )
4563 		{
4564 			sal_uLong nTblIdx = pTblNd->GetIndex();
4565 
4566 			// dann ueberpruefe ob Tabelle in der Selection liegt
4567 			if( bHasSel )
4568 			{
4569 				int bFound = sal_False;
4570 				SwPaM* pTmp = (SwPaM*)&rPam;
4571 				do {
4572 					const SwPosition *pStt = pTmp->Start(),
4573 									*pEnd = pTmp->End();
4574 					bFound = pStt->nNode.GetIndex() < nTblIdx &&
4575 							nTblIdx < pEnd->nNode.GetIndex();
4576 
4577 				} while( !bFound && &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ) );
4578 				if( !bFound )
4579 					continue;		// weitersuchen
4580 			}
4581 
4582 			// dann mal den Schutz aufheben
4583 			bChgd |= _UnProtectTblCells( *pTbl );
4584 		}
4585 
4586     GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
4587 	if( bChgd )
4588 		SetModified();
4589 
4590 	return bChgd;
4591 }
4592 
HasTblAnyProtection(const SwPosition * pPos,const String * pTblName,sal_Bool * pFullTblProtection)4593 sal_Bool SwDoc::HasTblAnyProtection( const SwPosition* pPos,
4594 								 const String* pTblName,
4595 								 sal_Bool* pFullTblProtection )
4596 {
4597 	sal_Bool bHasProtection = sal_False;
4598 	SwTable* pTbl = 0;
4599 	if( pTblName )
4600 		pTbl = SwTable::FindTable( FindTblFmtByName( *pTblName ) );
4601 	else if( pPos )
4602 	{
4603 		SwTableNode* pTblNd = pPos->nNode.GetNode().FindTableNode();
4604 		if( pTblNd )
4605 			pTbl = &pTblNd->GetTable();
4606 	}
4607 
4608 	if( pTbl )
4609 	{
4610 		SwTableSortBoxes& rSrtBox = pTbl->GetTabSortBoxes();
4611 		for( sal_uInt16 i = rSrtBox.Count(); i; )
4612 		{
4613 			SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
4614 			if( pBoxFmt->GetProtect().IsCntntProtected() )
4615 			{
4616 				if( !bHasProtection )
4617 				{
4618 					bHasProtection = sal_True;
4619 					if( !pFullTblProtection )
4620 						break;
4621 					*pFullTblProtection = sal_True;
4622 				}
4623 			}
4624 			else if( bHasProtection && pFullTblProtection )
4625 			{
4626 				*pFullTblProtection = sal_False;
4627 				break;
4628 			}
4629 		}
4630 	}
4631 	return bHasProtection;
4632 }
4633 
4634 #ifdef DEL_TABLE_REDLINES
lcl_DelRedlines(const SwTableNode & rNd,sal_Bool bCheckForOwnRedline)4635 lcl_DelRedlines::lcl_DelRedlines( const SwTableNode& rNd,
4636 									sal_Bool bCheckForOwnRedline )
4637 	: pDoc( (SwDoc*)rNd.GetNodes().GetDoc() )
4638 {
4639     pDoc->StartUndo(UNDO_EMPTY, NULL);
4640 	const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
4641 	if( !pDoc->IsIgnoreRedline() && rTbl.Count() )
4642 	{
4643 		sal_Bool bDelete = sal_True;
4644 		if( bCheckForOwnRedline )
4645 		{
4646 			sal_uInt16 nRedlPos = pDoc->GetRedlinePos( rNd, USHRT_MAX );
4647 			sal_uInt32 nSttNd = rNd.GetIndex(),
4648 					   nEndNd = rNd.EndOfSectionIndex();
4649 
4650 			for ( ; nRedlPos < rTbl.Count(); ++nRedlPos )
4651 			{
4652 				const SwRedline* pRedline = rTbl[ nRedlPos ];
4653 				const SwPosition* pStt = pRedline->Start(),
4654 						  		* pEnd = pStt == pRedline->GetPoint()
4655 						  							? pRedline->GetMark()
4656 													: pRedline->GetPoint();
4657 				if( pStt->nNode <= nSttNd )
4658 				{
4659 					if( pEnd->nNode >= nEndNd &&
4660 						pRedline->GetAuthor() == pDoc->GetRedlineAuthor() )
4661 					{
4662 						bDelete = sal_False;
4663 						break;
4664 					}
4665 				}
4666 				else
4667 					break;
4668 			}
4669 		}
4670 		if( bDelete )
4671 		{
4672 			SwPaM aPam(*rNd.EndOfSectionNode(), rNd);
4673 			pDoc->AcceptRedline( aPam, true );
4674 		}
4675 	}
4676 }
4677 #endif
4678 
4679 
4680