diff options
Diffstat (limited to 'sw/source/core/edit/edtab.cxx')
-rw-r--r-- | sw/source/core/edit/edtab.cxx | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/sw/source/core/edit/edtab.cxx b/sw/source/core/edit/edtab.cxx new file mode 100644 index 000000000..93036f735 --- /dev/null +++ b/sw/source/core/edit/edtab.cxx @@ -0,0 +1,531 @@ +/* -*- 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 <fesh.hxx> +#include <hintids.hxx> +#include <hints.hxx> + +#include <swwait.hxx> +#include <editsh.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentChartDataProviderAccess.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <IDocumentState.hxx> +#include <cntfrm.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <swundo.hxx> +#include <tblsel.hxx> +#include <cellfrm.hxx> +#include <cellatr.hxx> +#include <swtblfmt.hxx> +#include <swddetbl.hxx> +#include <mdiexp.hxx> +#include <itabenum.hxx> +#include <vcl/uitest/logger.hxx> +#include <vcl/uitest/eventdescription.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +namespace { + +void collectUIInformation(const OUString& rAction, const OUString& aParameters) +{ + EventDescription aDescription; + aDescription.aAction = rAction; + aDescription.aParameters = {{"parameters", aParameters}}; + aDescription.aID = "writer_edit"; + aDescription.aKeyWord = "SwEditWinUIObject"; + aDescription.aParent = "MainWindow"; + UITestLogger::getInstance().logEvent(aDescription); +} + +} + +//Added for bug #i119954# Application crashed if undo/redo convert nest table to text +static bool ConvertTableToText( const SwTableNode *pTableNode, sal_Unicode cCh ); + +static void ConvertNestedTablesToText( const SwTableLines &rTableLines, sal_Unicode cCh ) +{ + for (size_t n = 0; n < rTableLines.size(); ++n) + { + SwTableLine* pTableLine = rTableLines[ n ]; + for (size_t i = 0; i < pTableLine->GetTabBoxes().size(); ++i) + { + SwTableBox* pTableBox = pTableLine->GetTabBoxes()[ i ]; + if (pTableBox->GetTabLines().empty()) + { + SwNodeIndex nodeIndex( *pTableBox->GetSttNd(), 1 ); + SwNodeIndex endNodeIndex( *pTableBox->GetSttNd()->EndOfSectionNode() ); + for( ; nodeIndex < endNodeIndex ; ++nodeIndex ) + { + if ( SwTableNode* pTableNode = nodeIndex.GetNode().GetTableNode() ) + ConvertTableToText( pTableNode, cCh ); + } + } + else + { + ConvertNestedTablesToText( pTableBox->GetTabLines(), cCh ); + } + } + } +} + +bool ConvertTableToText( const SwTableNode *pConstTableNode, sal_Unicode cCh ) +{ + SwTableNode *pTableNode = const_cast< SwTableNode* >( pConstTableNode ); + ConvertNestedTablesToText( pTableNode->GetTable().GetTabLines(), cCh ); + return pTableNode->GetDoc()->TableToText( pTableNode, cCh ); +} +//End for bug #i119954# + +const SwTable& SwEditShell::InsertTable( const SwInsertTableOptions& rInsTableOpts, + sal_uInt16 nRows, sal_uInt16 nCols, + const SwTableAutoFormat* pTAFormat ) +{ + StartAllAction(); + SwPosition* pPos = GetCursor()->GetPoint(); + + bool bEndUndo = 0 != pPos->nContent.GetIndex(); + if( bEndUndo ) + { + StartUndo( SwUndoId::START ); + GetDoc()->getIDocumentContentOperations().SplitNode( *pPos, false ); + } + + // If called from a shell the adjust item is propagated + // from pPos to the new content nodes in the table. + const SwTable *pTable = GetDoc()->InsertTable( rInsTableOpts, *pPos, + nRows, nCols, + css::text::HoriOrientation::FULL, pTAFormat, + nullptr, true ); + if( bEndUndo ) + EndUndo( SwUndoId::END ); + + EndAllAction(); + + OUString parameter = " Columns : " + OUString::number( nCols ) + " , Rows : " + OUString::number( nRows ) + " "; + collectUIInformation("CREATE_TABLE", parameter); + + return *pTable; +} + +bool SwEditShell::TextToTable( const SwInsertTableOptions& rInsTableOpts, + sal_Unicode cCh, + const SwTableAutoFormat* pTAFormat ) +{ + SwWait aWait( *GetDoc()->GetDocShell(), true ); + bool bRet = false; + StartAllAction(); + for(const SwPaM& rPaM : GetCursor()->GetRingContainer()) + { + if( rPaM.HasMark() ) + bRet |= nullptr != GetDoc()->TextToTable( rInsTableOpts, rPaM, cCh, + css::text::HoriOrientation::FULL, pTAFormat ); + } + EndAllAction(); + return bRet; +} + +bool SwEditShell::TableToText( sal_Unicode cCh ) +{ + SwWait aWait( *GetDoc()->GetDocShell(), true ); + bool bRet = false; + SwPaM* pCursor = GetCursor(); + const SwTableNode* pTableNd = + GetDoc()->IsIdxInTable( pCursor->GetPoint()->nNode ); + if( IsTableMode() ) + { + ClearMark(); + pCursor = GetCursor(); + } + else if( !pTableNd || pCursor->GetNext() != pCursor ) + return bRet; + + // TL_CHART2: + // tell the charts about the table to be deleted and have them use their own data + GetDoc()->getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( &pTableNd->GetTable() ); + + StartAllAction(); + + // move current Cursor out of the listing area + SwNodeIndex aTabIdx( *pTableNd ); + pCursor->DeleteMark(); + pCursor->GetPoint()->nNode = *pTableNd->EndOfSectionNode(); + pCursor->GetPoint()->nContent.Assign( nullptr, 0 ); + // move sPoint and Mark out of the area! + pCursor->SetMark(); + pCursor->DeleteMark(); + + //Modified for bug #i119954# Application crashed if undo/redo convert nest table to text + StartUndo(); + bRet = ConvertTableToText( pTableNd, cCh ); + EndUndo(); + //End for bug #i119954# + pCursor->GetPoint()->nNode = aTabIdx; + + SwContentNode* pCNd = pCursor->GetContentNode(); + if( !pCNd ) + pCursor->Move( fnMoveForward, GoInContent ); + else + pCursor->GetPoint()->nContent.Assign( pCNd, 0 ); + + EndAllAction(); + return bRet; +} + +bool SwEditShell::IsTextToTableAvailable() const +{ + bool bOnlyText = false; + for(SwPaM& rPaM : GetCursor()->GetRingContainer()) + { + if( rPaM.HasMark() && *rPaM.GetPoint() != *rPaM.GetMark() ) + { + bOnlyText = true; + + // check if selection is in listing + sal_uLong nStt = rPaM.GetMark()->nNode.GetIndex(), + nEnd = rPaM.GetPoint()->nNode.GetIndex(); + if( nStt > nEnd ) { sal_uLong n = nStt; nStt = nEnd; nEnd = n; } + + for( ; nStt <= nEnd; ++nStt ) + if( !GetDoc()->GetNodes()[ nStt ]->IsTextNode() ) + { + bOnlyText = false; + break; + } + + if( !bOnlyText ) + break; + } + } + + return bOnlyText; +} + +void SwEditShell::InsertDDETable( const SwInsertTableOptions& rInsTableOpts, + SwDDEFieldType* pDDEType, + sal_uInt16 nRows, sal_uInt16 nCols ) +{ + SwPosition* pPos = GetCursor()->GetPoint(); + + StartAllAction(); + + bool bEndUndo = 0 != pPos->nContent.GetIndex(); + if( bEndUndo ) + { + StartUndo( SwUndoId::START ); + GetDoc()->getIDocumentContentOperations().SplitNode( *pPos, false ); + } + + const SwInsertTableOptions aInsTableOpts( rInsTableOpts.mnInsMode | SwInsertTableFlags::DefaultBorder, + rInsTableOpts.mnRowsToRepeat ); + SwTable* pTable = const_cast<SwTable*>(GetDoc()->InsertTable( aInsTableOpts, *pPos, + nRows, nCols, css::text::HoriOrientation::FULL )); + + SwTableNode* pTableNode = const_cast<SwTableNode*>(pTable->GetTabSortBoxes()[ 0 ]-> + GetSttNd()->FindTableNode()); + std::unique_ptr<SwDDETable> pDDETable(new SwDDETable( *pTable, pDDEType )); + pTableNode->SetNewTable( std::move(pDDETable) ); // set the DDE table + + if( bEndUndo ) + EndUndo( SwUndoId::END ); + + EndAllAction(); +} + +/** update fields of a listing */ +void SwEditShell::UpdateTable() +{ + const SwTableNode* pTableNd = IsCursorInTable(); + + if( pTableNd ) + { + StartAllAction(); + if( DoesUndo() ) + StartUndo(); + EndAllTableBoxEdit(); + SwTableFormulaUpdate aTableUpdate( &pTableNd->GetTable() ); + GetDoc()->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate ); + if( DoesUndo() ) + EndUndo(); + EndAllAction(); + } +} + +// get/set Change Mode + +TableChgMode SwEditShell::GetTableChgMode() const +{ + TableChgMode eMode; + const SwTableNode* pTableNd = IsCursorInTable(); + if( pTableNd ) + eMode = pTableNd->GetTable().GetTableChgMode(); + else + eMode = GetTableChgDefaultMode(); + return eMode; +} + +void SwEditShell::SetTableChgMode( TableChgMode eMode ) +{ + const SwTableNode* pTableNd = IsCursorInTable(); + + if( pTableNd ) + { + const_cast<SwTable&>(pTableNd->GetTable()).SetTableChgMode( eMode ); + if( !GetDoc()->getIDocumentState().IsModified() ) // Bug 57028 + { + GetDoc()->GetIDocumentUndoRedo().SetUndoNoResetModified(); + } + GetDoc()->getIDocumentState().SetModified(); + } +} + +bool SwEditShell::GetTableBoxFormulaAttrs( SfxItemSet& rSet ) const +{ + SwSelBoxes aBoxes; + if( IsTableMode() ) + ::GetTableSelCrs( *this, aBoxes ); + else + { + do { + SwFrame *pFrame = GetCurrFrame(); + do { + pFrame = pFrame->GetUpper(); + } while ( pFrame && !pFrame->IsCellFrame() ); + if ( pFrame ) + { + SwTableBox *pBox = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox()); + aBoxes.insert( pBox ); + } + } while( false ); + } + + for (size_t n = 0; n < aBoxes.size(); ++n) + { + const SwTableBox* pSelBox = aBoxes[ n ]; + const SwTableBoxFormat* pTableFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat()); + if( !n ) + { + // Convert formulae into external presentation + const SwTable& rTable = pSelBox->GetSttNd()->FindTableNode()->GetTable(); + + SwTableFormulaUpdate aTableUpdate( &rTable ); + aTableUpdate.m_eFlags = TBL_BOXNAME; + GetDoc()->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate ); + + rSet.Put( pTableFormat->GetAttrSet() ); + } + else + rSet.MergeValues( pTableFormat->GetAttrSet() ); + } + return 0 != rSet.Count(); +} + +void SwEditShell::SetTableBoxFormulaAttrs( const SfxItemSet& rSet ) +{ + SET_CURR_SHELL( this ); + SwSelBoxes aBoxes; + if( IsTableMode() ) + ::GetTableSelCrs( *this, aBoxes ); + else + { + do { + SwFrame *pFrame = GetCurrFrame(); + do { + pFrame = pFrame->GetUpper(); + } while ( pFrame && !pFrame->IsCellFrame() ); + if ( pFrame ) + { + SwTableBox *pBox = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox()); + aBoxes.insert( pBox ); + } + } while( false ); + } + + // When setting a formula, do not check further! + if( SfxItemState::SET == rSet.GetItemState( RES_BOXATR_FORMULA )) + ClearTableBoxContent(); + + StartAllAction(); + GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + for (size_t n = 0; n < aBoxes.size(); ++n) + { + GetDoc()->SetTableBoxFormulaAttrs( *aBoxes[ n ], rSet ); + } + GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + EndAllAction(); +} + +bool SwEditShell::IsTableBoxTextFormat() const +{ + if( IsTableMode() ) + return false; + + const SwTableBox *pBox = nullptr; + { + SwFrame *pFrame = GetCurrFrame(); + do { + pFrame = pFrame->GetUpper(); + } while ( pFrame && !pFrame->IsCellFrame() ); + if ( pFrame ) + pBox = static_cast<SwCellFrame*>(pFrame)->GetTabBox(); + } + + if( !pBox ) + return false; + + sal_uInt32 nFormat = 0; + const SfxPoolItem* pItem; + if( SfxItemState::SET == pBox->GetFrameFormat()->GetAttrSet().GetItemState( + RES_BOXATR_FORMAT, true, &pItem )) + { + nFormat = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue(); + return GetDoc()->GetNumberFormatter()->IsTextFormat( nFormat ); + } + + sal_uLong nNd = pBox->IsValidNumTextNd(); + if( ULONG_MAX == nNd ) + return true; + + const OUString& rText = GetDoc()->GetNodes()[ nNd ]->GetTextNode()->GetText(); + if( rText.isEmpty() ) + return false; + + double fVal; + return !GetDoc()->IsNumberFormat( rText, nFormat, fVal ); +} + +OUString SwEditShell::GetTableBoxText() const +{ + OUString sRet; + if( !IsTableMode() ) + { + const SwTableBox *pBox = nullptr; + { + SwFrame *pFrame = GetCurrFrame(); + do { + pFrame = pFrame->GetUpper(); + } while ( pFrame && !pFrame->IsCellFrame() ); + if ( pFrame ) + pBox = static_cast<SwCellFrame*>(pFrame)->GetTabBox(); + } + + sal_uLong nNd; + if( pBox && ULONG_MAX != ( nNd = pBox->IsValidNumTextNd() ) ) + sRet = GetDoc()->GetNodes()[ nNd ]->GetTextNode()->GetText(); + } + return sRet; +} + +void SwEditShell::SplitTable( SplitTable_HeadlineOption eMode ) +{ + SwPaM *pCursor = GetCursor(); + if( pCursor->GetNode().FindTableNode() ) + { + StartAllAction(); + GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr); + + GetDoc()->SplitTable( *pCursor->GetPoint(), eMode, true ); + + GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr); + ClearFEShellTabCols(*GetDoc(), nullptr); + EndAllAction(); + } +} + +bool SwEditShell::MergeTable( bool bWithPrev ) +{ + bool bRet = false; + SwPaM *pCursor = GetCursor(); + if( pCursor->GetNode().FindTableNode() ) + { + StartAllAction(); + GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr); + + bRet = GetDoc()->MergeTable( *pCursor->GetPoint(), bWithPrev ); + + GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr); + ClearFEShellTabCols(*GetDoc(), nullptr); + EndAllAction(); + } + return bRet; +} + +bool SwEditShell::CanMergeTable( bool bWithPrev, bool* pChkNxtPrv ) const +{ + bool bRet = false; + const SwPaM *pCursor = GetCursor(); + const SwTableNode* pTableNd = pCursor->GetNode().FindTableNode(); + if( pTableNd && dynamic_cast< const SwDDETable* >(&pTableNd->GetTable()) == nullptr) + { + bool bNew = pTableNd->GetTable().IsNewModel(); + const SwNodes& rNds = GetDoc()->GetNodes(); + if( pChkNxtPrv ) + { + const SwTableNode* pChkNd = rNds[ pTableNd->GetIndex() - 1 ]->FindTableNode(); + if( pChkNd && dynamic_cast< const SwDDETable* >(&pChkNd->GetTable()) == nullptr && + bNew == pChkNd->GetTable().IsNewModel() && + // Consider table in table case + pChkNd->EndOfSectionIndex() == pTableNd->GetIndex() - 1 ) + { + *pChkNxtPrv = true; + bRet = true; // using Prev is possible + } + else + { + pChkNd = rNds[ pTableNd->EndOfSectionIndex() + 1 ]->GetTableNode(); + if( pChkNd && dynamic_cast< const SwDDETable* >(&pChkNd->GetTable()) == nullptr && + bNew == pChkNd->GetTable().IsNewModel() ) + { + *pChkNxtPrv = false; + bRet = true; // using Next is possible + } + } + } + else + { + const SwTableNode* pTmpTableNd = nullptr; + + if( bWithPrev ) + { + pTmpTableNd = rNds[ pTableNd->GetIndex() - 1 ]->FindTableNode(); + // Consider table in table case + if ( pTmpTableNd && pTmpTableNd->EndOfSectionIndex() != pTableNd->GetIndex() - 1 ) + pTmpTableNd = nullptr; + } + else + pTmpTableNd = rNds[ pTableNd->EndOfSectionIndex() + 1 ]->GetTableNode(); + + bRet = pTmpTableNd && dynamic_cast< const SwDDETable* >(&pTmpTableNd->GetTable()) == nullptr && + bNew == pTmpTableNd->GetTable().IsNewModel(); + } + } + return bRet; +} + +/** create InsertDB as table Undo */ +void SwEditShell::AppendUndoForInsertFromDB( bool bIsTable ) +{ + GetDoc()->AppendUndoForInsertFromDB( *GetCursor(), bIsTable ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |