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 .
21 #include <hintids.hxx>
23 #include <vcl/errinf.hxx>
24 #include <basegfx/vector/b2dvector.hxx>
25 #include <editeng/protitem.hxx>
26 #include <editeng/brushitem.hxx>
27 #include <editeng/frmdiritem.hxx>
28 #include <svtools/ruler.hxx>
29 #include <osl/diagnose.h>
31 #include <fmtfsize.hxx>
32 #include <fmtornt.hxx>
38 #include <IDocumentState.hxx>
39 #include <IDocumentLayoutAccess.hxx>
40 #include <IDocumentRedlineAccess.hxx>
41 #include <IDocumentUndoRedo.hxx>
44 #include <notxtfrm.hxx>
45 #include <rootfrm.hxx>
46 #include <pagefrm.hxx>
49 #include <cellfrm.hxx>
51 #include <swtable.hxx>
52 #include <swddetbl.hxx>
55 #include <dialoghelp.hxx>
57 #include <tblafmt.hxx>
58 #include <cellatr.hxx>
64 #include <frmtool.hxx>
65 #include <fmtrowsplt.hxx>
67 #include <sortedobjs.hxx>
69 using namespace ::com::sun::star
;
71 // also see swtable.cxx
74 static bool IsSame( tools::Long nA
, tools::Long nB
) { return std::abs(nA
-nB
) <= COLFUZZY
; }
80 const std::unique_ptr
<SwWait
> m_pWait
;
81 // this seems really fishy: do some locking, if an arbitrary number of lines is exceeded
82 static const size_t our_kLineLimit
= 20;
83 static bool ShouldWait(size_t nCnt
, SwFrame
*pFrame
, size_t nCnt2
)
84 { return our_kLineLimit
< nCnt
|| our_kLineLimit
< nCnt2
|| (pFrame
&& our_kLineLimit
< pFrame
->ImplFindTabFrame()->GetTable()->GetTabLines().size()); }
86 TableWait(size_t nCnt
, SwFrame
*pFrame
, SwDocShell
&rDocShell
, size_t nCnt2
= 0)
87 : m_pWait( ShouldWait(nCnt
, pFrame
, nCnt2
) ? std::make_unique
<SwWait
>( rDocShell
, true ) : nullptr )
93 void SwFEShell::ParkCursorInTab()
95 SwCursor
* pSwCursor
= GetCursor();
97 OSL_ENSURE(pSwCursor
, "no SwCursor");
99 SwPosition aStartPos
= *pSwCursor
->GetPoint(), aEndPos
= aStartPos
;
101 /* Search least and greatest position in current cursor ring.
103 for(SwPaM
& rTmpCursor
: pSwCursor
->GetRingContainer())
105 SwCursor
* pTmpCursor
= static_cast<SwCursor
*>(&rTmpCursor
);
106 const SwPosition
* pPt
= pTmpCursor
->GetPoint(),
107 * pMk
= pTmpCursor
->GetMark();
109 if (*pPt
< aStartPos
)
115 if (*pMk
< aStartPos
)
125 /* @@@ semantic: SwCursor::operator=() is not implemented @@@ */
127 /* Set cursor to end of selection to ensure IsLastCellInRow works
130 SwCursor
aTmpCursor( aEndPos
, nullptr );
131 *pSwCursor
= aTmpCursor
;
134 /* Move the cursor out of the columns to delete and stay in the
135 same row. If the table has only one column the cursor will
136 stay in the row and the shell will take care of it. */
137 if (IsLastCellInRow())
139 /* If the cursor is in the last row of the table, first
140 try to move it to the previous cell. If that fails move
141 it to the next cell. */
144 SwCursor
aTmpCursor( aStartPos
, nullptr );
145 *pSwCursor
= aTmpCursor
;
148 if (! pSwCursor
->GoPrevCell())
150 SwCursor
aTmpCursor( aEndPos
, nullptr );
151 *pSwCursor
= aTmpCursor
;
152 pSwCursor
->GoNextCell();
157 /* If the cursor is not in the last row of the table, first
158 try to move it to the next cell. If that fails move it
159 to the previous cell. */
162 SwCursor
aTmpCursor( aEndPos
, nullptr );
163 *pSwCursor
= aTmpCursor
;
166 if (! pSwCursor
->GoNextCell())
168 SwCursor
aTmpCursor( aStartPos
, nullptr );
169 *pSwCursor
= aTmpCursor
;
170 pSwCursor
->GoPrevCell();
175 void SwFEShell::InsertRow( sal_uInt16 nCnt
, bool bBehind
)
177 // check if Point/Mark of current cursor are in a table
178 SwFrame
*pFrame
= GetCurrFrame();
179 if( !pFrame
|| !pFrame
->IsInTab() )
182 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
184 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
185 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
189 // pending drag & drop?
190 bool bAction
= ActionPend();
192 CurrShell
aCurr( this );
195 // search boxes via the layout
197 bool bSelectAll
= StartsWith_() == StartsWith::Table
&& ExtendedSelectedAll();
200 // Set the end of the selection to the last paragraph of the last cell of the table.
201 SwPaM
* pPaM
= getShellCursor(false);
202 SwNode
* pNode
= pPaM
->Start()->GetNode().FindTableNode()->EndOfSectionNode();
203 // pNode is the end node of the table, we want the last node before the end node of the last cell.
204 pPaM
->End()->Assign( pNode
->GetIndex() - 2 );
206 GetTableSel( *this, aBoxes
, SwTableSearchType::Row
);
208 TableWait
aWait( nCnt
, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
210 if ( !aBoxes
.empty() )
211 GetDoc()->InsertRow( aBoxes
, nCnt
, bBehind
, /*bInsertDummy=*/!bAction
);
213 EndAllActionAndCall();
216 void SwFEShell::InsertCol( sal_uInt16 nCnt
, bool bBehind
)
218 // check if Point/Mark of current cursor are in a table
219 SwFrame
*pFrame
= GetCurrFrame();
220 if( !pFrame
|| !pFrame
->IsInTab() )
223 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
225 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
226 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
230 CurrShell
aCurr( this );
232 if( !CheckSplitCells( *this, nCnt
+ 1, SwTableSearchType::Col
) )
234 ErrorHandler::HandleError( ERR_TBLINSCOL_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
235 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
239 // pending drag & drop?
240 bool bAction
= ActionPend();
243 // search boxes via the layout
245 GetTableSel( *this, aBoxes
, SwTableSearchType::Col
);
247 TableWait
aWait( nCnt
, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
249 if( !aBoxes
.empty() )
250 GetDoc()->InsertCol( aBoxes
, nCnt
, bBehind
, /*bInsertDummy=*/!bAction
);
252 EndAllActionAndCall();
255 // Determines if the current cursor is in the last row of the table.
256 bool SwFEShell::IsLastCellInRow() const
259 GetTabCols( aTabCols
);
260 bool bResult
= false;
262 if (IsTableRightToLeft())
263 /* If the table is right-to-left the last row is the most left one. */
264 bResult
= 0 == GetCurTabColNum();
266 /* If the table is left-to-right the last row is the most right one. */
267 bResult
= aTabCols
.Count() == GetCurTabColNum();
272 bool SwFEShell::DeleteCol()
274 // check if Point/Mark of current cursor are in a table
275 SwFrame
*pFrame
= GetCurrFrame();
276 if( !pFrame
|| !pFrame
->IsInTab() )
279 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
281 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
282 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
286 CurrShell
aCurr( this );
288 bool bRecordChanges
= GetDoc()->GetDocShell()->IsChangeRecording();
289 bool bRecordAndHideChanges
= bRecordChanges
&&
290 GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines();
292 // tracked deletion: remove only textbox content,
293 // and set IsNoTracked table box property to false
294 if ( bRecordChanges
)
296 StartUndo(SwUndoId::COL_DELETE
);
299 if ( SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this) )
300 pWrtShell
->SelectTableCol();
302 // search boxes via the layout
304 GetTableSel( *this, aBoxes
, SwTableSearchType::Col
);
306 TableWait
aWait( 20, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
308 SwTableNode
* pTableNd
= pFrame
->IsTextFrame()
309 ? static_cast<SwTextFrame
*>(pFrame
)->GetTextNodeFirst()->FindTableNode()
310 : static_cast<SwNoTextFrame
*>(pFrame
)->GetNode()->FindTableNode();
312 for (size_t i
= 0; i
< aBoxes
.size(); ++i
)
314 SwTableBox
*pBox
= aBoxes
[i
];
315 if ( pBox
->GetSttNd() )
317 SwNodeIndex
aIdx( *pBox
->GetSttNd(), 1 );
318 SwCursor
aCursor( SwPosition(aIdx
), nullptr );
319 SvxPrintItem
aHasTextChangesOnly(RES_PRINT
, false);
320 GetDoc()->SetBoxAttr( aCursor
, aHasTextChangesOnly
);
322 // add dummy text content to the empty box for change tracking
323 if ( pBox
->IsEmpty() )
325 IDocumentContentOperations
& rIDCO
= GetDoc()->getIDocumentContentOperations();
326 IDocumentRedlineAccess
& rIDRA
= GetDoc()->getIDocumentRedlineAccess();
327 RedlineFlags eOld
= rIDRA
.GetRedlineFlags();
328 rIDRA
.SetRedlineFlags_intern(RedlineFlags::NONE
);
329 rIDCO
.InsertString( aCursor
, OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR
) );
331 aCursor
.GetMark()->SetContent(0);
332 rIDRA
.SetRedlineFlags_intern( eOld
);
333 rIDCO
.DeleteAndJoin( aCursor
);
339 SwEditShell
* pEditShell
= GetDoc()->GetEditShell();
340 pEditShell
->Delete();
342 // remove cell frames in Hide Changes mode (and table frames, if needed)
343 if ( bRecordAndHideChanges
)
345 // remove all frames of the table, and make them again without the deleted ones
346 // TODO remove only the deleted frames
347 pTableNd
->DelFrames();
349 if ( !pTableNd
->GetTable().IsDeleted() )
351 pTableNd
->MakeOwnFrames();
355 EndAllActionAndCall();
356 EndUndo(SwUndoId::COL_DELETE
);
362 // search boxes via the layout
365 SwTableSearchType eSearchType
= SwTableSearchType::Col
;
367 // NewModel tables already ExpandColumnSelection, so don't do it here also.
368 const SwContentNode
* pContentNd
= getShellCursor(false)->GetPointNode().GetContentNode();
369 const SwTableNode
* pTableNd
= pContentNd
? pContentNd
->FindTableNode() : nullptr;
370 if (pTableNd
&& pTableNd
->GetTable().IsNewModel())
371 eSearchType
= SwTableSearchType::NONE
;
373 GetTableSel(*this, aBoxes
, eSearchType
);
374 if ( !aBoxes
.empty() )
376 TableWait
aWait( aBoxes
.size(), pFrame
, *GetDoc()->GetDocShell() );
378 // remove crsr from the deletion area.
379 // Put them behind/on the table; via the
380 // document position they will be put to the old position
381 while( !pFrame
->IsCellFrame() )
382 pFrame
= pFrame
->GetUpper();
386 // then delete the column
387 StartUndo(SwUndoId::COL_DELETE
);
388 bRet
= GetDoc()->DeleteRowCol(aBoxes
, SwDoc::RowColMode::DeleteColumn
);
389 EndUndo(SwUndoId::COL_DELETE
);
394 EndAllActionAndCall();
398 void SwFEShell::DeleteTable()
403 bool SwFEShell::DeleteRow(bool bCompleteTable
)
405 // check if Point/Mark of current cursor are in a table
406 SwFrame
*pFrame
= GetCurrFrame();
407 if( !pFrame
|| !pFrame
->IsInTab() )
410 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
412 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
413 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
417 CurrShell
aCurr( this );
419 bool bRecordChanges
= GetDoc()->GetDocShell()->IsChangeRecording();
420 bool bRecordAndHideChanges
= bRecordChanges
&&
421 GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines();
423 // tracked deletion: all rows have already had tracked row change in the table selection
424 if ( bRecordChanges
&& !SwDoc::HasRowNotTracked( *getShellCursor( false ) ) )
427 if ( bRecordChanges
)
428 StartUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
432 // tracked deletion: remove only textbox content,
433 // and set HasTextChangesOnly table line property to false
434 if ( bRecordChanges
)
436 SvxPrintItem
aHasTextChangesOnly(RES_PRINT
, false);
437 GetDoc()->SetRowNotTracked( *getShellCursor( false ), aHasTextChangesOnly
);
439 if ( SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this) )
440 pWrtShell
->SelectTableRow();
442 // don't need to remove the row frames in Show Changes mode
443 if ( !bRecordAndHideChanges
)
445 if (SwEditShell
* pEditShell
= GetDoc()->GetEditShell())
446 pEditShell
->Delete(false);
448 EndAllActionAndCall();
449 EndUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
455 // search for boxes via the layout
458 GetTableSel( *this, aBoxes
, SwTableSearchType::Row
);
460 if( !aBoxes
.empty() )
462 TableWait
aWait( aBoxes
.size(), pFrame
, *GetDoc()->GetDocShell() );
464 // Delete cursors from the deletion area.
465 // Then the cursor is:
466 // 1. the following row, if there is another row after this
467 // 2. the preceding row, if there is another row before this
468 // 3. otherwise below the table
470 SwTableNode
* pTableNd
= pFrame
->IsTextFrame()
471 ? static_cast<SwTextFrame
*>(pFrame
)->GetTextNodeFirst()->FindTableNode()
472 : static_cast<SwNoTextFrame
*>(pFrame
)->GetNode()->FindTableNode();
474 // search all boxes / lines
475 FndBox_
aFndBox( nullptr, nullptr );
477 FndPara
aPara( aBoxes
, &aFndBox
);
478 ForEach_FndLineCopyCol( pTableNd
->GetTable().GetTabLines(), &aPara
);
481 if( aFndBox
.GetLines().empty() )
483 EndAllActionAndCall();
489 FndBox_
* pFndBox
= &aFndBox
;
490 while( 1 == pFndBox
->GetLines().size() &&
491 1 == pFndBox
->GetLines().front()->GetBoxes().size())
493 FndBox_
*const pTmp
= pFndBox
->GetLines().front()->GetBoxes()[0].get();
494 if( pTmp
->GetBox()->GetSttNd() )
495 break; // otherwise too far
499 SwTableLine
* pDelLine
= pFndBox
->GetLines().back()->GetLine();
500 SwTableBox
* pDelBox
= pDelLine
->GetTabBoxes().back();
501 while( !pDelBox
->GetSttNd() )
503 SwTableLine
* pLn
= pDelBox
->GetTabLines().back();
504 pDelBox
= pLn
->GetTabBoxes().back();
506 SwTableBox
* pNextBox
= pDelLine
->FindNextBox( pTableNd
->GetTable(),
508 // skip deleted lines in Hide Changes mode with enabled change tracking
509 if ( bRecordAndHideChanges
)
511 SwRedlineTable::size_type nRedlinePos
= 0;
512 while( pNextBox
&& pNextBox
->GetUpper()->IsDeleted(nRedlinePos
) )
513 pNextBox
= pNextBox
->GetUpper()->FindNextBox( pTableNd
->GetTable(),
514 pNextBox
->GetUpper()->GetTabBoxes().back() );
517 // skip protected cells
519 pNextBox
->GetFrameFormat()->GetProtect().IsContentProtected() )
520 pNextBox
= pNextBox
->FindNextBox( pTableNd
->GetTable(), pNextBox
);
522 if( !pNextBox
) // no next? then the previous
524 pDelLine
= pFndBox
->GetLines().front()->GetLine();
525 pDelBox
= pDelLine
->GetTabBoxes()[ 0 ];
526 while( !pDelBox
->GetSttNd() )
527 pDelBox
= pDelBox
->GetTabLines()[0]->GetTabBoxes()[0];
528 pNextBox
= pDelLine
->FindPreviousBox( pTableNd
->GetTable(),
530 // skip previous deleted lines in Hide Changes mode with enabled change tracking
531 if ( bRecordAndHideChanges
)
533 SwRedlineTable::size_type nRedlinePos
= 0;
534 while( pNextBox
&& pNextBox
->GetUpper()->IsDeleted(nRedlinePos
) )
536 pNextBox
= pNextBox
->GetUpper()->FindPreviousBox( pTableNd
->GetTable(),
537 pNextBox
->GetUpper()->GetTabBoxes()[0] );
542 // skip previous protected cells
544 pNextBox
->GetFrameFormat()->GetProtect().IsContentProtected() )
545 pNextBox
= pNextBox
->FindPreviousBox( pTableNd
->GetTable(), pNextBox
);
548 // delete row content in Hide Changes mode
549 if ( bRecordAndHideChanges
)
551 SwEditShell
* pEditShell
= GetDoc()->GetEditShell();
553 // select the rows deleted with change tracking
554 if ( SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this) )
556 pWrtShell
->SelectTableRow();
557 SwCursor
* pTableCursor
= static_cast<SwCursor
*>(GetTableCursor());
558 auto pStt
= aBoxes
[0];
559 auto pEnd
= aBoxes
.back();
561 pTableCursor
->DeleteMark();
563 pTableCursor
= GetCursor(true);
567 // set start and end of the selection
568 pTableCursor
->GetPoint()->Assign( *pEnd
->GetSttNd()->EndOfSectionNode() );
569 pTableCursor
->Move( fnMoveBackward
, GoInContent
);
570 pTableCursor
->SetMark();
571 pTableCursor
->GetPoint()->Assign( *pStt
->GetSttNd()->EndOfSectionNode() );
572 pTableCursor
->Move( fnMoveBackward
, GoInContent
);
573 pWrtShell
->UpdateCursor();
578 pEditShell
->Delete(false);
582 if( pNextBox
) // put cursor here
583 nIdx
= pNextBox
->GetSttIdx() + 1;
584 else // otherwise below the table
585 nIdx
= pTableNd
->EndOfSectionIndex() + 1;
587 SwNodeIndex
aIdx( GetDoc()->GetNodes(), nIdx
);
588 SwContentNode
* pCNd
= aIdx
.GetNode().GetContentNode();
590 pCNd
= GetDoc()->GetNodes().GoNext( &aIdx
);
592 // remove row frames in Hide Changes mode (and table frames, if needed)
593 if ( bRecordAndHideChanges
)
595 // remove all frames of the table, and make them again without the deleted ones
596 // TODO remove only the deleted frames
597 pTableNd
->DelFrames();
598 if ( !pTableNd
->GetTable().IsDeleted() )
600 pTableNd
->MakeOwnFrames();
603 EndAllActionAndCall();
606 SwPaM
* pPam
= GetCursor();
607 pPam
->GetPoint()->Assign( *pCNd
, 0 );
608 pPam
->SetMark(); // both want something
610 if ( SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this) )
612 pWrtShell
->UpdateCursor();
613 // tdf#150578 enable the disabled table toolbar by (zero) cursor moving
614 pWrtShell
->Right( SwCursorSkipMode::Chars
, false, 0, false );
617 EndUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
623 SwPaM
* pPam
= GetCursor();
624 pPam
->GetPoint()->Assign( *pCNd
, 0 );
625 pPam
->SetMark(); // both want something
630 // now delete the lines
631 StartUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
632 bRet
= GetDoc()->DeleteRowCol( aBoxes
);
633 EndUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
638 EndAllActionAndCall();
642 TableMergeErr
SwFEShell::MergeTab()
644 // check if Point/Mark of current cursor are in a table
645 TableMergeErr nRet
= TableMergeErr::NoSelection
;
648 SwShellTableCursor
* pTableCursor
= GetTableCursor();
649 const SwTableNode
* pTableNd
= pTableCursor
->GetPointNode().FindTableNode();
650 if( dynamic_cast< const SwDDETable
* >(&pTableNd
->GetTable()) != nullptr )
652 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
653 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
657 CurrShell
aCurr( this );
660 TableWait
aWait(pTableCursor
->GetSelectedBoxesCount(), nullptr,
661 *GetDoc()->GetDocShell(),
662 pTableNd
->GetTable().GetTabLines().size() );
664 nRet
= GetDoc()->MergeTable( *pTableCursor
);
668 EndAllActionAndCall();
674 void SwFEShell::SplitTab( bool bVert
, sal_uInt16 nCnt
, bool bSameHeight
)
676 // check if Point/Mark of current cursor are in a table
677 SwFrame
*pFrame
= GetCurrFrame();
678 if( !pFrame
|| !pFrame
->IsInTab() )
681 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
683 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
684 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
688 CurrShell
aCurr( this );
690 if( bVert
&& !CheckSplitCells( *this, nCnt
+ 1, SwTableSearchType::NONE
) )
692 ErrorHandler::HandleError( ERR_TBLSPLIT_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
693 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
697 // search boxes via the layout
699 GetTableSel( *this, aBoxes
);
700 if( !aBoxes
.empty() )
702 TableWait
aWait( nCnt
, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
704 // now delete the columns
705 GetDoc()->SplitTable( aBoxes
, bVert
, nCnt
, bSameHeight
);
707 ClearFEShellTabCols(*GetDoc(), nullptr);
709 EndAllActionAndCall();
712 void SwFEShell::GetTabCols_(SwTabCols
&rToFill
, const SwFrame
*pBox
) const
714 const SwTabFrame
*pTab
= pBox
->FindTabFrame();
718 if (m_pColumnCache
->pLastTable
== pTab
->GetTable())
721 SwRectFnSet
aRectFnSet(pTab
);
723 const SwPageFrame
* pPage
= pTab
->FindPageFrame();
724 const sal_uLong nLeftMin
= aRectFnSet
.GetLeft(pTab
->getFrameArea()) -
725 aRectFnSet
.GetLeft(pPage
->getFrameArea());
726 const sal_uLong nRightMax
= aRectFnSet
.GetRight(pTab
->getFrameArea()) -
727 aRectFnSet
.GetLeft(pPage
->getFrameArea());
729 if (m_pColumnCache
->pLastTabFrame
!= pTab
)
731 // if TabFrame was changed, we only shift a little bit
732 // as the width is the same
733 SwRectFnSet
fnRectX(m_pColumnCache
->pLastTabFrame
);
734 if (fnRectX
.GetWidth(m_pColumnCache
->pLastTabFrame
->getFrameArea()) ==
735 aRectFnSet
.GetWidth(pTab
->getFrameArea()) )
737 m_pColumnCache
->pLastCols
->SetLeftMin( nLeftMin
);
739 m_pColumnCache
->pLastTabFrame
= pTab
;
746 m_pColumnCache
->pLastCols
->GetLeftMin () == o3tl::narrowing
<sal_uInt16
>(nLeftMin
) &&
747 m_pColumnCache
->pLastCols
->GetLeft () == o3tl::narrowing
<sal_uInt16
>(aRectFnSet
.GetLeft(pTab
->getFramePrintArea())) &&
748 m_pColumnCache
->pLastCols
->GetRight () == o3tl::narrowing
<sal_uInt16
>(aRectFnSet
.GetRight(pTab
->getFramePrintArea()))&&
749 m_pColumnCache
->pLastCols
->GetRightMax() == o3tl::narrowing
<sal_uInt16
>(nRightMax
) - m_pColumnCache
->pLastCols
->GetLeftMin() )
751 if (m_pColumnCache
->pLastCellFrame
!= pBox
)
753 pTab
->GetTable()->GetTabCols( *m_pColumnCache
->pLastCols
,
754 static_cast<const SwCellFrame
*>(pBox
)->GetTabBox(), true);
755 m_pColumnCache
->pLastCellFrame
= pBox
;
757 rToFill
= *m_pColumnCache
->pLastCols
;
763 m_pColumnCache
.reset();
767 SwDoc::GetTabCols( rToFill
, static_cast<const SwCellFrame
*>(pBox
) );
769 m_pColumnCache
.reset(new SwColCache
);
770 m_pColumnCache
->pLastCols
.reset(new SwTabCols(rToFill
));
771 m_pColumnCache
->pLastTable
= pTab
->GetTable();
772 m_pColumnCache
->pLastTabFrame
= pTab
;
773 m_pColumnCache
->pLastCellFrame
= pBox
;
777 void SwFEShell::GetTabRows_(SwTabCols
&rToFill
, const SwFrame
*pBox
) const
779 const SwTabFrame
*pTab
= pBox
->FindTabFrame();
783 if (m_pRowCache
->pLastTable
== pTab
->GetTable())
786 SwRectFnSet
aRectFnSet(pTab
);
787 const SwPageFrame
* pPage
= pTab
->FindPageFrame();
788 const tools::Long nLeftMin
= ( aRectFnSet
.IsVert() ?
789 pTab
->GetPrtLeft() - pPage
->getFrameArea().Left() :
790 pTab
->GetPrtTop() - pPage
->getFrameArea().Top() );
791 const tools::Long nLeft
= aRectFnSet
.IsVert() ? LONG_MAX
: 0;
792 const tools::Long nRight
= aRectFnSet
.GetHeight(pTab
->getFramePrintArea());
793 const tools::Long nRightMax
= aRectFnSet
.IsVert() ? nRight
: LONG_MAX
;
795 if (m_pRowCache
->pLastTabFrame
!= pTab
|| m_pRowCache
->pLastCellFrame
!= pBox
)
799 m_pRowCache
->pLastCols
->GetLeftMin () == nLeftMin
&&
800 m_pRowCache
->pLastCols
->GetLeft () == nLeft
&&
801 m_pRowCache
->pLastCols
->GetRight () == nRight
&&
802 m_pRowCache
->pLastCols
->GetRightMax() == nRightMax
)
804 rToFill
= *m_pRowCache
->pLastCols
;
814 SwDoc::GetTabRows( rToFill
, static_cast<const SwCellFrame
*>(pBox
) );
816 m_pRowCache
.reset(new SwColCache
);
817 m_pRowCache
->pLastCols
.reset(new SwTabCols(rToFill
));
818 m_pRowCache
->pLastTable
= pTab
->GetTable();
819 m_pRowCache
->pLastTabFrame
= pTab
;
820 m_pRowCache
->pLastCellFrame
= pBox
;
824 void SwFEShell::SetTabCols( const SwTabCols
&rNew
, bool bCurRowOnly
)
826 SwFrame
*pBox
= GetCurrFrame();
827 if( !pBox
|| !pBox
->IsInTab() )
830 CurrShell
aCurr( this );
835 pBox
= pBox
->GetUpper();
836 } while (pBox
&& !pBox
->IsCellFrame());
838 GetDoc()->SetTabCols( rNew
, bCurRowOnly
, static_cast<SwCellFrame
*>(pBox
) );
839 EndAllActionAndCall();
842 void SwFEShell::GetTabCols( SwTabCols
&rToFill
) const
844 const SwFrame
*pFrame
= GetCurrFrame();
845 if( !pFrame
|| !pFrame
->IsInTab() )
849 pFrame
= pFrame
->GetUpper();
851 while (pFrame
&& !pFrame
->IsCellFrame());
856 GetTabCols_( rToFill
, pFrame
);
859 void SwFEShell::GetTabRows( SwTabCols
&rToFill
) const
861 const SwFrame
*pFrame
= GetCurrFrame();
862 if( !pFrame
|| !pFrame
->IsInTab() )
866 pFrame
= pFrame
->GetUpper();
867 } while (pFrame
&& !pFrame
->IsCellFrame());
872 GetTabRows_( rToFill
, pFrame
);
875 void SwFEShell::SetTabRows( const SwTabCols
&rNew
, bool bCurColOnly
)
877 SwFrame
*pBox
= GetCurrFrame();
878 if( !pBox
|| !pBox
->IsInTab() )
881 CurrShell
aCurr( this );
886 pBox
= pBox
->GetUpper();
887 } while (pBox
&& !pBox
->IsCellFrame());
889 GetDoc()->SetTabRows( rNew
, bCurColOnly
, static_cast<SwCellFrame
*>(pBox
) );
890 EndAllActionAndCall();
893 void SwFEShell::GetMouseTabRows( SwTabCols
&rToFill
, const Point
&rPt
) const
895 const SwFrame
*pBox
= GetBox( rPt
);
897 GetTabRows_( rToFill
, pBox
);
900 void SwFEShell::SetMouseTabRows( const SwTabCols
&rNew
, bool bCurColOnly
, const Point
&rPt
)
902 const SwFrame
*pBox
= GetBox( rPt
);
905 CurrShell
aCurr( this );
907 GetDoc()->SetTabRows( rNew
, bCurColOnly
, static_cast<const SwCellFrame
*>(pBox
) );
908 EndAllActionAndCall();
912 void SwFEShell::SetRowSplit( const SwFormatRowSplit
& rNew
)
914 CurrShell
aCurr( this );
916 GetDoc()->SetRowSplit( *getShellCursor( false ), rNew
);
917 EndAllActionAndCall();
920 std::unique_ptr
<SwFormatRowSplit
> SwFEShell::GetRowSplit() const
922 return SwDoc::GetRowSplit( *getShellCursor( false ) );
925 void SwFEShell::SetRowHeight( const SwFormatFrameSize
&rNew
)
927 CurrShell
aCurr( this );
929 GetDoc()->SetRowHeight( *getShellCursor( false ), rNew
);
930 EndAllActionAndCall();
933 std::unique_ptr
<SwFormatFrameSize
> SwFEShell::GetRowHeight() const
935 return SwDoc::GetRowHeight( *getShellCursor( false ) );
938 bool SwFEShell::BalanceRowHeight( bool bTstOnly
, const bool bOptimize
)
940 CurrShell
aCurr( this );
943 bool bRet
= GetDoc()->BalanceRowHeight( *getShellCursor( false ), bTstOnly
, bOptimize
);
945 EndAllActionAndCall();
949 void SwFEShell::SetRowBackground( const SvxBrushItem
&rNew
)
951 CurrShell
aCurr( this );
953 GetDoc()->SetRowBackground( *getShellCursor( false ), rNew
);
954 EndAllActionAndCall();
957 bool SwFEShell::GetRowBackground( std::unique_ptr
<SvxBrushItem
>& rToFill
) const
959 return SwDoc::GetRowBackground( *getShellCursor( false ), rToFill
);
962 void SwFEShell::SetTabBorders( const SfxItemSet
& rSet
)
964 CurrShell
aCurr( this );
966 GetDoc()->SetTabBorders( *getShellCursor( false ), rSet
);
967 EndAllActionAndCall();
970 void SwFEShell::SetTabLineStyle( const Color
* pColor
, bool bSetLine
,
971 const editeng::SvxBorderLine
* pBorderLine
)
973 CurrShell
aCurr( this );
975 GetDoc()->SetTabLineStyle( *getShellCursor( false ),
976 pColor
, bSetLine
, pBorderLine
);
977 EndAllActionAndCall();
980 void SwFEShell::GetTabBorders( SfxItemSet
& rSet
) const
982 SwDoc::GetTabBorders( *getShellCursor( false ), rSet
);
985 void SwFEShell::SetBoxBackground( const SvxBrushItem
&rNew
)
987 CurrShell
aCurr( this );
989 GetDoc()->SetBoxAttr( *getShellCursor( false ), rNew
);
990 EndAllActionAndCall();
993 bool SwFEShell::GetBoxBackground( std::unique_ptr
<SvxBrushItem
>& rToFill
) const
995 std::unique_ptr
<SfxPoolItem
> aTemp
= std::move(rToFill
);
996 bool bRetval(SwDoc::GetBoxAttr(*getShellCursor( false ), aTemp
));
997 rToFill
.reset(static_cast<SvxBrushItem
*>(aTemp
.release()));
1001 void SwFEShell::SetBoxDirection( const SvxFrameDirectionItem
& rNew
)
1003 CurrShell
aCurr( this );
1005 GetDoc()->SetBoxAttr( *getShellCursor( false ), rNew
);
1006 EndAllActionAndCall();
1009 bool SwFEShell::GetBoxDirection( std::unique_ptr
<SvxFrameDirectionItem
>& rToFill
) const
1011 std::unique_ptr
<SfxPoolItem
> aTemp
= std::move(rToFill
);
1012 bool bRetval(SwDoc::GetBoxAttr(*getShellCursor( false ), aTemp
));
1013 rToFill
.reset(static_cast<SvxFrameDirectionItem
*>(aTemp
.release()));
1017 void SwFEShell::SetBoxAlign( sal_uInt16 nAlign
)
1019 CurrShell
aCurr( this );
1021 GetDoc()->SetBoxAlign( *getShellCursor( false ), nAlign
);
1022 EndAllActionAndCall();
1025 sal_uInt16
SwFEShell::GetBoxAlign() const
1027 return SwDoc::GetBoxAlign( *getShellCursor( false ) );
1030 void SwFEShell::SetTabBackground( const SvxBrushItem
&rNew
)
1032 SwFrame
*pFrame
= GetCurrFrame();
1033 if( !pFrame
|| !pFrame
->IsInTab() )
1036 CurrShell
aCurr( this );
1038 GetDoc()->SetAttr( rNew
, *pFrame
->ImplFindTabFrame()->GetFormat() );
1039 EndAllAction(); // no call, nothing changes!
1040 GetDoc()->getIDocumentState().SetModified();
1043 void SwFEShell::GetTabBackground( std::unique_ptr
<SvxBrushItem
>& rToFill
) const
1045 SwFrame
*pFrame
= GetCurrFrame();
1046 if( pFrame
&& pFrame
->IsInTab() )
1047 rToFill
= pFrame
->ImplFindTabFrame()->GetFormat()->makeBackgroundBrushItem();
1050 bool SwFEShell::HasWholeTabSelection() const
1052 // whole table selected?
1053 if ( IsTableMode() )
1056 ::GetTableSelCrs( *this, aBoxes
);
1057 if( !aBoxes
.empty() )
1059 const SwTableNode
*pTableNd
= IsCursorInTable();
1061 aBoxes
[0]->GetSttIdx() - 1 == pTableNd
->EndOfSectionNode()->StartOfSectionIndex() &&
1062 aBoxes
.back()->GetSttNd()->EndOfSectionIndex() + 1 == pTableNd
->EndOfSectionIndex();
1068 bool SwFEShell::HasBoxSelection() const
1070 if(!IsCursorInTable())
1072 // whole table selected?
1075 SwPaM
* pPam
= GetCursor();
1076 // empty boxes are also selected as the absence of selection
1078 if( pPam
->GetPoint() == pPam
->End())
1084 if( pPam
->GetPoint()->GetNodeIndex() -1 ==
1085 ( pNd
= &pPam
->GetPointNode())->StartOfSectionIndex() &&
1086 !pPam
->GetPoint()->GetContentIndex() &&
1087 pPam
->GetMark()->GetNodeIndex() + 1 ==
1088 pNd
->EndOfSectionIndex())
1090 SwNodeIndex
aIdx( *pNd
->EndOfSectionNode(), -1 );
1091 SwContentNode
* pCNd
= aIdx
.GetNode().GetContentNode();
1094 pCNd
= SwNodes::GoPrevious( &aIdx
);
1095 assert(pCNd
&& "no ContentNode in box ??");
1097 if( pPam
->GetMark()->GetContentIndex() == pCNd
->Len() )
1109 void SwFEShell::ProtectCells()
1111 SvxProtectItem
aProt( RES_PROTECT
);
1112 aProt
.SetContentProtect( true );
1114 CurrShell
aCurr( this );
1117 GetDoc()->SetBoxAttr( *getShellCursor( false ), aProt
);
1119 if( !IsCursorReadonly() )
1125 EndAllActionAndCall();
1128 // cancel table selection
1129 void SwFEShell::UnProtectCells()
1131 CurrShell
aCurr( this );
1136 ::GetTableSelCrs( *this, aBoxes
);
1139 SwFrame
*pFrame
= GetCurrFrame();
1141 pFrame
= pFrame
->GetUpper();
1142 } while ( pFrame
&& !pFrame
->IsCellFrame() );
1145 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
1146 aBoxes
.insert( pBox
);
1150 if( !aBoxes
.empty() )
1151 GetDoc()->UnProtectCells( aBoxes
);
1153 EndAllActionAndCall();
1156 void SwFEShell::UnProtectTables()
1158 CurrShell
aCurr( this );
1160 GetDoc()->UnProtectTables( *GetCursor() );
1161 EndAllActionAndCall();
1164 bool SwFEShell::HasTableAnyProtection( const OUString
* pTableName
,
1165 bool* pFullTableProtection
)
1167 return GetDoc()->HasTableAnyProtection( GetCursor()->GetPoint(), pTableName
,
1168 pFullTableProtection
);
1171 bool SwFEShell::CanUnProtectCells() const
1173 bool bUnProtectAvailable
= false;
1174 const SwTableNode
*pTableNd
= IsCursorInTable();
1175 if( pTableNd
&& !pTableNd
->IsProtect() )
1179 ::GetTableSelCrs( *this, aBoxes
);
1182 SwFrame
*pFrame
= GetCurrFrame();
1185 pFrame
= pFrame
->GetUpper();
1186 } while ( pFrame
&& !pFrame
->IsCellFrame() );
1189 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
1190 aBoxes
.insert( pBox
);
1193 if( !aBoxes
.empty() )
1194 bUnProtectAvailable
= ::HasProtectedCells( aBoxes
);
1196 return bUnProtectAvailable
;
1199 sal_uInt16
SwFEShell::GetRowsToRepeat() const
1201 const SwFrame
*pFrame
= GetCurrFrame();
1202 const SwTabFrame
*pTab
= pFrame
? pFrame
->FindTabFrame() : nullptr;
1204 return pTab
->GetTable()->GetRowsToRepeat();
1208 void SwFEShell::SetRowsToRepeat( sal_uInt16 nSet
)
1210 SwFrame
*pFrame
= GetCurrFrame();
1211 SwTabFrame
*pTab
= pFrame
? pFrame
->FindTabFrame() : nullptr;
1212 if( pTab
&& pTab
->GetTable()->GetRowsToRepeat() != nSet
)
1214 SwWait
aWait( *GetDoc()->GetDocShell(), true );
1215 CurrShell
aCurr( this );
1217 GetDoc()->SetRowsToRepeat( *pTab
->GetTable(), nSet
);
1218 EndAllActionAndCall();
1222 // returns the number of rows consecutively selected from top
1223 static sal_uInt16
lcl_GetRowNumber( const SwPosition
& rPos
)
1226 const SwContentNode
*pNd
;
1227 const SwContentFrame
*pFrame
;
1229 std::pair
<Point
, bool> const tmp(aTmpPt
, false);
1230 pNd
= rPos
.GetNode().GetContentNode();
1231 if( nullptr != pNd
)
1232 pFrame
= pNd
->getLayoutFrame(pNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), &rPos
, &tmp
);
1236 const SwFrame
* pRow
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->GetUpper() : nullptr;
1238 while (pRow
&& (!pRow
->GetUpper() || !pRow
->GetUpper()->IsTabFrame()))
1239 pRow
= pRow
->GetUpper();
1244 const SwTabFrame
* pTabFrame
= static_cast<const SwTabFrame
*>(pRow
->GetUpper());
1245 const SwTableLine
* pTabLine
= static_cast<const SwRowFrame
*>(pRow
)->GetTabLine();
1246 sal_uInt16 nRet
= USHRT_MAX
;
1248 while ( sal::static_int_cast
<SwTableLines::size_type
>(nI
) < pTabFrame
->GetTable()->GetTabLines().size() )
1250 if ( pTabFrame
->GetTable()->GetTabLines()[ nI
] == pTabLine
)
1261 sal_uInt16
SwFEShell::GetRowSelectionFromTop() const
1263 sal_uInt16 nRet
= 0;
1264 const SwPaM
* pPaM
= IsTableMode() ? GetTableCursor() : GetCursor_();
1265 const sal_uInt16 nPtLine
= lcl_GetRowNumber( *pPaM
->GetPoint() );
1267 if ( !IsTableMode() )
1269 nRet
= 0 == nPtLine
? 1 : 0;
1273 const sal_uInt16 nMkLine
= lcl_GetRowNumber( *pPaM
->GetMark() );
1275 if ( ( nPtLine
== 0 && nMkLine
!= USHRT_MAX
) ||
1276 ( nMkLine
== 0 && nPtLine
!= USHRT_MAX
) )
1278 nRet
= std::max( nPtLine
, nMkLine
) + 1;
1286 * 1. case: bRepeat = true
1287 * returns true if the current frame is located inside a table headline in
1290 * 2. case: bRepeat = false
1291 * returns true if the current frame is located inside a table headline OR
1292 * inside the first line of a table!!!
1294 bool SwFEShell::CheckHeadline( bool bRepeat
) const
1297 if ( !IsTableMode() )
1299 SwFrame
*pFrame
= GetCurrFrame(); // DONE MULTIIHEADER
1300 SwTabFrame
* pTab
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->FindTabFrame() : nullptr;
1305 bRet
= pTab
->IsFollow() && pTab
->IsInHeadline( *pFrame
);
1309 bRet
= static_cast<SwLayoutFrame
*>(pTab
->Lower())->IsAnLower( pFrame
) ||
1310 pTab
->IsInHeadline( *pFrame
);
1317 void SwFEShell::AdjustCellWidth( const bool bBalance
, const bool bNoShrink
)
1319 CurrShell
aCurr( this );
1322 // switch on wait-cursor, as we do not know how
1323 // much content is affected
1324 TableWait
aWait(std::numeric_limits
<size_t>::max(), nullptr,
1325 *GetDoc()->GetDocShell());
1327 GetDoc()->AdjustCellWidth( *getShellCursor( false ), bBalance
, bNoShrink
);
1328 EndAllActionAndCall();
1331 bool SwFEShell::IsAdjustCellWidthAllowed( bool bBalance
) const
1333 // at least one row with content should be contained in the selection
1335 SwFrame
*pFrame
= GetCurrFrame();
1336 if( !pFrame
|| !pFrame
->IsInTab() )
1340 ::GetTableSelCrs( *this, aBoxes
);
1343 return aBoxes
.size() > 1;
1345 if ( aBoxes
.empty() )
1349 pFrame
= pFrame
->GetUpper();
1351 while (pFrame
&& !pFrame
->IsCellFrame());
1356 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
1357 aBoxes
.insert( pBox
);
1360 for (size_t i
= 0; i
< aBoxes
.size(); ++i
)
1362 SwTableBox
*pBox
= aBoxes
[i
];
1363 if ( pBox
->GetSttNd() )
1365 SwNodeIndex
aIdx( *pBox
->GetSttNd(), 1 );
1366 SwTextNode
* pCNd
= aIdx
.GetNode().GetTextNode();
1368 pCNd
= static_cast<SwTextNode
*>(GetDoc()->GetNodes().GoNext( &aIdx
));
1372 if (!pCNd
->GetText().isEmpty())
1375 pCNd
= aIdx
.GetNode().GetTextNode();
1382 void SwFEShell::SetTableStyle(const OUString
& rStyleName
)
1384 // make sure SwDoc has the style
1385 SwTableAutoFormat
*pTableFormat
= GetDoc()->GetTableStyles().FindAutoFormat(rStyleName
);
1389 SwTableNode
*pTableNode
= const_cast<SwTableNode
*>(IsCursorInTable());
1393 // set the name & update
1394 UpdateTableStyleFormatting(pTableNode
, false, &rStyleName
);
1397 // AutoFormat for the table/table selection
1398 bool SwFEShell::SetTableStyle(const SwTableAutoFormat
& rStyle
)
1400 // make sure SwDoc has the style
1401 GetDoc()->GetTableStyles().AddAutoFormat(rStyle
);
1403 SwTableNode
*pTableNode
= const_cast<SwTableNode
*>(IsCursorInTable());
1407 // set the name & update
1408 return UpdateTableStyleFormatting(pTableNode
, false, &rStyle
.GetName());
1411 bool SwFEShell::UpdateTableStyleFormatting(SwTableNode
*pTableNode
,
1412 bool bResetDirect
, OUString
const*const pStyleName
)
1416 pTableNode
= const_cast<SwTableNode
*>(IsCursorInTable());
1417 if (!pTableNode
|| pTableNode
->GetTable().IsTableComplex())
1421 OUString
const aTableStyleName(pStyleName
1423 : pTableNode
->GetTable().GetTableStyleName());
1424 SwTableAutoFormat
* pTableStyle
= GetDoc()->GetTableStyles().FindAutoFormat(aTableStyleName
);
1430 // whole table or only current selection
1432 ::GetTableSelCrs( *this, aBoxes
);
1435 const SwTableSortBoxes
& rTBoxes
= pTableNode
->GetTable().GetTabSortBoxes();
1436 for (size_t n
= 0; n
< rTBoxes
.size(); ++n
)
1438 SwTableBox
* pBox
= rTBoxes
[ n
];
1439 aBoxes
.insert( pBox
);
1444 if( !aBoxes
.empty() )
1446 CurrShell
aCurr( this );
1448 bRet
= GetDoc()->SetTableAutoFormat(
1449 aBoxes
, *pTableStyle
, bResetDirect
, pStyleName
!= nullptr);
1450 ClearFEShellTabCols(*GetDoc(), nullptr);
1451 EndAllActionAndCall();
1458 bool SwFEShell::GetTableAutoFormat( SwTableAutoFormat
& rGet
)
1460 const SwTableNode
*pTableNd
= IsCursorInTable();
1461 if( !pTableNd
|| pTableNd
->GetTable().IsTableComplex() )
1466 if ( !IsTableMode() ) // if cursor are not current
1469 // whole table or only current selection
1471 ::GetTableSelCrs( *this, aBoxes
);
1474 const SwTableSortBoxes
& rTBoxes
= pTableNd
->GetTable().GetTabSortBoxes();
1475 for (size_t n
= 0; n
< rTBoxes
.size(); ++n
)
1477 SwTableBox
* pBox
= rTBoxes
[ n
];
1478 aBoxes
.insert( pBox
);
1482 return GetDoc()->GetTableAutoFormat( aBoxes
, rGet
);
1485 bool SwFEShell::DeleteTableSel()
1487 // check if SPoint/Mark of current cursor are in a table
1488 SwFrame
*pFrame
= GetCurrFrame();
1489 if( !pFrame
|| !pFrame
->IsInTab() )
1492 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
1494 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
1495 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
1499 CurrShell
aCurr( this );
1502 // search boxes via the layout
1505 GetTableSelCrs( *this, aBoxes
);
1506 if( !aBoxes
.empty() )
1508 TableWait
aWait( aBoxes
.size(), pFrame
, *GetDoc()->GetDocShell() );
1510 // cursor should be removed from deletion area.
1511 // Put them behind/on the table; via the document
1512 // position they'll be set to the old position
1513 while( !pFrame
->IsCellFrame() )
1514 pFrame
= pFrame
->GetUpper();
1515 ParkCursor( *static_cast<SwCellFrame
*>(pFrame
)->GetTabBox()->GetSttNd() );
1517 bRet
= GetDoc()->DeleteRowCol( aBoxes
);
1519 ClearFEShellTabCols(*GetDoc(), nullptr);
1523 EndAllActionAndCall();
1527 size_t SwFEShell::GetCurTabColNum() const
1529 //!!!GetCurMouseTabColNum() mitpflegen!!!!
1530 SwFrame
*pFrame
= GetCurrFrame();
1531 OSL_ENSURE( pFrame
, "Cursor parked?" );
1533 // check if SPoint/Mark of current cursor are in a table
1534 if (!pFrame
|| !pFrame
->IsInTab())
1539 // JP 26.09.95: why compare with ContentFrame
1540 // and not with CellFrame ????
1541 pFrame
= pFrame
->GetUpper();
1542 } while (pFrame
&& !pFrame
->IsCellFrame());
1549 SwRectFnSet
aRectFnSet(pFrame
);
1551 const SwPageFrame
* pPage
= pFrame
->FindPageFrame();
1553 // get TabCols, as only via these we get to the position
1555 GetTabCols( aTabCols
);
1557 if( pFrame
->FindTabFrame()->IsRightToLeft() )
1559 tools::Long nX
= aRectFnSet
.GetRight(pFrame
->getFrameArea()) - aRectFnSet
.GetLeft(pPage
->getFrameArea());
1561 const tools::Long nRight
= aTabCols
.GetLeftMin() + aTabCols
.GetRight();
1563 if ( !::IsSame( nX
, nRight
) )
1565 nX
= nRight
- nX
+ aTabCols
.GetLeft();
1566 for ( size_t i
= 0; i
< aTabCols
.Count(); ++i
)
1567 if ( ::IsSame( nX
, aTabCols
[i
] ) )
1576 const tools::Long nX
= aRectFnSet
.GetLeft(pFrame
->getFrameArea()) -
1577 aRectFnSet
.GetLeft(pPage
->getFrameArea());
1579 const tools::Long nLeft
= aTabCols
.GetLeftMin();
1581 if ( !::IsSame( nX
, nLeft
+ aTabCols
.GetLeft() ) )
1583 for ( size_t i
= 0; i
< aTabCols
.Count(); ++i
)
1584 if ( ::IsSame( nX
, nLeft
+ aTabCols
[i
] ) )
1594 static const SwFrame
*lcl_FindFrameInTab( const SwLayoutFrame
*pLay
, const Point
&rPt
, SwTwips nFuzzy
)
1596 const SwFrame
*pFrame
= pLay
->Lower();
1598 while( pFrame
&& pLay
->IsAnLower( pFrame
) )
1600 if ( pFrame
->getFrameArea().IsNear( rPt
, nFuzzy
) )
1602 if ( pFrame
->IsLayoutFrame() )
1604 const SwFrame
*pTmp
= ::lcl_FindFrameInTab( static_cast<const SwLayoutFrame
*>(pFrame
), rPt
, nFuzzy
);
1612 pFrame
= pFrame
->FindNext();
1618 static const SwCellFrame
*lcl_FindFrame( const SwLayoutFrame
*pLay
, const Point
&rPt
,
1619 SwTwips nFuzzy
, bool* pbRow
, bool* pbCol
)
1621 // bMouseMoveRowCols :
1622 // Method is called for
1623 // - Moving columns/rows with the mouse or
1624 // - Enhanced table selection
1625 const bool bMouseMoveRowCols
= nullptr == pbCol
;
1627 bool bCloseToRow
= false;
1628 bool bCloseToCol
= false;
1630 const SwFrame
*pFrame
= pLay
->ContainsContent();
1631 const SwFrame
* pRet
= nullptr;
1637 if ( pFrame
->IsInTab() )
1638 pFrame
= const_cast<SwFrame
*>(pFrame
)->ImplFindTabFrame();
1643 if ( pFrame
->IsTabFrame() )
1646 bool bSearchForFrameInTab
= true;
1647 SwTwips nTmpFuzzy
= nFuzzy
;
1649 if ( !bMouseMoveRowCols
)
1651 // We ignore nested tables for the enhanced table selection:
1652 while ( pFrame
->GetUpper()->IsInTab() )
1653 pFrame
= pFrame
->GetUpper()->FindTabFrame();
1655 // We first check if the given point is 'close' to the left or top
1656 // border of the table frame:
1657 OSL_ENSURE( pFrame
, "Nested table frame without outer table" );
1658 SwRectFnSet
aRectFnSet(pFrame
);
1659 const bool bRTL
= pFrame
->IsRightToLeft();
1661 SwRect aTabRect
= pFrame
->getFramePrintArea();
1662 aTabRect
.Pos() += pFrame
->getFrameArea().Pos();
1664 const SwTwips nLeft
= bRTL
?
1665 aRectFnSet
.GetRight(aTabRect
) :
1666 aRectFnSet
.GetLeft(aTabRect
);
1667 const SwTwips nTop
= aRectFnSet
.GetTop(aTabRect
);
1669 SwTwips
const rPointX
= aRectFnSet
.IsVert() ? aPt
.Y() : aPt
.X();
1670 SwTwips
const rPointY
= aRectFnSet
.IsVert() ? aPt
.X() : aPt
.Y();
1672 const SwTwips nXDiff
= aRectFnSet
.XDiff( nLeft
, rPointX
) * ( bRTL
? -1 : 1 );
1673 const SwTwips nYDiff
= aRectFnSet
.YDiff( nTop
, rPointY
);
1675 bCloseToRow
= nXDiff
>= 0 && nXDiff
< nFuzzy
;
1676 bCloseToCol
= nYDiff
>= 0 && nYDiff
< nFuzzy
;
1678 if ( bCloseToCol
&& 2 * nYDiff
> nFuzzy
)
1680 const SwFrame
* pPrev
= pFrame
->GetPrev();
1683 SwRect aPrevRect
= pPrev
->getFramePrintArea();
1684 aPrevRect
.Pos() += pPrev
->getFrameArea().Pos();
1686 if( aPrevRect
.Contains( rPt
) )
1688 bCloseToCol
= false;
1694 // If we found the point to be 'close' to the left or top border
1695 // of the table frame, we adjust the point to be on that border:
1696 if ( bCloseToRow
&& bCloseToCol
)
1697 aPt
= bRTL
? aTabRect
.TopRight() : aRectFnSet
.GetPos(aTabRect
);
1698 else if ( bCloseToRow
)
1699 aRectFnSet
.IsVert() ? aPt
.setY(nLeft
) : aPt
.setX(nLeft
);
1700 else if ( bCloseToCol
)
1701 aRectFnSet
.IsVert() ? aPt
.setX(nTop
) : aPt
.setY(nTop
);
1703 if ( !bCloseToRow
&& !bCloseToCol
)
1704 bSearchForFrameInTab
= false;
1706 // Since the point has been adjusted, we call lcl_FindFrameInTab()
1707 // with a fuzzy value of 1:
1711 const SwFrame
* pTmp
= bSearchForFrameInTab
?
1712 ::lcl_FindFrameInTab( static_cast<const SwLayoutFrame
*>(pFrame
), aPt
, nTmpFuzzy
) :
1721 pFrame
= pFrame
->FindNextCnt();
1723 } while ( pFrame
&& pLay
->IsAnLower( pFrame
) );
1726 if ( pFrame
&& pFrame
->IsInTab() && pLay
->IsAnLower( pFrame
) )
1730 // We allow mouse drag of table borders within nested tables,
1731 // but disallow hotspot selection of nested tables.
1732 if ( bMouseMoveRowCols
)
1734 // find the next cell frame
1735 while ( pFrame
&& !pFrame
->IsCellFrame() )
1736 pFrame
= pFrame
->GetUpper();
1740 // find the most upper cell frame:
1742 ( !pFrame
->IsCellFrame() ||
1743 !pFrame
->GetUpper()->GetUpper()->IsTabFrame() ||
1744 pFrame
->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) )
1745 pFrame
= pFrame
->GetUpper();
1748 if ( pFrame
) // Note: this condition should be the same like the while condition!!!
1750 // #i32329# Enhanced table selection
1751 // used for hotspot selection of tab/cols/rows
1752 if ( !bMouseMoveRowCols
)
1755 OSL_ENSURE( pbCol
&& pbRow
, "pbCol or pbRow missing" );
1757 if ( bCloseToRow
|| bCloseToCol
)
1759 *pbRow
= bCloseToRow
;
1760 *pbCol
= bCloseToCol
;
1767 // used for mouse move of columns/rows
1768 const SwTabFrame
* pTabFrame
= pFrame
->FindTabFrame();
1769 SwRect aTabRect
= pTabFrame
->getFramePrintArea();
1770 aTabRect
.Pos() += pTabFrame
->getFrameArea().Pos();
1772 SwRectFnSet
aRectFnSet(pTabFrame
);
1774 const SwTwips nTabTop
= aRectFnSet
.GetTop(aTabRect
);
1775 const SwTwips nMouseTop
= aRectFnSet
.IsVert() ? rPt
.X() : rPt
.Y();
1777 // Do not allow to drag upper table border:
1778 if ( !::IsSame( nTabTop
, nMouseTop
) )
1780 if ( ::IsSame( pFrame
->getFrameArea().Left(), rPt
.X() ) ||
1781 ::IsSame( pFrame
->getFrameArea().Right(),rPt
.X() ) )
1783 if ( pbRow
) *pbRow
= false;
1787 if ( ::IsSame( pFrame
->getFrameArea().Top(), rPt
.Y() ) ||
1788 ::IsSame( pFrame
->getFrameArea().Bottom(),rPt
.Y() ) )
1790 if ( pbRow
) *pbRow
= true;
1797 pFrame
= pFrame
->GetUpper();
1803 OSL_ENSURE( !pRet
|| pRet
->IsCellFrame(), "lcl_FindFrame() is supposed to find a cell frame!" );
1804 return pRet
&& pRet
->IsCellFrame() ? static_cast<const SwCellFrame
*>(pRet
) : nullptr;
1807 // pbCol = 0 => Used for moving table rows/cols with mouse
1808 // pbCol != 0 => Used for selecting table/rows/cols
1810 #define ENHANCED_TABLE_SELECTION_FUZZY 10
1812 const SwFrame
* SwFEShell::GetBox( const Point
&rPt
, bool* pbRow
, bool* pbCol
) const
1814 const SwPageFrame
*pPage
= static_cast<SwPageFrame
*>(GetLayout()->Lower());
1815 vcl::Window
* pOutWin
= GetWin();
1816 SwTwips nFuzzy
= COLFUZZY
;
1819 // #i32329# Enhanced table selection
1820 SwTwips nSize
= pbCol
? ENHANCED_TABLE_SELECTION_FUZZY
: RULER_MOUSE_MARGINWIDTH
;
1821 Size
aTmp( nSize
, nSize
);
1822 aTmp
= pOutWin
->PixelToLogic( aTmp
);
1823 nFuzzy
= aTmp
.Width();
1826 while ( pPage
&& !pPage
->getFrameArea().IsNear( rPt
, nFuzzy
) )
1827 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
1829 const SwCellFrame
*pFrame
= nullptr;
1832 // We cannot search the box by GetModelPositionForViewPoint or GetContentPos.
1833 // This would lead to a performance collapse for documents
1834 // with a lot of paragraphs/tables on one page
1838 if ( pPage
->GetSortedObjs() )
1840 for ( size_t i
= 0; !pFrame
&& i
< pPage
->GetSortedObjs()->size(); ++i
)
1842 SwAnchoredObject
* pObj
= (*pPage
->GetSortedObjs())[i
];
1843 if ( auto pFlyFrame
= pObj
->DynCastFlyFrame() )
1845 pFrame
= lcl_FindFrame( pFlyFrame
, rPt
, nFuzzy
, pbRow
, pbCol
);
1849 const SwLayoutFrame
*pLay
= static_cast<const SwLayoutFrame
*>(pPage
->Lower());
1850 while ( pLay
&& !pFrame
)
1852 pFrame
= lcl_FindFrame( pLay
, rPt
, nFuzzy
, pbRow
, pbCol
);
1853 pLay
= static_cast<const SwLayoutFrame
*>(pLay
->GetNext());
1859 /* Helper function*/
1860 /* calculated the distance between Point rC and Line Segment (rA, rB) */
1861 static double lcl_DistancePoint2Segment( const Point
& rA
, const Point
& rB
, const Point
& rC
)
1865 const basegfx::B2DVector
aBC( rC
.X() - rB
.X(), rC
.Y() - rB
.Y() );
1866 const basegfx::B2DVector
aAB( rB
.X() - rA
.X(), rB
.Y() - rA
.Y() );
1867 const double nDot1
= aBC
.scalar( aAB
);
1869 if ( nDot1
> 0 ) // check outside case 1
1870 nRet
= aBC
.getLength();
1873 const basegfx::B2DVector
aAC( rC
.X() - rA
.X(), rC
.Y() - rA
.Y() );
1874 const basegfx::B2DVector
aBA( rA
.X() - rB
.X(), rA
.Y() - rB
.Y() );
1875 const double nDot2
= aAC
.scalar( aBA
);
1877 if ( nDot2
> 0 ) // check outside case 2
1878 nRet
= aAC
.getLength();
1881 const double nDiv
= aAB
.getLength();
1882 nRet
= nDiv
? aAB
.cross( aAC
) / nDiv
: 0;
1886 return std::abs(nRet
);
1889 /* Helper function*/
1890 static Point
lcl_ProjectOntoClosestTableFrame( const SwTabFrame
& rTab
, const Point
& rPoint
, bool bRowDrag
)
1892 Point
aRet( rPoint
);
1893 const SwTabFrame
* pCurrentTab
= &rTab
;
1894 const bool bVert
= pCurrentTab
->IsVertical();
1895 const bool bRTL
= pCurrentTab
->IsRightToLeft();
1898 // bRowDrag = true => compare to left border of table
1899 // bRowDrag = false => compare to top border of table
1902 // bRowDrag = true => compare to right border of table
1903 // bRowDrag = false => compare to top border of table
1906 // bRowDrag = true => compare to right border of table
1907 // bRowDrag = false => compare to top border of table
1909 bool bRight
= false;
1913 if ( bVert
|| bRTL
)
1919 // used to find the minimal distance
1927 while ( pCurrentTab
)
1929 SwRect
aTabRect( pCurrentTab
->getFramePrintArea() );
1930 aTabRect
+= pCurrentTab
->getFrameArea().Pos();
1934 // distance to left table border
1935 aS1
= aTabRect
.TopLeft();
1936 aS2
= aTabRect
.BottomLeft();
1940 // distance to right table border
1941 aS1
= aTabRect
.TopRight();
1942 aS2
= aTabRect
.BottomRight();
1946 // distance to top table border
1947 aS1
= aTabRect
.TopLeft();
1948 aS2
= aTabRect
.TopRight();
1951 const double nDist
= lcl_DistancePoint2Segment( aS1
, aS2
, rPoint
);
1953 if ( nDist
< nMin
|| -1 == nMin
)
1960 pCurrentTab
= pCurrentTab
->GetFollow();
1963 // project onto closest line:
1964 if ( bLeft
|| bRight
)
1966 aRet
.setX(aMin1
.getX());
1967 if ( aRet
.getY() > aMin2
.getY() )
1968 aRet
.setY(aMin2
.getY());
1969 else if ( aRet
.getY() < aMin1
.getY() )
1970 aRet
.setY(aMin1
.getY());
1974 aRet
.setY(aMin1
.getY());
1975 if ( aRet
.getX() > aMin2
.getX() )
1976 aRet
.setX(aMin2
.getX());
1977 else if ( aRet
.getX() < aMin1
.getX() )
1978 aRet
.setX(aMin1
.getX());
1984 // #i32329# Enhanced table selection
1985 bool SwFEShell::SelTableRowCol( const Point
& rPt
, const Point
* pEnd
, bool bRowDrag
)
1992 SwPosition
* ppPos
[2] = { nullptr, nullptr };
1993 Point paPt
[2] = { rPt
, aEndPt
};
1994 bool pbRow
[2] = { false, false };
1995 bool pbCol
[2] = { false, false };
1997 // pEnd is set during dragging.
1998 for ( sal_uInt16 i
= 0; i
< ( pEnd
? 2 : 1 ); ++i
)
2000 const SwCellFrame
* pFrame
=
2001 static_cast<const SwCellFrame
*>(GetBox( paPt
[i
], &pbRow
[i
], &pbCol
[i
] ) );
2005 while( pFrame
&& pFrame
->Lower() && pFrame
->Lower()->IsRowFrame() )
2006 pFrame
= static_cast<const SwCellFrame
*>( static_cast<const SwLayoutFrame
*>( pFrame
->Lower() )->Lower() );
2007 if( pFrame
&& pFrame
->GetTabBox()->GetSttNd() &&
2008 pFrame
->GetTabBox()->GetSttNd()->IsInProtectSect() )
2014 const SwContentFrame
* pContent
= ::GetCellContent( *pFrame
);
2016 if ( pContent
&& pContent
->IsTextFrame() )
2019 ppPos
[i
] = new SwPosition(static_cast<SwTextFrame
const*>(pContent
)->MapViewToModelPos(TextFrameIndex(0)));
2021 // paPt[i] will not be used any longer, now we use it to store
2022 // a position inside the content frame
2023 paPt
[i
] = pContent
->getFrameArea().Center();
2027 // no calculation of end frame if start frame has not been found.
2028 if ( 1 == i
|| !ppPos
[0] || !pEnd
|| !pFrame
)
2031 // find 'closest' table frame to pEnd:
2032 const SwTabFrame
* pCurrentTab
= pFrame
->FindTabFrame();
2033 if ( pCurrentTab
->IsFollow() )
2034 pCurrentTab
= pCurrentTab
->FindMaster( true );
2036 const Point aProjection
= lcl_ProjectOntoClosestTableFrame( *pCurrentTab
, *pEnd
, bRowDrag
);
2037 paPt
[1] = aProjection
;
2042 SwShellCursor
* pCursor
= GetCursor_();
2043 SwCursorSaveState
aSaveState( *pCursor
);
2044 SwPosition
aOldPos( *pCursor
->GetPoint() );
2046 pCursor
->DeleteMark();
2047 *pCursor
->GetPoint() = *ppPos
[0];
2048 pCursor
->GetPtPos() = paPt
[0];
2050 if ( !pCursor
->IsInProtectTable() )
2052 bool bNewSelection
= true;
2056 if ( ppPos
[1]->GetNode().StartOfSectionNode() !=
2057 aOldPos
.GetNode().StartOfSectionNode() )
2060 SwCursorSaveState
aSaveState2( *pCursor
);
2061 *pCursor
->GetPoint() = *ppPos
[1];
2062 pCursor
->GetPtPos() = paPt
[1];
2064 if ( pCursor
->IsInProtectTable( false, false ) )
2066 pCursor
->RestoreSavePos();
2067 bNewSelection
= false;
2072 pCursor
->RestoreSavePos();
2073 bNewSelection
= false;
2077 if ( bNewSelection
)
2079 // #i35543# SelTableRowCol should remove any existing
2081 if ( IsTableMode() )
2082 TableCursorToCursor();
2084 if ( pbRow
[0] && pbCol
[0] )
2085 bRet
= SwCursorShell::SelTable();
2086 else if ( pbRow
[0] )
2087 bRet
= SwCursorShell::SelTableRowOrCol( true, true );
2088 else if ( pbCol
[0] )
2089 bRet
= SwCursorShell::SelTableRowOrCol( false, true );
2102 SwTab
SwFEShell::WhichMouseTabCol( const Point
&rPt
) const
2104 SwTab nRet
= SwTab::COL_NONE
;
2107 bool bSelect
= false;
2109 // First try: Do we get the row/col move cursor?
2110 const SwCellFrame
* pFrame
= static_cast<const SwCellFrame
*>(GetBox( rPt
, &bRow
));
2114 // Second try: Do we get the row/col/tab selection cursor?
2115 pFrame
= static_cast<const SwCellFrame
*>(GetBox( rPt
, &bRow
, &bCol
));
2121 while( pFrame
&& pFrame
->Lower() && pFrame
->Lower()->IsRowFrame() )
2122 pFrame
= static_cast<const SwCellFrame
*>(static_cast<const SwLayoutFrame
*>(pFrame
->Lower())->Lower());
2123 if( pFrame
&& pFrame
->GetTabBox()->GetSttNd() &&
2124 pFrame
->GetTabBox()->GetSttNd()->IsInProtectSect() )
2132 if ( pFrame
->IsVertical() )
2133 nRet
= bRow
? SwTab::COL_VERT
: SwTab::ROW_VERT
;
2135 nRet
= bRow
? SwTab::ROW_HORI
: SwTab::COL_HORI
;
2139 const SwTabFrame
* pTabFrame
= pFrame
->FindTabFrame();
2140 if ( pTabFrame
->IsVertical() )
2144 nRet
= SwTab::SEL_VERT
;
2148 nRet
= SwTab::ROWSEL_VERT
;
2152 nRet
= SwTab::COLSEL_VERT
;
2159 nRet
= pTabFrame
->IsRightToLeft() ?
2160 SwTab::SEL_HORI_RTL
:
2165 nRet
= pTabFrame
->IsRightToLeft() ?
2166 SwTab::ROWSEL_HORI_RTL
:
2171 nRet
= SwTab::COLSEL_HORI
;
2181 SwTextNode
* SwFEShell::GetNumRuleNodeAtPos( const Point
&rPt
)
2183 SwTextNode
* pResult
= nullptr;
2185 SwContentAtPos
aContentAtPos(IsAttrAtPos::NumLabel
);
2187 if( GetContentAtPos(rPt
, aContentAtPos
) && aContentAtPos
.aFnd
.pNode
)
2188 pResult
= aContentAtPos
.aFnd
.pNode
->GetTextNode();
2193 bool SwFEShell::IsNumLabel( const Point
&rPt
, int nMaxOffset
)
2195 bool bResult
= false;
2197 SwContentAtPos
aContentAtPos(IsAttrAtPos::NumLabel
);
2199 if( GetContentAtPos(rPt
, aContentAtPos
))
2201 if ((nMaxOffset
>= 0 && aContentAtPos
.nDist
<= nMaxOffset
) ||
2211 bool SwFEShell::IsVerticalModeAtNdAndPos( const SwTextNode
& _rTextNode
,
2212 const Point
& _rDocPos
)
2216 const SvxFrameDirection nTextDir
=
2217 _rTextNode
.GetTextDirection( SwPosition(_rTextNode
), &_rDocPos
);
2220 case SvxFrameDirection::Unknown
:
2221 case SvxFrameDirection::Horizontal_RL_TB
:
2222 case SvxFrameDirection::Horizontal_LR_TB
:
2227 case SvxFrameDirection::Vertical_LR_TB
:
2228 case SvxFrameDirection::Vertical_RL_TB
:
2239 void SwFEShell::GetMouseTabCols( SwTabCols
&rToFill
, const Point
&rPt
) const
2241 const SwFrame
*pBox
= GetBox( rPt
);
2243 GetTabCols_( rToFill
, pBox
);
2246 void SwFEShell::SetMouseTabCols( const SwTabCols
&rNew
, bool bCurRowOnly
,
2249 const SwFrame
*pBox
= GetBox( rPt
);
2252 CurrShell
aCurr( this );
2254 GetDoc()->SetTabCols( rNew
, bCurRowOnly
, static_cast<const SwCellFrame
*>(pBox
) );
2255 EndAllActionAndCall();
2259 sal_uInt16
SwFEShell::GetCurMouseColNum( const Point
&rPt
) const
2261 return GetCurColNum_( GetBox( rPt
), nullptr );
2264 size_t SwFEShell::GetCurMouseTabColNum( const Point
&rPt
) const
2266 //!!!GetCurTabColNum() mitpflegen!!!!
2269 const SwFrame
*pFrame
= GetBox( rPt
);
2270 OSL_ENSURE( pFrame
, "Table not found" );
2273 const tools::Long nX
= pFrame
->getFrameArea().Left();
2275 // get TabCols, only via these we get the position
2277 GetMouseTabCols( aTabCols
, rPt
);
2279 const tools::Long nLeft
= aTabCols
.GetLeftMin();
2281 if ( !::IsSame( nX
, nLeft
+ aTabCols
.GetLeft() ) )
2283 for ( size_t i
= 0; i
< aTabCols
.Count(); ++i
)
2284 if ( ::IsSame( nX
, nLeft
+ aTabCols
[i
] ) )
2294 void ClearFEShellTabCols(SwDoc
& rDoc
, SwTabFrame
const*const pFrame
)
2296 auto const pShell(rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell());
2299 for (SwViewShell
& rCurrentShell
: pShell
->GetRingContainer())
2301 if (auto const pFE
= dynamic_cast<SwFEShell
*>(&rCurrentShell
))
2303 pFE
->ClearColumnRowCache(pFrame
);
2309 void SwFEShell::ClearColumnRowCache(SwTabFrame
const*const pFrame
)
2313 if (pFrame
== nullptr || pFrame
== m_pColumnCache
->pLastTabFrame
)
2315 m_pColumnCache
.reset();
2320 if (pFrame
== nullptr || pFrame
== m_pRowCache
->pLastTabFrame
)
2322 m_pRowCache
.reset();
2327 void SwFEShell::GetTableAttr( SfxItemSet
&rSet
) const
2329 SwFrame
*pFrame
= GetCurrFrame();
2330 if( pFrame
&& pFrame
->IsInTab() )
2331 rSet
.Put( pFrame
->ImplFindTabFrame()->GetFormat()->GetAttrSet() );
2334 void SwFEShell::SetTableAttr( const SfxItemSet
&rNew
)
2336 SwFrame
*pFrame
= GetCurrFrame();
2337 if( pFrame
&& pFrame
->IsInTab() )
2339 CurrShell
aCurr( this );
2341 SwTabFrame
*pTab
= pFrame
->FindTabFrame();
2342 pTab
->GetTable()->SetHTMLTableLayout(std::shared_ptr
<SwHTMLTableLayout
>());
2343 GetDoc()->SetAttr( rNew
, *pTab
->GetFormat() );
2344 GetDoc()->getIDocumentState().SetModified();
2345 EndAllActionAndCall();
2349 // change a cell width/cell height/column width/row height
2350 void SwFEShell::SetColRowWidthHeight( TableChgWidthHeightType eType
, sal_uInt16 nDiff
)
2352 SwFrame
*pFrame
= GetCurrFrame();
2353 if( !pFrame
|| !pFrame
->IsInTab() )
2356 CurrShell
aCurr( this );
2360 pFrame
= pFrame
->GetUpper();
2361 } while( !pFrame
->IsCellFrame() );
2363 SwTabFrame
*pTab
= pFrame
->ImplFindTabFrame();
2365 // if the table is in relative values (USHRT_MAX)
2366 // then it should be recalculated to absolute values now
2367 const SwFormatFrameSize
& rTableFrameSz
= pTab
->GetFormat()->GetFrameSize();
2368 SwRectFnSet
aRectFnSet(pTab
);
2369 tools::Long nPrtWidth
= aRectFnSet
.GetWidth(pTab
->getFramePrintArea());
2370 TableChgWidthHeightType eTypePos
= extractPosition(eType
);
2371 if( TableChgMode::VarWidthChangeAbs
== pTab
->GetTable()->GetTableChgMode() &&
2372 ( eTypePos
== TableChgWidthHeightType::ColLeft
|| eTypePos
== TableChgWidthHeightType::ColRight
) &&
2373 text::HoriOrientation::NONE
== pTab
->GetFormat()->GetHoriOrient().GetHoriOrient() &&
2374 nPrtWidth
!= rTableFrameSz
.GetWidth() )
2376 SwFormatFrameSize
aSz( rTableFrameSz
);
2377 aSz
.SetWidth( pTab
->getFramePrintArea().Width() );
2378 pTab
->GetFormat()->SetFormatAttr( aSz
);
2381 SwTwips nLogDiff
= nDiff
;
2382 nLogDiff
*= pTab
->GetFormat()->GetFrameSize().GetWidth();
2383 nLogDiff
/= nPrtWidth
;
2385 /** The cells are destroyed in here */
2386 GetDoc()->SetColRowWidthHeight(
2387 *const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox()),
2388 eType
, nDiff
, nLogDiff
);
2390 ClearFEShellTabCols(*GetDoc(), nullptr);
2391 EndAllActionAndCall();
2394 static bool lcl_IsFormulaSelBoxes( const SwTable
& rTable
, const SwTableBoxFormula
& rFormula
,
2395 SwCellFrames
& rCells
)
2397 SwTableBoxFormula
aTmp( rFormula
);
2399 aTmp
.GetBoxesOfFormula(rTable
, aBoxes
);
2400 for (size_t nSelBoxes
= aBoxes
.size(); nSelBoxes
; )
2402 SwTableBox
* pBox
= aBoxes
[ --nSelBoxes
];
2404 if( std::none_of(rCells
.begin(), rCells
.end(), [&pBox
](SwCellFrame
* pFrame
) { return pFrame
->GetTabBox() == pBox
; }) )
2411 // ask formula for auto-sum
2412 void SwFEShell::GetAutoSum( OUString
& rFormula
) const
2414 SwFrame
*pFrame
= GetCurrFrame();
2415 SwTabFrame
*pTab
= pFrame
? pFrame
->ImplFindTabFrame() : nullptr;
2419 SwCellFrames aCells
;
2421 if( ::GetAutoSumSel( *this, aCells
))
2424 for( size_t n
= aCells
.size(); n
; )
2426 SwCellFrame
* pCFrame
= aCells
[ --n
];
2427 sal_uInt16 nBoxW
= pCFrame
->GetTabBox()->IsFormulaOrValueBox();
2433 if( USHRT_MAX
== nBoxW
)
2434 continue; // skip space at beginning
2436 // formula only if box is contained
2437 if( RES_BOXATR_FORMULA
== nBoxW
&&
2438 !::lcl_IsFormulaSelBoxes( *pTab
->GetTable(), pCFrame
->
2439 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells
))
2441 nW
= RES_BOXATR_VALUE
;
2442 // restore previous spaces!
2443 for( size_t i
= aCells
.size(); n
+1 < i
; )
2445 sFields
= "|<" + aCells
[--i
]->GetTabBox()->GetName() + ">"
2452 else if( RES_BOXATR_VALUE
== nW
)
2454 // search for values, Value/Formula/Text found -> include
2455 if( RES_BOXATR_FORMULA
== nBoxW
&&
2456 ::lcl_IsFormulaSelBoxes( *pTab
->GetTable(), pCFrame
->
2457 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells
))
2459 else if( USHRT_MAX
!= nBoxW
)
2460 sFields
= OUStringChar(cListDelim
) + sFields
;
2464 else if( RES_BOXATR_FORMULA
== nW
)
2466 // only continue search when the current formula points to
2467 // all boxes contained in the selection
2468 if( RES_BOXATR_FORMULA
== nBoxW
)
2470 if( !::lcl_IsFormulaSelBoxes( *pTab
->GetTable(), pCFrame
->
2471 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells
))
2473 // redo only for values!
2475 nW
= RES_BOXATR_VALUE
;
2477 // restore previous spaces!
2478 for( size_t i
= aCells
.size(); n
+1 < i
; )
2480 sFields
= "|<" + aCells
[--i
]->GetTabBox()->GetName() + ">"
2485 sFields
= OUStringChar(cListDelim
) + sFields
;
2487 else if( USHRT_MAX
== nBoxW
)
2490 continue; // ignore this box
2493 // all other stuff terminates the loop
2494 // possibly allow texts??
2497 sFields
= "<" + pCFrame
->GetTabBox()->GetName() + ">" + sFields
;
2501 rFormula
= OUString::createFromAscii( sCalc_Sum
);
2502 if (!sFields
.isEmpty())
2504 rFormula
+= "(" + sFields
+ ")";
2508 bool SwFEShell::IsTableRightToLeft() const
2510 SwFrame
*pFrame
= GetCurrFrame();
2511 SwTabFrame
*pTab
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->ImplFindTabFrame() : nullptr;
2514 return pTab
->IsRightToLeft();
2517 bool SwFEShell::IsMouseTableRightToLeft(const Point
&rPt
) const
2519 SwFrame
*pFrame
= const_cast<SwFrame
*>(GetBox( rPt
));
2520 const SwTabFrame
* pTabFrame
= pFrame
? pFrame
->ImplFindTabFrame() : nullptr;
2521 OSL_ENSURE( pTabFrame
, "Table not found" );
2522 return pTabFrame
&& pTabFrame
->IsRightToLeft();
2525 bool SwFEShell::IsTableVertical() const
2527 SwFrame
*pFrame
= GetCurrFrame();
2528 SwTabFrame
*pTab
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->ImplFindTabFrame() : nullptr;
2531 return pTab
->IsVertical();
2534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */