summaryrefslogtreecommitdiffstats
path: root/sw/source/core/crsr/trvltbl.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sw/source/core/crsr/trvltbl.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/crsr/trvltbl.cxx')
-rw-r--r--sw/source/core/crsr/trvltbl.cxx929
1 files changed, 929 insertions, 0 deletions
diff --git a/sw/source/core/crsr/trvltbl.cxx b/sw/source/core/crsr/trvltbl.cxx
new file mode 100644
index 000000000..12b8eae08
--- /dev/null
+++ b/sw/source/core/crsr/trvltbl.cxx
@@ -0,0 +1,929 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hintids.hxx>
+#include <crsrsh.hxx>
+#include <doc.hxx>
+#include <cntfrm.hxx>
+#include <editsh.hxx>
+#include <pam.hxx>
+#include <swtable.hxx>
+#include <frmfmt.hxx>
+#include <viscrs.hxx>
+#include "callnk.hxx"
+#include <tabfrm.hxx>
+#include <ndtxt.hxx>
+#include <shellres.hxx>
+#include <cellfrm.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <osl/diagnose.h>
+#include <svx/srchdlg.hxx>
+
+/// set cursor into next/previous cell
+bool SwCursorShell::GoNextCell( bool bAppendLine )
+{
+ bool bRet = false;
+ const SwTableNode* pTableNd = nullptr;
+
+ if( IsTableMode() || nullptr != ( pTableNd = IsCursorInTable() ))
+ {
+ SwCursor* pCursor = m_pTableCursor ? m_pTableCursor : m_pCurrentCursor;
+ SwCallLink aLk( *this ); // watch Cursor-Moves
+ bRet = true;
+
+ // Check if we have to move the cursor to a covered cell before
+ // proceeding:
+ const SwNode* pTableBoxStartNode = pCursor->GetNode().FindTableBoxStartNode();
+ const SwTableBox* pTableBox = nullptr;
+
+ if ( pCursor->GetCursorRowSpanOffset() )
+ {
+ pTableBox = pTableBoxStartNode->GetTableBox();
+ if (pTableBox && pTableBox->getRowSpan() > 1)
+ {
+ if ( !pTableNd )
+ pTableNd = IsCursorInTable();
+ assert (pTableNd);
+ pTableBox = & pTableBox->FindEndOfRowSpan( pTableNd->GetTable(),
+ o3tl::narrowing<sal_uInt16>(pTableBox->getRowSpan() + pCursor->GetCursorRowSpanOffset() ) );
+ pTableBoxStartNode = pTableBox->GetSttNd();
+ }
+ }
+
+ SwNodeIndex aCellStt( *pTableBoxStartNode->EndOfSectionNode(), 1 );
+
+ // if there is another StartNode after the EndNode of a cell then
+ // there is another cell
+ if( !aCellStt.GetNode().IsStartNode() )
+ {
+ if( pCursor->HasMark() || !bAppendLine )
+ bRet = false;
+ else if (pTableNd)
+ {
+ // if there is no list anymore then create new one
+ if ( !pTableBox )
+ pTableBox = pTableNd->GetTable().GetTableBox(
+ pCursor->GetPoint()->nNode.GetNode().
+ StartOfSectionIndex() );
+
+ OSL_ENSURE( pTableBox, "Box is not in this table" );
+ SwSelBoxes aBoxes;
+
+ // the document might change; w/o Action views would not be notified
+ static_cast<SwEditShell*>(this)->StartAllAction();
+ bRet = mxDoc->InsertRow( SwTable::SelLineFromBox( pTableBox, aBoxes, false ));
+ static_cast<SwEditShell*>(this)->EndAllAction();
+ }
+ }
+ bRet = bRet && pCursor->GoNextCell();
+ if( bRet )
+ UpdateCursor();
+ }
+ return bRet;
+}
+
+bool SwCursorShell::GoPrevCell()
+{
+ bool bRet = false;
+ if( IsTableMode() || IsCursorInTable() )
+ {
+ SwCursor* pCursor = m_pTableCursor ? m_pTableCursor : m_pCurrentCursor;
+ SwCallLink aLk( *this ); // watch Cursor-Moves
+ bRet = pCursor->GoPrevCell();
+ if( bRet )
+ UpdateCursor(); // update current cursor
+ }
+ return bRet;
+}
+
+static const SwFrame* lcl_FindMostUpperCellFrame( const SwFrame* pFrame )
+{
+ while ( pFrame &&
+ ( !pFrame->IsCellFrame() ||
+ !pFrame->GetUpper()->GetUpper()->IsTabFrame() ||
+ pFrame->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) )
+ {
+ pFrame = pFrame->GetUpper();
+ }
+ return pFrame;
+}
+
+bool SwCursorShell::SelTableRowOrCol( bool bRow, bool bRowSimple )
+{
+ // check if the current cursor's SPoint/Mark are in a table
+ SwFrame *pFrame = GetCurrFrame();
+ if( !pFrame->IsInTab() )
+ return false;
+
+ const SwTabFrame* pTabFrame = pFrame->FindTabFrame();
+ const SwTabFrame* pMasterTabFrame = pTabFrame->IsFollow() ? pTabFrame->FindMaster( true ) : pTabFrame;
+ const SwTable* pTable = pTabFrame->GetTable();
+
+ CurrShell aCurr( this );
+
+ const SwTableBox* pStt = nullptr;
+ const SwTableBox* pEnd = nullptr;
+
+ // search box based on layout
+ SwSelBoxes aBoxes;
+ SwTableSearchType eType = bRow ? SwTableSearchType::Row : SwTableSearchType::Col;
+ const bool bCheckProtected = !IsReadOnlyAvailable();
+
+ if( bCheckProtected )
+ eType = static_cast<SwTableSearchType>(eType | SwTableSearchType::Protect);
+
+ if ( !bRowSimple )
+ {
+ GetTableSel( *this, aBoxes, eType );
+
+ if( aBoxes.empty() )
+ return false;
+
+ pStt = aBoxes[0];
+ pEnd = aBoxes.back();
+ }
+ // #i32329# Enhanced table selection
+ else if ( pTable->IsNewModel() )
+ {
+ const SwShellCursor *pCursor = GetCursor_();
+ SwTable::SearchType eSearchType = bRow ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL;
+ pTable->CreateSelection( *pCursor, aBoxes, eSearchType, bCheckProtected );
+ if( aBoxes.empty() )
+ return false;
+
+ pStt = aBoxes[0];
+ pEnd = aBoxes.back();
+
+ m_eEnhancedTableSel = eSearchType;
+ }
+ else
+ {
+ const SwShellCursor *pCursor = GetCursor_();
+ const SwFrame* pStartFrame = pFrame;
+ const SwContentNode *pCNd = pCursor->GetContentNode( false );
+ std::pair<Point, bool> const tmp(pCursor->GetMkPos(), true);
+ const SwFrame* pEndFrame = pCNd
+ ? pCNd->getLayoutFrame(GetLayout(), nullptr, &tmp)
+ : nullptr;
+
+ if ( bRow )
+ {
+ pStartFrame = lcl_FindMostUpperCellFrame( pStartFrame );
+ pEndFrame = lcl_FindMostUpperCellFrame( pEndFrame );
+ }
+
+ if ( !pStartFrame || !pEndFrame )
+ return false;
+
+ const bool bVert = pFrame->ImplFindTabFrame()->IsVertical();
+
+ // If we select upwards it is sufficient to set pStt and pEnd
+ // to the first resp. last box of the selection obtained from
+ // GetTableSel. However, selecting downwards requires the frames
+ // located at the corners of the selection. This does not work
+ // for column selections in vertical tables:
+ const bool bSelectUp = ( bVert && !bRow ) ||
+ *pCursor->GetPoint() <= *pCursor->GetMark();
+ SwCellFrames aCells;
+ GetTableSel( static_cast<const SwCellFrame*>(pStartFrame),
+ static_cast<const SwCellFrame*>(pEndFrame),
+ aBoxes, bSelectUp ? nullptr : &aCells, eType );
+
+ if( aBoxes.empty() || ( !bSelectUp && 4 != aCells.size() ) )
+ return false;
+
+ if ( bSelectUp )
+ {
+ pStt = aBoxes[0];
+ pEnd = aBoxes.back();
+ }
+ else
+ {
+ // will become point of table cursor
+ pStt = aCells[bVert ? 0 : (bRow ? 2 : 1)]->GetTabBox();
+ // will become mark of table cursor
+ pEnd = aCells[bVert ? 3 : (bRow ? 1 : 2)]->GetTabBox();
+ }
+ }
+
+ // if no table cursor exists, create one
+ if( !m_pTableCursor )
+ {
+ m_pTableCursor = new SwShellTableCursor( *this, *m_pCurrentCursor->GetPoint() );
+ m_pCurrentCursor->DeleteMark();
+ m_pCurrentCursor->SwSelPaintRects::Hide();
+ }
+
+ m_pTableCursor->DeleteMark();
+
+ // set start and end of a column
+ m_pTableCursor->GetPoint()->nNode = *pEnd->GetSttNd();
+ m_pTableCursor->Move( fnMoveForward, GoInContent );
+ m_pTableCursor->SetMark();
+ m_pTableCursor->GetPoint()->nNode = *pStt->GetSttNd()->EndOfSectionNode();
+ m_pTableCursor->Move( fnMoveBackward, GoInContent );
+
+ // set PtPos 'close' to the reference table, otherwise we might get problems
+ // with the repeated headlines check in UpdateCursor():
+ if ( !bRow )
+ m_pTableCursor->GetPtPos() = pMasterTabFrame->IsVertical()
+ ? pMasterTabFrame->getFrameArea().TopRight()
+ : pMasterTabFrame->getFrameArea().TopLeft();
+
+ UpdateCursor();
+ return true;
+}
+
+bool SwCursorShell::SelTable()
+{
+ // check if the current cursor's SPoint/Mark are in a table
+ SwFrame *pFrame = GetCurrFrame();
+ if( !pFrame->IsInTab() )
+ return false;
+
+ const SwTabFrame *pTableFrame = pFrame->ImplFindTabFrame();
+ const SwTabFrame* pMasterTabFrame = pTableFrame->IsFollow() ? pTableFrame->FindMaster( true ) : pTableFrame;
+ const SwTableNode* pTableNd = pTableFrame->GetTable()->GetTableNode();
+
+ CurrShell aCurr( this );
+
+ if( !m_pTableCursor )
+ {
+ m_pTableCursor = new SwShellTableCursor( *this, *m_pCurrentCursor->GetPoint() );
+ m_pCurrentCursor->DeleteMark();
+ m_pCurrentCursor->SwSelPaintRects::Hide();
+ }
+
+ m_pTableCursor->DeleteMark();
+ m_pTableCursor->GetPoint()->nNode = *pTableNd;
+ m_pTableCursor->Move( fnMoveForward, GoInContent );
+ m_pTableCursor->SetMark();
+ // set MkPos 'close' to the master table, otherwise we might get problems
+ // with the repeated headlines check in UpdateCursor():
+ m_pTableCursor->GetMkPos() = pMasterTabFrame->IsVertical() ? pMasterTabFrame->getFrameArea().TopRight() : pMasterTabFrame->getFrameArea().TopLeft();
+ m_pTableCursor->GetPoint()->nNode = *pTableNd->EndOfSectionNode();
+ m_pTableCursor->Move( fnMoveBackward, GoInContent );
+ UpdateCursor();
+ return true;
+}
+
+bool SwCursorShell::SelTableBox()
+{
+ // if we're in a table, create a table cursor, and select the cell
+ // that the current cursor's point resides in
+
+ // search for start node of our table box. If not found, exit really
+ const SwStartNode* pStartNode =
+ m_pCurrentCursor->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
+
+#if OSL_DEBUG_LEVEL > 0
+ // the old code checks whether we're in a table by asking the
+ // frame. This should yield the same result as searching for the
+ // table box start node, right?
+ SwFrame *pFrame = GetCurrFrame();
+ OSL_ENSURE( !pFrame->IsInTab() == !(pStartNode != nullptr),
+ "Schroedinger's table: We're in a box, and also we aren't." );
+#endif
+ if( pStartNode == nullptr )
+ return false;
+
+ CurrShell aCurr( this );
+
+ // create a table cursor, if there isn't one already
+ if( !m_pTableCursor )
+ {
+ m_pTableCursor = new SwShellTableCursor( *this, *m_pCurrentCursor->GetPoint() );
+ m_pCurrentCursor->DeleteMark();
+ m_pCurrentCursor->SwSelPaintRects::Hide();
+ }
+
+ // select the complete box with our shiny new m_pTableCursor
+ // 1. delete mark, and move point to first content node in box
+ m_pTableCursor->DeleteMark();
+ *(m_pTableCursor->GetPoint()) = SwPosition( *pStartNode );
+ m_pTableCursor->Move( fnMoveForward, GoInNode );
+
+ // 2. set mark, and move point to last content node in box
+ m_pTableCursor->SetMark();
+ *(m_pTableCursor->GetPoint()) = SwPosition( *(pStartNode->EndOfSectionNode()) );
+ m_pTableCursor->Move( fnMoveBackward, GoInNode );
+
+ // 3. exchange
+ m_pTableCursor->Exchange();
+
+ // with some luck, UpdateCursor() will now update everything that
+ // needs updating
+ UpdateCursor();
+
+ return true;
+}
+
+// TODO: provide documentation
+/** get the next non-protected cell inside a table
+
+ @param[in,out] rIdx is on a table node
+ @param bInReadOnly ???
+
+ @return <false> if no suitable cell could be found, otherwise <rIdx> points
+ to content in a suitable cell and <true> is returned.
+*/
+static bool lcl_FindNextCell( SwNodeIndex& rIdx, bool bInReadOnly )
+{
+ // check protected cells
+ SwNodeIndex aTmp( rIdx, 2 ); // TableNode + StartNode
+
+ // the resulting cell should be in that table:
+ const SwTableNode* pTableNd = rIdx.GetNode().GetTableNode();
+
+ if ( !pTableNd )
+ {
+ OSL_FAIL( "lcl_FindNextCell not celled with table start node!" );
+ return false;
+ }
+
+ const SwNode* pTableEndNode = pTableNd->EndOfSectionNode();
+
+ SwNodes& rNds = aTmp.GetNode().GetNodes();
+ SwContentNode* pCNd = aTmp.GetNode().GetContentNode();
+
+ // no content node => go to next content node
+ if( !pCNd )
+ pCNd = rNds.GoNext( &aTmp );
+
+ // robust
+ if ( !pCNd )
+ return false;
+
+ SwContentFrame* pFrame = pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
+
+ if ( nullptr == pFrame || pCNd->FindTableNode() != pTableNd ||
+ (!bInReadOnly && pFrame->IsProtected() ) )
+ {
+ // we are not located inside a 'valid' cell. We have to continue searching...
+
+ // skip behind current section. This might be the end of the table cell
+ // or behind an inner section or...
+ aTmp.Assign( *pCNd->EndOfSectionNode(), 1 );
+
+ // loop to find a suitable cell...
+ for( ;; )
+ {
+ SwNode* pNd = &aTmp.GetNode();
+
+ // we break this loop if we reached the end of the table.
+ // to make this code even more robust, we also break if we are
+ // already behind the table end node:
+ if( pNd == pTableEndNode || /*robust: */ pNd->GetIndex() > pTableEndNode->GetIndex() )
+ return false;
+
+ // ok, get the next content node:
+ pCNd = aTmp.GetNode().GetContentNode();
+ if( nullptr == pCNd )
+ pCNd = rNds.GoNext( &aTmp );
+
+ // robust:
+ if ( !pCNd )
+ return false;
+
+ // check if we have found a suitable table cell:
+ pFrame = pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
+
+ if ( nullptr != pFrame && pCNd->FindTableNode() == pTableNd &&
+ (bInReadOnly || !pFrame->IsProtected() ) )
+ {
+ // finally, we have found a suitable table cell => set index and return
+ rIdx = *pCNd;
+ return true;
+ }
+
+ // continue behind the current section:
+ aTmp.Assign( *pCNd->EndOfSectionNode(), +1 );
+ }
+ }
+ rIdx = *pCNd;
+ return true;
+}
+
+/// see lcl_FindNextCell()
+static bool lcl_FindPrevCell( SwNodeIndex& rIdx, bool bInReadOnly )
+{
+ SwNodeIndex aTmp( rIdx, -2 ); // TableNode + EndNode
+
+ const SwNode* pTableEndNode = &rIdx.GetNode();
+ const SwTableNode* pTableNd = pTableEndNode->StartOfSectionNode()->GetTableNode();
+
+ if ( !pTableNd )
+ {
+ OSL_FAIL( "lcl_FindPrevCell not celled with table start node!" );
+ return false;
+ }
+
+ SwContentNode* pCNd = aTmp.GetNode().GetContentNode();
+
+ if( !pCNd )
+ pCNd = SwNodes::GoPrevious( &aTmp );
+
+ if ( !pCNd )
+ return false;
+
+ SwContentFrame* pFrame = pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
+
+ if( nullptr == pFrame || pCNd->FindTableNode() != pTableNd ||
+ (!bInReadOnly && pFrame->IsProtected() ))
+ {
+ // skip before current section
+ aTmp.Assign( *pCNd->StartOfSectionNode(), -1 );
+ for( ;; )
+ {
+ SwNode* pNd = &aTmp.GetNode();
+
+ if( pNd == pTableNd || pNd->GetIndex() < pTableNd->GetIndex() )
+ return false;
+
+ pCNd = aTmp.GetNode().GetContentNode();
+ if( nullptr == pCNd )
+ pCNd = SwNodes::GoPrevious( &aTmp );
+
+ if ( !pCNd )
+ return false;
+
+ pFrame = pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
+
+ if( nullptr != pFrame && pCNd->FindTableNode() == pTableNd &&
+ (bInReadOnly || !pFrame->IsProtected() ) )
+ {
+ rIdx = *pCNd;
+ return true; // ok, not protected
+ }
+ aTmp.Assign( *pCNd->StartOfSectionNode(), -1 );
+ }
+ }
+ rIdx = *pCNd;
+ return true;
+}
+
+bool GotoPrevTable( SwPaM& rCurrentCursor, SwMoveFnCollection const & fnPosTable,
+ bool bInReadOnly )
+{
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
+
+ SwNodeIndex aIdx( rCurrentCursor.GetPoint()->nNode );
+
+ SwTableNode* pTableNd = aIdx.GetNode().FindTableNode();
+ if( pTableNd )
+ {
+ // #i26532#: If we are inside a table, we may not go backward to the
+ // table start node, because we would miss any tables inside this table.
+ SwTableNode* pInnerTableNd = nullptr;
+ SwNodeIndex aTmpIdx( aIdx );
+ while( aTmpIdx.GetIndex() &&
+ nullptr == ( pInnerTableNd = aTmpIdx.GetNode().StartOfSectionNode()->GetTableNode()) )
+ --aTmpIdx;
+
+ if( pInnerTableNd == pTableNd )
+ aIdx.Assign( *pTableNd, -1 );
+ }
+
+ SwNodeIndex aOldIdx = aIdx;
+ SwNodeOffset nLastNd(rCurrentCursor.GetDoc().GetNodes().Count() - 1);
+ do {
+ while( aIdx.GetIndex() &&
+ nullptr == ( pTableNd = aIdx.GetNode().StartOfSectionNode()->GetTableNode()) )
+ {
+ --aIdx;
+ if ( aIdx == aOldIdx )
+ {
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
+ return false;
+ }
+ }
+
+ if ( !aIdx.GetIndex() )
+ {
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
+ aIdx = nLastNd;
+ continue;
+ }
+
+ {
+ if( &fnPosTable == &fnMoveForward ) // at the beginning?
+ {
+ aIdx = *aIdx.GetNode().StartOfSectionNode();
+ if( !lcl_FindNextCell( aIdx, bInReadOnly ))
+ {
+ // skip table
+ aIdx.Assign( *pTableNd, -1 );
+ continue;
+ }
+ }
+ else
+ {
+ // check protected cells
+ if( !lcl_FindNextCell( aIdx, bInReadOnly ))
+ {
+ // skip table
+ aIdx.Assign( *pTableNd, -1 );
+ continue;
+ }
+ }
+
+ SwTextNode* pTextNode = aIdx.GetNode().GetTextNode();
+ if ( pTextNode )
+ {
+ rCurrentCursor.GetPoint()->nNode = *pTextNode;
+ rCurrentCursor.GetPoint()->nContent.Assign( pTextNode, &fnPosTable == &fnMoveBackward ?
+ pTextNode->Len() :
+ 0 );
+ }
+ return true;
+ }
+ } while( true );
+
+ return false;
+}
+
+bool GotoNextTable( SwPaM& rCurrentCursor, SwMoveFnCollection const & fnPosTable,
+ bool bInReadOnly )
+{
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
+
+ SwNodeIndex aIdx( rCurrentCursor.GetPoint()->nNode );
+ SwTableNode* pTableNd = aIdx.GetNode().FindTableNode();
+
+ if( pTableNd )
+ aIdx.Assign( *pTableNd->EndOfSectionNode(), 1 );
+
+ SwNodeIndex aOldIdx = aIdx;
+ SwNodeOffset nLastNd(rCurrentCursor.GetDoc().GetNodes().Count() - 1);
+ do {
+ while( aIdx.GetIndex() < nLastNd &&
+ nullptr == ( pTableNd = aIdx.GetNode().GetTableNode()) )
+ {
+ ++aIdx;
+ if ( aIdx == aOldIdx )
+ {
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
+ return false;
+ }
+ }
+
+ if ( aIdx.GetIndex() == nLastNd )
+ {
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
+ aIdx = SwNodeOffset(0);
+ continue;
+ }
+
+ assert( pTableNd ); // coverity, should never be nullptr
+
+ if( &fnPosTable == &fnMoveForward ) // at the beginning?
+ {
+ if( !lcl_FindNextCell( aIdx, bInReadOnly ))
+ {
+ // skip table
+ aIdx.Assign( *pTableNd->EndOfSectionNode(), + 1 );
+ continue;
+ }
+ }
+ else
+ {
+ aIdx = *aIdx.GetNode().EndOfSectionNode();
+ // check protected cells
+ if( !lcl_FindNextCell( aIdx, bInReadOnly ))
+ {
+ // skip table
+ aIdx.Assign( *pTableNd->EndOfSectionNode(), + 1 );
+ continue;
+ }
+ }
+
+ SwTextNode* pTextNode = aIdx.GetNode().GetTextNode();
+ if ( pTextNode )
+ {
+ rCurrentCursor.GetPoint()->nNode = *pTextNode;
+ rCurrentCursor.GetPoint()->nContent.Assign( pTextNode, &fnPosTable == &fnMoveBackward ?
+ pTextNode->Len() :
+ 0 );
+ }
+ return true;
+
+ } while( true );
+
+ // the flow is such that it is not possible to get there
+
+ return false;
+}
+
+bool GotoCurrTable( SwPaM& rCurrentCursor, SwMoveFnCollection const & fnPosTable,
+ bool bInReadOnly )
+{
+ SwTableNode* pTableNd = rCurrentCursor.GetPoint()->nNode.GetNode().FindTableNode();
+ if( !pTableNd )
+ return false;
+
+ SwTextNode* pTextNode = nullptr;
+ if( &fnPosTable == &fnMoveBackward ) // to the end of the table
+ {
+ SwNodeIndex aIdx( *pTableNd->EndOfSectionNode() );
+ if( !lcl_FindPrevCell( aIdx, bInReadOnly ))
+ return false;
+ pTextNode = aIdx.GetNode().GetTextNode();
+ }
+ else
+ {
+ SwNodeIndex aIdx( *pTableNd );
+ if( !lcl_FindNextCell( aIdx, bInReadOnly ))
+ return false;
+ pTextNode = aIdx.GetNode().GetTextNode();
+ }
+
+ if ( pTextNode )
+ {
+ rCurrentCursor.GetPoint()->nNode = *pTextNode;
+ rCurrentCursor.GetPoint()->nContent.Assign( pTextNode, &fnPosTable == &fnMoveBackward ?
+ pTextNode->Len() :
+ 0 );
+ }
+
+ return true;
+}
+
+bool SwCursor::MoveTable( SwWhichTable fnWhichTable, SwMoveFnCollection const & fnPosTable )
+{
+ bool bRet = false;
+ SwTableCursor* pTableCursor = dynamic_cast<SwTableCursor*>(this);
+
+ if( pTableCursor || !HasMark() )
+ {
+ SwCursorSaveState aSaveState( *this );
+ bRet = (*fnWhichTable)( *this, fnPosTable, IsReadOnlyAvailable() ) &&
+ !IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
+ SwCursorSelOverFlags::Toggle );
+ }
+ return bRet;
+}
+
+bool SwCursorShell::MoveTable( SwWhichTable fnWhichTable, SwMoveFnCollection const & fnPosTable )
+{
+ SwCallLink aLk( *this ); // watch Cursor-Moves; call Link if needed
+
+ SwShellCursor* pCursor = m_pTableCursor ? m_pTableCursor : m_pCurrentCursor;
+ bool bCheckPos;
+ bool bRet;
+ SwNodeOffset nPtNd(0);
+ sal_Int32 nPtCnt = 0;
+
+ if ( !m_pTableCursor && m_pCurrentCursor->HasMark() )
+ {
+ // switch to table mode
+ m_pTableCursor = new SwShellTableCursor( *this, *m_pCurrentCursor->GetPoint() );
+ m_pCurrentCursor->DeleteMark();
+ m_pCurrentCursor->SwSelPaintRects::Hide();
+ m_pTableCursor->SetMark();
+ pCursor = m_pTableCursor;
+ bCheckPos = false;
+ }
+ else
+ {
+ bCheckPos = true;
+ nPtNd = pCursor->GetPoint()->nNode.GetIndex();
+ nPtCnt = pCursor->GetPoint()->nContent.GetIndex();
+ }
+
+ bRet = pCursor->MoveTable( fnWhichTable, fnPosTable );
+
+ if( bRet )
+ {
+ // #i45028# - set "top" position for repeated headline rows
+ pCursor->GetPtPos() = Point();
+
+ UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
+
+ if( bCheckPos &&
+ pCursor->GetPoint()->nNode.GetIndex() == nPtNd &&
+ pCursor->GetPoint()->nContent.GetIndex() == nPtCnt )
+ bRet = false;
+ }
+ return bRet;
+}
+
+bool SwCursorShell::IsTableComplexForChart()
+{
+ bool bRet = false;
+
+ // Here we may trigger table formatting so we better do that inside an action
+ StartAction();
+ const SwTableNode* pTNd = m_pCurrentCursor->GetPoint()->nNode.GetNode().FindTableNode();
+ if( pTNd )
+ {
+ // in a table; check if table or section is balanced
+ OUString sSel;
+ if( m_pTableCursor )
+ sSel = GetBoxNms();
+ bRet = pTNd->GetTable().IsTableComplexForChart( sSel );
+ }
+ EndAction();
+
+ return bRet;
+}
+
+OUString SwCursorShell::GetBoxNms() const
+{
+ OUString sNm;
+ const SwPosition* pPos;
+ SwFrame* pFrame;
+
+ if( IsTableMode() )
+ {
+ SwContentNode *pCNd = m_pTableCursor->Start()->nNode.GetNode().GetContentNode();
+ pFrame = pCNd ? pCNd->getLayoutFrame( GetLayout() ) : nullptr;
+ if( !pFrame )
+ return sNm;
+
+ do {
+ pFrame = pFrame->GetUpper();
+ } while ( pFrame && !pFrame->IsCellFrame() );
+
+ OSL_ENSURE( pFrame, "no frame for this box" );
+
+ if( !pFrame )
+ return sNm;
+
+ sNm = static_cast<SwCellFrame*>(pFrame)->GetTabBox()->GetName() + ":";
+ pPos = m_pTableCursor->End();
+ }
+ else
+ {
+ const SwTableNode* pTableNd = IsCursorInTable();
+ if( !pTableNd )
+ return sNm;
+ pPos = GetCursor()->GetPoint();
+ }
+
+ SwContentNode* pCNd = pPos->nNode.GetNode().GetContentNode();
+ pFrame = pCNd ? pCNd->getLayoutFrame( GetLayout() ) : nullptr;
+
+ if( pFrame )
+ {
+ do {
+ pFrame = pFrame->GetUpper();
+ } while ( pFrame && !pFrame->IsCellFrame() );
+
+ if( pFrame )
+ sNm += static_cast<SwCellFrame*>(pFrame)->GetTabBox()->GetName();
+ }
+ return sNm;
+}
+
+bool SwCursorShell::GotoTable( const OUString& rName )
+{
+ SwCallLink aLk( *this ); // watch Cursor-Moves
+ bool bRet = !m_pTableCursor && m_pCurrentCursor->GotoTable( rName );
+ if( bRet )
+ {
+ m_pCurrentCursor->GetPtPos() = Point();
+ UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
+ SwCursorShell::READONLY );
+ }
+ return bRet;
+}
+
+bool SwCursorShell::CheckTableBoxContent( const SwPosition* pPos )
+{
+ if( !m_pBoxIdx || !m_pBoxPtr || IsSelTableCells() || !IsAutoUpdateCells() )
+ return false;
+
+ // check if box content is consistent with given box format, reset if not
+ SwTableBox* pChkBox = nullptr;
+ SwStartNode* pSttNd = nullptr;
+ if( !pPos )
+ {
+ // get stored position
+ if (nullptr != (pSttNd = m_pBoxIdx->GetNode().GetStartNode()) &&
+ SwTableBoxStartNode == pSttNd->GetStartNodeType() &&
+ m_pBoxPtr == pSttNd->FindTableNode()->GetTable().
+ GetTableBox( m_pBoxIdx->GetIndex() ) )
+ pChkBox = m_pBoxPtr;
+ }
+ else
+ {
+ pSttNd = pPos->nNode.GetNode().FindSttNodeByType( SwTableBoxStartNode );
+ if( pSttNd)
+ pChkBox = pSttNd->FindTableNode()->GetTable().GetTableBox( pSttNd->GetIndex() );
+ }
+
+ // box has more than one paragraph
+ if( pChkBox && pSttNd->GetIndex() + SwNodeOffset(2) != pSttNd->EndOfSectionIndex() )
+ pChkBox = nullptr;
+
+ // destroy pointer before next action starts
+ if( !pPos && !pChkBox )
+ ClearTableBoxContent();
+
+ // cursor not anymore in this section?
+ if( pChkBox && !pPos &&
+ ( m_pCurrentCursor->HasMark() || m_pCurrentCursor->GetNext() != m_pCurrentCursor ||
+ pSttNd->GetIndex() + 1 == m_pCurrentCursor->GetPoint()->nNode.GetIndex() ))
+ pChkBox = nullptr;
+
+ // Did the content of a box change at all? This is important if e.g. Undo
+ // could not restore the content properly.
+ if( pChkBox )
+ {
+ const SwTextNode* pNd = GetDoc()->GetNodes()[
+ pSttNd->GetIndex() + 1 ]->GetTextNode();
+ if( !pNd ||
+ ( pNd->GetText() == SwViewShell::GetShellRes()->aCalc_Error &&
+ SfxItemState::SET == pChkBox->GetFrameFormat()->
+ GetItemState( RES_BOXATR_FORMULA )) )
+ pChkBox = nullptr;
+ }
+
+ if( pChkBox )
+ {
+ // destroy pointer before next action starts
+ ClearTableBoxContent();
+ StartAction();
+ GetDoc()->ChkBoxNumFormat( *pChkBox, true );
+ EndAction();
+ }
+
+ return nullptr != pChkBox;
+}
+
+void SwCursorShell::SaveTableBoxContent( const SwPosition* pPos )
+{
+ if( IsSelTableCells() || !IsAutoUpdateCells() )
+ return ;
+
+ if( !pPos )
+ pPos = m_pCurrentCursor->GetPoint();
+
+ SwStartNode* pSttNd = pPos->nNode.GetNode().FindSttNodeByType( SwTableBoxStartNode );
+
+ bool bCheckBox = false;
+ if( pSttNd && m_pBoxIdx )
+ {
+ if( pSttNd == &m_pBoxIdx->GetNode() )
+ pSttNd = nullptr;
+ else
+ bCheckBox = true;
+ }
+ else
+ bCheckBox = nullptr != m_pBoxIdx;
+
+ if( bCheckBox )
+ {
+ // check m_pBoxIdx
+ SwPosition aPos( *m_pBoxIdx );
+ CheckTableBoxContent( &aPos );
+ }
+
+ if( pSttNd )
+ {
+ m_pBoxPtr = pSttNd->FindTableNode()->GetTable().GetTableBox( pSttNd->GetIndex() );
+
+ if( m_pBoxIdx )
+ *m_pBoxIdx = *pSttNd;
+ else
+ m_pBoxIdx = new SwNodeIndex( *pSttNd );
+ }
+}
+
+void SwCursorShell::ClearTableBoxContent()
+{
+ delete m_pBoxIdx;
+ m_pBoxIdx = nullptr;
+ m_pBoxPtr = nullptr;
+}
+
+bool SwCursorShell::EndAllTableBoxEdit()
+{
+ bool bRet = false;
+ for(SwViewShell& rSh : GetRingContainer())
+ {
+ if( auto pCursorShell = dynamic_cast<SwCursorShell *>(&rSh) )
+ bRet |= pCursorShell->CheckTableBoxContent(
+ pCursorShell->m_pCurrentCursor->GetPoint() );
+
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */