1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <hintids.hxx>
22 #include <osl/diagnose.h>
23 #include <svl/numformat.hxx>
26 #include <IDocumentUndoRedo.hxx>
27 #include <DocumentContentOperationsManager.hxx>
28 #include <IDocumentRedlineAccess.hxx>
29 #include <IDocumentFieldsAccess.hxx>
30 #include <IDocumentLayoutAccess.hxx>
31 #include <IDocumentStylePoolAccess.hxx>
33 #include <swtable.hxx>
36 #include <poolfmt.hxx>
37 #include <cellatr.hxx>
39 #include <fmtanchr.hxx>
41 #include <UndoTable.hxx>
42 #include <fmtfsize.hxx>
43 #include <frameformats.hxx>
48 static void lcl_CpyBox( const SwTable
& rCpyTable
, const SwTableBox
* pCpyBox
,
49 SwTable
& rDstTable
, SwTableBox
* pDstBox
,
50 bool bDelContent
, SwUndoTableCpyTable
* pUndo
);
52 // The following type will be used by table copy functions to describe
53 // the structure of tables (or parts of tables).
54 // It's for new table model only.
66 typedef std::vector
< BoxSpanInfo
> BoxStructure
;
67 typedef std::vector
< BoxStructure
> LineStructure
;
68 typedef std::deque
< sal_uLong
> ColumnStructure
;
76 typedef std::vector
< SubBox
> SubLine
;
77 typedef std::vector
< SubLine
> SubTable
;
82 LineStructure maLines
;
83 ColumnStructure maCols
;
84 sal_uInt16 mnStartCol
;
86 void addLine( sal_uInt16
&rLine
, const SwTableBoxes
&, const SwSelBoxes
*,
88 void addBox( sal_uInt16 nLine
, const SwSelBoxes
*, SwTableBox
*pBox
,
89 sal_uLong
&rnB
, sal_uInt16
&rnC
, ColumnStructure::iterator
& rpCl
,
90 BoxStructure::iterator
& rpSel
, bool &rbSel
, bool bCover
);
91 void incColSpan( sal_uInt16 nLine
, sal_uInt16 nCol
);
92 explicit TableStructure( const SwTable
& rTable
);
93 TableStructure( const SwTable
& rTable
, FndBox_
&rFndBox
,
94 const SwSelBoxes
& rSelBoxes
,
95 LineStructure::size_type nMinSize
);
96 LineStructure::size_type
getLineCount() const
97 { return maLines
.size(); }
98 void moreLines( const SwTable
& rTable
);
99 void assignBoxes( const TableStructure
&rSource
);
100 void copyBoxes( const SwTable
& rSource
, SwTable
& rDstTable
,
101 SwUndoTableCpyTable
* pUndo
) const;
104 SubTable::iterator
insertSubLine( SubTable
& rSubTable
, SwTableLine
& rLine
,
105 const SubTable::iterator
& pStartLn
);
107 SubTable::iterator
insertSubBox( SubTable
& rSubTable
, SwTableBox
& rBox
,
108 SubTable::iterator pStartLn
, const SubTable::iterator
& pEndLn
)
110 if( !rBox
.GetTabLines().empty() )
112 SubTable::size_type nSize
= static_cast<SubTable::size_type
>(std::distance( pStartLn
, pEndLn
));
113 if( nSize
< rBox
.GetTabLines().size() )
116 for( const auto& rSubBox
: *pStartLn
)
119 aSub
.mpBox
= rSubBox
.mpBox
;
120 aSub
.mbCovered
= true;
121 aSubLine
.push_back( aSub
);
125 rSubTable
.insert( pEndLn
, aSubLine
);
126 } while( ++nSize
< rBox
.GetTabLines().size() );
128 for( auto pLine
: rBox
.GetTabLines() )
129 pStartLn
= insertSubLine( rSubTable
, *pLine
, pStartLn
);
130 OSL_ENSURE( pStartLn
== pEndLn
, "Sub line confusion" );
136 aSub
.mbCovered
= false;
137 while( pStartLn
!= pEndLn
)
139 pStartLn
->push_back( aSub
);
140 aSub
.mbCovered
= true;
147 SubTable::iterator
insertSubLine( SubTable
& rSubTable
, SwTableLine
& rLine
,
148 const SubTable::iterator
& pStartLn
)
150 SubTable::iterator pMax
= pStartLn
;
152 SubTable::difference_type nMax
= 1;
153 for( auto pBox
: rLine
.GetTabBoxes() )
155 SubTable::iterator pTmp
= insertSubBox( rSubTable
, *pBox
, pStartLn
, pMax
);
156 SubTable::difference_type nTmp
= std::distance( pStartLn
, pTmp
);
166 TableStructure::TableStructure( const SwTable
& rTable
) :
167 maLines( rTable
.GetTabLines().size() ), mnStartCol(USHRT_MAX
),
170 maCols
.push_front(0);
172 for( auto pLine
: rTable
.GetTabLines() )
173 addLine( nCnt
, pLine
->GetTabBoxes(), nullptr, rTable
.IsNewModel() );
176 TableStructure::TableStructure( const SwTable
& rTable
,
177 FndBox_
&rFndBox
, const SwSelBoxes
& rSelBoxes
,
178 LineStructure::size_type nMinSize
)
179 : mnStartCol(USHRT_MAX
), mnAddLine(0)
181 if( rFndBox
.GetLines().empty() )
184 bool bNoSelection
= rSelBoxes
.size() < 2;
185 FndLines_t
&rFndLines
= rFndBox
.GetLines();
186 maCols
.push_front(0);
187 const SwTableLine
* pLine
= rFndLines
.front()->GetLine();
188 const sal_uInt16 nStartLn
= rTable
.GetTabLines().GetPos( pLine
);
189 SwTableLines::size_type nEndLn
= nStartLn
;
190 if( rFndLines
.size() > 1 )
192 pLine
= rFndLines
.back()->GetLine();
193 nEndLn
= rTable
.GetTabLines().GetPos( pLine
);
195 if( nStartLn
< USHRT_MAX
&& nEndLn
< USHRT_MAX
)
197 const SwTableLines
&rLines
= rTable
.GetTabLines();
198 if( bNoSelection
&& nMinSize
> nEndLn
- nStartLn
+ 1 )
200 SwTableLines::size_type nNewEndLn
= nStartLn
+ nMinSize
- 1;
201 if( nNewEndLn
>= rLines
.size() )
203 mnAddLine
= nNewEndLn
- rLines
.size() + 1;
204 nNewEndLn
= rLines
.size() - 1;
206 while( nEndLn
< nNewEndLn
)
208 SwTableLine
*pLine2
= rLines
[ ++nEndLn
];
209 SwTableBox
*pTmpBox
= pLine2
->GetTabBoxes()[0];
210 FndLine_
*pInsLine
= new FndLine_( pLine2
, &rFndBox
);
211 pInsLine
->GetBoxes().insert(pInsLine
->GetBoxes().begin(), std::make_unique
<FndBox_
>(pTmpBox
, pInsLine
));
212 rFndLines
.push_back(std::unique_ptr
<FndLine_
>(pInsLine
));
215 maLines
.resize( nEndLn
- nStartLn
+ 1 );
216 const SwSelBoxes
* pSelBoxes
= &rSelBoxes
;
218 for( SwTableLines::size_type nLine
= nStartLn
; nLine
<= nEndLn
; ++nLine
)
220 addLine( nCnt
, rLines
[nLine
]->GetTabBoxes(),
221 pSelBoxes
, rTable
.IsNewModel() );
226 if( bNoSelection
&& mnStartCol
< USHRT_MAX
)
228 sal_uInt16 nIdx
= std::min(mnStartCol
, o3tl::narrowing
<sal_uInt16
>(maLines
[0].size()));
229 mnStartCol
= std::accumulate(maLines
[0].begin(), maLines
[0].begin() + nIdx
, sal_uInt16(0),
230 [](sal_uInt16 sum
, const BoxSpanInfo
& rInfo
) { return sum
+ rInfo
.mnColSpan
; });
233 mnStartCol
= USHRT_MAX
;
236 void TableStructure::addLine( sal_uInt16
&rLine
, const SwTableBoxes
& rBoxes
,
237 const SwSelBoxes
* pSelBoxes
, bool bNewModel
)
239 bool bComplex
= false;
241 for( SwTableBoxes::size_type nBox
= 0; !bComplex
&& nBox
< rBoxes
.size(); ++nBox
)
242 bComplex
= !rBoxes
[nBox
]->GetTabLines().empty();
247 aSubTable
.push_back( aSubLine
);
248 SubTable::iterator pStartLn
= aSubTable
.begin();
249 SubTable::iterator pEndLn
= aSubTable
.end();
250 for( auto pBox
: rBoxes
)
251 insertSubBox( aSubTable
, *pBox
, pStartLn
, pEndLn
);
252 SubTable::size_type nSize
= aSubTable
.size();
255 maLines
.resize( maLines
.size() + nSize
- 1 );
256 while( pStartLn
!= pEndLn
)
258 bool bSelected
= false;
259 sal_uLong nBorder
= 0;
261 maLines
[rLine
].reserve( pStartLn
->size() );
262 BoxStructure::iterator pSel
= maLines
[rLine
].end();
263 ColumnStructure::iterator pCol
= maCols
.begin();
264 for( const auto& rBox
: *pStartLn
)
266 addBox( rLine
, pSelBoxes
, rBox
.mpBox
, nBorder
, nCol
,
267 pCol
, pSel
, bSelected
, rBox
.mbCovered
);
276 bool bSelected
= false;
277 sal_uLong nBorder
= 0;
279 maLines
[rLine
].reserve( rBoxes
.size() );
280 ColumnStructure::iterator pCol
= maCols
.begin();
281 BoxStructure::iterator pSel
= maLines
[rLine
].end();
282 for( auto pBox
: rBoxes
)
283 addBox( rLine
, pSelBoxes
, pBox
, nBorder
, nCol
,
284 pCol
, pSel
, bSelected
, false );
289 void TableStructure::addBox( sal_uInt16 nLine
, const SwSelBoxes
* pSelBoxes
,
290 SwTableBox
*pBox
, sal_uLong
&rnBorder
, sal_uInt16
&rnCol
,
291 ColumnStructure::iterator
& rpCol
, BoxStructure::iterator
& rpSel
,
292 bool &rbSelected
, bool bCovered
)
296 pSelBoxes
->end() != pSelBoxes
->find( pBox
) )
298 aInfo
.mbSelected
= true;
299 if( mnStartCol
== USHRT_MAX
)
301 mnStartCol
= o3tl::narrowing
<sal_uInt16
>(maLines
[nLine
].size());
302 if( pSelBoxes
->size() < 2 )
305 aInfo
.mbSelected
= false;
310 aInfo
.mbSelected
= false;
311 rnBorder
+= pBox
->GetFrameFormat()->GetFrameSize().GetWidth();
312 const sal_uInt16 nLeftCol
= rnCol
;
313 while( rpCol
!= maCols
.end() && *rpCol
< rnBorder
)
318 if( rpCol
== maCols
.end() || *rpCol
> rnBorder
)
320 rpCol
= maCols
.insert( rpCol
, rnBorder
);
321 incColSpan( nLine
, rnCol
);
323 aInfo
.mnColSpan
= rnCol
- nLeftCol
;
324 aInfo
.mpCopy
= nullptr;
325 aInfo
.mpBox
= bCovered
? nullptr : pBox
;
326 maLines
[nLine
].push_back( aInfo
);
327 if( !aInfo
.mbSelected
)
332 while( rpSel
!= maLines
[nLine
].end() )
334 rpSel
->mbSelected
= true;
340 rpSel
= maLines
[nLine
].end();
346 void TableStructure::moreLines( const SwTable
& rTable
)
351 const SwTableLines
&rLines
= rTable
.GetTabLines();
352 const sal_uInt16 nLineCount
= rLines
.size();
353 if( nLineCount
< mnAddLine
)
354 mnAddLine
= nLineCount
;
355 sal_uInt16 nLine
= o3tl::narrowing
<sal_uInt16
>(maLines
.size());
356 maLines
.resize( nLine
+ mnAddLine
);
359 SwTableLine
*pLine
= rLines
[ nLineCount
- mnAddLine
];
360 addLine( nLine
, pLine
->GetTabBoxes(), nullptr, rTable
.IsNewModel() );
365 void TableStructure::incColSpan( sal_uInt16 nLineMax
, sal_uInt16 nNewCol
)
367 for( sal_uInt16 nLine
= 0; nLine
< nLineMax
; ++nLine
)
369 BoxStructure::iterator pInfo
= maLines
[nLine
].begin();
370 BoxStructure::iterator pEnd
= maLines
[nLine
].end();
371 tools::Long nCol
= pInfo
->mnColSpan
;
372 while( nNewCol
> nCol
&& ++pInfo
!= pEnd
)
373 nCol
+= pInfo
->mnColSpan
;
375 ++(pInfo
->mnColSpan
);
379 void TableStructure::assignBoxes( const TableStructure
&rSource
)
381 LineStructure::const_iterator pFirstLine
= rSource
.maLines
.begin();
382 LineStructure::const_iterator pLastLine
= rSource
.maLines
.end();
383 if( pFirstLine
== pLastLine
)
385 LineStructure::const_iterator pCurrLine
= pFirstLine
;
386 LineStructure::size_type nLineCount
= maLines
.size();
387 sal_uInt16 nFirstStartCol
= 0;
389 BoxStructure::const_iterator pFirstBox
= pFirstLine
->begin();
390 if( pFirstBox
!= pFirstLine
->end() && pFirstBox
->mpBox
&&
391 pFirstBox
->mpBox
->getDummyFlag() )
392 nFirstStartCol
= pFirstBox
->mnColSpan
;
394 for( LineStructure::size_type nLine
= 0; nLine
< nLineCount
; ++nLine
)
396 BoxStructure::const_iterator pFirstBox
= pCurrLine
->begin();
397 BoxStructure::const_iterator pLastBox
= pCurrLine
->end();
398 sal_uInt16 nCurrStartCol
= mnStartCol
;
399 if( pFirstBox
!= pLastBox
)
401 BoxStructure::const_iterator pTmpBox
= pLastBox
;
403 if( pTmpBox
->mpBox
&& pTmpBox
->mpBox
->getDummyFlag() )
405 if( pFirstBox
!= pLastBox
&& pFirstBox
->mpBox
&&
406 pFirstBox
->mpBox
->getDummyFlag() )
408 if( nCurrStartCol
< USHRT_MAX
)
410 if( pFirstBox
->mnColSpan
> nFirstStartCol
)
411 nCurrStartCol
+= pFirstBox
->mnColSpan
- nFirstStartCol
;
416 if( pFirstBox
!= pLastBox
)
418 BoxStructure::const_iterator pCurrBox
= pFirstBox
;
419 BoxStructure
&rBox
= maLines
[nLine
];
420 BoxStructure::size_type nBoxCount
= rBox
.size();
422 for( BoxStructure::size_type nBox
= 0; nBox
< nBoxCount
; ++nBox
)
424 BoxSpanInfo
& rInfo
= rBox
[nBox
];
425 nCol
+= rInfo
.mnColSpan
;
426 if( rInfo
.mbSelected
|| nCol
> nCurrStartCol
)
428 rInfo
.mpCopy
= pCurrBox
->mpBox
;
429 if( rInfo
.mbSelected
&& rInfo
.mpCopy
->getDummyFlag() )
432 if( pCurrBox
== pLastBox
)
434 pCurrBox
= pFirstBox
;
435 if( pCurrBox
->mpBox
->getDummyFlag() )
438 rInfo
.mpCopy
= pCurrBox
->mpBox
;
441 if( pCurrBox
== pLastBox
)
443 if( rInfo
.mbSelected
)
444 pCurrBox
= pFirstBox
;
447 rInfo
.mbSelected
= rInfo
.mpCopy
== nullptr;
451 rInfo
.mbSelected
= rInfo
.mpCopy
== nullptr;
456 if( pCurrLine
== pLastLine
)
457 pCurrLine
= pFirstLine
;
461 void TableStructure::copyBoxes( const SwTable
& rSource
, SwTable
& rDstTable
,
462 SwUndoTableCpyTable
* pUndo
) const
464 LineStructure::size_type nLineCount
= maLines
.size();
465 for( LineStructure::size_type nLine
= 0; nLine
< nLineCount
; ++nLine
)
467 const BoxStructure
&rBox
= maLines
[nLine
];
468 BoxStructure::size_type nBoxCount
= rBox
.size();
469 for( BoxStructure::size_type nBox
= 0; nBox
< nBoxCount
; ++nBox
)
471 const BoxSpanInfo
& rInfo
= rBox
[nBox
];
472 if( ( rInfo
.mpCopy
&& !rInfo
.mpCopy
->getDummyFlag() )
473 || rInfo
.mbSelected
)
475 SwTableBox
*pBox
= rInfo
.mpBox
;
476 if( pBox
&& pBox
->getRowSpan() > 0 )
477 lcl_CpyBox( rSource
, rInfo
.mpCopy
, rDstTable
, pBox
,
485 /** Copy Table into this Box.
486 Copy all Boxes of a Line into the corresponding Boxes. The old content
487 is deleted by doing this.
488 If no Box is left the remaining content goes to the Box of a "BaseLine".
489 If there's no Line anymore, put it also into the last Box of a "BaseLine". */
490 static void lcl_CpyBox( const SwTable
& rCpyTable
, const SwTableBox
* pCpyBox
,
491 SwTable
& rDstTable
, SwTableBox
* pDstBox
,
492 bool bDelContent
, SwUndoTableCpyTable
* pUndo
)
494 OSL_ENSURE( ( !pCpyBox
|| pCpyBox
->GetSttNd() ) && pDstBox
->GetSttNd(),
495 "No content in this Box" );
497 SwDoc
* pCpyDoc
= rCpyTable
.GetFrameFormat()->GetDoc();
498 SwDoc
* pDoc
= rDstTable
.GetFrameFormat()->GetDoc();
500 // First copy the new content and then delete the old one.
501 // Do not create empty Sections, otherwise they will be deleted!
502 std::unique_ptr
< SwNodeRange
> pRg( pCpyBox
?
503 new SwNodeRange ( *pCpyBox
->GetSttNd(), SwNodeOffset(1),
504 *pCpyBox
->GetSttNd()->EndOfSectionNode() ) : nullptr );
506 SwNodeIndex
aInsIdx( *pDstBox
->GetSttNd(), bDelContent
? SwNodeOffset(1) :
507 pDstBox
->GetSttNd()->EndOfSectionIndex() -
508 pDstBox
->GetSttIdx() );
511 pUndo
->AddBoxBefore( *pDstBox
, bDelContent
);
513 bool bUndoRedline
= pUndo
&& pDoc
->getIDocumentRedlineAccess().IsRedlineOn();
514 ::sw::UndoGuard
const undoGuard(pDoc
->GetIDocumentUndoRedo());
516 SwNodeIndex
aSavePos( aInsIdx
, -1 );
518 pCpyDoc
->GetDocumentContentOperationsManager().CopyWithFlyInFly(*pRg
, aInsIdx
.GetNode(), nullptr, false);
520 pDoc
->GetNodes().MakeTextNode( aInsIdx
.GetNode(), pDoc
->GetDfltTextFormatColl() );
523 SwTableLine
* pLine
= pDstBox
->GetUpper();
524 while( pLine
->GetUpper() )
525 pLine
= pLine
->GetUpper()->GetUpper();
527 bool bReplaceColl
= true;
528 if( bDelContent
&& !bUndoRedline
)
530 // Delete the Fly first, then the corresponding Nodes
531 SwNodeIndex
aEndNdIdx( *aInsIdx
.GetNode().EndOfSectionNode() );
535 SwPosition
aMvPos( aInsIdx
);
536 SwContentNode
* pCNd
= SwNodes::GoPrevious( &aMvPos
);
537 assert(pCNd
); // keep coverity happy
538 aMvPos
.SetContent( pCNd
->Len() );
539 SwDoc::CorrAbs( aInsIdx
, aEndNdIdx
, aMvPos
);
542 // If we still have FlyFrames hanging around, delete them too
543 for(sw::SpzFrameFormat
* pFly
: *pDoc
->GetSpzFrameFormats())
545 SwFormatAnchor
const*const pAnchor
= &pFly
->GetAnchor();
546 SwNode
const*const pAnchorNode
= pAnchor
->GetAnchorNode();
548 ((RndStdIds::FLY_AT_PARA
== pAnchor
->GetAnchorId()) ||
549 (RndStdIds::FLY_AT_CHAR
== pAnchor
->GetAnchorId())) &&
550 aInsIdx
<= *pAnchorNode
&& *pAnchorNode
<= aEndNdIdx
.GetNode() )
552 pDoc
->getIDocumentLayoutAccess().DelLayoutFormat( pFly
);
556 // If DestBox is a Headline Box and has Table style set, then
557 // DO NOT automatically set the TableHeadline style!
558 if( 1 < rDstTable
.GetTabLines().size() &&
559 pLine
== rDstTable
.GetTabLines().front() )
561 SwContentNode
* pCNd
= aInsIdx
.GetNode().GetContentNode();
564 SwNodeIndex
aTmp( aInsIdx
);
565 pCNd
= pDoc
->GetNodes().GoNext( &aTmp
);
569 RES_POOLCOLL_TABLE_HDLN
!=
570 pCNd
->GetFormatColl()->GetPoolFormatId() )
571 bReplaceColl
= false;
574 pDoc
->GetNodes().Delete( aInsIdx
, aEndNdIdx
.GetIndex() - aInsIdx
.GetIndex() );
577 //b6341295: Table copy redlining will be managed by AddBoxAfter()
579 pUndo
->AddBoxAfter( *pDstBox
, aInsIdx
, bDelContent
);
582 SwTextNode
*const pTextNd
= aSavePos
.GetNode().GetTextNode();
586 const sal_uInt16 nPoolId
= pTextNd
->GetTextColl()->GetPoolFormatId();
588 (( 1 < rDstTable
.GetTabLines().size() &&
589 pLine
== rDstTable
.GetTabLines().front() )
590 // Is the Table's content still valid?
591 ? RES_POOLCOLL_TABLE
== nPoolId
592 : RES_POOLCOLL_TABLE_HDLN
== nPoolId
) )
594 SwTextFormatColl
* pColl
= pDoc
->getIDocumentStylePoolAccess().GetTextCollFromPool(
595 o3tl::narrowing
<sal_uInt16
>(
596 RES_POOLCOLL_TABLE
== nPoolId
597 ? RES_POOLCOLL_TABLE_HDLN
598 : RES_POOLCOLL_TABLE
) );
599 if( pColl
) // Apply style
601 SwPaM
aPam( aSavePos
);
603 aPam
.Move( fnMoveForward
, GoInSection
);
604 pDoc
->SetTextFormatColl( aPam
, pColl
);
608 // Delete the current Formula/Format/Value values
609 if( SfxItemState::SET
== pDstBox
->GetFrameFormat()->GetItemState( RES_BOXATR_FORMAT
) ||
610 SfxItemState::SET
== pDstBox
->GetFrameFormat()->GetItemState( RES_BOXATR_FORMULA
) ||
611 SfxItemState::SET
== pDstBox
->GetFrameFormat()->GetItemState( RES_BOXATR_VALUE
) )
613 pDstBox
->ClaimFrameFormat()->ResetFormatAttr( RES_BOXATR_FORMAT
,
617 // Copy the TableBoxAttributes - Formula/Format/Value
621 SfxItemSetFixed
<RES_BOXATR_FORMAT
, RES_BOXATR_VALUE
> aBoxAttrSet( pCpyDoc
->GetAttrPool() );
622 aBoxAttrSet
.Put( pCpyBox
->GetFrameFormat()->GetAttrSet() );
623 if( !aBoxAttrSet
.Count() )
626 const SwTableBoxNumFormat
* pItem
;
627 SvNumberFormatter
* pN
= pDoc
->GetNumberFormatter( false );
628 if( pN
&& pN
->HasMergeFormatTable() &&
629 (pItem
= aBoxAttrSet
.GetItemIfSet( RES_BOXATR_FORMAT
, false )) )
631 sal_uLong nOldIdx
= pItem
->GetValue();
632 sal_uLong nNewIdx
= pN
->GetMergeFormatIndex( nOldIdx
);
633 if( nNewIdx
!= nOldIdx
)
634 aBoxAttrSet
.Put( SwTableBoxNumFormat( nNewIdx
));
636 pDstBox
->ClaimFrameFormat()->SetFormatAttr( aBoxAttrSet
);
639 bool SwTable::InsNewTable( const SwTable
& rCpyTable
, const SwSelBoxes
& rSelBoxes
,
640 SwUndoTableCpyTable
* pUndo
)
642 SwDoc
* pDoc
= GetFrameFormat()->GetDoc();
643 SwDoc
* pCpyDoc
= rCpyTable
.GetFrameFormat()->GetDoc();
645 SwTableNumFormatMerge
aTNFM( *pCpyDoc
, *pDoc
);
647 // Analyze source structure
648 TableStructure
aCopyStruct( rCpyTable
);
650 // Analyze target structure (from start box) and selected substructure
651 FndBox_
aFndBox( nullptr, nullptr );
652 { // get all boxes/lines
653 FndPara
aPara( rSelBoxes
, &aFndBox
);
654 ForEach_FndLineCopyCol( GetTabLines(), &aPara
);
656 TableStructure
aTarget( *this, aFndBox
, rSelBoxes
, aCopyStruct
.getLineCount() );
659 if( aTarget
.mnAddLine
&& IsNewModel() )
662 aBoxes
.insert( GetTabLines().back()->GetTabBoxes().front() );
664 pUndo
->InsertRow( *this, aBoxes
, aTarget
.mnAddLine
);
666 InsertRow( pDoc
, aBoxes
, aTarget
.mnAddLine
, /*bBehind*/true );
668 aTarget
.moreLines( *this );
672 // Find mapping, if needed extend target table and/or selection
673 aTarget
.assignBoxes( aCopyStruct
);
676 const_cast<SwTable
*>(&rCpyTable
)->SwitchFormulasToRelativeRepresentation();
680 aFndBox
.SetTableLines( *this );
682 aFndBox
.ClearLineBehind();
683 aFndBox
.DelFrames( *this );
686 aTarget
.copyBoxes( rCpyTable
, *this, pUndo
);
688 // adjust row span attributes accordingly
691 aFndBox
.MakeFrames( *this );
696 /** Copy Table into this Box.
697 Copy all Boxes of a Line into the corresponding Boxes. The old content is
698 deleted by doing this.
699 If no Box is left the remaining content goes to the Box of a "BaseLine".
700 If there's no Line anymore, put it also into the last Box of a "BaseLine". */
701 bool SwTable::InsTable( const SwTable
& rCpyTable
, const SwNodeIndex
& rSttBox
,
702 SwUndoTableCpyTable
* pUndo
)
704 SetHTMLTableLayout(std::shared_ptr
<SwHTMLTableLayout
>()); // Delete HTML Layout
706 SwDoc
* pDoc
= GetFrameFormat()->GetDoc();
708 SwTableNode
* pTableNd
= SwDoc::IsIdxInTable( rSttBox
);
710 // Find the Box, to which should be copied:
711 SwTableBox
* pMyBox
= GetTableBox(
712 rSttBox
.GetNode().FindTableBoxStartNode()->GetIndex() );
714 OSL_ENSURE( pMyBox
, "Index is not in a Box in this Table" );
716 // First delete the Table's Frames
717 FndBox_
aFndBox( nullptr, nullptr );
718 aFndBox
.DelFrames( pTableNd
->GetTable() );
720 SwDoc
* pCpyDoc
= rCpyTable
.GetFrameFormat()->GetDoc();
722 const_cast<SwTable
*>(&rCpyTable
)->SwitchFormulasToRelativeRepresentation();
724 SwTableNumFormatMerge
aTNFM( *pCpyDoc
, *pDoc
);
726 bool bDelContent
= true;
727 const SwTableBox
* pTmp
;
729 for( auto pLine
: rCpyTable
.GetTabLines() )
731 // Get the first from the CopyLine
732 const SwTableBox
* pCpyBox
= pLine
->GetTabBoxes().front();
733 while( !pCpyBox
->GetTabLines().empty() )
734 pCpyBox
= pCpyBox
->GetTabLines().front()->GetTabBoxes().front();
737 // First copy the new content and then delete the old one.
738 // Do not create empty Sections, otherwise they will be deleted!
739 lcl_CpyBox( rCpyTable
, pCpyBox
, *this, pMyBox
, bDelContent
, pUndo
);
741 pTmp
= pCpyBox
->FindNextBox( rCpyTable
, pCpyBox
, false );
743 break; // no more Boxes
746 pTmp
= pMyBox
->FindNextBox( *this, pMyBox
, false );
748 bDelContent
= false; // No space left?
750 pMyBox
= const_cast<SwTableBox
*>(pTmp
);
754 // Find the topmost Line
755 SwTableLine
* pNxtLine
= pMyBox
->GetUpper();
756 while( pNxtLine
->GetUpper() )
757 pNxtLine
= pNxtLine
->GetUpper()->GetUpper();
758 const SwTableLines::size_type nPos
= GetTabLines().GetPos( pNxtLine
) + 1;
760 if( nPos
>= GetTabLines().size() )
761 bDelContent
= false; // there is none, all goes into the last Box
764 // Find the next Box with content
765 pNxtLine
= GetTabLines()[ nPos
];
766 pMyBox
= pNxtLine
->GetTabBoxes().front();
767 while( !pMyBox
->GetTabLines().empty() )
768 pMyBox
= pMyBox
->GetTabLines().front()->GetTabBoxes().front();
773 aFndBox
.MakeFrames( pTableNd
->GetTable() ); // Create the Frames anew
777 bool SwTable::InsTable( const SwTable
& rCpyTable
, const SwSelBoxes
& rSelBoxes
,
778 SwUndoTableCpyTable
* pUndo
)
780 OSL_ENSURE( !rSelBoxes
.empty(), "Missing selection" );
782 SetHTMLTableLayout(std::shared_ptr
<SwHTMLTableLayout
>()); // Delete HTML Layout
784 if( IsNewModel() || rCpyTable
.IsNewModel() )
785 return InsNewTable( rCpyTable
, rSelBoxes
, pUndo
);
787 OSL_ENSURE( !rCpyTable
.IsTableComplex(), "Table too complex" );
789 SwDoc
* pDoc
= GetFrameFormat()->GetDoc();
790 SwDoc
* pCpyDoc
= rCpyTable
.GetFrameFormat()->GetDoc();
792 SwTableNumFormatMerge
aTNFM( *pCpyDoc
, *pDoc
);
795 FndBox_
aFndBox( nullptr, nullptr );
796 // Find all Boxes/Lines
798 FndPara
aPara( rSelBoxes
, &aFndBox
);
799 ForEach_FndLineCopyCol( GetTabLines(), &aPara
);
802 // Special case: If a Box is located in a Table, copy it to all selected
804 if( 1 != rCpyTable
.GetTabSortBoxes().size() )
808 const FndLines_t::size_type nFndCnt
= aFndBox
.GetLines().size();
812 // Check if we have enough space for all Lines and Boxes
813 SwTableLines::size_type nTstLns
= 0;
814 pFLine
= aFndBox
.GetLines().front().get();
815 sal_uInt16 nSttLine
= GetTabLines().GetPos( pFLine
->GetLine() );
816 // Do we have as many rows, actually?
819 // Is there still enough space in the Table?
820 if( (GetTabLines().size() - nSttLine
) <
821 rCpyTable
.GetTabLines().size() )
823 // If we don't have enough Lines, then see if we can insert
824 // new ones to reach our goal. But only if the SSelection
826 if( 1 < rSelBoxes
.size() )
829 const sal_uInt16 nNewLns
= rCpyTable
.GetTabLines().size() -
830 (GetTabLines().size() - nSttLine
);
832 // See if the Box count is high enough for the Lines
833 SwTableLine
* pLastLn
= GetTabLines().back();
835 SwTableBox
* pSttBox
= pFLine
->GetBoxes()[0]->GetBox();
836 const SwTableBoxes::size_type nSttBox
= pFLine
->GetLine()->GetBoxPos( pSttBox
);
837 for( SwTableLines::size_type n
= rCpyTable
.GetTabLines().size() - nNewLns
;
838 n
< rCpyTable
.GetTabLines().size(); ++n
)
840 SwTableLine
* pCpyLn
= rCpyTable
.GetTabLines()[ n
];
842 if( pLastLn
->GetTabBoxes().size() < nSttBox
||
843 ( pLastLn
->GetTabBoxes().size() - nSttBox
) <
844 pCpyLn
->GetTabBoxes().size() )
848 for( SwTableBoxes::size_type nBx
= 0; nBx
< pCpyLn
->GetTabBoxes().size(); ++nBx
)
849 if( !pLastLn
->GetTabBoxes()[ nSttBox
+ nBx
]->GetSttNd() )
852 // We have enough space for the to-be-copied, so insert new
854 SwTableBox
* pInsBox
= pLastLn
->GetTabBoxes()[ nSttBox
];
855 OSL_ENSURE( pInsBox
&& pInsBox
->GetSttNd(),
856 "no ContentBox or it's not in this Table" );
860 ? !pUndo
->InsertRow( *this, SelLineFromBox( pInsBox
,
862 : !InsertRow( pDoc
, SelLineFromBox( pInsBox
,
863 aBoxes
), nNewLns
, /*bBehind*/true ) )
867 nTstLns
= rCpyTable
.GetTabLines().size(); // copy this many
869 else if( 0 == (nFndCnt
% rCpyTable
.GetTabLines().size()) )
872 return false; // not enough space for the rows
874 for( SwTableLines::size_type nLn
= 0; nLn
< nTstLns
; ++nLn
)
876 // We have enough rows, so check the Boxes per row
877 pFLine
= aFndBox
.GetLines()[ nLn
% nFndCnt
].get();
878 SwTableLine
* pLine
= pFLine
->GetLine();
879 SwTableBox
* pSttBox
= pFLine
->GetBoxes()[0]->GetBox();
880 const SwTableBoxes::size_type nSttBox
= pLine
->GetBoxPos( pSttBox
);
881 std::unique_ptr
<FndLine_
> pInsFLine
;
884 // We have more rows in the ClipBoard than we have selected
885 pInsFLine
.reset(new FndLine_( GetTabLines()[ nSttLine
+ nLn
],
887 pLine
= pInsFLine
->GetLine();
889 SwTableLine
* pCpyLn
= rCpyTable
.GetTabLines()[ nLn
%
890 rCpyTable
.GetTabLines().size() ];
892 // Selected too few rows?
895 // We insert a new row into the FndBox
896 if( pLine
->GetTabBoxes().size() < nSttBox
||
897 pLine
->GetTabBoxes().size() - nSttBox
< pFLine
->GetBoxes().size() )
903 for (FndBoxes_t::size_type nBx
= 0; nBx
< pFLine
->GetBoxes().size(); ++nBx
)
905 SwTableBox
*pTmpBox
= pLine
->GetTabBoxes()[ nSttBox
+ nBx
];
906 if( !pTmpBox
->GetSttNd() )
910 // if Ok, insert the Box into the FndLine
911 pFndBox
= new FndBox_( pTmpBox
, pInsFLine
.get() );
912 pInsFLine
->GetBoxes().insert( pInsFLine
->GetBoxes().begin() + nBx
,
913 std::unique_ptr
<FndBox_
>(pFndBox
));
915 aFndBox
.GetLines().insert( aFndBox
.GetLines().begin() + nLn
, std::move(pInsFLine
));
917 else if( pFLine
->GetBoxes().size() == 1 )
919 if( pLine
->GetTabBoxes().size() < nSttBox
||
920 ( pLine
->GetTabBoxes().size() - nSttBox
) <
921 pCpyLn
->GetTabBoxes().size() )
925 for( SwTableBoxes::size_type nBx
= 0; nBx
< pCpyLn
->GetTabBoxes().size(); ++nBx
)
927 SwTableBox
*pTmpBox
= pLine
->GetTabBoxes()[ nSttBox
+ nBx
];
928 if( !pTmpBox
->GetSttNd() )
930 // if Ok, insert the Box into the FndLine
931 if( nBx
== pFLine
->GetBoxes().size() )
933 pFndBox
= new FndBox_( pTmpBox
, pFLine
);
934 pFLine
->GetBoxes().insert(pFLine
->GetBoxes().begin() + nBx
,
935 std::unique_ptr
<FndBox_
>(pFndBox
));
941 // Match the selected Boxes with the ones in the Clipboard
943 if( 0 != ( pFLine
->GetBoxes().size() %
944 pCpyLn
->GetTabBoxes().size() ))
948 for (auto &rpBox
: pFLine
->GetBoxes())
950 if (!rpBox
->GetBox()->GetSttNd())
956 if( aFndBox
.GetLines().empty() )
961 const_cast<SwTable
*>(&rCpyTable
)->SwitchFormulasToRelativeRepresentation();
965 aFndBox
.SetTableLines( *this );
966 //Not dispose accessible table
967 aFndBox
.DelFrames( *this );
969 if( 1 == rCpyTable
.GetTabSortBoxes().size() )
971 SwTableBox
*pTmpBx
= rCpyTable
.GetTabSortBoxes()[0];
972 for (size_t n
= 0; n
< rSelBoxes
.size(); ++n
)
974 lcl_CpyBox( rCpyTable
, pTmpBx
, *this,
975 rSelBoxes
[n
], true, pUndo
);
979 for (FndLines_t::size_type nLn
= 0; nLn
< aFndBox
.GetLines().size(); ++nLn
)
981 pFLine
= aFndBox
.GetLines()[ nLn
].get();
982 SwTableLine
* pCpyLn
= rCpyTable
.GetTabLines()[
983 nLn
% rCpyTable
.GetTabLines().size() ];
984 for (FndBoxes_t::size_type nBx
= 0; nBx
< pFLine
->GetBoxes().size(); ++nBx
)
986 // Copy the pCpyBox into pMyBox
987 lcl_CpyBox( rCpyTable
, pCpyLn
->GetTabBoxes()[
988 nBx
% pCpyLn
->GetTabBoxes().size() ],
989 *this, pFLine
->GetBoxes()[nBx
]->GetBox(), true, pUndo
);
993 aFndBox
.MakeFrames( *this );
997 static void FndContentLine( const SwTableLine
* pLine
, SwSelBoxes
* pPara
);
999 static void FndContentBox( const SwTableBox
* pBox
, SwSelBoxes
* pPara
)
1001 if( !pBox
->GetTabLines().empty() )
1003 for( const SwTableLine
* pLine
: pBox
->GetTabLines() )
1004 FndContentLine( pLine
, pPara
);
1007 pPara
->insert( const_cast<SwTableBox
*>(pBox
) );
1010 static void FndContentLine( const SwTableLine
* pLine
, SwSelBoxes
* pPara
)
1012 for( const SwTableBox
* pBox
: pLine
->GetTabBoxes() )
1013 FndContentBox(pBox
, pPara
);
1016 // Find all Boxes with content in this Box
1017 SwSelBoxes
& SwTable::SelLineFromBox( const SwTableBox
* pBox
,
1018 SwSelBoxes
& rBoxes
, bool bToTop
)
1020 SwTableLine
* pLine
= const_cast<SwTableLine
*>(pBox
->GetUpper());
1022 while( pLine
->GetUpper() )
1023 pLine
= pLine
->GetUpper()->GetUpper();
1025 // Delete all old ones
1027 for( const auto& rpBox
: pLine
->GetTabBoxes() )
1028 FndContentBox(rpBox
, &rBoxes
);
1032 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */