1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <hintids.hxx>
27 #include <IDocumentUndoRedo.hxx>
28 #include <IDocumentChartDataProviderAccess.hxx>
29 #include <IDocumentFieldsAccess.hxx>
30 #include <IDocumentState.hxx>
34 #include <swtable.hxx>
37 #include <cellfrm.hxx>
38 #include <cellatr.hxx>
39 #include <swtblfmt.hxx>
40 #include <swddetbl.hxx>
42 #include <itabenum.hxx>
43 #include <vcl/uitest/logger.hxx>
44 #include <vcl/uitest/eventdescription.hxx>
46 using namespace ::com::sun::star
;
47 using namespace ::com::sun::star::uno
;
50 void collectUIInformation(const OUString
& rAction
, const OUString
& aParameters
)
52 EventDescription aDescription
;
53 aDescription
.aAction
= rAction
;
54 aDescription
.aParameters
= {{"parameters", aParameters
}};
55 aDescription
.aID
= "writer_edit";
56 aDescription
.aKeyWord
= "SwEditWinUIObject";
57 aDescription
.aParent
= "MainWindow";
58 UITestLogger::getInstance().logEvent(aDescription
);
63 //Added for bug #i119954# Application crashed if undo/redo convert nest table to text
64 static bool ConvertTableToText( const SwTableNode
*pTableNode
, sal_Unicode cCh
);
66 static void ConvertNestedTablesToText( const SwTableLines
&rTableLines
, sal_Unicode cCh
)
68 for (size_t n
= 0; n
< rTableLines
.size(); ++n
)
70 SwTableLine
* pTableLine
= rTableLines
[ n
];
71 for (size_t i
= 0; i
< pTableLine
->GetTabBoxes().size(); ++i
)
73 SwTableBox
* pTableBox
= pTableLine
->GetTabBoxes()[ i
];
74 if (pTableBox
->GetTabLines().empty())
76 SwNodeIndex
nodeIndex( *pTableBox
->GetSttNd(), 1 );
77 SwNodeIndex
endNodeIndex( *pTableBox
->GetSttNd()->EndOfSectionNode() );
78 for( ; nodeIndex
< endNodeIndex
; ++nodeIndex
)
80 if ( SwTableNode
* pTableNode
= nodeIndex
.GetNode().GetTableNode() )
81 ConvertTableToText( pTableNode
, cCh
);
86 ConvertNestedTablesToText( pTableBox
->GetTabLines(), cCh
);
92 bool ConvertTableToText( const SwTableNode
*pConstTableNode
, sal_Unicode cCh
)
94 SwTableNode
*pTableNode
= const_cast< SwTableNode
* >( pConstTableNode
);
95 ConvertNestedTablesToText( pTableNode
->GetTable().GetTabLines(), cCh
);
96 return pTableNode
->GetDoc().TableToText( pTableNode
, cCh
);
98 //End for bug #i119954#
100 const SwTable
& SwEditShell::InsertTable( const SwInsertTableOptions
& rInsTableOpts
,
101 sal_uInt16 nRows
, sal_uInt16 nCols
,
102 const SwTableAutoFormat
* pTAFormat
)
105 SwPosition
* pPos
= GetCursor()->GetPoint();
107 bool bEndUndo
= 0 != pPos
->nContent
.GetIndex();
110 StartUndo( SwUndoId::START
);
111 GetDoc()->getIDocumentContentOperations().SplitNode( *pPos
, false );
114 // If called from a shell the adjust item is propagated
115 // from pPos to the new content nodes in the table.
116 const SwTable
*pTable
= GetDoc()->InsertTable( rInsTableOpts
, *pPos
,
118 css::text::HoriOrientation::FULL
, pTAFormat
,
121 EndUndo( SwUndoId::END
);
125 OUString parameter
= " Columns : " + OUString::number( nCols
) + " , Rows : " + OUString::number( nRows
) + " ";
126 collectUIInformation("CREATE_TABLE", parameter
);
131 bool SwEditShell::TextToTable( const SwInsertTableOptions
& rInsTableOpts
,
133 const SwTableAutoFormat
* pTAFormat
)
135 SwWait
aWait( *GetDoc()->GetDocShell(), true );
138 for(const SwPaM
& rPaM
: GetCursor()->GetRingContainer())
141 bRet
|= nullptr != GetDoc()->TextToTable( rInsTableOpts
, rPaM
, cCh
,
142 css::text::HoriOrientation::FULL
, pTAFormat
);
148 bool SwEditShell::TableToText( sal_Unicode cCh
)
150 SwWait
aWait( *GetDoc()->GetDocShell(), true );
151 SwPaM
* pCursor
= GetCursor();
152 const SwTableNode
* pTableNd
=
153 GetDoc()->IsIdxInTable( pCursor
->GetPoint()->nNode
);
160 pCursor
= GetCursor();
162 else if (pCursor
->GetNext() != pCursor
)
166 // tell the charts about the table to be deleted and have them use their own data
167 GetDoc()->getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( &pTableNd
->GetTable() );
171 // move current Cursor out of the listing area
172 SwNodeIndex
aTabIdx( *pTableNd
);
173 pCursor
->DeleteMark();
174 pCursor
->GetPoint()->nNode
= *pTableNd
->EndOfSectionNode();
175 pCursor
->GetPoint()->nContent
.Assign( nullptr, 0 );
176 // move sPoint and Mark out of the area!
178 pCursor
->DeleteMark();
180 //Modified for bug #i119954# Application crashed if undo/redo convert nest table to text
182 bool bRet
= ConvertTableToText( pTableNd
, cCh
);
184 //End for bug #i119954#
185 pCursor
->GetPoint()->nNode
= aTabIdx
;
187 SwContentNode
* pCNd
= pCursor
->GetContentNode();
189 pCursor
->Move( fnMoveForward
, GoInContent
);
191 pCursor
->GetPoint()->nContent
.Assign( pCNd
, 0 );
197 bool SwEditShell::IsTextToTableAvailable() const
199 bool bOnlyText
= false;
200 for(SwPaM
& rPaM
: GetCursor()->GetRingContainer())
202 if( rPaM
.HasMark() && *rPaM
.GetPoint() != *rPaM
.GetMark() )
206 // check if selection is in listing
207 sal_uLong nStt
= rPaM
.GetMark()->nNode
.GetIndex(),
208 nEnd
= rPaM
.GetPoint()->nNode
.GetIndex();
209 if( nStt
> nEnd
) { sal_uLong n
= nStt
; nStt
= nEnd
; nEnd
= n
; }
211 for( ; nStt
<= nEnd
; ++nStt
)
212 if( !GetDoc()->GetNodes()[ nStt
]->IsTextNode() )
226 void SwEditShell::InsertDDETable( const SwInsertTableOptions
& rInsTableOpts
,
227 SwDDEFieldType
* pDDEType
,
228 sal_uInt16 nRows
, sal_uInt16 nCols
)
230 SwPosition
* pPos
= GetCursor()->GetPoint();
234 bool bEndUndo
= 0 != pPos
->nContent
.GetIndex();
237 StartUndo( SwUndoId::START
);
238 GetDoc()->getIDocumentContentOperations().SplitNode( *pPos
, false );
241 const SwInsertTableOptions
aInsTableOpts( rInsTableOpts
.mnInsMode
| SwInsertTableFlags::DefaultBorder
,
242 rInsTableOpts
.mnRowsToRepeat
);
243 SwTable
* pTable
= const_cast<SwTable
*>(GetDoc()->InsertTable( aInsTableOpts
, *pPos
,
244 nRows
, nCols
, css::text::HoriOrientation::FULL
));
246 SwTableNode
* pTableNode
= const_cast<SwTableNode
*>(pTable
->GetTabSortBoxes()[ 0 ]->
247 GetSttNd()->FindTableNode());
248 std::unique_ptr
<SwDDETable
> pDDETable(new SwDDETable( *pTable
, pDDEType
));
249 pTableNode
->SetNewTable( std::move(pDDETable
) ); // set the DDE table
252 EndUndo( SwUndoId::END
);
257 /** update fields of a listing */
258 void SwEditShell::UpdateTable()
260 const SwTableNode
* pTableNd
= IsCursorInTable();
267 EndAllTableBoxEdit();
268 SwTableFormulaUpdate
aTableUpdate( &pTableNd
->GetTable() );
269 GetDoc()->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate
);
276 // get/set Change Mode
278 TableChgMode
SwEditShell::GetTableChgMode() const
281 const SwTableNode
* pTableNd
= IsCursorInTable();
283 eMode
= pTableNd
->GetTable().GetTableChgMode();
285 eMode
= GetTableChgDefaultMode();
289 void SwEditShell::SetTableChgMode( TableChgMode eMode
)
291 const SwTableNode
* pTableNd
= IsCursorInTable();
295 const_cast<SwTable
&>(pTableNd
->GetTable()).SetTableChgMode( eMode
);
296 if( !GetDoc()->getIDocumentState().IsModified() ) // Bug 57028
298 GetDoc()->GetIDocumentUndoRedo().SetUndoNoResetModified();
300 GetDoc()->getIDocumentState().SetModified();
304 bool SwEditShell::GetTableBoxFormulaAttrs( SfxItemSet
& rSet
) const
308 ::GetTableSelCrs( *this, aBoxes
);
312 SwFrame
*pFrame
= GetCurrFrame();
314 pFrame
= pFrame
->GetUpper();
315 } while ( pFrame
&& !pFrame
->IsCellFrame() );
318 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
319 aBoxes
.insert( pBox
);
324 for (size_t n
= 0; n
< aBoxes
.size(); ++n
)
326 const SwTableBox
* pSelBox
= aBoxes
[ n
];
327 const SwTableBoxFormat
* pTableFormat
= static_cast<SwTableBoxFormat
*>(pSelBox
->GetFrameFormat());
330 // Convert formulae into external presentation
331 const SwTable
& rTable
= pSelBox
->GetSttNd()->FindTableNode()->GetTable();
333 SwTableFormulaUpdate
aTableUpdate( &rTable
);
334 aTableUpdate
.m_eFlags
= TBL_BOXNAME
;
335 GetDoc()->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate
);
337 rSet
.Put( pTableFormat
->GetAttrSet() );
340 rSet
.MergeValues( pTableFormat
->GetAttrSet() );
342 return 0 != rSet
.Count();
345 void SwEditShell::SetTableBoxFormulaAttrs( const SfxItemSet
& rSet
)
347 CurrShell
aCurr( this );
350 ::GetTableSelCrs( *this, aBoxes
);
354 SwFrame
*pFrame
= GetCurrFrame();
356 pFrame
= pFrame
->GetUpper();
357 } while ( pFrame
&& !pFrame
->IsCellFrame() );
360 SwTableBox
*pBox
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
361 aBoxes
.insert( pBox
);
366 // When setting a formula, do not check further!
367 if( SfxItemState::SET
== rSet
.GetItemState( RES_BOXATR_FORMULA
))
368 ClearTableBoxContent();
371 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START
, nullptr );
372 for (size_t n
= 0; n
< aBoxes
.size(); ++n
)
374 GetDoc()->SetTableBoxFormulaAttrs( *aBoxes
[ n
], rSet
);
376 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END
, nullptr );
380 bool SwEditShell::IsTableBoxTextFormat() const
385 const SwTableBox
*pBox
= nullptr;
387 SwFrame
*pFrame
= GetCurrFrame();
389 pFrame
= pFrame
->GetUpper();
390 } while ( pFrame
&& !pFrame
->IsCellFrame() );
392 pBox
= static_cast<SwCellFrame
*>(pFrame
)->GetTabBox();
398 sal_uInt32 nFormat
= 0;
399 const SfxPoolItem
* pItem
;
400 if( SfxItemState::SET
== pBox
->GetFrameFormat()->GetAttrSet().GetItemState(
401 RES_BOXATR_FORMAT
, true, &pItem
))
403 nFormat
= static_cast<const SwTableBoxNumFormat
*>(pItem
)->GetValue();
404 return GetDoc()->GetNumberFormatter()->IsTextFormat( nFormat
);
407 sal_uLong nNd
= pBox
->IsValidNumTextNd();
408 if( ULONG_MAX
== nNd
)
411 const OUString
& rText
= GetDoc()->GetNodes()[ nNd
]->GetTextNode()->GetText();
412 if( rText
.isEmpty() )
416 return !GetDoc()->IsNumberFormat( rText
, nFormat
, fVal
);
419 OUString
SwEditShell::GetTableBoxText() const
424 const SwTableBox
*pBox
= nullptr;
426 SwFrame
*pFrame
= GetCurrFrame();
428 pFrame
= pFrame
->GetUpper();
429 } while ( pFrame
&& !pFrame
->IsCellFrame() );
431 pBox
= static_cast<SwCellFrame
*>(pFrame
)->GetTabBox();
435 if( pBox
&& ULONG_MAX
!= ( nNd
= pBox
->IsValidNumTextNd() ) )
436 sRet
= GetDoc()->GetNodes()[ nNd
]->GetTextNode()->GetText();
441 void SwEditShell::SplitTable( SplitTable_HeadlineOption eMode
)
443 SwPaM
*pCursor
= GetCursor();
444 if( pCursor
->GetNode().FindTableNode() )
447 GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY
, nullptr);
449 GetDoc()->SplitTable( *pCursor
->GetPoint(), eMode
, true );
451 GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY
, nullptr);
452 ClearFEShellTabCols(*GetDoc(), nullptr);
457 bool SwEditShell::MergeTable( bool bWithPrev
)
460 SwPaM
*pCursor
= GetCursor();
461 if( pCursor
->GetNode().FindTableNode() )
464 GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY
, nullptr);
466 bRet
= GetDoc()->MergeTable( *pCursor
->GetPoint(), bWithPrev
);
468 GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY
, nullptr);
469 ClearFEShellTabCols(*GetDoc(), nullptr);
475 bool SwEditShell::CanMergeTable( bool bWithPrev
, bool* pChkNxtPrv
) const
478 const SwPaM
*pCursor
= GetCursor();
479 const SwTableNode
* pTableNd
= pCursor
->GetNode().FindTableNode();
480 if( pTableNd
&& dynamic_cast< const SwDDETable
* >(&pTableNd
->GetTable()) == nullptr)
482 bool bNew
= pTableNd
->GetTable().IsNewModel();
483 const SwNodes
& rNds
= GetDoc()->GetNodes();
486 const SwTableNode
* pChkNd
= rNds
[ pTableNd
->GetIndex() - 1 ]->FindTableNode();
487 if( pChkNd
&& dynamic_cast< const SwDDETable
* >(&pChkNd
->GetTable()) == nullptr &&
488 bNew
== pChkNd
->GetTable().IsNewModel() &&
489 // Consider table in table case
490 pChkNd
->EndOfSectionIndex() == pTableNd
->GetIndex() - 1 )
493 bRet
= true; // using Prev is possible
497 pChkNd
= rNds
[ pTableNd
->EndOfSectionIndex() + 1 ]->GetTableNode();
498 if( pChkNd
&& dynamic_cast< const SwDDETable
* >(&pChkNd
->GetTable()) == nullptr &&
499 bNew
== pChkNd
->GetTable().IsNewModel() )
502 bRet
= true; // using Next is possible
508 const SwTableNode
* pTmpTableNd
= nullptr;
512 pTmpTableNd
= rNds
[ pTableNd
->GetIndex() - 1 ]->FindTableNode();
513 // Consider table in table case
514 if ( pTmpTableNd
&& pTmpTableNd
->EndOfSectionIndex() != pTableNd
->GetIndex() - 1 )
515 pTmpTableNd
= nullptr;
518 pTmpTableNd
= rNds
[ pTableNd
->EndOfSectionIndex() + 1 ]->GetTableNode();
520 bRet
= pTmpTableNd
&& dynamic_cast< const SwDDETable
* >(&pTmpTableNd
->GetTable()) == nullptr &&
521 bNew
== pTmpTableNd
->GetTable().IsNewModel();
527 /** create InsertDB as table Undo */
528 void SwEditShell::AppendUndoForInsertFromDB( bool bIsTable
)
530 GetDoc()->AppendUndoForInsertFromDB( *GetCursor(), bIsTable
);
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */