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 <svx/svdview.hxx>
39 #include <IDocumentState.hxx>
40 #include <IDocumentLayoutAccess.hxx>
41 #include <IDocumentRedlineAccess.hxx>
42 #include <IDocumentUndoRedo.hxx>
45 #include <notxtfrm.hxx>
46 #include <rootfrm.hxx>
47 #include <pagefrm.hxx>
50 #include <cellfrm.hxx>
52 #include <swtable.hxx>
53 #include <swddetbl.hxx>
56 #include <dialoghelp.hxx>
58 #include <tblafmt.hxx>
59 #include <cellatr.hxx>
65 #include <frmtool.hxx>
66 #include <fmtrowsplt.hxx>
68 #include <sortedobjs.hxx>
69 #include <shellres.hxx>
71 using namespace ::com::sun::star
;
73 // also see swtable.cxx
76 static bool IsSame( SwDoc
& rDoc
, tools::Long nA
, tools::Long nB
)
78 const SwViewShell
*pVSh
= rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell();
80 return std::abs(nA
-nB
) <= COLFUZZY
;
82 SdrView
* pDrawView
= const_cast<SdrView
*>(pVSh
->GetDrawView());
83 const auto nOld
= pDrawView
->GetHitTolerancePixel();
84 pDrawView
->SetHitTolerancePixel( COLFUZZY
/4 );
85 bool bRet
= std::abs(nA
-nB
) <= pDrawView
->getHitTolLog();
86 pDrawView
->SetHitTolerancePixel( nOld
);
94 const std::unique_ptr
<SwWait
> m_pWait
;
95 // this seems really fishy: do some locking, if an arbitrary number of lines is exceeded
96 static const size_t our_kLineLimit
= 20;
97 static bool ShouldWait(size_t nCnt
, SwFrame
*pFrame
, size_t nCnt2
)
98 { return our_kLineLimit
< nCnt
|| our_kLineLimit
< nCnt2
|| (pFrame
&& our_kLineLimit
< pFrame
->ImplFindTabFrame()->GetTable()->GetTabLines().size()); }
100 TableWait(size_t nCnt
, SwFrame
*pFrame
, SwDocShell
&rDocShell
, size_t nCnt2
= 0)
101 : m_pWait( ShouldWait(nCnt
, pFrame
, nCnt2
) ? std::make_unique
<SwWait
>( rDocShell
, true ) : nullptr )
107 void SwFEShell::ParkCursorInTab()
109 SwCursor
* pSwCursor
= GetCursor();
111 OSL_ENSURE(pSwCursor
, "no SwCursor");
113 SwPosition aStartPos
= *pSwCursor
->GetPoint(), aEndPos
= aStartPos
;
115 /* Search least and greatest position in current cursor ring.
117 for(SwPaM
& rTmpCursor
: pSwCursor
->GetRingContainer())
119 SwCursor
* pTmpCursor
= static_cast<SwCursor
*>(&rTmpCursor
);
120 const SwPosition
* pPt
= pTmpCursor
->GetPoint(),
121 * pMk
= pTmpCursor
->GetMark();
123 if (*pPt
< aStartPos
)
129 if (*pMk
< aStartPos
)
139 /* @@@ semantic: SwCursor::operator=() is not implemented @@@ */
141 /* Set cursor to end of selection to ensure IsLastCellInRow works
144 SwCursor
aTmpCursor( aEndPos
, nullptr );
145 *pSwCursor
= aTmpCursor
;
148 /* Move the cursor out of the columns to delete and stay in the
149 same row. If the table has only one column the cursor will
150 stay in the row and the shell will take care of it. */
151 if (IsLastCellInRow())
153 /* If the cursor is in the last row of the table, first
154 try to move it to the previous cell. If that fails move
155 it to the next cell. */
158 SwCursor
aTmpCursor( aStartPos
, nullptr );
159 *pSwCursor
= aTmpCursor
;
162 if (! pSwCursor
->GoPrevCell())
164 SwCursor
aTmpCursor( aEndPos
, nullptr );
165 *pSwCursor
= aTmpCursor
;
166 pSwCursor
->GoNextCell();
171 /* If the cursor is not in the last row of the table, first
172 try to move it to the next cell. If that fails move it
173 to the previous cell. */
176 SwCursor
aTmpCursor( aEndPos
, nullptr );
177 *pSwCursor
= aTmpCursor
;
180 if (! pSwCursor
->GoNextCell())
182 SwCursor
aTmpCursor( aStartPos
, nullptr );
183 *pSwCursor
= aTmpCursor
;
184 pSwCursor
->GoPrevCell();
189 void SwFEShell::InsertRow( sal_uInt16 nCnt
, bool bBehind
)
191 // check if Point/Mark of current cursor are in a table
192 SwFrame
*pFrame
= GetCurrFrame();
193 if( !pFrame
|| !pFrame
->IsInTab() )
196 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
198 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
199 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
203 // pending drag & drop?
204 bool bAction
= ActionPend();
206 CurrShell
aCurr( this );
209 // search boxes via the layout
211 bool bSelectAll
= StartsWith_() == StartsWith::Table
&& ExtendedSelectedAll();
214 // Set the end of the selection to the last paragraph of the last cell of the table.
215 SwPaM
* pPaM
= getShellCursor(false);
216 SwNode
* pNode
= pPaM
->Start()->GetNode().FindTableNode()->EndOfSectionNode();
217 // pNode is the end node of the table, we want the last node before the end node of the last cell.
218 pPaM
->End()->Assign( pNode
->GetIndex() - 2 );
220 GetTableSel( *this, aBoxes
, SwTableSearchType::Row
);
222 TableWait
aWait( nCnt
, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
224 if ( !aBoxes
.empty() )
225 GetDoc()->InsertRow( aBoxes
, nCnt
, bBehind
, /*bInsertDummy=*/!bAction
);
227 EndAllActionAndCall();
230 void SwFEShell::InsertCol( sal_uInt16 nCnt
, bool bBehind
)
232 // check if Point/Mark of current cursor are in a table
233 SwFrame
*pFrame
= GetCurrFrame();
234 if( !pFrame
|| !pFrame
->IsInTab() )
237 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
239 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
240 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
244 CurrShell
aCurr( this );
246 if( !CheckSplitCells( *this, nCnt
+ 1, SwTableSearchType::Col
) )
248 ErrorHandler::HandleError( ERR_TBLINSCOL_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
249 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
253 // pending drag & drop?
254 bool bAction
= ActionPend();
257 // search boxes via the layout
259 GetTableSel( *this, aBoxes
, SwTableSearchType::Col
);
261 TableWait
aWait( nCnt
, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
263 if( !aBoxes
.empty() )
264 GetDoc()->InsertCol( aBoxes
, nCnt
, bBehind
, /*bInsertDummy=*/!bAction
);
266 EndAllActionAndCall();
269 // Determines if the current cursor is in the last row of the table.
270 bool SwFEShell::IsLastCellInRow() const
273 GetTabCols( aTabCols
);
274 bool bResult
= false;
276 if (IsTableRightToLeft())
277 /* If the table is right-to-left the last row is the most left one. */
278 bResult
= 0 == GetCurTabColNum();
280 /* If the table is left-to-right the last row is the most right one. */
281 bResult
= aTabCols
.Count() == GetCurTabColNum();
286 bool SwFEShell::DeleteCol()
288 // check if Point/Mark of current cursor are in a table
289 SwFrame
*pFrame
= GetCurrFrame();
290 if( !pFrame
|| !pFrame
->IsInTab() )
293 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
295 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
296 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
300 CurrShell
aCurr( this );
302 bool bRecordChanges
= GetDoc()->GetDocShell()->IsChangeRecording();
303 bool bRecordAndHideChanges
= bRecordChanges
&&
304 GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines();
306 // tracked deletion: remove only textbox content,
307 // and set IsNoTracked table box property to false
308 if ( bRecordChanges
)
310 StartUndo(SwUndoId::COL_DELETE
);
313 if ( SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this) )
314 pWrtShell
->SelectTableCol();
316 // search boxes via the layout
318 GetTableSel( *this, aBoxes
, SwTableSearchType::Col
);
320 TableWait
aWait( 20, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
322 SwTableNode
* pTableNd
= pFrame
->IsTextFrame()
323 ? static_cast<SwTextFrame
*>(pFrame
)->GetTextNodeFirst()->FindTableNode()
324 : static_cast<SwNoTextFrame
*>(pFrame
)->GetNode()->FindTableNode();
326 for (size_t i
= 0; i
< aBoxes
.size(); ++i
)
328 SwTableBox
*pBox
= aBoxes
[i
];
329 if ( pBox
->GetSttNd() )
331 SwNodeIndex
aIdx( *pBox
->GetSttNd(), 1 );
332 SwCursor
aCursor( SwPosition(aIdx
), nullptr );
333 SvxPrintItem
aHasTextChangesOnly(RES_PRINT
, false);
334 GetDoc()->SetBoxAttr( aCursor
, aHasTextChangesOnly
);
336 // add dummy text content to the empty box for change tracking
337 if ( pBox
->IsEmpty() )
339 IDocumentContentOperations
& rIDCO
= GetDoc()->getIDocumentContentOperations();
340 IDocumentRedlineAccess
& rIDRA
= GetDoc()->getIDocumentRedlineAccess();
341 RedlineFlags eOld
= rIDRA
.GetRedlineFlags();
342 rIDRA
.SetRedlineFlags_intern(RedlineFlags::NONE
);
343 rIDCO
.InsertString( aCursor
, OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR
) );
345 aCursor
.GetMark()->SetContent(0);
346 rIDRA
.SetRedlineFlags_intern( eOld
);
347 rIDCO
.DeleteAndJoin( aCursor
);
353 SwEditShell
* pEditShell
= GetDoc()->GetEditShell();
354 pEditShell
->Delete();
356 // remove cell frames in Hide Changes mode (and table frames, if needed)
357 if ( bRecordAndHideChanges
)
359 // remove all frames of the table, and make them again without the deleted ones
360 // TODO remove only the deleted frames
361 pTableNd
->DelFrames();
363 if ( !pTableNd
->GetTable().IsDeleted() )
365 pTableNd
->MakeOwnFrames();
369 EndAllActionAndCall();
370 EndUndo(SwUndoId::COL_DELETE
);
376 // search boxes via the layout
379 SwTableSearchType eSearchType
= SwTableSearchType::Col
;
381 // NewModel tables already ExpandColumnSelection, so don't do it here also.
382 const SwContentNode
* pContentNd
= getShellCursor(false)->GetPointNode().GetContentNode();
383 const SwTableNode
* pTableNd
= pContentNd
? pContentNd
->FindTableNode() : nullptr;
384 if (pTableNd
&& pTableNd
->GetTable().IsNewModel())
385 eSearchType
= SwTableSearchType::NONE
;
387 GetTableSel(*this, aBoxes
, eSearchType
);
388 if ( !aBoxes
.empty() )
390 TableWait
aWait( aBoxes
.size(), pFrame
, *GetDoc()->GetDocShell() );
392 // remove crsr from the deletion area.
393 // Put them behind/on the table; via the
394 // document position they will be put to the old position
395 while( !pFrame
->IsCellFrame() )
396 pFrame
= pFrame
->GetUpper();
400 // then delete the column
401 StartUndo(SwUndoId::COL_DELETE
);
402 bRet
= GetDoc()->DeleteRowCol(aBoxes
, SwDoc::RowColMode::DeleteColumn
);
403 EndUndo(SwUndoId::COL_DELETE
);
408 EndAllActionAndCall();
412 void SwFEShell::DeleteTable()
417 bool SwFEShell::DeleteRow(bool bCompleteTable
)
419 // check if Point/Mark of current cursor are in a table
420 SwFrame
*pFrame
= GetCurrFrame();
421 if( !pFrame
|| !pFrame
->IsInTab() )
424 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
426 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
427 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
431 CurrShell
aCurr( this );
433 bool bRecordChanges
= GetDoc()->GetDocShell()->IsChangeRecording();
434 bool bRecordAndHideChanges
= bRecordChanges
&&
435 GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines();
437 // tracked deletion: all rows have already had tracked row change in the table selection
438 if ( bRecordChanges
&& !SwDoc::HasRowNotTracked( *getShellCursor( false ) ) )
441 if ( bRecordChanges
)
442 StartUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
446 // tracked deletion: remove only textbox content,
447 // and set HasTextChangesOnly table line property to false
448 SwEditShell
* pEditShell
= nullptr;
449 if ( bRecordChanges
)
451 pEditShell
= GetDoc()->GetEditShell();
452 SvxPrintItem
aHasTextChangesOnly(RES_PRINT
, false);
453 GetDoc()->SetRowNotTracked( *getShellCursor( false ), aHasTextChangesOnly
);
455 if ( SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this) )
456 pWrtShell
->SelectTableRow();
458 // don't need to remove the row frames in Show Changes mode
459 if ( !bRecordAndHideChanges
)
462 pEditShell
->Delete(false);
464 EndAllActionAndCall();
465 EndUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
471 // search for boxes via the layout
474 GetTableSel( *this, aBoxes
, SwTableSearchType::Row
);
476 if( !aBoxes
.empty() )
478 TableWait
aWait( aBoxes
.size(), pFrame
, *GetDoc()->GetDocShell() );
480 // Delete cursors from the deletion area.
481 // Then the cursor is:
482 // 1. the following row, if there is another row after this
483 // 2. the preceding row, if there is another row before this
484 // 3. otherwise below the table
486 SwTableNode
* pTableNd
= pFrame
->IsTextFrame()
487 ? static_cast<SwTextFrame
*>(pFrame
)->GetTextNodeFirst()->FindTableNode()
488 : static_cast<SwNoTextFrame
*>(pFrame
)->GetNode()->FindTableNode();
490 // search all boxes / lines
491 FndBox_
aFndBox( nullptr, nullptr );
493 FndPara
aPara( aBoxes
, &aFndBox
);
494 ForEach_FndLineCopyCol( pTableNd
->GetTable().GetTabLines(), &aPara
);
497 if( aFndBox
.GetLines().empty() )
499 EndAllActionAndCall();
505 FndBox_
* pFndBox
= &aFndBox
;
506 while( 1 == pFndBox
->GetLines().size() &&
507 1 == pFndBox
->GetLines().front()->GetBoxes().size())
509 FndBox_
*const pTmp
= pFndBox
->GetLines().front()->GetBoxes()[0].get();
510 if( pTmp
->GetBox()->GetSttNd() )
511 break; // otherwise too far
515 SwTableLine
* pDelLine
= pFndBox
->GetLines().back()->GetLine();
516 SwTableBox
* pDelBox
= pDelLine
->GetTabBoxes().back();
517 while( !pDelBox
->GetSttNd() )
519 SwTableLine
* pLn
= pDelBox
->GetTabLines().back();
520 pDelBox
= pLn
->GetTabBoxes().back();
522 SwTableBox
* pNextBox
= pDelLine
->FindNextBox( pTableNd
->GetTable(),
524 // skip deleted lines in Hide Changes mode with enabled change tracking
525 if ( bRecordAndHideChanges
)
527 SwRedlineTable::size_type nRedlinePos
= 0;
528 while( pNextBox
&& pNextBox
->GetUpper()->IsDeleted(nRedlinePos
) )
529 pNextBox
= pNextBox
->GetUpper()->FindNextBox( pTableNd
->GetTable(),
530 pNextBox
->GetUpper()->GetTabBoxes().back() );
533 // skip protected cells
535 pNextBox
->GetFrameFormat()->GetProtect().IsContentProtected() )
536 pNextBox
= pNextBox
->FindNextBox( pTableNd
->GetTable(), pNextBox
);
538 if( !pNextBox
) // no next? then the previous
540 pDelLine
= pFndBox
->GetLines().front()->GetLine();
541 pDelBox
= pDelLine
->GetTabBoxes()[ 0 ];
542 while( !pDelBox
->GetSttNd() )
543 pDelBox
= pDelBox
->GetTabLines()[0]->GetTabBoxes()[0];
544 pNextBox
= pDelLine
->FindPreviousBox( pTableNd
->GetTable(),
546 // skip previous deleted lines in Hide Changes mode with enabled change tracking
547 if ( bRecordAndHideChanges
)
549 SwRedlineTable::size_type nRedlinePos
= 0;
550 while( pNextBox
&& pNextBox
->GetUpper()->IsDeleted(nRedlinePos
) )
552 pNextBox
= pNextBox
->GetUpper()->FindPreviousBox( pTableNd
->GetTable(),
553 pNextBox
->GetUpper()->GetTabBoxes()[0] );
558 // skip previous protected cells
560 pNextBox
->GetFrameFormat()->GetProtect().IsContentProtected() )
561 pNextBox
= pNextBox
->FindPreviousBox( pTableNd
->GetTable(), pNextBox
);
564 // delete row content in Hide Changes mode
565 if ( pEditShell
&& bRecordAndHideChanges
)
567 // select the row deleted with change tracking cell by cell to handle
568 // the already deleted cells
569 SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this);
570 for (SwSelBoxes::size_type nBox
= 0; pWrtShell
&& nBox
< aBoxes
.size(); ++nBox
)
572 pWrtShell
->SelectTableRow();
573 SwCursor
* pTableCursor
= static_cast<SwCursor
*>(GetTableCursor());
574 auto pStart
= aBoxes
[nBox
];
576 pTableCursor
= GetCursor(true);
580 // set start and end of the selection
581 pTableCursor
->DeleteMark();
582 pTableCursor
->GetPoint()->Assign( *pStart
->GetSttNd()->EndOfSectionNode() );
583 pTableCursor
->Move( fnMoveBackward
, GoInContent
);
584 pWrtShell
->UpdateCursor();
587 pEditShell
->Delete(false);
592 if( pNextBox
) // put cursor here
593 nIdx
= pNextBox
->GetSttIdx() + 1;
594 else // otherwise below the table
595 nIdx
= pTableNd
->EndOfSectionIndex() + 1;
597 SwNodeIndex
aIdx( GetDoc()->GetNodes(), nIdx
);
598 SwContentNode
* pCNd
= aIdx
.GetNode().GetContentNode();
600 pCNd
= SwNodes::GoNext(&aIdx
);
602 // remove row frames in Hide Changes mode (and table frames, if needed)
603 if ( bRecordAndHideChanges
)
605 // remove all frames of the table, and make them again without the deleted ones
606 // TODO remove only the deleted frames
607 pTableNd
->DelFrames();
608 if ( !pTableNd
->GetTable().IsDeleted() )
610 pTableNd
->MakeOwnFrames();
613 EndAllActionAndCall();
616 SwPaM
* pPam
= GetCursor();
617 pPam
->GetPoint()->Assign( *pCNd
, 0 );
618 pPam
->SetMark(); // both want something
620 if ( SwWrtShell
* pWrtShell
= dynamic_cast<SwWrtShell
*>(this) )
622 pWrtShell
->UpdateCursor();
623 // tdf#150578 enable the disabled table toolbar by (zero) cursor moving
624 pWrtShell
->Right( SwCursorSkipMode::Chars
, false, 0, false );
627 EndUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
633 SwPaM
* pPam
= GetCursor();
634 pPam
->GetPoint()->Assign( *pCNd
, 0 );
635 pPam
->SetMark(); // both want something
640 // now delete the lines
641 StartUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
642 bRet
= GetDoc()->DeleteRowCol( aBoxes
);
643 EndUndo(bCompleteTable
? SwUndoId::UI_TABLE_DELETE
: SwUndoId::ROW_DELETE
);
648 EndAllActionAndCall();
652 TableMergeErr
SwFEShell::MergeTab()
654 // check if Point/Mark of current cursor are in a table
655 TableMergeErr nRet
= TableMergeErr::NoSelection
;
658 SwShellTableCursor
* pTableCursor
= GetTableCursor();
659 const SwTableNode
* pTableNd
= pTableCursor
->GetPointNode().FindTableNode();
660 if( dynamic_cast< const SwDDETable
* >(&pTableNd
->GetTable()) != nullptr )
662 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
663 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
667 CurrShell
aCurr( this );
670 TableWait
aWait(pTableCursor
->GetSelectedBoxesCount(), nullptr,
671 *GetDoc()->GetDocShell(),
672 pTableNd
->GetTable().GetTabLines().size() );
674 nRet
= GetDoc()->MergeTable( *pTableCursor
);
678 EndAllActionAndCall();
684 void SwFEShell::SplitTab( bool bVert
, sal_uInt16 nCnt
, bool bSameHeight
)
686 // check if Point/Mark of current cursor are in a table
687 SwFrame
*pFrame
= GetCurrFrame();
688 if( !pFrame
|| !pFrame
->IsInTab() )
691 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
693 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
694 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
698 CurrShell
aCurr( this );
700 if( bVert
&& !CheckSplitCells( *this, nCnt
+ 1, SwTableSearchType::NONE
) )
702 ErrorHandler::HandleError( ERR_TBLSPLIT_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
703 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
707 // search boxes via the layout
709 GetTableSel( *this, aBoxes
);
710 if( !aBoxes
.empty() )
712 TableWait
aWait( nCnt
, pFrame
, *GetDoc()->GetDocShell(), aBoxes
.size() );
714 // now delete the columns
715 GetDoc()->SplitTable( aBoxes
, bVert
, nCnt
, bSameHeight
);
717 ClearFEShellTabCols(*GetDoc(), nullptr);
719 EndAllActionAndCall();
722 void SwFEShell::GetTabCols_(SwTabCols
&rToFill
, const SwFrame
*pBox
) const
724 const SwTabFrame
*pTab
= pBox
->FindTabFrame();
728 if (m_pColumnCache
->pLastTable
== pTab
->GetTable())
731 SwRectFnSet
aRectFnSet(pTab
);
733 const SwPageFrame
* pPage
= pTab
->FindPageFrame();
734 const sal_uLong nLeftMin
= aRectFnSet
.GetLeft(pTab
->getFrameArea()) -
735 aRectFnSet
.GetLeft(pPage
->getFrameArea());
736 const sal_uLong nRightMax
= aRectFnSet
.GetRight(pTab
->getFrameArea()) -
737 aRectFnSet
.GetLeft(pPage
->getFrameArea());
739 if (m_pColumnCache
->pLastTabFrame
!= pTab
)
741 // if TabFrame was changed, we only shift a little bit
742 // as the width is the same
743 SwRectFnSet
fnRectX(m_pColumnCache
->pLastTabFrame
);
744 if (fnRectX
.GetWidth(m_pColumnCache
->pLastTabFrame
->getFrameArea()) ==
745 aRectFnSet
.GetWidth(pTab
->getFrameArea()) )
747 m_pColumnCache
->pLastCols
->SetLeftMin( nLeftMin
);
749 m_pColumnCache
->pLastTabFrame
= pTab
;
756 m_pColumnCache
->pLastCols
->GetLeftMin () == o3tl::narrowing
<sal_uInt16
>(nLeftMin
) &&
757 m_pColumnCache
->pLastCols
->GetLeft () == o3tl::narrowing
<sal_uInt16
>(aRectFnSet
.GetLeft(pTab
->getFramePrintArea())) &&
758 m_pColumnCache
->pLastCols
->GetRight () == o3tl::narrowing
<sal_uInt16
>(aRectFnSet
.GetRight(pTab
->getFramePrintArea()))&&
759 m_pColumnCache
->pLastCols
->GetRightMax() == o3tl::narrowing
<sal_uInt16
>(nRightMax
) - m_pColumnCache
->pLastCols
->GetLeftMin() )
761 if (m_pColumnCache
->pLastCellFrame
!= pBox
)
763 pTab
->GetTable()->GetTabCols( *m_pColumnCache
->pLastCols
,
764 static_cast<const SwCellFrame
*>(pBox
)->GetTabBox(), true);
765 m_pColumnCache
->pLastCellFrame
= pBox
;
767 rToFill
= *m_pColumnCache
->pLastCols
;
773 m_pColumnCache
.reset();
777 SwDoc::GetTabCols( rToFill
, static_cast<const SwCellFrame
*>(pBox
) );
779 m_pColumnCache
.reset(new SwColCache
);
780 m_pColumnCache
->pLastCols
.reset(new SwTabCols(rToFill
));
781 m_pColumnCache
->pLastTable
= pTab
->GetTable();
782 m_pColumnCache
->pLastTabFrame
= pTab
;
783 m_pColumnCache
->pLastCellFrame
= pBox
;
787 void SwFEShell::GetTabRows_(SwTabCols
&rToFill
, const SwFrame
*pBox
) const
789 const SwTabFrame
*pTab
= pBox
->FindTabFrame();
793 if (m_pRowCache
->pLastTable
== pTab
->GetTable())
796 SwRectFnSet
aRectFnSet(pTab
);
797 const SwPageFrame
* pPage
= pTab
->FindPageFrame();
798 const tools::Long nLeftMin
= ( aRectFnSet
.IsVert() ?
799 pTab
->GetPrtLeft() - pPage
->getFrameArea().Left() :
800 pTab
->GetPrtTop() - pPage
->getFrameArea().Top() );
801 const tools::Long nLeft
= aRectFnSet
.IsVert() ? LONG_MAX
: 0;
802 const tools::Long nRight
= aRectFnSet
.GetHeight(pTab
->getFramePrintArea());
803 const tools::Long nRightMax
= aRectFnSet
.IsVert() ? nRight
: LONG_MAX
;
805 if (m_pRowCache
->pLastTabFrame
!= pTab
|| m_pRowCache
->pLastCellFrame
!= pBox
)
809 m_pRowCache
->pLastCols
->GetLeftMin () == nLeftMin
&&
810 m_pRowCache
->pLastCols
->GetLeft () == nLeft
&&
811 m_pRowCache
->pLastCols
->GetRight () == nRight
&&
812 m_pRowCache
->pLastCols
->GetRightMax() == nRightMax
)
814 rToFill
= *m_pRowCache
->pLastCols
;
824 SwDoc::GetTabRows( rToFill
, static_cast<const SwCellFrame
*>(pBox
) );
826 m_pRowCache
.reset(new SwColCache
);
827 m_pRowCache
->pLastCols
.reset(new SwTabCols(rToFill
));
828 m_pRowCache
->pLastTable
= pTab
->GetTable();
829 m_pRowCache
->pLastTabFrame
= pTab
;
830 m_pRowCache
->pLastCellFrame
= pBox
;
834 void SwFEShell::SetTabCols( const SwTabCols
&rNew
, bool bCurRowOnly
)
836 SwFrame
*pBox
= GetCurrFrame();
837 if( !pBox
|| !pBox
->IsInTab() )
840 CurrShell
aCurr( this );
845 pBox
= pBox
->GetUpper();
846 } while (pBox
&& !pBox
->IsCellFrame());
848 GetDoc()->SetTabCols( rNew
, bCurRowOnly
, static_cast<SwCellFrame
*>(pBox
) );
849 EndAllActionAndCall();
852 void SwFEShell::GetTabCols( SwTabCols
&rToFill
) const
854 const SwFrame
*pFrame
= GetCurrFrame();
855 if( !pFrame
|| !pFrame
->IsInTab() )
859 pFrame
= pFrame
->GetUpper();
861 while (pFrame
&& !pFrame
->IsCellFrame());
866 GetTabCols_( rToFill
, pFrame
);
869 void SwFEShell::GetTabRows( SwTabCols
&rToFill
) const
871 const SwFrame
*pFrame
= GetCurrFrame();
872 if( !pFrame
|| !pFrame
->IsInTab() )
876 pFrame
= pFrame
->GetUpper();
877 } while (pFrame
&& !pFrame
->IsCellFrame());
882 GetTabRows_( rToFill
, pFrame
);
885 void SwFEShell::SetTabRows( const SwTabCols
&rNew
, bool bCurColOnly
)
887 SwFrame
*pBox
= GetCurrFrame();
888 if( !pBox
|| !pBox
->IsInTab() )
891 CurrShell
aCurr( this );
896 pBox
= pBox
->GetUpper();
897 } while (pBox
&& !pBox
->IsCellFrame());
899 GetDoc()->SetTabRows( rNew
, bCurColOnly
, static_cast<SwCellFrame
*>(pBox
) );
900 EndAllActionAndCall();
903 void SwFEShell::GetMouseTabRows( SwTabCols
&rToFill
, const Point
&rPt
) const
905 const SwFrame
*pBox
= GetBox( rPt
);
907 GetTabRows_( rToFill
, pBox
);
910 void SwFEShell::SetMouseTabRows( const SwTabCols
&rNew
, bool bCurColOnly
, const Point
&rPt
)
912 const SwFrame
*pBox
= GetBox( rPt
);
915 CurrShell
aCurr( this );
917 GetDoc()->SetTabRows( rNew
, bCurColOnly
, static_cast<const SwCellFrame
*>(pBox
) );
918 EndAllActionAndCall();
922 void SwFEShell::SetRowSplit( const SwFormatRowSplit
& rNew
)
924 CurrShell
aCurr( this );
926 GetDoc()->SetRowSplit( *getShellCursor( false ), rNew
);
927 EndAllActionAndCall();
930 std::unique_ptr
<SwFormatRowSplit
> SwFEShell::GetRowSplit() const
932 return SwDoc::GetRowSplit( *getShellCursor( false ) );
935 void SwFEShell::SetRowHeight( const SwFormatFrameSize
&rNew
)
937 CurrShell
aCurr( this );
939 GetDoc()->SetRowHeight( *getShellCursor( false ), rNew
);
940 EndAllActionAndCall();
943 std::unique_ptr
<SwFormatFrameSize
> SwFEShell::GetRowHeight() const
945 return SwDoc::GetRowHeight( *getShellCursor( false ) );
948 bool SwFEShell::BalanceRowHeight( bool bTstOnly
, const bool bOptimize
)
950 CurrShell
aCurr( this );
953 bool bRet
= GetDoc()->BalanceRowHeight( *getShellCursor( false ), bTstOnly
, bOptimize
);
955 EndAllActionAndCall();
959 void SwFEShell::SetRowBackground( const SvxBrushItem
&rNew
)
961 CurrShell
aCurr( this );
963 GetDoc()->SetRowBackground( *getShellCursor( false ), rNew
);
964 EndAllActionAndCall();
967 bool SwFEShell::GetRowBackground( std::unique_ptr
<SvxBrushItem
>& rToFill
) const
969 return SwDoc::GetRowBackground( *getShellCursor( false ), rToFill
);
972 void SwFEShell::SetTabBorders( const SfxItemSet
& rSet
)
974 CurrShell
aCurr( this );
976 GetDoc()->SetTabBorders( *getShellCursor( false ), rSet
);
977 EndAllActionAndCall();
980 void SwFEShell::SetTabLineStyle( const Color
* pColor
, bool bSetLine
,
981 const editeng::SvxBorderLine
* pBorderLine
)
983 CurrShell
aCurr( this );
985 GetDoc()->SetTabLineStyle( *getShellCursor( false ),
986 pColor
, bSetLine
, pBorderLine
);
987 EndAllActionAndCall();
990 void SwFEShell::GetTabBorders( SfxItemSet
& rSet
) const
992 SwDoc::GetTabBorders( *getShellCursor( false ), rSet
);
995 void SwFEShell::SetBoxBackground( const SvxBrushItem
&rNew
)
997 CurrShell
aCurr( this );
999 GetDoc()->SetBoxAttr( *getShellCursor( false ), rNew
);
1000 EndAllActionAndCall();
1003 bool SwFEShell::GetBoxBackground( std::unique_ptr
<SvxBrushItem
>& rToFill
) const
1005 std::unique_ptr
<SfxPoolItem
> aTemp
= std::move(rToFill
);
1006 bool bRetval(SwDoc::GetBoxAttr(*getShellCursor( false ), aTemp
));
1007 rToFill
.reset(static_cast<SvxBrushItem
*>(aTemp
.release()));
1011 void SwFEShell::SetBoxDirection( const SvxFrameDirectionItem
& rNew
)
1013 CurrShell
aCurr( this );
1015 GetDoc()->SetBoxAttr( *getShellCursor( false ), rNew
);
1016 EndAllActionAndCall();
1019 bool SwFEShell::GetBoxDirection( std::unique_ptr
<SvxFrameDirectionItem
>& rToFill
) const
1021 std::unique_ptr
<SfxPoolItem
> aTemp
= std::move(rToFill
);
1022 bool bRetval(SwDoc::GetBoxAttr(*getShellCursor( false ), aTemp
));
1023 rToFill
.reset(static_cast<SvxFrameDirectionItem
*>(aTemp
.release()));
1027 void SwFEShell::SetBoxAlign( sal_uInt16 nAlign
)
1029 CurrShell
aCurr( this );
1031 GetDoc()->SetBoxAlign( *getShellCursor( false ), nAlign
);
1032 EndAllActionAndCall();
1035 sal_uInt16
SwFEShell::GetBoxAlign() const
1037 return SwDoc::GetBoxAlign( *getShellCursor( false ) );
1040 void SwFEShell::SetTabBackground( const SvxBrushItem
&rNew
)
1042 SwFrame
*pFrame
= GetCurrFrame();
1043 if( !pFrame
|| !pFrame
->IsInTab() )
1046 CurrShell
aCurr( this );
1048 GetDoc()->SetAttr( rNew
, *pFrame
->ImplFindTabFrame()->GetFormat() );
1049 EndAllAction(); // no call, nothing changes!
1050 GetDoc()->getIDocumentState().SetModified();
1053 void SwFEShell::GetTabBackground( std::unique_ptr
<SvxBrushItem
>& rToFill
) const
1055 SwFrame
*pFrame
= GetCurrFrame();
1056 if( pFrame
&& pFrame
->IsInTab() )
1057 rToFill
= pFrame
->ImplFindTabFrame()->GetFormat()->makeBackgroundBrushItem();
1060 bool SwFEShell::HasWholeTabSelection() const
1062 // whole table selected?
1063 if ( IsTableMode() )
1066 ::GetTableSelCrs( *this, aBoxes
);
1067 if( !aBoxes
.empty() )
1069 const SwTableNode
*pTableNd
= IsCursorInTable();
1071 aBoxes
[0]->GetSttIdx() - 1 == pTableNd
->EndOfSectionNode()->StartOfSectionIndex() &&
1072 aBoxes
.back()->GetSttNd()->EndOfSectionIndex() + 1 == pTableNd
->EndOfSectionIndex();
1078 bool SwFEShell::HasBoxSelection() const
1080 if(!IsCursorInTable())
1082 // whole table selected?
1085 SwPaM
* pPam
= GetCursor();
1086 // empty boxes are also selected as the absence of selection
1088 if( pPam
->GetPoint() == pPam
->End())
1094 if( pPam
->GetPoint()->GetNodeIndex() -1 ==
1095 ( pNd
= &pPam
->GetPointNode())->StartOfSectionIndex() &&
1096 !pPam
->GetPoint()->GetContentIndex() &&
1097 pPam
->GetMark()->GetNodeIndex() + 1 ==
1098 pNd
->EndOfSectionIndex())
1100 SwNodeIndex
aIdx( *pNd
->EndOfSectionNode(), -1 );
1101 SwContentNode
* pCNd
= aIdx
.GetNode().GetContentNode();
1104 pCNd
= SwNodes::GoPrevious( &aIdx
);
1105 assert(pCNd
&& "no ContentNode in box ??");
1107 if( pPam
->GetMark()->GetContentIndex() == pCNd
->Len() )
1119 void SwFEShell::ProtectCells()
1121 SvxProtectItem
aProt( RES_PROTECT
);
1122 aProt
.SetContentProtect( true );
1124 CurrShell
aCurr( this );
1127 GetDoc()->SetBoxAttr( *getShellCursor( false ), aProt
);
1129 if( !IsCursorReadonly() )
1135 EndAllActionAndCall();
1138 // cancel table selection
1139 void SwFEShell::UnProtectCells()
1141 CurrShell
aCurr( this );
1146 ::GetTableSelCrs( *this, aBoxes
);
1149 SwFrame
*pFrame
= GetCurrFrame();
1151 pFrame
= pFrame
->GetUpper();
1152 } while ( pFrame
&& !pFrame
->IsCellFrame() );
1155 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
1156 aBoxes
.insert( pBox
);
1160 if( !aBoxes
.empty() )
1161 GetDoc()->UnProtectCells( aBoxes
);
1163 EndAllActionAndCall();
1166 void SwFEShell::UnProtectTables()
1168 CurrShell
aCurr( this );
1170 GetDoc()->UnProtectTables( *GetCursor() );
1171 EndAllActionAndCall();
1174 bool SwFEShell::HasTableAnyProtection( const OUString
* pTableName
,
1175 bool* pFullTableProtection
)
1177 return GetDoc()->HasTableAnyProtection( GetCursor()->GetPoint(), pTableName
,
1178 pFullTableProtection
);
1181 bool SwFEShell::CanUnProtectCells() const
1183 bool bUnProtectAvailable
= false;
1184 const SwTableNode
*pTableNd
= IsCursorInTable();
1185 if( pTableNd
&& !pTableNd
->IsProtect() )
1189 ::GetTableSelCrs( *this, aBoxes
);
1192 SwFrame
*pFrame
= GetCurrFrame();
1195 pFrame
= pFrame
->GetUpper();
1196 } while ( pFrame
&& !pFrame
->IsCellFrame() );
1199 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
1200 aBoxes
.insert( pBox
);
1203 if( !aBoxes
.empty() )
1204 bUnProtectAvailable
= ::HasProtectedCells( aBoxes
);
1206 return bUnProtectAvailable
;
1209 sal_uInt16
SwFEShell::GetRowsToRepeat() const
1211 const SwFrame
*pFrame
= GetCurrFrame();
1212 const SwTabFrame
*pTab
= pFrame
? pFrame
->FindTabFrame() : nullptr;
1214 return pTab
->GetTable()->GetRowsToRepeat();
1218 void SwFEShell::SetRowsToRepeat( sal_uInt16 nSet
)
1220 SwFrame
*pFrame
= GetCurrFrame();
1221 SwTabFrame
*pTab
= pFrame
? pFrame
->FindTabFrame() : nullptr;
1222 if( pTab
&& pTab
->GetTable()->GetRowsToRepeat() != nSet
)
1224 SwWait
aWait( *GetDoc()->GetDocShell(), true );
1225 CurrShell
aCurr( this );
1227 GetDoc()->SetRowsToRepeat( *pTab
->GetTable(), nSet
);
1228 EndAllActionAndCall();
1232 // returns the number of rows consecutively selected from top
1233 static sal_uInt16
lcl_GetRowNumber( const SwPosition
& rPos
)
1236 const SwContentNode
*pNd
;
1237 const SwContentFrame
*pFrame
;
1239 std::pair
<Point
, bool> const tmp(aTmpPt
, false);
1240 pNd
= rPos
.GetNode().GetContentNode();
1241 if( nullptr != pNd
)
1242 pFrame
= pNd
->getLayoutFrame(pNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), &rPos
, &tmp
);
1246 const SwFrame
* pRow
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->GetUpper() : nullptr;
1248 while (pRow
&& (!pRow
->GetUpper() || !pRow
->GetUpper()->IsTabFrame()))
1249 pRow
= pRow
->GetUpper();
1254 const SwTabFrame
* pTabFrame
= static_cast<const SwTabFrame
*>(pRow
->GetUpper());
1255 const SwTableLine
* pTabLine
= static_cast<const SwRowFrame
*>(pRow
)->GetTabLine();
1256 sal_uInt16 nRet
= USHRT_MAX
;
1258 while ( sal::static_int_cast
<SwTableLines::size_type
>(nI
) < pTabFrame
->GetTable()->GetTabLines().size() )
1260 if ( pTabFrame
->GetTable()->GetTabLines()[ nI
] == pTabLine
)
1271 sal_uInt16
SwFEShell::GetRowSelectionFromTop() const
1273 sal_uInt16 nRet
= 0;
1274 const SwPaM
* pPaM
= IsTableMode() ? GetTableCursor() : GetCursor_();
1275 const sal_uInt16 nPtLine
= lcl_GetRowNumber( *pPaM
->GetPoint() );
1277 if ( !IsTableMode() )
1279 nRet
= 0 == nPtLine
? 1 : 0;
1283 const sal_uInt16 nMkLine
= lcl_GetRowNumber( *pPaM
->GetMark() );
1285 if ( ( nPtLine
== 0 && nMkLine
!= USHRT_MAX
) ||
1286 ( nMkLine
== 0 && nPtLine
!= USHRT_MAX
) )
1288 nRet
= std::max( nPtLine
, nMkLine
) + 1;
1296 * 1. case: bRepeat = true
1297 * returns true if the current frame is located inside a table headline in
1300 * 2. case: bRepeat = false
1301 * returns true if the current frame is located inside a table headline OR
1302 * inside the first line of a table!!!
1304 bool SwFEShell::CheckHeadline( bool bRepeat
) const
1307 if ( !IsTableMode() )
1309 SwFrame
*pFrame
= GetCurrFrame(); // DONE MULTIIHEADER
1310 SwTabFrame
* pTab
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->FindTabFrame() : nullptr;
1315 bRet
= pTab
->IsFollow() && pTab
->IsInHeadline( *pFrame
);
1319 if (SwFrame
* pLower
= pTab
->Lower())
1321 bRet
= static_cast<SwLayoutFrame
*>(pLower
)->IsAnLower( pFrame
) ||
1322 pTab
->IsInHeadline( *pFrame
);
1330 void SwFEShell::AdjustCellWidth( const bool bBalance
, const bool bNoShrink
)
1332 CurrShell
aCurr( this );
1335 // switch on wait-cursor, as we do not know how
1336 // much content is affected
1337 TableWait
aWait(std::numeric_limits
<size_t>::max(), nullptr,
1338 *GetDoc()->GetDocShell());
1340 GetDoc()->AdjustCellWidth( *getShellCursor( false ), bBalance
, bNoShrink
);
1341 EndAllActionAndCall();
1344 bool SwFEShell::IsAdjustCellWidthAllowed( bool bBalance
) const
1346 // at least one row with content should be contained in the selection
1348 SwFrame
*pFrame
= GetCurrFrame();
1349 if( !pFrame
|| !pFrame
->IsInTab() )
1353 ::GetTableSelCrs( *this, aBoxes
);
1356 return aBoxes
.size() > 1;
1358 if ( aBoxes
.empty() )
1362 pFrame
= pFrame
->GetUpper();
1364 while (pFrame
&& !pFrame
->IsCellFrame());
1369 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
1370 aBoxes
.insert( pBox
);
1373 for (size_t i
= 0; i
< aBoxes
.size(); ++i
)
1375 SwTableBox
*pBox
= aBoxes
[i
];
1376 if ( pBox
->GetSttNd() )
1378 SwNodeIndex
aIdx( *pBox
->GetSttNd(), 1 );
1379 SwTextNode
* pCNd
= aIdx
.GetNode().GetTextNode();
1381 pCNd
= static_cast<SwTextNode
*>(SwNodes::GoNext(&aIdx
));
1385 if (!pCNd
->GetText().isEmpty())
1388 pCNd
= aIdx
.GetNode().GetTextNode();
1395 void SwFEShell::SetTableStyle(const OUString
& rStyleName
)
1397 // make sure SwDoc has the style
1398 SwTableAutoFormat
*pTableFormat
= GetDoc()->GetTableStyles().FindAutoFormat(rStyleName
);
1402 SwTableNode
*pTableNode
= const_cast<SwTableNode
*>(IsCursorInTable());
1406 // set the name & update
1407 UpdateTableStyleFormatting(pTableNode
, false, &rStyleName
);
1410 bool SwFEShell::ResetTableStyle()
1412 SwTableNode
*pTableNode
= const_cast<SwTableNode
*>(IsCursorInTable());
1416 OUString takingAddressOfRValue
;
1417 return UpdateTableStyleFormatting(pTableNode
, false, &takingAddressOfRValue
);
1420 // AutoFormat for the table/table selection
1421 bool SwFEShell::SetTableStyle(const SwTableAutoFormat
& rStyle
)
1423 // make sure SwDoc has the style
1424 GetDoc()->GetTableStyles().AddAutoFormat(rStyle
);
1426 SwTableNode
*pTableNode
= const_cast<SwTableNode
*>(IsCursorInTable());
1430 // set the name & update
1431 return UpdateTableStyleFormatting(pTableNode
, false, &rStyle
.GetName());
1434 bool SwFEShell::UpdateTableStyleFormatting(SwTableNode
*pTableNode
,
1435 bool bResetDirect
, OUString
const*const pStyleName
)
1439 pTableNode
= const_cast<SwTableNode
*>(IsCursorInTable());
1440 if (!pTableNode
|| pTableNode
->GetTable().IsTableComplex())
1444 OUString
const aTableStyleName(pStyleName
1446 : pTableNode
->GetTable().GetTableStyleName());
1448 std::unique_ptr
<SwTableAutoFormat
> pNone
;
1449 SwTableAutoFormat
* pTableStyle
;
1450 if (pStyleName
&& pStyleName
->isEmpty())
1452 pNone
.reset(new SwTableAutoFormat(SwViewShell::GetShellRes()->aStrNone
));
1453 pNone
->DisableAll();
1454 pTableStyle
= pNone
.get();
1458 pTableStyle
= GetDoc()->GetTableStyles().FindAutoFormat(aTableStyleName
);
1465 // whole table or only current selection
1467 ::GetTableSelCrs( *this, aBoxes
);
1470 const SwTableSortBoxes
& rTBoxes
= pTableNode
->GetTable().GetTabSortBoxes();
1471 for (size_t n
= 0; n
< rTBoxes
.size(); ++n
)
1473 SwTableBox
* pBox
= rTBoxes
[ n
];
1474 aBoxes
.insert( pBox
);
1479 if( !aBoxes
.empty() )
1481 CurrShell
aCurr( this );
1483 bRet
= GetDoc()->SetTableAutoFormat(
1484 aBoxes
, *pTableStyle
, bResetDirect
, pStyleName
);
1485 ClearFEShellTabCols(*GetDoc(), nullptr);
1486 EndAllActionAndCall();
1493 bool SwFEShell::GetTableAutoFormat( SwTableAutoFormat
& rGet
)
1495 const SwTableNode
*pTableNd
= IsCursorInTable();
1496 if( !pTableNd
|| pTableNd
->GetTable().IsTableComplex() )
1501 if ( !IsTableMode() ) // if cursor are not current
1504 // whole table or only current selection
1506 ::GetTableSelCrs( *this, aBoxes
);
1509 const SwTableSortBoxes
& rTBoxes
= pTableNd
->GetTable().GetTabSortBoxes();
1510 for (size_t n
= 0; n
< rTBoxes
.size(); ++n
)
1512 SwTableBox
* pBox
= rTBoxes
[ n
];
1513 aBoxes
.insert( pBox
);
1517 return GetDoc()->GetTableAutoFormat( aBoxes
, rGet
);
1520 bool SwFEShell::DeleteTableSel()
1522 // check if SPoint/Mark of current cursor are in a table
1523 SwFrame
*pFrame
= GetCurrFrame();
1524 if( !pFrame
|| !pFrame
->IsInTab() )
1527 if( dynamic_cast< const SwDDETable
* >(pFrame
->ImplFindTabFrame()->GetTable()) != nullptr )
1529 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR
, GetFrameWeld(GetDoc()->GetDocShell()),
1530 DialogMask::MessageInfo
| DialogMask::ButtonsOk
);
1534 CurrShell
aCurr( this );
1537 // search boxes via the layout
1540 GetTableSelCrs( *this, aBoxes
);
1541 if( !aBoxes
.empty() )
1543 TableWait
aWait( aBoxes
.size(), pFrame
, *GetDoc()->GetDocShell() );
1545 // cursor should be removed from deletion area.
1546 // Put them behind/on the table; via the document
1547 // position they'll be set to the old position
1548 while( !pFrame
->IsCellFrame() )
1549 pFrame
= pFrame
->GetUpper();
1550 ParkCursor( *static_cast<SwCellFrame
*>(pFrame
)->GetTabBox()->GetSttNd() );
1552 bRet
= GetDoc()->DeleteRowCol( aBoxes
);
1554 ClearFEShellTabCols(*GetDoc(), nullptr);
1558 EndAllActionAndCall();
1562 size_t SwFEShell::GetCurTabColNum() const
1564 //!!!GetCurMouseTabColNum() mitpflegen!!!!
1565 SwFrame
*pFrame
= GetCurrFrame();
1566 OSL_ENSURE( pFrame
, "Cursor parked?" );
1568 // check if SPoint/Mark of current cursor are in a table
1569 if (!pFrame
|| !pFrame
->IsInTab())
1574 // JP 26.09.95: why compare with ContentFrame
1575 // and not with CellFrame ????
1576 pFrame
= pFrame
->GetUpper();
1577 } while (pFrame
&& !pFrame
->IsCellFrame());
1584 SwRectFnSet
aRectFnSet(pFrame
);
1586 const SwPageFrame
* pPage
= pFrame
->FindPageFrame();
1588 // get TabCols, as only via these we get to the position
1590 GetTabCols( aTabCols
);
1592 if( pFrame
->FindTabFrame()->IsRightToLeft() )
1594 tools::Long nX
= aRectFnSet
.GetRight(pFrame
->getFrameArea()) - aRectFnSet
.GetLeft(pPage
->getFrameArea());
1596 const tools::Long nRight
= aTabCols
.GetLeftMin() + aTabCols
.GetRight();
1598 if ( !::IsSame( *GetDoc(), nX
, nRight
) )
1600 nX
= nRight
- nX
+ aTabCols
.GetLeft();
1601 for ( size_t i
= 0; i
< aTabCols
.Count(); ++i
)
1602 if ( ::IsSame( *GetDoc(), nX
, aTabCols
[i
] ) )
1611 const tools::Long nX
= aRectFnSet
.GetLeft(pFrame
->getFrameArea()) -
1612 aRectFnSet
.GetLeft(pPage
->getFrameArea());
1614 const tools::Long nLeft
= aTabCols
.GetLeftMin();
1616 if ( !::IsSame( *GetDoc(), nX
, nLeft
+ aTabCols
.GetLeft() ) )
1618 for ( size_t i
= 0; i
< aTabCols
.Count(); ++i
)
1619 if ( ::IsSame( *GetDoc(), nX
, nLeft
+ aTabCols
[i
] ) )
1629 static const SwFrame
*lcl_FindFrameInTab( const SwLayoutFrame
*pLay
, const Point
&rPt
, SwTwips nFuzzy
)
1631 const SwFrame
*pFrame
= pLay
->Lower();
1633 while( pFrame
&& pLay
->IsAnLower( pFrame
) )
1635 if ( pFrame
->getFrameArea().IsNear( rPt
, nFuzzy
) )
1637 if ( pFrame
->IsLayoutFrame() )
1639 const SwFrame
*pTmp
= ::lcl_FindFrameInTab( static_cast<const SwLayoutFrame
*>(pFrame
), rPt
, nFuzzy
);
1647 pFrame
= pFrame
->FindNext();
1653 static const SwCellFrame
*lcl_FindFrame( SwDoc
& rDoc
, const SwLayoutFrame
*pLay
, const Point
&rPt
,
1654 SwTwips nFuzzy
, bool* pbRow
, bool* pbCol
)
1656 // bMouseMoveRowCols :
1657 // Method is called for
1658 // - Moving columns/rows with the mouse or
1659 // - Enhanced table selection
1660 const bool bMouseMoveRowCols
= nullptr == pbCol
;
1662 bool bCloseToRow
= false;
1663 bool bCloseToCol
= false;
1665 const SwFrame
*pFrame
= pLay
->ContainsContent();
1666 const SwFrame
* pRet
= nullptr;
1672 if ( pFrame
->IsInTab() )
1673 pFrame
= const_cast<SwFrame
*>(pFrame
)->ImplFindTabFrame();
1678 if ( pFrame
->IsTabFrame() )
1681 bool bSearchForFrameInTab
= true;
1682 SwTwips nTmpFuzzy
= nFuzzy
;
1684 if ( !bMouseMoveRowCols
)
1686 // We ignore nested tables for the enhanced table selection:
1687 while ( pFrame
->GetUpper()->IsInTab() )
1688 pFrame
= pFrame
->GetUpper()->FindTabFrame();
1690 // We first check if the given point is 'close' to the left or top
1691 // border of the table frame:
1692 OSL_ENSURE( pFrame
, "Nested table frame without outer table" );
1693 SwRectFnSet
aRectFnSet(pFrame
);
1694 const bool bRTL
= pFrame
->IsRightToLeft();
1696 SwRect aTabRect
= pFrame
->getFramePrintArea();
1697 aTabRect
.Pos() += pFrame
->getFrameArea().Pos();
1699 const SwTwips nLeft
= bRTL
?
1700 aRectFnSet
.GetRight(aTabRect
) :
1701 aRectFnSet
.GetLeft(aTabRect
);
1702 const SwTwips nTop
= aRectFnSet
.GetTop(aTabRect
);
1704 SwTwips
const rPointX
= aRectFnSet
.IsVert() ? aPt
.Y() : aPt
.X();
1705 SwTwips
const rPointY
= aRectFnSet
.IsVert() ? aPt
.X() : aPt
.Y();
1707 const SwTwips nXDiff
= aRectFnSet
.XDiff( nLeft
, rPointX
) * ( bRTL
? -1 : 1 );
1708 const SwTwips nYDiff
= aRectFnSet
.YDiff( nTop
, rPointY
);
1710 bCloseToRow
= nXDiff
>= 0 && nXDiff
< nFuzzy
;
1711 bCloseToCol
= nYDiff
>= 0 && nYDiff
< nFuzzy
;
1713 if ( bCloseToCol
&& 2 * nYDiff
> nFuzzy
)
1715 const SwFrame
* pPrev
= pFrame
->GetPrev();
1718 SwRect aPrevRect
= pPrev
->getFramePrintArea();
1719 aPrevRect
.Pos() += pPrev
->getFrameArea().Pos();
1721 if( aPrevRect
.Contains( rPt
) )
1723 bCloseToCol
= false;
1729 // If we found the point to be 'close' to the left or top border
1730 // of the table frame, we adjust the point to be on that border:
1731 if ( bCloseToRow
&& bCloseToCol
)
1732 aPt
= bRTL
? aTabRect
.TopRight() : aRectFnSet
.GetPos(aTabRect
);
1733 else if ( bCloseToRow
)
1734 aRectFnSet
.IsVert() ? aPt
.setY(nLeft
) : aPt
.setX(nLeft
);
1735 else if ( bCloseToCol
)
1736 aRectFnSet
.IsVert() ? aPt
.setX(nTop
) : aPt
.setY(nTop
);
1738 if ( !bCloseToRow
&& !bCloseToCol
)
1739 bSearchForFrameInTab
= false;
1741 // Since the point has been adjusted, we call lcl_FindFrameInTab()
1742 // with a fuzzy value of 1:
1746 const SwFrame
* pTmp
= bSearchForFrameInTab
?
1747 ::lcl_FindFrameInTab( static_cast<const SwLayoutFrame
*>(pFrame
), aPt
, nTmpFuzzy
) :
1756 pFrame
= pFrame
->FindNextCnt();
1758 } while ( pFrame
&& pLay
->IsAnLower( pFrame
) );
1761 if ( pFrame
&& pFrame
->IsInTab() && pLay
->IsAnLower( pFrame
) )
1765 // We allow mouse drag of table borders within nested tables,
1766 // but disallow hotspot selection of nested tables.
1767 if ( bMouseMoveRowCols
)
1769 // find the next cell frame
1770 while ( pFrame
&& !pFrame
->IsCellFrame() )
1771 pFrame
= pFrame
->GetUpper();
1775 // find the most upper cell frame:
1777 ( !pFrame
->IsCellFrame() ||
1778 !pFrame
->GetUpper()->GetUpper()->IsTabFrame() ||
1779 pFrame
->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) )
1780 pFrame
= pFrame
->GetUpper();
1783 if ( pFrame
) // Note: this condition should be the same like the while condition!!!
1785 // #i32329# Enhanced table selection
1786 // used for hotspot selection of tab/cols/rows
1787 if ( !bMouseMoveRowCols
)
1790 assert(pbCol
&& pbRow
&& "pbCol or pbRow missing");
1792 if ( bCloseToRow
|| bCloseToCol
)
1794 *pbRow
= bCloseToRow
;
1795 *pbCol
= bCloseToCol
;
1802 // used for mouse move of columns/rows
1803 const SwTabFrame
* pTabFrame
= pFrame
->FindTabFrame();
1804 SwRect aTabRect
= pTabFrame
->getFramePrintArea();
1805 aTabRect
.Pos() += pTabFrame
->getFrameArea().Pos();
1807 SwRectFnSet
aRectFnSet(pTabFrame
);
1809 const SwTwips nTabTop
= aRectFnSet
.GetTop(aTabRect
);
1810 const SwTwips nMouseTop
= aRectFnSet
.IsVert() ? rPt
.X() : rPt
.Y();
1812 // Do not allow to drag upper table border:
1813 if ( !::IsSame( rDoc
, nTabTop
, nMouseTop
) )
1815 if ( ::IsSame( rDoc
, pFrame
->getFrameArea().Left(), rPt
.X() ) ||
1816 ::IsSame( rDoc
, pFrame
->getFrameArea().Right(),rPt
.X() ) )
1818 if ( pbRow
) *pbRow
= false;
1822 if ( ::IsSame( rDoc
, pFrame
->getFrameArea().Top(), rPt
.Y() ) ||
1823 ::IsSame( rDoc
, pFrame
->getFrameArea().Bottom(),rPt
.Y() ) )
1825 if ( pbRow
) *pbRow
= true;
1832 pFrame
= pFrame
->GetUpper();
1838 OSL_ENSURE( !pRet
|| pRet
->IsCellFrame(), "lcl_FindFrame() is supposed to find a cell frame!" );
1839 return pRet
&& pRet
->IsCellFrame() ? static_cast<const SwCellFrame
*>(pRet
) : nullptr;
1842 // pbCol = 0 => Used for moving table rows/cols with mouse
1843 // pbCol != 0 => Used for selecting table/rows/cols
1845 #define ENHANCED_TABLE_SELECTION_FUZZY 10
1847 const SwFrame
* SwFEShell::GetBox( const Point
&rPt
, bool* pbRow
, bool* pbCol
) const
1849 const SwPageFrame
*pPage
= static_cast<SwPageFrame
*>(GetLayout()->Lower());
1850 vcl::Window
* pOutWin
= GetWin();
1851 SwTwips nFuzzy
= COLFUZZY
;
1854 // #i32329# Enhanced table selection
1855 SwTwips nSize
= pbCol
? ENHANCED_TABLE_SELECTION_FUZZY
: RULER_MOUSE_MARGINWIDTH
;
1856 Size
aTmp( nSize
, nSize
);
1857 aTmp
= pOutWin
->PixelToLogic( aTmp
);
1858 nFuzzy
= aTmp
.Width();
1861 while ( pPage
&& !pPage
->getFrameArea().IsNear( rPt
, nFuzzy
) )
1862 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
1864 const SwCellFrame
*pFrame
= nullptr;
1867 // We cannot search the box by GetModelPositionForViewPoint or GetContentPos.
1868 // This would lead to a performance collapse for documents
1869 // with a lot of paragraphs/tables on one page
1873 if ( pPage
->GetSortedObjs() )
1875 for ( size_t i
= 0; !pFrame
&& i
< pPage
->GetSortedObjs()->size(); ++i
)
1877 SwAnchoredObject
* pObj
= (*pPage
->GetSortedObjs())[i
];
1878 if ( auto pFlyFrame
= pObj
->DynCastFlyFrame() )
1880 pFrame
= lcl_FindFrame( *GetDoc(), pFlyFrame
, rPt
, nFuzzy
, pbRow
, pbCol
);
1884 const SwLayoutFrame
*pLay
= static_cast<const SwLayoutFrame
*>(pPage
->Lower());
1885 while ( pLay
&& !pFrame
)
1887 pFrame
= lcl_FindFrame( *GetDoc(), pLay
, rPt
, nFuzzy
, pbRow
, pbCol
);
1888 pLay
= static_cast<const SwLayoutFrame
*>(pLay
->GetNext());
1894 /* Helper function*/
1895 /* calculated the distance between Point rC and Line Segment (rA, rB) */
1896 static double lcl_DistancePoint2Segment( const Point
& rA
, const Point
& rB
, const Point
& rC
)
1900 const basegfx::B2DVector
aBC( rC
.X() - rB
.X(), rC
.Y() - rB
.Y() );
1901 const basegfx::B2DVector
aAB( rB
.X() - rA
.X(), rB
.Y() - rA
.Y() );
1902 const double nDot1
= aBC
.scalar( aAB
);
1904 if ( nDot1
> 0 ) // check outside case 1
1905 nRet
= aBC
.getLength();
1908 const basegfx::B2DVector
aAC( rC
.X() - rA
.X(), rC
.Y() - rA
.Y() );
1909 const basegfx::B2DVector
aBA( rA
.X() - rB
.X(), rA
.Y() - rB
.Y() );
1910 const double nDot2
= aAC
.scalar( aBA
);
1912 if ( nDot2
> 0 ) // check outside case 2
1913 nRet
= aAC
.getLength();
1916 const double nDiv
= aAB
.getLength();
1917 nRet
= nDiv
? aAB
.cross( aAC
) / nDiv
: 0;
1921 return std::abs(nRet
);
1924 /* Helper function*/
1925 static Point
lcl_ProjectOntoClosestTableFrame( const SwTabFrame
& rTab
, const Point
& rPoint
, bool bRowDrag
)
1927 Point
aRet( rPoint
);
1928 const SwTabFrame
* pCurrentTab
= &rTab
;
1929 const bool bVert
= pCurrentTab
->IsVertical();
1930 const bool bRTL
= pCurrentTab
->IsRightToLeft();
1933 // bRowDrag = true => compare to left border of table
1934 // bRowDrag = false => compare to top border of table
1937 // bRowDrag = true => compare to right border of table
1938 // bRowDrag = false => compare to top border of table
1941 // bRowDrag = true => compare to right border of table
1942 // bRowDrag = false => compare to top border of table
1944 bool bRight
= false;
1948 if ( bVert
|| bRTL
)
1954 // used to find the minimal distance
1962 while ( pCurrentTab
)
1964 SwRect
aTabRect( pCurrentTab
->getFramePrintArea() );
1965 aTabRect
+= pCurrentTab
->getFrameArea().Pos();
1969 // distance to left table border
1970 aS1
= aTabRect
.TopLeft();
1971 aS2
= aTabRect
.BottomLeft();
1975 // distance to right table border
1976 aS1
= aTabRect
.TopRight();
1977 aS2
= aTabRect
.BottomRight();
1981 // distance to top table border
1982 aS1
= aTabRect
.TopLeft();
1983 aS2
= aTabRect
.TopRight();
1986 const double nDist
= lcl_DistancePoint2Segment( aS1
, aS2
, rPoint
);
1988 if ( nDist
< nMin
|| -1 == nMin
)
1995 pCurrentTab
= pCurrentTab
->GetFollow();
1998 // project onto closest line:
1999 if ( bLeft
|| bRight
)
2001 aRet
.setX(aMin1
.getX());
2002 if ( aRet
.getY() > aMin2
.getY() )
2003 aRet
.setY(aMin2
.getY());
2004 else if ( aRet
.getY() < aMin1
.getY() )
2005 aRet
.setY(aMin1
.getY());
2009 aRet
.setY(aMin1
.getY());
2010 if ( aRet
.getX() > aMin2
.getX() )
2011 aRet
.setX(aMin2
.getX());
2012 else if ( aRet
.getX() < aMin1
.getX() )
2013 aRet
.setX(aMin1
.getX());
2019 // #i32329# Enhanced table selection
2020 bool SwFEShell::SelTableRowCol( const Point
& rPt
, const Point
* pEnd
, bool bRowDrag
)
2027 SwPosition
* ppPos
[2] = { nullptr, nullptr };
2028 Point paPt
[2] = { rPt
, aEndPt
};
2029 bool pbRow
[2] = { false, false };
2030 bool pbCol
[2] = { false, false };
2032 // pEnd is set during dragging.
2033 for ( sal_uInt16 i
= 0; i
< ( pEnd
? 2 : 1 ); ++i
)
2035 const SwCellFrame
* pFrame
=
2036 static_cast<const SwCellFrame
*>(GetBox( paPt
[i
], &pbRow
[i
], &pbCol
[i
] ) );
2040 const SwFrame
* pLower
= pFrame
->Lower();
2041 while( pLower
&& pLower
->IsRowFrame() )
2043 pFrame
= static_cast<const SwCellFrame
*>( static_cast<const SwLayoutFrame
*>( pLower
)->Lower() );
2044 pLower
= pFrame
? pFrame
->Lower() : nullptr;
2046 if( pFrame
&& pFrame
->GetTabBox()->GetSttNd() &&
2047 pFrame
->GetTabBox()->GetSttNd()->IsInProtectSect() )
2053 const SwContentFrame
* pContent
= ::GetCellContent( *pFrame
);
2055 if ( pContent
&& pContent
->IsTextFrame() )
2058 ppPos
[i
] = new SwPosition(static_cast<SwTextFrame
const*>(pContent
)->MapViewToModelPos(TextFrameIndex(0)));
2060 // paPt[i] will not be used any longer, now we use it to store
2061 // a position inside the content frame
2062 paPt
[i
] = pContent
->getFrameArea().Center();
2066 // no calculation of end frame if start frame has not been found.
2067 if ( 1 == i
|| !ppPos
[0] || !pEnd
|| !pFrame
)
2070 // find 'closest' table frame to pEnd:
2071 const SwTabFrame
* pCurrentTab
= pFrame
->FindTabFrame();
2072 if ( pCurrentTab
->IsFollow() )
2073 pCurrentTab
= pCurrentTab
->FindMaster( true );
2075 const Point aProjection
= lcl_ProjectOntoClosestTableFrame( *pCurrentTab
, *pEnd
, bRowDrag
);
2076 paPt
[1] = aProjection
;
2081 SwShellCursor
* pCursor
= GetCursor_();
2082 SwCursorSaveState
aSaveState( *pCursor
);
2083 SwPosition
aOldPos( *pCursor
->GetPoint() );
2085 pCursor
->DeleteMark();
2086 *pCursor
->GetPoint() = *ppPos
[0];
2087 pCursor
->GetPtPos() = paPt
[0];
2089 if ( !pCursor
->IsInProtectTable() )
2091 bool bNewSelection
= true;
2095 if ( ppPos
[1]->GetNode().StartOfSectionNode() !=
2096 aOldPos
.GetNode().StartOfSectionNode() )
2099 SwCursorSaveState
aSaveState2( *pCursor
);
2100 *pCursor
->GetPoint() = *ppPos
[1];
2101 pCursor
->GetPtPos() = paPt
[1];
2103 if ( pCursor
->IsInProtectTable( false, false ) )
2105 pCursor
->RestoreSavePos();
2106 bNewSelection
= false;
2111 pCursor
->RestoreSavePos();
2112 bNewSelection
= false;
2116 if ( bNewSelection
)
2118 // #i35543# SelTableRowCol should remove any existing
2120 if ( IsTableMode() )
2121 TableCursorToCursor();
2123 if ( pbRow
[0] && pbCol
[0] )
2124 bRet
= SwCursorShell::SelTable();
2125 else if ( pbRow
[0] )
2126 bRet
= SwCursorShell::SelTableRowOrCol( true, true );
2127 else if ( pbCol
[0] )
2128 bRet
= SwCursorShell::SelTableRowOrCol( false, true );
2141 SwTab
SwFEShell::WhichMouseTabCol( const Point
&rPt
) const
2143 SwTab nRet
= SwTab::COL_NONE
;
2146 bool bSelect
= false;
2148 // First try: Do we get the row/col move cursor?
2149 const SwCellFrame
* pFrame
= static_cast<const SwCellFrame
*>(GetBox( rPt
, &bRow
));
2153 // Second try: Do we get the row/col/tab selection cursor?
2154 pFrame
= static_cast<const SwCellFrame
*>(GetBox( rPt
, &bRow
, &bCol
));
2160 const SwFrame
* pLower
= pFrame
->Lower();
2161 while( pLower
&& pLower
->IsRowFrame() )
2163 pFrame
= static_cast<const SwCellFrame
*>(static_cast<const SwLayoutFrame
*>(pLower
)->Lower());
2164 pLower
= pFrame
? pFrame
->Lower() : nullptr;
2166 if( pFrame
&& ((pFrame
->GetTabBox()->GetSttNd() &&
2167 pFrame
->GetTabBox()->GetSttNd()->IsInProtectSect()) || (pFrame
->GetTabBox()->getRowSpan() < 0)))
2175 if ( pFrame
->IsVertical() )
2176 nRet
= bRow
? SwTab::COL_VERT
: SwTab::ROW_VERT
;
2178 nRet
= bRow
? SwTab::ROW_HORI
: SwTab::COL_HORI
;
2182 const SwTabFrame
* pTabFrame
= pFrame
->FindTabFrame();
2183 if ( pTabFrame
->IsVertical() )
2187 nRet
= SwTab::SEL_VERT
;
2191 nRet
= SwTab::ROWSEL_VERT
;
2195 nRet
= SwTab::COLSEL_VERT
;
2202 nRet
= pTabFrame
->IsRightToLeft() ?
2203 SwTab::SEL_HORI_RTL
:
2208 nRet
= pTabFrame
->IsRightToLeft() ?
2209 SwTab::ROWSEL_HORI_RTL
:
2214 nRet
= SwTab::COLSEL_HORI
;
2224 SwTextNode
* SwFEShell::GetNumRuleNodeAtPos( const Point
&rPt
)
2226 SwTextNode
* pResult
= nullptr;
2228 SwContentAtPos
aContentAtPos(IsAttrAtPos::NumLabel
);
2230 if( GetContentAtPos(rPt
, aContentAtPos
) && aContentAtPos
.aFnd
.pNode
)
2231 pResult
= aContentAtPos
.aFnd
.pNode
->GetTextNode();
2236 bool SwFEShell::IsNumLabel( const Point
&rPt
, int nMaxOffset
)
2238 bool bResult
= false;
2240 SwContentAtPos
aContentAtPos(IsAttrAtPos::NumLabel
);
2242 if( GetContentAtPos(rPt
, aContentAtPos
))
2244 if ((nMaxOffset
>= 0 && aContentAtPos
.nDist
<= nMaxOffset
) ||
2254 bool SwFEShell::IsVerticalModeAtNdAndPos( const SwTextNode
& _rTextNode
,
2255 const Point
& _rDocPos
)
2259 const SvxFrameDirection nTextDir
=
2260 _rTextNode
.GetTextDirection( SwPosition(_rTextNode
), &_rDocPos
);
2263 case SvxFrameDirection::Unknown
:
2264 case SvxFrameDirection::Horizontal_RL_TB
:
2265 case SvxFrameDirection::Horizontal_LR_TB
:
2270 case SvxFrameDirection::Vertical_LR_TB
:
2271 case SvxFrameDirection::Vertical_RL_TB
:
2282 void SwFEShell::GetMouseTabCols( SwTabCols
&rToFill
, const Point
&rPt
) const
2284 const SwFrame
*pBox
= GetBox( rPt
);
2286 GetTabCols_( rToFill
, pBox
);
2289 void SwFEShell::SetMouseTabCols( const SwTabCols
&rNew
, bool bCurRowOnly
,
2292 const SwFrame
*pBox
= GetBox( rPt
);
2295 CurrShell
aCurr( this );
2297 GetDoc()->SetTabCols( rNew
, bCurRowOnly
, static_cast<const SwCellFrame
*>(pBox
) );
2298 EndAllActionAndCall();
2302 sal_uInt16
SwFEShell::GetCurMouseColNum( const Point
&rPt
) const
2304 return GetCurColNum_( GetBox( rPt
), nullptr );
2307 size_t SwFEShell::GetCurMouseTabColNum( const Point
&rPt
) const
2309 //!!!GetCurTabColNum() mitpflegen!!!!
2312 const SwFrame
*pFrame
= GetBox( rPt
);
2313 OSL_ENSURE( pFrame
, "Table not found" );
2316 const tools::Long nX
= pFrame
->getFrameArea().Left();
2318 // get TabCols, only via these we get the position
2320 GetMouseTabCols( aTabCols
, rPt
);
2322 const tools::Long nLeft
= aTabCols
.GetLeftMin();
2324 if ( !::IsSame( *GetDoc(), nX
, nLeft
+ aTabCols
.GetLeft() ) )
2326 for ( size_t i
= 0; i
< aTabCols
.Count(); ++i
)
2327 if ( ::IsSame( *GetDoc(), nX
, nLeft
+ aTabCols
[i
] ) )
2337 void ClearFEShellTabCols(SwDoc
& rDoc
, SwTabFrame
const*const pFrame
)
2339 auto const pShell(rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell());
2342 for (SwViewShell
& rCurrentShell
: pShell
->GetRingContainer())
2344 if (auto const pFE
= dynamic_cast<SwFEShell
*>(&rCurrentShell
))
2346 pFE
->ClearColumnRowCache(pFrame
);
2352 void SwFEShell::ClearColumnRowCache(SwTabFrame
const*const pFrame
)
2356 if (pFrame
== nullptr || pFrame
== m_pColumnCache
->pLastTabFrame
)
2358 m_pColumnCache
.reset();
2363 if (pFrame
== nullptr || pFrame
== m_pRowCache
->pLastTabFrame
)
2365 m_pRowCache
.reset();
2370 void SwFEShell::GetTableAttr( SfxItemSet
&rSet
) const
2372 SwFrame
*pFrame
= GetCurrFrame();
2373 if( pFrame
&& pFrame
->IsInTab() )
2374 rSet
.Put( pFrame
->ImplFindTabFrame()->GetFormat()->GetAttrSet() );
2377 void SwFEShell::SetTableAttr( const SfxItemSet
&rNew
)
2379 SwFrame
*pFrame
= GetCurrFrame();
2380 if( pFrame
&& pFrame
->IsInTab() )
2382 CurrShell
aCurr( this );
2384 SwTabFrame
*pTab
= pFrame
->FindTabFrame();
2385 pTab
->GetTable()->SetHTMLTableLayout(std::shared_ptr
<SwHTMLTableLayout
>());
2386 GetDoc()->SetAttr( rNew
, *pTab
->GetFormat() );
2387 GetDoc()->getIDocumentState().SetModified();
2388 EndAllActionAndCall();
2392 // change a cell width/cell height/column width/row height
2393 void SwFEShell::SetColRowWidthHeight( TableChgWidthHeightType eType
, sal_uInt16 nDiff
)
2395 SwFrame
*pFrame
= GetCurrFrame();
2396 if( !pFrame
|| !pFrame
->IsInTab() )
2399 CurrShell
aCurr( this );
2403 pFrame
= pFrame
->GetUpper();
2404 } while( !pFrame
->IsCellFrame() );
2406 SwTabFrame
*pTab
= pFrame
->ImplFindTabFrame();
2408 // if the table is in relative values (USHRT_MAX)
2409 // then it should be recalculated to absolute values now
2410 const SwFormatFrameSize
& rTableFrameSz
= pTab
->GetFormat()->GetFrameSize();
2411 SwRectFnSet
aRectFnSet(pTab
);
2412 tools::Long nPrtWidth
= aRectFnSet
.GetWidth(pTab
->getFramePrintArea());
2413 TableChgWidthHeightType eTypePos
= extractPosition(eType
);
2414 if( TableChgMode::VarWidthChangeAbs
== pTab
->GetTable()->GetTableChgMode() &&
2415 ( eTypePos
== TableChgWidthHeightType::ColLeft
|| eTypePos
== TableChgWidthHeightType::ColRight
) &&
2416 text::HoriOrientation::NONE
== pTab
->GetFormat()->GetHoriOrient().GetHoriOrient() &&
2417 nPrtWidth
!= rTableFrameSz
.GetWidth() )
2419 SwFormatFrameSize
aSz( rTableFrameSz
);
2420 aSz
.SetWidth( pTab
->getFramePrintArea().Width() );
2421 pTab
->GetFormat()->SetFormatAttr( aSz
);
2424 SwTwips nLogDiff
= nDiff
;
2425 nLogDiff
*= pTab
->GetFormat()->GetFrameSize().GetWidth();
2426 nLogDiff
/= nPrtWidth
;
2428 /** The cells are destroyed in here */
2429 GetDoc()->SetColRowWidthHeight(
2430 *const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox()),
2431 eType
, nDiff
, nLogDiff
);
2433 ClearFEShellTabCols(*GetDoc(), nullptr);
2434 EndAllActionAndCall();
2437 static bool lcl_IsFormulaSelBoxes( const SwTable
& rTable
, const SwTableBoxFormula
& rFormula
,
2438 SwCellFrames
& rCells
)
2440 SwTableBoxFormula
aTmp( rFormula
);
2442 aTmp
.GetBoxesOfFormula(rTable
, aBoxes
);
2443 for (size_t nSelBoxes
= aBoxes
.size(); nSelBoxes
; )
2445 SwTableBox
* pBox
= aBoxes
[ --nSelBoxes
];
2447 if( std::none_of(rCells
.begin(), rCells
.end(), [&pBox
](SwCellFrame
* pFrame
) { return pFrame
->GetTabBox() == pBox
; }) )
2454 // ask formula for auto-sum
2455 void SwFEShell::GetAutoSum( OUString
& rFormula
) const
2457 SwFrame
*pFrame
= GetCurrFrame();
2458 SwTabFrame
*pTab
= pFrame
? pFrame
->ImplFindTabFrame() : nullptr;
2462 SwCellFrames aCells
;
2464 if( ::GetAutoSumSel( *this, aCells
))
2467 for( size_t n
= aCells
.size(); n
; )
2469 SwCellFrame
* pCFrame
= aCells
[ --n
];
2470 sal_uInt16 nBoxW
= pCFrame
->GetTabBox()->IsFormulaOrValueBox();
2476 if( USHRT_MAX
== nBoxW
)
2477 continue; // skip space at beginning
2479 // formula only if box is contained
2480 if( RES_BOXATR_FORMULA
== nBoxW
&&
2481 !::lcl_IsFormulaSelBoxes( *pTab
->GetTable(), pCFrame
->
2482 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells
))
2484 nW
= RES_BOXATR_VALUE
;
2485 // restore previous spaces!
2486 for( size_t i
= aCells
.size(); n
+1 < i
; )
2488 sFields
= "|<" + aCells
[--i
]->GetTabBox()->GetName() + ">"
2495 else if( RES_BOXATR_VALUE
== nW
)
2497 // search for values, Value/Formula/Text found -> include
2498 if( RES_BOXATR_FORMULA
== nBoxW
&&
2499 ::lcl_IsFormulaSelBoxes( *pTab
->GetTable(), pCFrame
->
2500 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells
))
2502 else if( USHRT_MAX
!= nBoxW
)
2503 sFields
= OUStringChar(cListDelim
) + sFields
;
2507 else if( RES_BOXATR_FORMULA
== nW
)
2509 // only continue search when the current formula points to
2510 // all boxes contained in the selection
2511 if( RES_BOXATR_FORMULA
== nBoxW
)
2513 if( !::lcl_IsFormulaSelBoxes( *pTab
->GetTable(), pCFrame
->
2514 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells
))
2516 // redo only for values!
2518 nW
= RES_BOXATR_VALUE
;
2520 // restore previous spaces!
2521 for( size_t i
= aCells
.size(); n
+1 < i
; )
2523 sFields
= "|<" + aCells
[--i
]->GetTabBox()->GetName() + ">"
2528 sFields
= OUStringChar(cListDelim
) + sFields
;
2530 else if( USHRT_MAX
== nBoxW
)
2533 continue; // ignore this box
2536 // all other stuff terminates the loop
2537 // possibly allow texts??
2540 sFields
= "<" + pCFrame
->GetTabBox()->GetName() + ">" + sFields
;
2544 rFormula
= sCalc_Sum
;
2545 if (!sFields
.isEmpty())
2547 rFormula
+= "(" + sFields
+ ")";
2551 bool SwFEShell::IsTableRightToLeft() const
2553 SwFrame
*pFrame
= GetCurrFrame();
2554 SwTabFrame
*pTab
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->ImplFindTabFrame() : nullptr;
2557 return pTab
->IsRightToLeft();
2560 bool SwFEShell::IsMouseTableRightToLeft(const Point
&rPt
) const
2562 SwFrame
*pFrame
= const_cast<SwFrame
*>(GetBox( rPt
));
2563 const SwTabFrame
* pTabFrame
= pFrame
? pFrame
->ImplFindTabFrame() : nullptr;
2564 OSL_ENSURE( pTabFrame
, "Table not found" );
2565 return pTabFrame
&& pTabFrame
->IsRightToLeft();
2568 bool SwFEShell::IsTableVertical() const
2570 SwFrame
*pFrame
= GetCurrFrame();
2571 SwTabFrame
*pTab
= (pFrame
&& pFrame
->IsInTab()) ? pFrame
->ImplFindTabFrame() : nullptr;
2574 return pTab
->IsVertical();
2577 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */