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