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