nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / core / frmedt / fetab.cxx
blob97878a01e3ea0b19c927122276efeb252876caeb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
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 <swwait.hxx>
30 #include <fmtfsize.hxx>
31 #include <fmtornt.hxx>
32 #include <frmatr.hxx>
33 #include <fesh.hxx>
34 #include <doc.hxx>
35 #include <IDocumentState.hxx>
36 #include <IDocumentLayoutAccess.hxx>
37 #include <cntfrm.hxx>
38 #include <txtfrm.hxx>
39 #include <notxtfrm.hxx>
40 #include <rootfrm.hxx>
41 #include <pagefrm.hxx>
42 #include <tabfrm.hxx>
43 #include <rowfrm.hxx>
44 #include <cellfrm.hxx>
45 #include <flyfrm.hxx>
46 #include <swtable.hxx>
47 #include <swddetbl.hxx>
48 #include <ndtxt.hxx>
49 #include <calc.hxx>
50 #include <dialoghelp.hxx>
51 #include <tabcol.hxx>
52 #include <tblafmt.hxx>
53 #include <cellatr.hxx>
54 #include <pam.hxx>
55 #include <viscrs.hxx>
56 #include <tblsel.hxx>
57 #include <swerror.h>
58 #include <swundo.hxx>
59 #include <frmtool.hxx>
60 #include <fmtrowsplt.hxx>
61 #include <node.hxx>
62 #include <sortedobjs.hxx>
64 using namespace ::com::sun::star;
66 // also see swtable.cxx
67 #define COLFUZZY 20L
69 static bool IsSame( tools::Long nA, tools::Long nB ) { return std::abs(nA-nB) <= COLFUZZY; }
71 namespace {
73 class TableWait
75 const std::unique_ptr<SwWait> m_pWait;
76 // this seems really fishy: do some locking, if an arbitrary number of lines is exceeded
77 static const size_t our_kLineLimit = 20;
78 static bool ShouldWait(size_t nCnt, SwFrame *pFrame, size_t nCnt2)
79 { return our_kLineLimit < nCnt || our_kLineLimit < nCnt2 || (pFrame && our_kLineLimit < pFrame->ImplFindTabFrame()->GetTable()->GetTabLines().size()); }
80 public:
81 TableWait(size_t nCnt, SwFrame *pFrame, SwDocShell &rDocShell, size_t nCnt2 = 0)
82 : m_pWait( ShouldWait(nCnt, pFrame, nCnt2) ? std::make_unique<SwWait>( rDocShell, true ) : nullptr )
83 { }
88 void SwFEShell::ParkCursorInTab()
90 SwCursor * pSwCursor = GetSwCursor();
92 OSL_ENSURE(pSwCursor, "no SwCursor");
94 SwPosition aStartPos = *pSwCursor->GetPoint(), aEndPos = aStartPos;
96 /* Search least and greatest position in current cursor ring.
98 for(SwPaM& rTmpCursor : pSwCursor->GetRingContainer())
100 SwCursor* pTmpCursor = static_cast<SwCursor *>(&rTmpCursor);
101 const SwPosition * pPt = pTmpCursor->GetPoint(),
102 * pMk = pTmpCursor->GetMark();
104 if (*pPt < aStartPos)
105 aStartPos = *pPt;
107 if (*pPt > aEndPos)
108 aEndPos = *pPt;
110 if (*pMk < aStartPos)
111 aStartPos = *pMk;
113 if (*pMk > aEndPos)
114 aEndPos = *pMk;
118 KillPams();
120 /* @@@ semantic: SwCursor::operator=() is not implemented @@@ */
122 /* Set cursor to end of selection to ensure IsLastCellInRow works
123 properly. */
125 SwCursor aTmpCursor( aEndPos, nullptr );
126 *pSwCursor = aTmpCursor;
129 /* Move the cursor out of the columns to delete and stay in the
130 same row. If the table has only one column the cursor will
131 stay in the row and the shell will take care of it. */
132 if (IsLastCellInRow())
134 /* If the cursor is in the last row of the table, first
135 try to move it to the previous cell. If that fails move
136 it to the next cell. */
139 SwCursor aTmpCursor( aStartPos, nullptr );
140 *pSwCursor = aTmpCursor;
143 if (! pSwCursor->GoPrevCell())
145 SwCursor aTmpCursor( aEndPos, nullptr );
146 *pSwCursor = aTmpCursor;
147 pSwCursor->GoNextCell();
150 else
152 /* If the cursor is not in the last row of the table, first
153 try to move it to the next cell. If that fails move it
154 to the previous cell. */
157 SwCursor aTmpCursor( aEndPos, nullptr );
158 *pSwCursor = aTmpCursor;
161 if (! pSwCursor->GoNextCell())
163 SwCursor aTmpCursor( aStartPos, nullptr );
164 *pSwCursor = aTmpCursor;
165 pSwCursor->GoPrevCell();
170 void SwFEShell::InsertRow( sal_uInt16 nCnt, bool bBehind )
172 // check if Point/Mark of current cursor are in a table
173 SwFrame *pFrame = GetCurrFrame();
174 if( !pFrame || !pFrame->IsInTab() )
175 return;
177 if( dynamic_cast< const SwDDETable* >(pFrame->ImplFindTabFrame()->GetTable()) != nullptr )
179 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
180 DialogMask::MessageInfo | DialogMask::ButtonsOk );
181 return;
184 CurrShell aCurr( this );
185 StartAllAction();
187 // search boxes via the layout
188 SwSelBoxes aBoxes;
189 bool bSelectAll = StartsWithTable() && ExtendedSelectedAll();
190 if (bSelectAll)
192 // Set the end of the selection to the last paragraph of the last cell of the table.
193 SwPaM* pPaM = getShellCursor(false);
194 SwNode* pNode = pPaM->Start()->nNode.GetNode().FindTableNode()->EndOfSectionNode();
195 // pNode is the end node of the table, we want the last node before the end node of the last cell.
196 pPaM->End()->nNode = pNode->GetIndex() - 2;
197 pPaM->End()->nContent.Assign(pPaM->End()->nNode.GetNode().GetContentNode(), 0);
199 GetTableSel( *this, aBoxes, SwTableSearchType::Row );
201 TableWait aWait( nCnt, pFrame, *GetDoc()->GetDocShell(), aBoxes.size() );
203 if ( !aBoxes.empty() )
204 GetDoc()->InsertRow( aBoxes, nCnt, bBehind );
206 EndAllActionAndCall();
209 void SwFEShell::InsertCol( sal_uInt16 nCnt, bool bBehind )
211 // check if Point/Mark of current cursor are in a table
212 SwFrame *pFrame = GetCurrFrame();
213 if( !pFrame || !pFrame->IsInTab() )
214 return;
216 if( dynamic_cast< const SwDDETable* >(pFrame->ImplFindTabFrame()->GetTable()) != nullptr )
218 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
219 DialogMask::MessageInfo | DialogMask::ButtonsOk );
220 return;
223 CurrShell aCurr( this );
225 if( !CheckSplitCells( *this, nCnt + 1, SwTableSearchType::Col ) )
227 ErrorHandler::HandleError( ERR_TBLINSCOL_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
228 DialogMask::MessageInfo | DialogMask::ButtonsOk );
229 return;
232 StartAllAction();
233 // search boxes via the layout
234 SwSelBoxes aBoxes;
235 GetTableSel( *this, aBoxes, SwTableSearchType::Col );
237 TableWait aWait( nCnt, pFrame, *GetDoc()->GetDocShell(), aBoxes.size() );
239 if( !aBoxes.empty() )
240 GetDoc()->InsertCol( aBoxes, nCnt, bBehind );
242 EndAllActionAndCall();
245 // Determines if the current cursor is in the last row of the table.
246 bool SwFEShell::IsLastCellInRow() const
248 SwTabCols aTabCols;
249 GetTabCols( aTabCols );
250 bool bResult = false;
252 if (IsTableRightToLeft())
253 /* If the table is right-to-left the last row is the most left one. */
254 bResult = 0 == GetCurTabColNum();
255 else
256 /* If the table is left-to-right the last row is the most right one. */
257 bResult = aTabCols.Count() == GetCurTabColNum();
259 return bResult;
262 bool SwFEShell::DeleteCol()
264 // check if Point/Mark of current cursor are in a table
265 SwFrame *pFrame = GetCurrFrame();
266 if( !pFrame || !pFrame->IsInTab() )
267 return false;
269 if( dynamic_cast< const SwDDETable* >(pFrame->ImplFindTabFrame()->GetTable()) != nullptr )
271 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
272 DialogMask::MessageInfo | DialogMask::ButtonsOk );
273 return false;
276 CurrShell aCurr( this );
277 StartAllAction();
279 // search boxes via the layout
280 bool bRet;
281 SwSelBoxes aBoxes;
282 GetTableSel( *this, aBoxes, SwTableSearchType::Col );
283 if ( !aBoxes.empty() )
285 TableWait aWait( aBoxes.size(), pFrame, *GetDoc()->GetDocShell() );
287 // remove crsr from the deletion area.
288 // Put them behind/on the table; via the
289 // document position they will be put to the old position
290 while( !pFrame->IsCellFrame() )
291 pFrame = pFrame->GetUpper();
293 ParkCursorInTab();
295 // then delete the column
296 StartUndo(SwUndoId::COL_DELETE);
297 bRet = GetDoc()->DeleteRowCol( aBoxes, true );
298 EndUndo(SwUndoId::COL_DELETE);
301 else
302 bRet = false;
304 EndAllActionAndCall();
305 return bRet;
308 void SwFEShell::DeleteTable()
310 DeleteRow(true);
313 bool SwFEShell::DeleteRow(bool bCompleteTable)
315 // check if Point/Mark of current cursor are in a table
316 SwFrame *pFrame = GetCurrFrame();
317 if( !pFrame || !pFrame->IsInTab() )
318 return false;
320 if( dynamic_cast< const SwDDETable* >(pFrame->ImplFindTabFrame()->GetTable()) != nullptr )
322 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
323 DialogMask::MessageInfo | DialogMask::ButtonsOk );
324 return false;
327 CurrShell aCurr( this );
328 StartAllAction();
330 // search for boxes via the layout
331 bool bRet;
332 SwSelBoxes aBoxes;
333 GetTableSel( *this, aBoxes, SwTableSearchType::Row );
335 if( !aBoxes.empty() )
337 TableWait aWait( aBoxes.size(), pFrame, *GetDoc()->GetDocShell() );
339 // Delete cursors from the deletion area.
340 // Then the cursor is:
341 // 1. the following row, if there is another row after this
342 // 2. the preceding row, if there is another row before this
343 // 3. otherwise below the table
345 SwTableNode* pTableNd = pFrame->IsTextFrame()
346 ? static_cast<SwTextFrame*>(pFrame)->GetTextNodeFirst()->FindTableNode()
347 : static_cast<SwNoTextFrame*>(pFrame)->GetNode()->FindTableNode();
349 // search all boxes / lines
350 FndBox_ aFndBox( nullptr, nullptr );
352 FndPara aPara( aBoxes, &aFndBox );
353 ForEach_FndLineCopyCol( pTableNd->GetTable().GetTabLines(), &aPara );
356 if( aFndBox.GetLines().empty() )
358 EndAllActionAndCall();
359 return false;
362 KillPams();
364 FndBox_* pFndBox = &aFndBox;
365 while( 1 == pFndBox->GetLines().size() &&
366 1 == pFndBox->GetLines().front()->GetBoxes().size())
368 FndBox_ *const pTmp = pFndBox->GetLines().front()->GetBoxes()[0].get();
369 if( pTmp->GetBox()->GetSttNd() )
370 break; // otherwise too far
371 pFndBox = pTmp;
374 SwTableLine* pDelLine = pFndBox->GetLines().back()->GetLine();
375 SwTableBox* pDelBox = pDelLine->GetTabBoxes().back();
376 while( !pDelBox->GetSttNd() )
378 SwTableLine* pLn = pDelBox->GetTabLines().back();
379 pDelBox = pLn->GetTabBoxes().back();
381 SwTableBox* pNextBox = pDelLine->FindNextBox( pTableNd->GetTable(),
382 pDelBox );
383 while( pNextBox &&
384 pNextBox->GetFrameFormat()->GetProtect().IsContentProtected() )
385 pNextBox = pNextBox->FindNextBox( pTableNd->GetTable(), pNextBox );
387 if( !pNextBox ) // no next? then the previous
389 pDelLine = pFndBox->GetLines().front()->GetLine();
390 pDelBox = pDelLine->GetTabBoxes()[ 0 ];
391 while( !pDelBox->GetSttNd() )
392 pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
393 pNextBox = pDelLine->FindPreviousBox( pTableNd->GetTable(),
394 pDelBox );
395 while( pNextBox &&
396 pNextBox->GetFrameFormat()->GetProtect().IsContentProtected() )
397 pNextBox = pNextBox->FindPreviousBox( pTableNd->GetTable(), pNextBox );
400 sal_uLong nIdx;
401 if( pNextBox ) // put cursor here
402 nIdx = pNextBox->GetSttIdx() + 1;
403 else // otherwise below the table
404 nIdx = pTableNd->EndOfSectionIndex() + 1;
406 SwNodeIndex aIdx( GetDoc()->GetNodes(), nIdx );
407 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
408 if( !pCNd )
409 pCNd = GetDoc()->GetNodes().GoNext( &aIdx );
411 if( pCNd )
413 SwPaM* pPam = GetCursor();
414 pPam->GetPoint()->nNode = aIdx;
415 pPam->GetPoint()->nContent.Assign( pCNd, 0 );
416 pPam->SetMark(); // both want something
417 pPam->DeleteMark();
421 // now delete the lines
422 StartUndo(bCompleteTable ? SwUndoId::UI_TABLE_DELETE : SwUndoId::ROW_DELETE);
423 bRet = GetDoc()->DeleteRowCol( aBoxes );
424 EndUndo(bCompleteTable ? SwUndoId::UI_TABLE_DELETE : SwUndoId::ROW_DELETE);
426 else
427 bRet = false;
429 EndAllActionAndCall();
430 return bRet;
433 TableMergeErr SwFEShell::MergeTab()
435 // check if Point/Mark of current cursor are in a table
436 TableMergeErr nRet = TableMergeErr::NoSelection;
437 if( IsTableMode() )
439 SwShellTableCursor* pTableCursor = GetTableCursor();
440 const SwTableNode* pTableNd = pTableCursor->GetNode().FindTableNode();
441 if( dynamic_cast< const SwDDETable* >(&pTableNd->GetTable()) != nullptr )
443 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
444 DialogMask::MessageInfo | DialogMask::ButtonsOk );
446 else
448 CurrShell aCurr( this );
449 StartAllAction();
451 TableWait aWait(pTableCursor->GetSelectedBoxesCount(), nullptr,
452 *GetDoc()->GetDocShell(),
453 pTableNd->GetTable().GetTabLines().size() );
455 nRet = GetDoc()->MergeTable( *pTableCursor );
457 KillPams();
459 EndAllActionAndCall();
462 return nRet;
465 void SwFEShell::SplitTab( bool bVert, sal_uInt16 nCnt, bool bSameHeight )
467 // check if Point/Mark of current cursor are in a table
468 SwFrame *pFrame = GetCurrFrame();
469 if( !pFrame || !pFrame->IsInTab() )
470 return;
472 if( dynamic_cast< const SwDDETable* >(pFrame->ImplFindTabFrame()->GetTable()) != nullptr )
474 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
475 DialogMask::MessageInfo | DialogMask::ButtonsOk );
476 return;
479 CurrShell aCurr( this );
481 if( bVert && !CheckSplitCells( *this, nCnt + 1, SwTableSearchType::NONE ) )
483 ErrorHandler::HandleError( ERR_TBLSPLIT_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
484 DialogMask::MessageInfo | DialogMask::ButtonsOk );
485 return;
487 StartAllAction();
488 // search boxes via the layout
489 SwSelBoxes aBoxes;
490 GetTableSel( *this, aBoxes );
491 if( !aBoxes.empty() )
493 TableWait aWait( nCnt, pFrame, *GetDoc()->GetDocShell(), aBoxes.size() );
495 // now delete the columns
496 GetDoc()->SplitTable( aBoxes, bVert, nCnt, bSameHeight );
498 ClearFEShellTabCols(*GetDoc(), nullptr);
500 EndAllActionAndCall();
503 void SwFEShell::GetTabCols_(SwTabCols &rToFill, const SwFrame *pBox) const
505 const SwTabFrame *pTab = pBox->FindTabFrame();
506 if (m_pColumnCache)
508 bool bDel = true;
509 if (m_pColumnCache->pLastTable == pTab->GetTable())
511 bDel = false;
512 SwRectFnSet aRectFnSet(pTab);
514 const SwPageFrame* pPage = pTab->FindPageFrame();
515 const sal_uLong nLeftMin = aRectFnSet.GetLeft(pTab->getFrameArea()) -
516 aRectFnSet.GetLeft(pPage->getFrameArea());
517 const sal_uLong nRightMax = aRectFnSet.GetRight(pTab->getFrameArea()) -
518 aRectFnSet.GetLeft(pPage->getFrameArea());
520 if (m_pColumnCache->pLastTabFrame != pTab)
522 // if TabFrame was changed, we only shift a little bit
523 // as the width is the same
524 SwRectFnSet fnRectX(m_pColumnCache->pLastTabFrame);
525 if (fnRectX.GetWidth(m_pColumnCache->pLastTabFrame->getFrameArea()) ==
526 aRectFnSet.GetWidth(pTab->getFrameArea()) )
528 m_pColumnCache->pLastCols->SetLeftMin( nLeftMin );
530 m_pColumnCache->pLastTabFrame = pTab;
532 else
533 bDel = true;
536 if ( !bDel &&
537 m_pColumnCache->pLastCols->GetLeftMin () == static_cast<sal_uInt16>(nLeftMin) &&
538 m_pColumnCache->pLastCols->GetLeft () == static_cast<sal_uInt16>(aRectFnSet.GetLeft(pTab->getFramePrintArea())) &&
539 m_pColumnCache->pLastCols->GetRight () == static_cast<sal_uInt16>(aRectFnSet.GetRight(pTab->getFramePrintArea()))&&
540 m_pColumnCache->pLastCols->GetRightMax() == static_cast<sal_uInt16>(nRightMax) - m_pColumnCache->pLastCols->GetLeftMin() )
542 if (m_pColumnCache->pLastCellFrame != pBox)
544 pTab->GetTable()->GetTabCols( *m_pColumnCache->pLastCols,
545 static_cast<const SwCellFrame*>(pBox)->GetTabBox(), true);
546 m_pColumnCache->pLastCellFrame = pBox;
548 rToFill = *m_pColumnCache->pLastCols;
550 else
551 bDel = true;
553 if ( bDel )
554 m_pColumnCache.reset();
556 if (!m_pColumnCache)
558 SwDoc::GetTabCols( rToFill, static_cast<const SwCellFrame*>(pBox) );
560 m_pColumnCache.reset(new SwColCache);
561 m_pColumnCache->pLastCols.reset(new SwTabCols(rToFill));
562 m_pColumnCache->pLastTable = pTab->GetTable();
563 m_pColumnCache->pLastTabFrame = pTab;
564 m_pColumnCache->pLastCellFrame = pBox;
568 void SwFEShell::GetTabRows_(SwTabCols &rToFill, const SwFrame *pBox) const
570 const SwTabFrame *pTab = pBox->FindTabFrame();
571 if (m_pRowCache)
573 bool bDel = true;
574 if (m_pRowCache->pLastTable == pTab->GetTable())
576 bDel = false;
577 SwRectFnSet aRectFnSet(pTab);
578 const SwPageFrame* pPage = pTab->FindPageFrame();
579 const tools::Long nLeftMin = ( aRectFnSet.IsVert() ?
580 pTab->GetPrtLeft() - pPage->getFrameArea().Left() :
581 pTab->GetPrtTop() - pPage->getFrameArea().Top() );
582 const tools::Long nLeft = aRectFnSet.IsVert() ? LONG_MAX : 0;
583 const tools::Long nRight = aRectFnSet.GetHeight(pTab->getFramePrintArea());
584 const tools::Long nRightMax = aRectFnSet.IsVert() ? nRight : LONG_MAX;
586 if (m_pRowCache->pLastTabFrame != pTab || m_pRowCache->pLastCellFrame != pBox)
587 bDel = true;
589 if ( !bDel &&
590 m_pRowCache->pLastCols->GetLeftMin () == nLeftMin &&
591 m_pRowCache->pLastCols->GetLeft () == nLeft &&
592 m_pRowCache->pLastCols->GetRight () == nRight &&
593 m_pRowCache->pLastCols->GetRightMax() == nRightMax )
595 rToFill = *m_pRowCache->pLastCols;
597 else
598 bDel = true;
600 if ( bDel )
601 m_pRowCache.reset();
603 if (!m_pRowCache)
605 SwDoc::GetTabRows( rToFill, static_cast<const SwCellFrame*>(pBox) );
607 m_pRowCache.reset(new SwColCache);
608 m_pRowCache->pLastCols.reset(new SwTabCols(rToFill));
609 m_pRowCache->pLastTable = pTab->GetTable();
610 m_pRowCache->pLastTabFrame = pTab;
611 m_pRowCache->pLastCellFrame = pBox;
615 void SwFEShell::SetTabCols( const SwTabCols &rNew, bool bCurRowOnly )
617 SwFrame *pBox = GetCurrFrame();
618 if( !pBox || !pBox->IsInTab() )
619 return;
621 CurrShell aCurr( this );
622 StartAllAction();
626 pBox = pBox->GetUpper();
627 } while (pBox && !pBox->IsCellFrame());
629 GetDoc()->SetTabCols( rNew, bCurRowOnly, static_cast<SwCellFrame*>(pBox) );
630 EndAllActionAndCall();
633 void SwFEShell::GetTabCols( SwTabCols &rToFill ) const
635 const SwFrame *pFrame = GetCurrFrame();
636 if( !pFrame || !pFrame->IsInTab() )
637 return;
640 pFrame = pFrame->GetUpper();
642 while (pFrame && !pFrame->IsCellFrame());
644 if (!pFrame)
645 return;
647 GetTabCols_( rToFill, pFrame );
650 void SwFEShell::GetTabRows( SwTabCols &rToFill ) const
652 const SwFrame *pFrame = GetCurrFrame();
653 if( !pFrame || !pFrame->IsInTab() )
654 return;
657 pFrame = pFrame->GetUpper();
658 } while (pFrame && !pFrame->IsCellFrame());
660 if (!pFrame)
661 return;
663 GetTabRows_( rToFill, pFrame );
666 void SwFEShell::SetTabRows( const SwTabCols &rNew, bool bCurColOnly )
668 SwFrame *pBox = GetCurrFrame();
669 if( !pBox || !pBox->IsInTab() )
670 return;
672 CurrShell aCurr( this );
673 StartAllAction();
677 pBox = pBox->GetUpper();
678 } while (pBox && !pBox->IsCellFrame());
680 GetDoc()->SetTabRows( rNew, bCurColOnly, static_cast<SwCellFrame*>(pBox) );
681 EndAllActionAndCall();
684 void SwFEShell::GetMouseTabRows( SwTabCols &rToFill, const Point &rPt ) const
686 const SwFrame *pBox = GetBox( rPt );
687 if ( pBox )
688 GetTabRows_( rToFill, pBox );
691 void SwFEShell::SetMouseTabRows( const SwTabCols &rNew, bool bCurColOnly, const Point &rPt )
693 const SwFrame *pBox = GetBox( rPt );
694 if( pBox )
696 CurrShell aCurr( this );
697 StartAllAction();
698 GetDoc()->SetTabRows( rNew, bCurColOnly, static_cast<const SwCellFrame*>(pBox) );
699 EndAllActionAndCall();
703 void SwFEShell::SetRowSplit( const SwFormatRowSplit& rNew )
705 CurrShell aCurr( this );
706 StartAllAction();
707 GetDoc()->SetRowSplit( *getShellCursor( false ), rNew );
708 EndAllActionAndCall();
711 std::unique_ptr<SwFormatRowSplit> SwFEShell::GetRowSplit() const
713 return SwDoc::GetRowSplit( *getShellCursor( false ) );
716 void SwFEShell::SetRowHeight( const SwFormatFrameSize &rNew )
718 CurrShell aCurr( this );
719 StartAllAction();
720 GetDoc()->SetRowHeight( *getShellCursor( false ), rNew );
721 EndAllActionAndCall();
724 std::unique_ptr<SwFormatFrameSize> SwFEShell::GetRowHeight() const
726 return SwDoc::GetRowHeight( *getShellCursor( false ) );
729 bool SwFEShell::BalanceRowHeight( bool bTstOnly, const bool bOptimize )
731 CurrShell aCurr( this );
732 if( !bTstOnly )
733 StartAllAction();
734 bool bRet = GetDoc()->BalanceRowHeight( *getShellCursor( false ), bTstOnly, bOptimize );
735 if( !bTstOnly )
736 EndAllActionAndCall();
737 return bRet;
740 void SwFEShell::SetRowBackground( const SvxBrushItem &rNew )
742 CurrShell aCurr( this );
743 StartAllAction();
744 GetDoc()->SetRowBackground( *getShellCursor( false ), rNew );
745 EndAllActionAndCall();
748 bool SwFEShell::GetRowBackground( std::unique_ptr<SvxBrushItem>& rToFill ) const
750 return SwDoc::GetRowBackground( *getShellCursor( false ), rToFill );
753 void SwFEShell::SetTabBorders( const SfxItemSet& rSet )
755 CurrShell aCurr( this );
756 StartAllAction();
757 GetDoc()->SetTabBorders( *getShellCursor( false ), rSet );
758 EndAllActionAndCall();
761 void SwFEShell::SetTabLineStyle( const Color* pColor, bool bSetLine,
762 const editeng::SvxBorderLine* pBorderLine )
764 CurrShell aCurr( this );
765 StartAllAction();
766 GetDoc()->SetTabLineStyle( *getShellCursor( false ),
767 pColor, bSetLine, pBorderLine );
768 EndAllActionAndCall();
771 void SwFEShell::GetTabBorders( SfxItemSet& rSet ) const
773 SwDoc::GetTabBorders( *getShellCursor( false ), rSet );
776 void SwFEShell::SetBoxBackground( const SvxBrushItem &rNew )
778 CurrShell aCurr( this );
779 StartAllAction();
780 GetDoc()->SetBoxAttr( *getShellCursor( false ), rNew );
781 EndAllActionAndCall();
784 bool SwFEShell::GetBoxBackground( std::unique_ptr<SvxBrushItem>& rToFill ) const
786 std::unique_ptr<SfxPoolItem> aTemp = std::move(rToFill);
787 bool bRetval(SwDoc::GetBoxAttr(*getShellCursor( false ), aTemp));
788 rToFill.reset(static_cast<SvxBrushItem*>(aTemp.release()));
789 return bRetval;
792 void SwFEShell::SetBoxDirection( const SvxFrameDirectionItem& rNew )
794 CurrShell aCurr( this );
795 StartAllAction();
796 GetDoc()->SetBoxAttr( *getShellCursor( false ), rNew );
797 EndAllActionAndCall();
800 bool SwFEShell::GetBoxDirection( std::unique_ptr<SvxFrameDirectionItem>& rToFill ) const
802 std::unique_ptr<SfxPoolItem> aTemp = std::move(rToFill);
803 bool bRetval(SwDoc::GetBoxAttr(*getShellCursor( false ), aTemp));
804 rToFill.reset(static_cast<SvxFrameDirectionItem*>(aTemp.release()));
805 return bRetval;
808 void SwFEShell::SetBoxAlign( sal_uInt16 nAlign )
810 CurrShell aCurr( this );
811 StartAllAction();
812 GetDoc()->SetBoxAlign( *getShellCursor( false ), nAlign );
813 EndAllActionAndCall();
816 sal_uInt16 SwFEShell::GetBoxAlign() const
818 return SwDoc::GetBoxAlign( *getShellCursor( false ) );
821 void SwFEShell::SetTabBackground( const SvxBrushItem &rNew )
823 SwFrame *pFrame = GetCurrFrame();
824 if( !pFrame || !pFrame->IsInTab() )
825 return;
827 CurrShell aCurr( this );
828 StartAllAction();
829 GetDoc()->SetAttr( rNew, *pFrame->ImplFindTabFrame()->GetFormat() );
830 EndAllAction(); // no call, nothing changes!
831 GetDoc()->getIDocumentState().SetModified();
834 void SwFEShell::GetTabBackground( std::unique_ptr<SvxBrushItem>& rToFill ) const
836 SwFrame *pFrame = GetCurrFrame();
837 if( pFrame && pFrame->IsInTab() )
838 rToFill = pFrame->ImplFindTabFrame()->GetFormat()->makeBackgroundBrushItem();
841 bool SwFEShell::HasWholeTabSelection() const
843 // whole table selected?
844 if ( IsTableMode() )
846 SwSelBoxes aBoxes;
847 ::GetTableSelCrs( *this, aBoxes );
848 if( !aBoxes.empty() )
850 const SwTableNode *pTableNd = IsCursorInTable();
851 return pTableNd &&
852 aBoxes[0]->GetSttIdx() - 1 == pTableNd->EndOfSectionNode()->StartOfSectionIndex() &&
853 aBoxes.back()->GetSttNd()->EndOfSectionIndex() + 1 == pTableNd->EndOfSectionIndex();
856 return false;
859 bool SwFEShell::HasBoxSelection() const
861 if(!IsCursorInTable())
862 return false;
863 // whole table selected?
864 if( IsTableMode() )
865 return true;
866 SwPaM* pPam = GetCursor();
867 // empty boxes are also selected as the absence of selection
868 bool bChg = false;
869 if( pPam->GetPoint() == pPam->End())
871 bChg = true;
872 pPam->Exchange();
874 SwNode* pNd;
875 if( pPam->GetPoint()->nNode.GetIndex() -1 ==
876 ( pNd = &pPam->GetNode())->StartOfSectionIndex() &&
877 !pPam->GetPoint()->nContent.GetIndex() &&
878 pPam->GetMark()->nNode.GetIndex() + 1 ==
879 pNd->EndOfSectionIndex())
881 SwNodeIndex aIdx( *pNd->EndOfSectionNode(), -1 );
882 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
883 if( !pCNd )
885 pCNd = SwNodes::GoPrevious( &aIdx );
886 OSL_ENSURE( pCNd, "no ContentNode in box ??" );
888 if( pPam->GetMark()->nContent == pCNd->Len() )
890 if( bChg )
891 pPam->Exchange();
892 return true;
895 if( bChg )
896 pPam->Exchange();
897 return false;
900 void SwFEShell::ProtectCells()
902 SvxProtectItem aProt( RES_PROTECT );
903 aProt.SetContentProtect( true );
905 CurrShell aCurr( this );
906 StartAllAction();
908 GetDoc()->SetBoxAttr( *getShellCursor( false ), aProt );
910 if( !IsCursorReadonly() )
912 if( IsTableMode() )
913 ClearMark();
914 ParkCursorInTab();
916 EndAllActionAndCall();
919 // cancel table selection
920 void SwFEShell::UnProtectCells()
922 CurrShell aCurr( this );
923 StartAllAction();
925 SwSelBoxes aBoxes;
926 if( IsTableMode() )
927 ::GetTableSelCrs( *this, aBoxes );
928 else
930 SwFrame *pFrame = GetCurrFrame();
931 do {
932 pFrame = pFrame->GetUpper();
933 } while ( pFrame && !pFrame->IsCellFrame() );
934 if( pFrame )
936 SwTableBox *pBox = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox());
937 aBoxes.insert( pBox );
941 if( !aBoxes.empty() )
942 GetDoc()->UnProtectCells( aBoxes );
944 EndAllActionAndCall();
947 void SwFEShell::UnProtectTables()
949 CurrShell aCurr( this );
950 StartAllAction();
951 GetDoc()->UnProtectTables( *GetCursor() );
952 EndAllActionAndCall();
955 bool SwFEShell::HasTableAnyProtection( const OUString* pTableName,
956 bool* pFullTableProtection )
958 return GetDoc()->HasTableAnyProtection( GetCursor()->GetPoint(), pTableName,
959 pFullTableProtection );
962 bool SwFEShell::CanUnProtectCells() const
964 bool bUnProtectAvailable = false;
965 const SwTableNode *pTableNd = IsCursorInTable();
966 if( pTableNd && !pTableNd->IsProtect() )
968 SwSelBoxes aBoxes;
969 if( IsTableMode() )
970 ::GetTableSelCrs( *this, aBoxes );
971 else
973 SwFrame *pFrame = GetCurrFrame();
974 do {
975 pFrame = pFrame->GetUpper();
976 } while ( pFrame && !pFrame->IsCellFrame() );
977 if( pFrame )
979 SwTableBox *pBox = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox());
980 aBoxes.insert( pBox );
983 if( !aBoxes.empty() )
984 bUnProtectAvailable = ::HasProtectedCells( aBoxes );
986 return bUnProtectAvailable;
989 sal_uInt16 SwFEShell::GetRowsToRepeat() const
991 const SwFrame *pFrame = GetCurrFrame();
992 const SwTabFrame *pTab = pFrame ? pFrame->FindTabFrame() : nullptr;
993 if( pTab )
994 return pTab->GetTable()->GetRowsToRepeat();
995 return 0;
998 void SwFEShell::SetRowsToRepeat( sal_uInt16 nSet )
1000 SwFrame *pFrame = GetCurrFrame();
1001 SwTabFrame *pTab = pFrame ? pFrame->FindTabFrame() : nullptr;
1002 if( pTab && pTab->GetTable()->GetRowsToRepeat() != nSet )
1004 SwWait aWait( *GetDoc()->GetDocShell(), true );
1005 CurrShell aCurr( this );
1006 StartAllAction();
1007 GetDoc()->SetRowsToRepeat( *pTab->GetTable(), nSet );
1008 EndAllActionAndCall();
1012 // returns the number of rows consecutively selected from top
1013 static sal_uInt16 lcl_GetRowNumber( const SwPosition& rPos )
1015 Point aTmpPt;
1016 const SwContentNode *pNd;
1017 const SwContentFrame *pFrame;
1019 std::pair<Point, bool> const tmp(aTmpPt, false);
1020 pNd = rPos.nNode.GetNode().GetContentNode();
1021 if( nullptr != pNd )
1022 pFrame = pNd->getLayoutFrame(pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), &rPos, &tmp);
1023 else
1024 pFrame = nullptr;
1026 const SwFrame* pRow = (pFrame && pFrame->IsInTab()) ? pFrame->GetUpper() : nullptr;
1028 while (pRow && (!pRow->GetUpper() || !pRow->GetUpper()->IsTabFrame()))
1029 pRow = pRow->GetUpper();
1031 if (!pRow)
1032 return USHRT_MAX;
1034 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(pRow->GetUpper());
1035 const SwTableLine* pTabLine = static_cast<const SwRowFrame*>(pRow)->GetTabLine();
1036 sal_uInt16 nRet = USHRT_MAX;
1037 sal_uInt16 nI = 0;
1038 while ( sal::static_int_cast<SwTableLines::size_type>(nI) < pTabFrame->GetTable()->GetTabLines().size() )
1040 if ( pTabFrame->GetTable()->GetTabLines()[ nI ] == pTabLine )
1042 nRet = nI;
1043 break;
1045 ++nI;
1048 return nRet;
1051 sal_uInt16 SwFEShell::GetRowSelectionFromTop() const
1053 sal_uInt16 nRet = 0;
1054 const SwPaM* pPaM = IsTableMode() ? GetTableCursor() : GetCursor_();
1055 const sal_uInt16 nPtLine = lcl_GetRowNumber( *pPaM->GetPoint() );
1057 if ( !IsTableMode() )
1059 nRet = 0 == nPtLine ? 1 : 0;
1061 else
1063 const sal_uInt16 nMkLine = lcl_GetRowNumber( *pPaM->GetMark() );
1065 if ( ( nPtLine == 0 && nMkLine != USHRT_MAX ) ||
1066 ( nMkLine == 0 && nPtLine != USHRT_MAX ) )
1068 nRet = std::max( nPtLine, nMkLine ) + 1;
1072 return nRet;
1076 * 1. case: bRepeat = true
1077 * returns true if the current frame is located inside a table headline in
1078 * a follow frame
1080 * 2. case: bRepeat = false
1081 * returns true if the current frame is located inside a table headline OR
1082 * inside the first line of a table!!!
1084 bool SwFEShell::CheckHeadline( bool bRepeat ) const
1086 bool bRet = false;
1087 if ( !IsTableMode() )
1089 SwFrame *pFrame = GetCurrFrame(); // DONE MULTIIHEADER
1090 SwTabFrame* pTab = (pFrame && pFrame->IsInTab()) ? pFrame->FindTabFrame() : nullptr;
1091 if (pTab)
1093 if ( bRepeat )
1095 bRet = pTab->IsFollow() && pTab->IsInHeadline( *pFrame );
1097 else
1099 bRet = static_cast<SwLayoutFrame*>(pTab->Lower())->IsAnLower( pFrame ) ||
1100 pTab->IsInHeadline( *pFrame );
1104 return bRet;
1107 void SwFEShell::AdjustCellWidth( const bool bBalance, const bool bNoShrink )
1109 CurrShell aCurr( this );
1110 StartAllAction();
1112 // switch on wait-cursor, as we do not know how
1113 // much content is affected
1114 TableWait aWait(std::numeric_limits<size_t>::max(), nullptr,
1115 *GetDoc()->GetDocShell());
1117 GetDoc()->AdjustCellWidth( *getShellCursor( false ), bBalance, bNoShrink );
1118 EndAllActionAndCall();
1121 bool SwFEShell::IsAdjustCellWidthAllowed( bool bBalance ) const
1123 // at least one row with content should be contained in the selection
1125 SwFrame *pFrame = GetCurrFrame();
1126 if( !pFrame || !pFrame->IsInTab() )
1127 return false;
1129 SwSelBoxes aBoxes;
1130 ::GetTableSelCrs( *this, aBoxes );
1132 if ( bBalance )
1133 return aBoxes.size() > 1;
1135 if ( aBoxes.empty() )
1139 pFrame = pFrame->GetUpper();
1141 while (pFrame && !pFrame->IsCellFrame());
1143 if (!pFrame)
1144 return false;
1146 SwTableBox *pBox = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox());
1147 aBoxes.insert( pBox );
1150 for (size_t i = 0; i < aBoxes.size(); ++i)
1152 SwTableBox *pBox = aBoxes[i];
1153 if ( pBox->GetSttNd() )
1155 SwNodeIndex aIdx( *pBox->GetSttNd(), 1 );
1156 SwTextNode* pCNd = aIdx.GetNode().GetTextNode();
1157 if( !pCNd )
1158 pCNd = static_cast<SwTextNode*>(GetDoc()->GetNodes().GoNext( &aIdx ));
1160 while ( pCNd )
1162 if (!pCNd->GetText().isEmpty())
1163 return true;
1164 ++aIdx;
1165 pCNd = aIdx.GetNode().GetTextNode();
1169 return false;
1172 bool SwFEShell::SetTableStyle(const OUString& rStyleName)
1174 // make sure SwDoc has the style
1175 SwTableAutoFormat *pTableFormat = GetDoc()->GetTableStyles().FindAutoFormat(rStyleName);
1176 if (!pTableFormat)
1177 return false;
1179 SwTableNode *pTableNode = const_cast<SwTableNode*>(IsCursorInTable());
1180 if (!pTableNode)
1181 return false;
1183 // set the name & update
1184 return UpdateTableStyleFormatting(pTableNode, false, &rStyleName);
1187 // AutoFormat for the table/table selection
1188 bool SwFEShell::SetTableStyle(const SwTableAutoFormat& rStyle)
1190 // make sure SwDoc has the style
1191 GetDoc()->GetTableStyles().AddAutoFormat(rStyle);
1193 SwTableNode *pTableNode = const_cast<SwTableNode*>(IsCursorInTable());
1194 if (!pTableNode)
1195 return false;
1197 // set the name & update
1198 return UpdateTableStyleFormatting(pTableNode, false, &rStyle.GetName());
1201 bool SwFEShell::UpdateTableStyleFormatting(SwTableNode *pTableNode,
1202 bool bResetDirect, OUString const*const pStyleName)
1204 if (!pTableNode)
1206 pTableNode = const_cast<SwTableNode*>(IsCursorInTable());
1207 if (!pTableNode || pTableNode->GetTable().IsTableComplex())
1208 return false;
1211 OUString const aTableStyleName(pStyleName
1212 ? *pStyleName
1213 : pTableNode->GetTable().GetTableStyleName());
1214 SwTableAutoFormat* pTableStyle = GetDoc()->GetTableStyles().FindAutoFormat(aTableStyleName);
1215 if (!pTableStyle)
1216 return false;
1218 SwSelBoxes aBoxes;
1220 // whole table or only current selection
1221 if( IsTableMode() )
1222 ::GetTableSelCrs( *this, aBoxes );
1223 else
1225 const SwTableSortBoxes& rTBoxes = pTableNode->GetTable().GetTabSortBoxes();
1226 for (size_t n = 0; n < rTBoxes.size(); ++n)
1228 SwTableBox* pBox = rTBoxes[ n ];
1229 aBoxes.insert( pBox );
1233 bool bRet;
1234 if( !aBoxes.empty() )
1236 CurrShell aCurr( this );
1237 StartAllAction();
1238 bRet = GetDoc()->SetTableAutoFormat(
1239 aBoxes, *pTableStyle, bResetDirect, pStyleName != nullptr);
1240 ClearFEShellTabCols(*GetDoc(), nullptr);
1241 EndAllActionAndCall();
1243 else
1244 bRet = false;
1245 return bRet;
1248 bool SwFEShell::GetTableAutoFormat( SwTableAutoFormat& rGet )
1250 const SwTableNode *pTableNd = IsCursorInTable();
1251 if( !pTableNd || pTableNd->GetTable().IsTableComplex() )
1252 return false;
1254 SwSelBoxes aBoxes;
1256 if ( !IsTableMode() ) // if cursor are not current
1257 GetCursor();
1259 // whole table or only current selection
1260 if( IsTableMode() )
1261 ::GetTableSelCrs( *this, aBoxes );
1262 else
1264 const SwTableSortBoxes& rTBoxes = pTableNd->GetTable().GetTabSortBoxes();
1265 for (size_t n = 0; n < rTBoxes.size(); ++n)
1267 SwTableBox* pBox = rTBoxes[ n ];
1268 aBoxes.insert( pBox );
1272 return GetDoc()->GetTableAutoFormat( aBoxes, rGet );
1275 bool SwFEShell::DeleteTableSel()
1277 // check if SPoint/Mark of current cursor are in a table
1278 SwFrame *pFrame = GetCurrFrame();
1279 if( !pFrame || !pFrame->IsInTab() )
1280 return false;
1282 if( dynamic_cast< const SwDDETable* >(pFrame->ImplFindTabFrame()->GetTable()) != nullptr )
1284 ErrorHandler::HandleError( ERR_TBLDDECHG_ERROR, GetFrameWeld(GetDoc()->GetDocShell()),
1285 DialogMask::MessageInfo | DialogMask::ButtonsOk );
1286 return false;
1289 CurrShell aCurr( this );
1290 StartAllAction();
1292 // search boxes via the layout
1293 bool bRet;
1294 SwSelBoxes aBoxes;
1295 GetTableSelCrs( *this, aBoxes );
1296 if( !aBoxes.empty() )
1298 TableWait aWait( aBoxes.size(), pFrame, *GetDoc()->GetDocShell() );
1300 // cursor should be removed from deletion area.
1301 // Put them behind/on the table; via the document
1302 // position they'll be set to the old position
1303 while( !pFrame->IsCellFrame() )
1304 pFrame = pFrame->GetUpper();
1305 ParkCursor( SwNodeIndex( *static_cast<SwCellFrame*>(pFrame)->GetTabBox()->GetSttNd() ));
1307 bRet = GetDoc()->DeleteRowCol( aBoxes );
1309 ClearFEShellTabCols(*GetDoc(), nullptr);
1311 else
1312 bRet = false;
1313 EndAllActionAndCall();
1314 return bRet;
1317 size_t SwFEShell::GetCurTabColNum() const
1319 //!!!GetCurMouseTabColNum() mitpflegen!!!!
1320 SwFrame *pFrame = GetCurrFrame();
1321 OSL_ENSURE( pFrame, "Cursor parked?" );
1323 // check if SPoint/Mark of current cursor are in a table
1324 if (!pFrame || !pFrame->IsInTab())
1325 return 0;
1329 // JP 26.09.95: why compare with ContentFrame
1330 // and not with CellFrame ????
1331 pFrame = pFrame->GetUpper();
1332 } while (pFrame && !pFrame->IsCellFrame());
1334 if (!pFrame)
1335 return 0;
1337 size_t nRet = 0;
1339 SwRectFnSet aRectFnSet(pFrame);
1341 const SwPageFrame* pPage = pFrame->FindPageFrame();
1343 // get TabCols, as only via these we get to the position
1344 SwTabCols aTabCols;
1345 GetTabCols( aTabCols );
1347 if( pFrame->FindTabFrame()->IsRightToLeft() )
1349 tools::Long nX = aRectFnSet.GetRight(pFrame->getFrameArea()) - aRectFnSet.GetLeft(pPage->getFrameArea());
1351 const tools::Long nRight = aTabCols.GetLeftMin() + aTabCols.GetRight();
1353 if ( !::IsSame( nX, nRight ) )
1355 nX = nRight - nX + aTabCols.GetLeft();
1356 for ( size_t i = 0; i < aTabCols.Count(); ++i )
1357 if ( ::IsSame( nX, aTabCols[i] ) )
1359 nRet = i + 1;
1360 break;
1364 else
1366 const tools::Long nX = aRectFnSet.GetLeft(pFrame->getFrameArea()) -
1367 aRectFnSet.GetLeft(pPage->getFrameArea());
1369 const tools::Long nLeft = aTabCols.GetLeftMin();
1371 if ( !::IsSame( nX, nLeft + aTabCols.GetLeft() ) )
1373 for ( size_t i = 0; i < aTabCols.Count(); ++i )
1374 if ( ::IsSame( nX, nLeft + aTabCols[i] ) )
1376 nRet = i + 1;
1377 break;
1381 return nRet;
1384 static const SwFrame *lcl_FindFrameInTab( const SwLayoutFrame *pLay, const Point &rPt, SwTwips nFuzzy )
1386 const SwFrame *pFrame = pLay->Lower();
1388 while( pFrame && pLay->IsAnLower( pFrame ) )
1390 if ( pFrame->getFrameArea().IsNear( rPt, nFuzzy ) )
1392 if ( pFrame->IsLayoutFrame() )
1394 const SwFrame *pTmp = ::lcl_FindFrameInTab( static_cast<const SwLayoutFrame*>(pFrame), rPt, nFuzzy );
1395 if ( pTmp )
1396 return pTmp;
1399 return pFrame;
1402 pFrame = pFrame->FindNext();
1405 return nullptr;
1408 static const SwCellFrame *lcl_FindFrame( const SwLayoutFrame *pLay, const Point &rPt,
1409 SwTwips nFuzzy, bool* pbRow, bool* pbCol )
1411 // bMouseMoveRowCols :
1412 // Method is called for
1413 // - Moving columns/rows with the mouse or
1414 // - Enhanced table selection
1415 const bool bMouseMoveRowCols = nullptr == pbCol;
1417 bool bCloseToRow = false;
1418 bool bCloseToCol = false;
1420 const SwFrame *pFrame = pLay->ContainsContent();
1421 const SwFrame* pRet = nullptr;
1423 if ( pFrame )
1427 if ( pFrame->IsInTab() )
1428 pFrame = const_cast<SwFrame*>(pFrame)->ImplFindTabFrame();
1430 if (!pFrame)
1431 break;
1433 if ( pFrame->IsTabFrame() )
1435 Point aPt( rPt );
1436 bool bSearchForFrameInTab = true;
1437 SwTwips nTmpFuzzy = nFuzzy;
1439 if ( !bMouseMoveRowCols )
1441 // We ignore nested tables for the enhanced table selection:
1442 while ( pFrame->GetUpper()->IsInTab() )
1443 pFrame = pFrame->GetUpper()->FindTabFrame();
1445 // We first check if the given point is 'close' to the left or top
1446 // border of the table frame:
1447 OSL_ENSURE( pFrame, "Nested table frame without outer table" );
1448 SwRectFnSet aRectFnSet(pFrame);
1449 const bool bRTL = pFrame->IsRightToLeft();
1451 SwRect aTabRect = pFrame->getFramePrintArea();
1452 aTabRect.Pos() += pFrame->getFrameArea().Pos();
1454 const SwTwips nLeft = bRTL ?
1455 aRectFnSet.GetRight(aTabRect) :
1456 aRectFnSet.GetLeft(aTabRect);
1457 const SwTwips nTop = aRectFnSet.GetTop(aTabRect);
1459 SwTwips const rPointX = aRectFnSet.IsVert() ? aPt.Y() : aPt.X();
1460 SwTwips const rPointY = aRectFnSet.IsVert() ? aPt.X() : aPt.Y();
1462 const SwTwips nXDiff = aRectFnSet.XDiff( nLeft, rPointX ) * ( bRTL ? -1 : 1 );
1463 const SwTwips nYDiff = aRectFnSet.YDiff( nTop, rPointY );
1465 bCloseToRow = nXDiff >= 0 && nXDiff < nFuzzy;
1466 bCloseToCol = nYDiff >= 0 && nYDiff < nFuzzy;
1468 if ( bCloseToCol && 2 * nYDiff > nFuzzy )
1470 const SwFrame* pPrev = pFrame->GetPrev();
1471 if ( pPrev )
1473 SwRect aPrevRect = pPrev->getFramePrintArea();
1474 aPrevRect.Pos() += pPrev->getFrameArea().Pos();
1476 if( aPrevRect.IsInside( rPt ) )
1478 bCloseToCol = false;
1484 // If we found the point to be 'close' to the left or top border
1485 // of the table frame, we adjust the point to be on that border:
1486 if ( bCloseToRow && bCloseToCol )
1487 aPt = bRTL ? aTabRect.TopRight() : aRectFnSet.GetPos(aTabRect);
1488 else if ( bCloseToRow )
1489 aRectFnSet.IsVert() ? aPt.setY(nLeft) : aPt.setX(nLeft);
1490 else if ( bCloseToCol )
1491 aRectFnSet.IsVert() ? aPt.setX(nTop) : aPt.setY(nTop);
1493 if ( !bCloseToRow && !bCloseToCol )
1494 bSearchForFrameInTab = false;
1496 // Since the point has been adjusted, we call lcl_FindFrameInTab()
1497 // with a fuzzy value of 1:
1498 nTmpFuzzy = 1;
1501 const SwFrame* pTmp = bSearchForFrameInTab ?
1502 ::lcl_FindFrameInTab( static_cast<const SwLayoutFrame*>(pFrame), aPt, nTmpFuzzy ) :
1503 nullptr;
1505 if ( pTmp )
1507 pFrame = pTmp;
1508 break;
1511 pFrame = pFrame->FindNextCnt();
1513 } while ( pFrame && pLay->IsAnLower( pFrame ) );
1516 if ( pFrame && pFrame->IsInTab() && pLay->IsAnLower( pFrame ) )
1520 // We allow mouse drag of table borders within nested tables,
1521 // but disallow hotspot selection of nested tables.
1522 if ( bMouseMoveRowCols )
1524 // find the next cell frame
1525 while ( pFrame && !pFrame->IsCellFrame() )
1526 pFrame = pFrame->GetUpper();
1528 else
1530 // find the most upper cell frame:
1531 while ( pFrame &&
1532 ( !pFrame->IsCellFrame() ||
1533 !pFrame->GetUpper()->GetUpper()->IsTabFrame() ||
1534 pFrame->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) )
1535 pFrame = pFrame->GetUpper();
1538 if ( pFrame ) // Note: this condition should be the same like the while condition!!!
1540 // #i32329# Enhanced table selection
1541 // used for hotspot selection of tab/cols/rows
1542 if ( !bMouseMoveRowCols )
1545 OSL_ENSURE( pbCol && pbRow, "pbCol or pbRow missing" );
1547 if ( bCloseToRow || bCloseToCol )
1549 *pbRow = bCloseToRow;
1550 *pbCol = bCloseToCol;
1551 pRet = pFrame;
1552 break;
1555 else
1557 // used for mouse move of columns/rows
1558 const SwTabFrame* pTabFrame = pFrame->FindTabFrame();
1559 SwRect aTabRect = pTabFrame->getFramePrintArea();
1560 aTabRect.Pos() += pTabFrame->getFrameArea().Pos();
1562 SwRectFnSet aRectFnSet(pTabFrame);
1564 const SwTwips nTabTop = aRectFnSet.GetTop(aTabRect);
1565 const SwTwips nMouseTop = aRectFnSet.IsVert() ? rPt.X() : rPt.Y();
1567 // Do not allow to drag upper table border:
1568 if ( !::IsSame( nTabTop, nMouseTop ) )
1570 if ( ::IsSame( pFrame->getFrameArea().Left(), rPt.X() ) ||
1571 ::IsSame( pFrame->getFrameArea().Right(),rPt.X() ) )
1573 if ( pbRow ) *pbRow = false;
1574 pRet = pFrame;
1575 break;
1577 if ( ::IsSame( pFrame->getFrameArea().Top(), rPt.Y() ) ||
1578 ::IsSame( pFrame->getFrameArea().Bottom(),rPt.Y() ) )
1580 if ( pbRow ) *pbRow = true;
1581 pRet = pFrame;
1582 break;
1587 pFrame = pFrame->GetUpper();
1589 } while ( pFrame );
1592 // robust:
1593 OSL_ENSURE( !pRet || pRet->IsCellFrame(), "lcl_FindFrame() is supposed to find a cell frame!" );
1594 return pRet && pRet->IsCellFrame() ? static_cast<const SwCellFrame*>(pRet) : nullptr;
1597 // pbCol = 0 => Used for moving table rows/cols with mouse
1598 // pbCol != 0 => Used for selecting table/rows/cols
1600 #define ENHANCED_TABLE_SELECTION_FUZZY 10
1602 const SwFrame* SwFEShell::GetBox( const Point &rPt, bool* pbRow, bool* pbCol ) const
1604 const SwPageFrame *pPage = static_cast<SwPageFrame*>(GetLayout()->Lower());
1605 vcl::Window* pOutWin = GetWin();
1606 SwTwips nFuzzy = COLFUZZY;
1607 if( pOutWin )
1609 // #i32329# Enhanced table selection
1610 SwTwips nSize = pbCol ? ENHANCED_TABLE_SELECTION_FUZZY : RULER_MOUSE_MARGINWIDTH;
1611 Size aTmp( nSize, nSize );
1612 aTmp = pOutWin->PixelToLogic( aTmp );
1613 nFuzzy = aTmp.Width();
1616 while ( pPage && !pPage->getFrameArea().IsNear( rPt, nFuzzy ) )
1617 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
1619 const SwCellFrame *pFrame = nullptr;
1620 if ( pPage )
1622 // We cannot search the box by GetModelPositionForViewPoint or GetContentPos.
1623 // This would lead to a performance collapse for documents
1624 // with a lot of paragraphs/tables on one page
1625 //(BrowseMode!)
1627 // check flys first
1628 if ( pPage->GetSortedObjs() )
1630 for ( size_t i = 0; !pFrame && i < pPage->GetSortedObjs()->size(); ++i )
1632 SwAnchoredObject* pObj = (*pPage->GetSortedObjs())[i];
1633 if ( auto pFlyFrame = dynamic_cast<SwFlyFrame*>( pObj) )
1635 pFrame = lcl_FindFrame( pFlyFrame, rPt, nFuzzy, pbRow, pbCol );
1639 const SwLayoutFrame *pLay = static_cast<const SwLayoutFrame*>(pPage->Lower());
1640 while ( pLay && !pFrame )
1642 pFrame = lcl_FindFrame( pLay, rPt, nFuzzy, pbRow, pbCol );
1643 pLay = static_cast<const SwLayoutFrame*>(pLay->GetNext());
1646 return pFrame;
1649 /* Helper function*/
1650 /* calculated the distance between Point rC and Line Segment (rA, rB) */
1651 static double lcl_DistancePoint2Segment( const Point& rA, const Point& rB, const Point& rC )
1653 double nRet = 0;
1655 const basegfx::B2DVector aBC( rC.X() - rB.X(), rC.Y() - rB.Y() );
1656 const basegfx::B2DVector aAB( rB.X() - rA.X(), rB.Y() - rA.Y() );
1657 const double nDot1 = aBC.scalar( aAB );
1659 if ( nDot1 > 0 ) // check outside case 1
1660 nRet = aBC.getLength();
1661 else
1663 const basegfx::B2DVector aAC( rC.X() - rA.X(), rC.Y() - rA.Y() );
1664 const basegfx::B2DVector aBA( rA.X() - rB.X(), rA.Y() - rB.Y() );
1665 const double nDot2 = aAC.scalar( aBA );
1667 if ( nDot2 > 0 ) // check outside case 2
1668 nRet = aAC.getLength();
1669 else
1671 const double nDiv = aAB.getLength();
1672 nRet = nDiv ? aAB.cross( aAC ) / nDiv : 0;
1676 return std::abs(nRet);
1679 /* Helper function*/
1680 static Point lcl_ProjectOntoClosestTableFrame( const SwTabFrame& rTab, const Point& rPoint, bool bRowDrag )
1682 Point aRet( rPoint );
1683 const SwTabFrame* pCurrentTab = &rTab;
1684 const bool bVert = pCurrentTab->IsVertical();
1685 const bool bRTL = pCurrentTab->IsRightToLeft();
1687 // Western Layout:
1688 // bRowDrag = true => compare to left border of table
1689 // bRowDrag = false => compare to top border of table
1691 // Asian Layout:
1692 // bRowDrag = true => compare to right border of table
1693 // bRowDrag = false => compare to top border of table
1695 // RTL Layout:
1696 // bRowDrag = true => compare to right border of table
1697 // bRowDrag = false => compare to top border of table
1698 bool bLeft = false;
1699 bool bRight = false;
1701 if ( bRowDrag )
1703 if ( bVert || bRTL )
1704 bRight = true;
1705 else
1706 bLeft = true;
1709 // used to find the minimal distance
1710 double nMin = -1;
1711 Point aMin1;
1712 Point aMin2;
1714 Point aS1;
1715 Point aS2;
1717 while ( pCurrentTab )
1719 SwRect aTabRect( pCurrentTab->getFramePrintArea() );
1720 aTabRect += pCurrentTab->getFrameArea().Pos();
1722 if ( bLeft )
1724 // distance to left table border
1725 aS1 = aTabRect.TopLeft();
1726 aS2 = aTabRect.BottomLeft();
1728 else if ( bRight )
1730 // distance to right table border
1731 aS1 = aTabRect.TopRight();
1732 aS2 = aTabRect.BottomRight();
1734 else //if ( bTop )
1736 // distance to top table border
1737 aS1 = aTabRect.TopLeft();
1738 aS2 = aTabRect.TopRight();
1741 const double nDist = lcl_DistancePoint2Segment( aS1, aS2, rPoint );
1743 if ( nDist < nMin || -1 == nMin )
1745 aMin1 = aS1;
1746 aMin2 = aS2;
1747 nMin = nDist;
1750 pCurrentTab = pCurrentTab->GetFollow();
1753 // project onto closest line:
1754 if ( bLeft || bRight )
1756 aRet.setX(aMin1.getX());
1757 if ( aRet.getY() > aMin2.getY() )
1758 aRet.setY(aMin2.getY());
1759 else if ( aRet.getY() < aMin1.getY() )
1760 aRet.setY(aMin1.getY());
1762 else
1764 aRet.setY(aMin1.getY());
1765 if ( aRet.getX() > aMin2.getX() )
1766 aRet.setX(aMin2.getX());
1767 else if ( aRet.getX() < aMin1.getX() )
1768 aRet.setX(aMin1.getX());
1771 return aRet;
1774 // #i32329# Enhanced table selection
1775 bool SwFEShell::SelTableRowCol( const Point& rPt, const Point* pEnd, bool bRowDrag )
1777 bool bRet = false;
1778 Point aEndPt;
1779 if ( pEnd )
1780 aEndPt = *pEnd;
1782 SwPosition* ppPos[2] = { nullptr, nullptr };
1783 Point paPt [2] = { rPt, aEndPt };
1784 bool pbRow[2] = { false, false };
1785 bool pbCol[2] = { false, false };
1787 // pEnd is set during dragging.
1788 for ( sal_uInt16 i = 0; i < ( pEnd ? 2 : 1 ); ++i )
1790 const SwCellFrame* pFrame =
1791 static_cast<const SwCellFrame*>(GetBox( paPt[i], &pbRow[i], &pbCol[i] ) );
1793 if( pFrame )
1795 while( pFrame && pFrame->Lower() && pFrame->Lower()->IsRowFrame() )
1796 pFrame = static_cast<const SwCellFrame*>( static_cast<const SwLayoutFrame*>( pFrame->Lower() )->Lower() );
1797 if( pFrame && pFrame->GetTabBox()->GetSttNd() &&
1798 pFrame->GetTabBox()->GetSttNd()->IsInProtectSect() )
1799 pFrame = nullptr;
1802 if ( pFrame )
1804 const SwContentFrame* pContent = ::GetCellContent( *pFrame );
1806 if ( pContent && pContent->IsTextFrame() )
1809 ppPos[i] = new SwPosition(static_cast<SwTextFrame const*>(pContent)->MapViewToModelPos(TextFrameIndex(0)));
1811 // paPt[i] will not be used any longer, now we use it to store
1812 // a position inside the content frame
1813 paPt[i] = pContent->getFrameArea().Center();
1817 // no calculation of end frame if start frame has not been found.
1818 if ( 1 == i || !ppPos[0] || !pEnd || !pFrame )
1819 break;
1821 // find 'closest' table frame to pEnd:
1822 const SwTabFrame* pCurrentTab = pFrame->FindTabFrame();
1823 if ( pCurrentTab->IsFollow() )
1824 pCurrentTab = pCurrentTab->FindMaster( true );
1826 const Point aProjection = lcl_ProjectOntoClosestTableFrame( *pCurrentTab, *pEnd, bRowDrag );
1827 paPt[1] = aProjection;
1830 if ( ppPos[0] )
1832 SwShellCursor* pCursor = GetCursor_();
1833 SwCursorSaveState aSaveState( *pCursor );
1834 SwPosition aOldPos( *pCursor->GetPoint() );
1836 pCursor->DeleteMark();
1837 *pCursor->GetPoint() = *ppPos[0];
1838 pCursor->GetPtPos() = paPt[0];
1840 if ( !pCursor->IsInProtectTable() )
1842 bool bNewSelection = true;
1844 if ( ppPos[1] )
1846 if ( ppPos[1]->nNode.GetNode().StartOfSectionNode() !=
1847 aOldPos.nNode.GetNode().StartOfSectionNode() )
1849 pCursor->SetMark();
1850 SwCursorSaveState aSaveState2( *pCursor );
1851 *pCursor->GetPoint() = *ppPos[1];
1852 pCursor->GetPtPos() = paPt[1];
1854 if ( pCursor->IsInProtectTable( false, false ) )
1856 pCursor->RestoreSavePos();
1857 bNewSelection = false;
1860 else
1862 pCursor->RestoreSavePos();
1863 bNewSelection = false;
1867 if ( bNewSelection )
1869 // #i35543# SelTableRowCol should remove any existing
1870 // table cursor:
1871 if ( IsTableMode() )
1872 TableCursorToCursor();
1874 if ( pbRow[0] && pbCol[0] )
1875 bRet = SwCursorShell::SelTable();
1876 else if ( pbRow[0] )
1877 bRet = SwCursorShell::SelTableRowOrCol( true, true );
1878 else if ( pbCol[0] )
1879 bRet = SwCursorShell::SelTableRowOrCol( false, true );
1881 else
1882 bRet = true;
1885 delete ppPos[0];
1886 delete ppPos[1];
1889 return bRet;
1892 SwTab SwFEShell::WhichMouseTabCol( const Point &rPt ) const
1894 SwTab nRet = SwTab::COL_NONE;
1895 bool bRow = false;
1896 bool bCol = false;
1897 bool bSelect = false;
1899 // First try: Do we get the row/col move cursor?
1900 const SwCellFrame* pFrame = static_cast<const SwCellFrame*>(GetBox( rPt, &bRow ));
1902 if ( !pFrame )
1904 // Second try: Do we get the row/col/tab selection cursor?
1905 pFrame = static_cast<const SwCellFrame*>(GetBox( rPt, &bRow, &bCol ));
1906 bSelect = true;
1909 if( pFrame )
1911 while( pFrame && pFrame->Lower() && pFrame->Lower()->IsRowFrame() )
1912 pFrame = static_cast<const SwCellFrame*>(static_cast<const SwLayoutFrame*>(pFrame->Lower())->Lower());
1913 if( pFrame && pFrame->GetTabBox()->GetSttNd() &&
1914 pFrame->GetTabBox()->GetSttNd()->IsInProtectSect() )
1915 pFrame = nullptr;
1918 if( pFrame )
1920 if ( !bSelect )
1922 if ( pFrame->IsVertical() )
1923 nRet = bRow ? SwTab::COL_VERT : SwTab::ROW_VERT;
1924 else
1925 nRet = bRow ? SwTab::ROW_HORI : SwTab::COL_HORI;
1927 else
1929 const SwTabFrame* pTabFrame = pFrame->FindTabFrame();
1930 if ( pTabFrame->IsVertical() )
1932 if ( bRow && bCol )
1934 nRet = SwTab::SEL_VERT;
1936 else if ( bRow )
1938 nRet = SwTab::ROWSEL_VERT;
1940 else if ( bCol )
1942 nRet = SwTab::COLSEL_VERT;
1945 else
1947 if ( bRow && bCol )
1949 nRet = pTabFrame->IsRightToLeft() ?
1950 SwTab::SEL_HORI_RTL :
1951 SwTab::SEL_HORI;
1953 else if ( bRow )
1955 nRet = pTabFrame->IsRightToLeft() ?
1956 SwTab::ROWSEL_HORI_RTL :
1957 SwTab::ROWSEL_HORI;
1959 else if ( bCol )
1961 nRet = SwTab::COLSEL_HORI;
1967 return nRet;
1970 // -> #i23726#
1971 SwTextNode * SwFEShell::GetNumRuleNodeAtPos( const Point &rPt)
1973 SwTextNode * pResult = nullptr;
1975 SwContentAtPos aContentAtPos(IsAttrAtPos::NumLabel);
1977 if( GetContentAtPos(rPt, aContentAtPos) && aContentAtPos.aFnd.pNode)
1978 pResult = aContentAtPos.aFnd.pNode->GetTextNode();
1980 return pResult;
1983 bool SwFEShell::IsNumLabel( const Point &rPt, int nMaxOffset )
1985 bool bResult = false;
1987 SwContentAtPos aContentAtPos(IsAttrAtPos::NumLabel);
1989 if( GetContentAtPos(rPt, aContentAtPos))
1991 if ((nMaxOffset >= 0 && aContentAtPos.nDist <= nMaxOffset) ||
1992 (nMaxOffset < 0))
1993 bResult = true;
1996 return bResult;
1998 // <- #i23726#
2000 // #i42921#
2001 bool SwFEShell::IsVerticalModeAtNdAndPos( const SwTextNode& _rTextNode,
2002 const Point& _rDocPos )
2004 bool bRet( false );
2006 const SvxFrameDirection nTextDir =
2007 _rTextNode.GetTextDirection( SwPosition(_rTextNode), &_rDocPos );
2008 switch ( nTextDir )
2010 case SvxFrameDirection::Unknown:
2011 case SvxFrameDirection::Horizontal_RL_TB:
2012 case SvxFrameDirection::Horizontal_LR_TB:
2014 bRet = false;
2016 break;
2017 case SvxFrameDirection::Vertical_LR_TB:
2018 case SvxFrameDirection::Vertical_RL_TB:
2020 bRet = true;
2022 break;
2023 default: break;
2026 return bRet;
2029 void SwFEShell::GetMouseTabCols( SwTabCols &rToFill, const Point &rPt ) const
2031 const SwFrame *pBox = GetBox( rPt );
2032 if ( pBox )
2033 GetTabCols_( rToFill, pBox );
2036 void SwFEShell::SetMouseTabCols( const SwTabCols &rNew, bool bCurRowOnly,
2037 const Point &rPt )
2039 const SwFrame *pBox = GetBox( rPt );
2040 if( pBox )
2042 CurrShell aCurr( this );
2043 StartAllAction();
2044 GetDoc()->SetTabCols( rNew, bCurRowOnly, static_cast<const SwCellFrame*>(pBox) );
2045 EndAllActionAndCall();
2049 sal_uInt16 SwFEShell::GetCurMouseColNum( const Point &rPt ) const
2051 return GetCurColNum_( GetBox( rPt ), nullptr );
2054 size_t SwFEShell::GetCurMouseTabColNum( const Point &rPt ) const
2056 //!!!GetCurTabColNum() mitpflegen!!!!
2057 size_t nRet = 0;
2059 const SwFrame *pFrame = GetBox( rPt );
2060 OSL_ENSURE( pFrame, "Table not found" );
2061 if( pFrame )
2063 const tools::Long nX = pFrame->getFrameArea().Left();
2065 // get TabCols, only via these we get the position
2066 SwTabCols aTabCols;
2067 GetMouseTabCols( aTabCols, rPt );
2069 const tools::Long nLeft = aTabCols.GetLeftMin();
2071 if ( !::IsSame( nX, nLeft + aTabCols.GetLeft() ) )
2073 for ( size_t i = 0; i < aTabCols.Count(); ++i )
2074 if ( ::IsSame( nX, nLeft + aTabCols[i] ) )
2076 nRet = i + 1;
2077 break;
2081 return nRet;
2084 void ClearFEShellTabCols(SwDoc & rDoc, SwTabFrame const*const pFrame)
2086 auto const pShell(rDoc.getIDocumentLayoutAccess().GetCurrentViewShell());
2087 if (pShell)
2089 for (SwViewShell& rCurrentShell : pShell->GetRingContainer())
2091 if (auto const pFE = dynamic_cast<SwFEShell *>(&rCurrentShell))
2093 pFE->ClearColumnRowCache(pFrame);
2099 void SwFEShell::ClearColumnRowCache(SwTabFrame const*const pFrame)
2101 if (m_pColumnCache)
2103 if (pFrame == nullptr || pFrame == m_pColumnCache->pLastTabFrame)
2105 m_pColumnCache.reset();
2108 if (m_pRowCache)
2110 if (pFrame == nullptr || pFrame == m_pRowCache->pLastTabFrame)
2112 m_pRowCache.reset();
2117 void SwFEShell::GetTableAttr( SfxItemSet &rSet ) const
2119 SwFrame *pFrame = GetCurrFrame();
2120 if( pFrame && pFrame->IsInTab() )
2121 rSet.Put( pFrame->ImplFindTabFrame()->GetFormat()->GetAttrSet() );
2124 void SwFEShell::SetTableAttr( const SfxItemSet &rNew )
2126 SwFrame *pFrame = GetCurrFrame();
2127 if( pFrame && pFrame->IsInTab() )
2129 CurrShell aCurr( this );
2130 StartAllAction();
2131 SwTabFrame *pTab = pFrame->FindTabFrame();
2132 pTab->GetTable()->SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());
2133 GetDoc()->SetAttr( rNew, *pTab->GetFormat() );
2134 GetDoc()->getIDocumentState().SetModified();
2135 EndAllActionAndCall();
2139 // change a cell width/cell height/column width/row height
2140 void SwFEShell::SetColRowWidthHeight( TableChgWidthHeightType eType, sal_uInt16 nDiff )
2142 SwFrame *pFrame = GetCurrFrame();
2143 if( !pFrame || !pFrame->IsInTab() )
2144 return;
2146 CurrShell aCurr( this );
2147 StartAllAction();
2149 do {
2150 pFrame = pFrame->GetUpper();
2151 } while( !pFrame->IsCellFrame() );
2153 SwTabFrame *pTab = pFrame->ImplFindTabFrame();
2155 // if the table is in relative values (USHRT_MAX)
2156 // then it should be recalculated to absolute values now
2157 const SwFormatFrameSize& rTableFrameSz = pTab->GetFormat()->GetFrameSize();
2158 SwRectFnSet aRectFnSet(pTab);
2159 tools::Long nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
2160 TableChgWidthHeightType eTypePos = extractPosition(eType);
2161 if( TableChgMode::VarWidthChangeAbs == pTab->GetTable()->GetTableChgMode() &&
2162 ( eTypePos == TableChgWidthHeightType::ColLeft || eTypePos == TableChgWidthHeightType::ColRight ) &&
2163 text::HoriOrientation::NONE == pTab->GetFormat()->GetHoriOrient().GetHoriOrient() &&
2164 nPrtWidth != rTableFrameSz.GetWidth() )
2166 SwFormatFrameSize aSz( rTableFrameSz );
2167 aSz.SetWidth( pTab->getFramePrintArea().Width() );
2168 pTab->GetFormat()->SetFormatAttr( aSz );
2171 SwTwips nLogDiff = nDiff;
2172 nLogDiff *= pTab->GetFormat()->GetFrameSize().GetWidth();
2173 nLogDiff /= nPrtWidth;
2175 /** The cells are destroyed in here */
2176 GetDoc()->SetColRowWidthHeight(
2177 *const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox()),
2178 eType, nDiff, nLogDiff );
2180 ClearFEShellTabCols(*GetDoc(), nullptr);
2181 EndAllActionAndCall();
2184 static bool lcl_IsFormulaSelBoxes( const SwTable& rTable, const SwTableBoxFormula& rFormula,
2185 SwCellFrames& rCells )
2187 SwTableBoxFormula aTmp( rFormula );
2188 SwSelBoxes aBoxes;
2189 aTmp.GetBoxesOfFormula(rTable, aBoxes);
2190 for (size_t nSelBoxes = aBoxes.size(); nSelBoxes; )
2192 SwTableBox* pBox = aBoxes[ --nSelBoxes ];
2194 if( std::none_of(rCells.begin(), rCells.end(), [&pBox](SwCellFrame* pFrame) { return pFrame->GetTabBox() == pBox; }) )
2195 return false;
2198 return true;
2201 // ask formula for auto-sum
2202 void SwFEShell::GetAutoSum( OUString& rFormula ) const
2204 SwFrame *pFrame = GetCurrFrame();
2205 SwTabFrame *pTab = pFrame ? pFrame->ImplFindTabFrame() : nullptr;
2206 if( !pTab )
2207 return;
2209 SwCellFrames aCells;
2210 OUString sFields;
2211 if( ::GetAutoSumSel( *this, aCells ))
2213 sal_uInt16 nW = 0;
2214 for( size_t n = aCells.size(); n; )
2216 SwCellFrame* pCFrame = aCells[ --n ];
2217 sal_uInt16 nBoxW = pCFrame->GetTabBox()->IsFormulaOrValueBox();
2218 if( !nBoxW )
2219 break;
2221 if( !nW )
2223 if( USHRT_MAX == nBoxW )
2224 continue; // skip space at beginning
2226 // formula only if box is contained
2227 if( RES_BOXATR_FORMULA == nBoxW &&
2228 !::lcl_IsFormulaSelBoxes( *pTab->GetTable(), pCFrame->
2229 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells))
2231 nW = RES_BOXATR_VALUE;
2232 // restore previous spaces!
2233 for( size_t i = aCells.size(); n+1 < i; )
2235 sFields = "|<" + aCells[--i]->GetTabBox()->GetName() + ">"
2236 + sFields;
2239 else
2240 nW = nBoxW;
2242 else if( RES_BOXATR_VALUE == nW )
2244 // search for values, Value/Formula/Text found -> include
2245 if( RES_BOXATR_FORMULA == nBoxW &&
2246 ::lcl_IsFormulaSelBoxes( *pTab->GetTable(), pCFrame->
2247 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells ))
2248 break;
2249 else if( USHRT_MAX != nBoxW )
2250 sFields = OUStringChar(cListDelim) + sFields;
2251 else
2252 break;
2254 else if( RES_BOXATR_FORMULA == nW )
2256 // only continue search when the current formula points to
2257 // all boxes contained in the selection
2258 if( RES_BOXATR_FORMULA == nBoxW )
2260 if( !::lcl_IsFormulaSelBoxes( *pTab->GetTable(), pCFrame->
2261 GetTabBox()->GetFrameFormat()->GetTableBoxFormula(), aCells ))
2263 // redo only for values!
2265 nW = RES_BOXATR_VALUE;
2266 sFields.clear();
2267 // restore previous spaces!
2268 for( size_t i = aCells.size(); n+1 < i; )
2270 sFields = "|<" + aCells[--i]->GetTabBox()->GetName() + ">"
2271 + sFields;
2274 else
2275 sFields = OUStringChar(cListDelim) + sFields;
2277 else if( USHRT_MAX == nBoxW )
2278 break;
2279 else
2280 continue; // ignore this box
2282 else
2283 // all other stuff terminates the loop
2284 // possibly allow texts??
2285 break;
2287 sFields = "<" + pCFrame->GetTabBox()->GetName() + ">" + sFields;
2291 rFormula = OUString::createFromAscii( sCalc_Sum );
2292 if (!sFields.isEmpty())
2294 rFormula += "(" + sFields + ")";
2298 bool SwFEShell::IsTableRightToLeft() const
2300 SwFrame *pFrame = GetCurrFrame();
2301 SwTabFrame *pTab = (pFrame && pFrame->IsInTab()) ? pFrame->ImplFindTabFrame() : nullptr;
2302 if (!pTab)
2303 return false;
2304 return pTab->IsRightToLeft();
2307 bool SwFEShell::IsMouseTableRightToLeft(const Point &rPt) const
2309 SwFrame *pFrame = const_cast<SwFrame *>(GetBox( rPt ));
2310 const SwTabFrame* pTabFrame = pFrame ? pFrame->ImplFindTabFrame() : nullptr;
2311 OSL_ENSURE( pTabFrame, "Table not found" );
2312 return pTabFrame && pTabFrame->IsRightToLeft();
2315 bool SwFEShell::IsTableVertical() const
2317 SwFrame *pFrame = GetCurrFrame();
2318 SwTabFrame *pTab = (pFrame && pFrame->IsInTab()) ? pFrame->ImplFindTabFrame() : nullptr;
2319 if (!pTab)
2320 return false;
2321 return pTab->IsVertical();
2324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */