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 <sal/config.h>
25 #include <osl/diagnose.h>
26 #include <vcl/svapp.hxx>
27 #include <vcl/weld.hxx>
28 #include <sfx2/app.hxx>
29 #include <sfx2/bindings.hxx>
30 #include <unotools/charclass.hxx>
32 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
36 #include <globstr.hrc>
37 #include <scresid.hxx>
38 #include <globalnames.hxx>
39 #include <undodat.hxx>
40 #include <undotab.hxx>
41 #include <undoblk.hxx>
42 #include <dpobject.hxx>
43 #include <dpshttab.hxx>
44 #include <dbdocfun.hxx>
45 #include <consoli.hxx>
47 #include <progress.hxx>
48 #include <olinetab.hxx>
49 #include <patattr.hxx>
51 #include <docpool.hxx>
52 #include <uiitems.hxx>
54 #include <sizedev.hxx>
55 #include <clipparam.hxx>
56 #include <rowheightcontext.hxx>
57 #include <refupdatecontext.hxx>
59 using com::sun::star::script::XLibraryContainer
;
60 using com::sun::star::script::vba::XVBACompatibility
;
61 using com::sun::star::container::XNameContainer
;
62 using com::sun::star::uno::Reference
;
63 using com::sun::star::uno::UNO_QUERY
;
65 using ::std::unique_ptr
;
68 // former viewfunc/dbfunc methods
70 void ScDocShell::ErrorMessage(TranslateId pGlobStrId
)
72 //! StopMarking at the (active) view?
74 weld::Window
* pParent
= GetActiveDialogParent();
75 weld::WaitObject
aWaitOff( pParent
);
76 bool bFocus
= pParent
&& pParent
->has_focus();
78 if (pGlobStrId
&& pGlobStrId
== STR_PROTECTIONERR
)
82 pGlobStrId
= STR_READONLYERR
;
86 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(pParent
,
87 VclMessageType::Info
, VclButtonsType::Ok
,
88 ScResId(pGlobStrId
)));
92 pParent
->grab_focus();
95 bool ScDocShell::IsEditable() const
97 // import into read-only document is possible - must be extended if other filters use api
98 // #i108547# MSOOXML filter uses "IsChangeReadOnlyEnabled" property
100 return !IsReadOnly() || m_pDocument
->IsImportingXML() || m_pDocument
->IsChangeReadOnlyEnabled();
103 void ScDocShell::DBAreaDeleted( SCTAB nTab
, SCCOL nX1
, SCROW nY1
, SCCOL nX2
)
105 ScDocShellModificator
aModificator( *this );
106 // the auto-filter is in the first row of the area
107 m_pDocument
->RemoveFlagsTab( nX1
, nY1
, nX2
, nY1
, nTab
, ScMF::Auto
);
108 PostPaint( nX1
, nY1
, nTab
, nX2
, nY1
, nTab
, PaintPartFlags::Grid
);
109 // No SetDocumentModified, as the unnamed database range might have to be restored later.
110 // The UNO hint is broadcast directly instead, to keep UNO objects in valid state.
111 m_pDocument
->BroadcastUno( SfxHint( SfxHintId::DataChanged
) );
114 ScDBData
* ScDocShell::GetDBData( const ScRange
& rMarked
, ScGetDBMode eMode
, ScGetDBSelection eSel
)
116 SCCOL nCol
= rMarked
.aStart
.Col();
117 SCROW nRow
= rMarked
.aStart
.Row();
118 SCTAB nTab
= rMarked
.aStart
.Tab();
120 SCCOL nStartCol
= nCol
;
121 SCROW nStartRow
= nRow
;
122 SCTAB nStartTab
= nTab
;
123 SCCOL nEndCol
= rMarked
.aEnd
.Col();
124 SCROW nEndRow
= rMarked
.aEnd
.Row();
125 // Not simply GetDBAtCursor: The continuous data range for "unnamed" (GetDataArea) may be
126 // located next to the cursor; so a named DB range needs to be searched for there as well.
127 ScDBCollection
* pColl
= m_pDocument
->GetDBCollection();
128 ScDBData
* pData
= m_pDocument
->GetDBAtArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
130 pData
= pColl
->GetDBNearCursor(nCol
, nRow
, nTab
);
132 bool bSelected
= ( eSel
== ScGetDBSelection::ForceMark
||
133 (rMarked
.aStart
!= rMarked
.aEnd
&& eSel
!= ScGetDBSelection::RowDown
) );
134 bool bOnlyDown
= (!bSelected
&& eSel
== ScGetDBSelection::RowDown
&& rMarked
.aStart
.Row() == rMarked
.aEnd
.Row());
136 bool bUseThis
= false;
139 // take range, if nothing else is marked
146 pData
->GetArea( nDummy
, nOldCol1
,nOldRow1
, nOldCol2
,nOldRow2
);
147 bool bIsNoName
= ( pData
->GetName() == STR_DB_LOCAL_NONAME
);
152 if ( bIsNoName
&& (eMode
== SC_DB_MAKE
|| eMode
== SC_DB_AUTOFILTER
) )
154 // If nothing marked or only one row marked, adapt
155 // "unnamed" to contiguous area.
160 nEndCol
= rMarked
.aEnd
.Col();
161 nEndRow
= rMarked
.aEnd
.Row();
168 m_pDocument
->GetDataArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
, false, bOnlyDown
);
169 if ( nOldCol1
!= nStartCol
|| nOldCol2
!= nEndCol
|| nOldRow1
!= nStartRow
)
170 bUseThis
= false; // doesn't fit at all
171 else if ( nOldRow2
!= nEndRow
)
173 // extend range to new end row
174 pData
->SetArea( nTab
, nOldCol1
,nOldRow1
, nOldCol2
,nEndRow
);
180 if ( nOldCol1
== nStartCol
&& nOldRow1
== nStartRow
&&
181 nOldCol2
== nEndCol
&& nOldRow2
== nEndRow
) // marked precisely?
184 bUseThis
= false; // always take marking (Bug 11964)
187 // never take "unnamed" for import
189 if ( bUseThis
&& eMode
== SC_DB_IMPORT
&& bIsNoName
)
195 pData
->GetArea( nStartTab
, nStartCol
,nStartRow
, nEndCol
,nEndRow
);
197 else if ( eMode
== SC_DB_OLD
)
199 pData
= nullptr; // nothing found
204 { // continuous range
209 nEndCol
= rMarked
.aEnd
.Col();
210 nEndRow
= rMarked
.aEnd
.Row();
217 m_pDocument
->GetDataArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
, false, bOnlyDown
);
220 bool bHasHeader
= m_pDocument
->HasColHeader( nStartCol
,nStartRow
, nEndCol
,nEndRow
, nTab
);
222 ScDBData
* pNoNameData
= m_pDocument
->GetAnonymousDBData(nTab
);
223 if ( eMode
!= SC_DB_IMPORT
&& pNoNameData
)
225 // Do not reset AutoFilter range during temporary operations on
226 // other ranges, use the document global temporary anonymous range
227 // instead. But, if AutoFilter is to be toggled then do use the
228 // sheet-local DB range.
229 bool bSheetLocal
= true;
230 if (eMode
!= SC_DB_AUTOFILTER
&& pNoNameData
->HasAutoFilter())
233 pNoNameData
= m_pDocument
->GetAnonymousDBData();
236 m_pDocument
->SetAnonymousDBData( std::unique_ptr
<ScDBData
>(new ScDBData( STR_DB_LOCAL_NONAME
,
237 nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
, true, bHasHeader
) ) );
238 pNoNameData
= m_pDocument
->GetAnonymousDBData();
240 // ScDocShell::CancelAutoDBRange() would restore the
241 // sheet-local anonymous DBData from pOldAutoDBRange, unset so
242 // that won't happen with data of a previous sheet-local
244 m_pOldAutoDBRange
.reset();
246 else if (!m_pOldAutoDBRange
)
248 // store the old unnamed database range with its settings for undo
249 // (store at the first change, get the state before all changes)
250 m_pOldAutoDBRange
.reset( new ScDBData( *pNoNameData
) );
252 else if (m_pOldAutoDBRange
->GetTab() != pNoNameData
->GetTab())
254 // Different sheet-local unnamed DB range than the previous one.
255 *m_pOldAutoDBRange
= *pNoNameData
;
258 SCCOL nOldX1
; // take old range away cleanly
259 SCROW nOldY1
; //! (UNDO ???)
263 pNoNameData
->GetArea( nOldTab
, nOldX1
, nOldY1
, nOldX2
, nOldY2
);
265 // If previously bHasHeader was set and the new range starts on the
266 // same row and intersects the old column range, then don't reset
267 // bHasHeader but assume that the new range still has headers, just
268 // some are empty or numeric.
269 if (!bHasHeader
&& pNoNameData
->HasHeader() && nTab
== nOldTab
&& nStartRow
== nOldY1
&&
270 nStartCol
<= nOldY2
&& nOldY1
<= nEndCol
)
273 // Remove AutoFilter button flags only for sheet-local DB range,
274 // not if a temporary is used.
276 DBAreaDeleted( nOldTab
, nOldX1
, nOldY1
, nOldX2
);
278 pNoNameData
->SetSortParam( ScSortParam() ); // reset parameter
279 pNoNameData
->SetQueryParam( ScQueryParam() );
280 pNoNameData
->SetSubTotalParam( ScSubTotalParam() );
282 pNoNameData
->SetArea( nTab
, nStartCol
,nStartRow
, nEndCol
,nEndRow
); // set anew
283 pNoNameData
->SetByRow( true );
284 pNoNameData
->SetHeader( bHasHeader
);
285 pNoNameData
->SetAutoFilter( false );
289 std::unique_ptr
<ScDBCollection
> pUndoColl
;
291 if (eMode
==SC_DB_IMPORT
)
293 m_pDocument
->PreprocessDBDataUpdate();
294 pUndoColl
.reset( new ScDBCollection( *pColl
) ); // Undo for import range
296 OUString aImport
= ScResId( STR_DBNAME_IMPORT
);
297 tools::Long nCount
= 0;
298 const ScDBData
* pDummy
= nullptr;
299 ScDBCollection::NamedDBs
& rDBs
= pColl
->getNamedDBs();
304 aNewName
= aImport
+ OUString::number( nCount
);
305 pDummy
= rDBs
.findByUpperName(ScGlobal::getCharClass().uppercase(aNewName
));
308 pNoNameData
= new ScDBData( aNewName
, nTab
,
309 nStartCol
,nStartRow
, nEndCol
,nEndRow
,
311 bool ins
= rDBs
.insert(std::unique_ptr
<ScDBData
>(pNoNameData
));
312 assert(ins
); (void)ins
;
316 pNoNameData
= new ScDBData(STR_DB_LOCAL_NONAME
, nTab
,
317 nStartCol
,nStartRow
, nEndCol
,nEndRow
,
319 m_pDocument
->SetAnonymousDBData(nTab
, std::unique_ptr
<ScDBData
>(pNoNameData
));
324 m_pDocument
->CompileHybridFormula();
326 GetUndoManager()->AddUndoAction( std::make_unique
<ScUndoDBData
>( this,
327 std::move(pUndoColl
),
328 std::make_unique
<ScDBCollection
>( *pColl
) ) );
331 // no longer needed to register new range at the Sba
333 // announce "Import1", etc., at the Navigator
334 if (eMode
==SC_DB_IMPORT
)
335 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged
) );
343 ScDBData
* ScDocShell::GetAnonymousDBData(const ScRange
& rRange
)
345 ScDBCollection
* pColl
= m_pDocument
->GetDBCollection();
349 ScDBData
* pData
= pColl
->getAnonDBs().getByRange(rRange
);
353 if (!pData
->HasHeader())
355 bool bHasHeader
= m_pDocument
->HasColHeader(
356 rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), rRange
.aStart
.Tab());
357 pData
->SetHeader(bHasHeader
);
363 std::unique_ptr
<ScDBData
> ScDocShell::GetOldAutoDBRange()
365 return std::move(m_pOldAutoDBRange
);
368 void ScDocShell::CancelAutoDBRange()
370 // called when dialog is cancelled
372 if ( !m_pOldAutoDBRange
)
375 SCTAB nTab
= GetCurTab();
376 ScDBData
* pDBData
= m_pDocument
->GetAnonymousDBData(nTab
);
384 pDBData
->GetArea( nRangeTab
, nRangeX1
, nRangeY1
, nRangeX2
, nRangeY2
);
385 DBAreaDeleted( nRangeTab
, nRangeX1
, nRangeY1
, nRangeX2
);
387 *pDBData
= *m_pOldAutoDBRange
; // restore old settings
389 if ( m_pOldAutoDBRange
->HasAutoFilter() )
391 // restore AutoFilter buttons
392 m_pOldAutoDBRange
->GetArea( nRangeTab
, nRangeX1
, nRangeY1
, nRangeX2
, nRangeY2
);
393 m_pDocument
->ApplyFlagsTab( nRangeX1
, nRangeY1
, nRangeX2
, nRangeY1
, nRangeTab
, ScMF::Auto
);
394 PostPaint( nRangeX1
, nRangeY1
, nRangeTab
, nRangeX2
, nRangeY1
, nRangeTab
, PaintPartFlags::Grid
);
398 m_pOldAutoDBRange
.reset();
402 //! merge with docfunc
404 bool ScDocShell::AdjustRowHeight( SCROW nStartRow
, SCROW nEndRow
, SCTAB nTab
)
406 ScSizeDeviceProvider
aProv(this);
408 sc::RowHeightContext
aCxt(m_pDocument
->MaxRow(), aProv
.GetPPTX(), aProv
.GetPPTY(), aZoom
, aZoom
, aProv
.GetDevice());
409 bool bChange
= m_pDocument
->SetOptimalHeight(aCxt
, nStartRow
,nEndRow
, nTab
, true);
413 // tdf#76183: recalculate objects' positions
414 m_pDocument
->SetDrawPageSize(nTab
);
416 PostPaint( 0,nStartRow
,nTab
, m_pDocument
->MaxCol(),m_pDocument
->MaxRow(),nTab
, PaintPartFlags::Grid
|PaintPartFlags::Left
);
422 void ScDocShell::UpdateAllRowHeights( const ScMarkData
* pTabMark
)
424 // update automatic row heights
426 ScSizeDeviceProvider
aProv(this);
428 sc::RowHeightContext
aCxt(m_pDocument
->MaxRow(), aProv
.GetPPTX(), aProv
.GetPPTY(), aZoom
, aZoom
, aProv
.GetDevice());
429 m_pDocument
->UpdateAllRowHeights(aCxt
, pTabMark
);
432 void ScDocShell::UpdatePendingRowHeights( SCTAB nUpdateTab
, bool bBefore
)
434 bool bIsUndoEnabled
= m_pDocument
->IsUndoEnabled();
435 m_pDocument
->EnableUndo( false );
436 m_pDocument
->LockStreamValid( true ); // ignore draw page size (but not formula results)
437 if ( bBefore
) // check all sheets up to nUpdateTab
439 SCTAB nTabCount
= m_pDocument
->GetTableCount();
440 if ( nUpdateTab
>= nTabCount
)
441 nUpdateTab
= nTabCount
-1; // nUpdateTab is inclusive
443 ScMarkData
aUpdateSheets(m_pDocument
->GetSheetLimits());
445 for (nTab
=0; nTab
<=nUpdateTab
; ++nTab
)
446 if ( m_pDocument
->IsPendingRowHeights( nTab
) )
447 aUpdateSheets
.SelectTable( nTab
, true );
449 if (aUpdateSheets
.GetSelectCount())
450 UpdateAllRowHeights(&aUpdateSheets
); // update with a single progress bar
452 for (nTab
=0; nTab
<=nUpdateTab
; ++nTab
)
453 if ( aUpdateSheets
.GetTableSelect( nTab
) )
455 m_pDocument
->UpdatePageBreaks( nTab
);
456 m_pDocument
->SetPendingRowHeights( nTab
, false );
459 else // only nUpdateTab
461 if ( m_pDocument
->IsPendingRowHeights( nUpdateTab
) )
463 AdjustRowHeight( 0, m_pDocument
->MaxRow(), nUpdateTab
);
464 m_pDocument
->UpdatePageBreaks( nUpdateTab
);
465 m_pDocument
->SetPendingRowHeights( nUpdateTab
, false );
468 m_pDocument
->LockStreamValid( false );
469 m_pDocument
->EnableUndo( bIsUndoEnabled
);
472 void ScDocShell::RefreshPivotTables( const ScRange
& rSource
)
474 ScDPCollection
* pColl
= m_pDocument
->GetDPCollection();
478 ScDBDocFunc
aFunc(*this);
479 for (size_t i
= 0, n
= pColl
->GetCount(); i
< n
; ++i
)
481 ScDPObject
& rOld
= (*pColl
)[i
];
483 const ScSheetSourceDesc
* pSheetDesc
= rOld
.GetSheetDesc();
484 if (pSheetDesc
&& pSheetDesc
->GetSourceRange().Intersects(rSource
))
485 aFunc
.UpdatePivotTable(rOld
, true, false);
489 static OUString
lcl_GetAreaName( ScDocument
* pDoc
, const ScArea
* pArea
)
491 ScDBData
* pData
= pDoc
->GetDBAtArea( pArea
->nTab
, pArea
->nColStart
, pArea
->nRowStart
,
492 pArea
->nColEnd
, pArea
->nRowEnd
);
494 return pData
->GetName();
497 pDoc
->GetName( pArea
->nTab
, aName
);
501 void ScDocShell::DoConsolidate( const ScConsolidateParam
& rParam
, bool bRecord
)
509 for (nPos
=0; nPos
<rParam
.nDataAreaCount
; nPos
++)
511 ScArea
const & rArea
= rParam
.pDataAreas
[nPos
];
512 nColSize
= std::max( nColSize
, SCCOL( rArea
.nColEnd
- rArea
.nColStart
+ 1 ) );
513 nRowSize
= std::max( nRowSize
, SCROW( rArea
.nRowEnd
- rArea
.nRowStart
+ 1 ) );
515 // test if source data were moved
516 if (rParam
.bReferenceData
)
517 if (rArea
.nTab
== rParam
.nTab
&& rArea
.nRowEnd
>= rParam
.nRow
)
523 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
524 VclMessageType::Info
, VclButtonsType::Ok
,
525 ScResId(STR_CONSOLIDATE_ERR1
)));
532 weld::WaitObject
aWait( GetActiveDialogParent() );
533 ScDocShellModificator
aModificator( *this );
536 ScDBData
* pDestData
= m_pDocument
->GetDBAtCursor( rParam
.nCol
, rParam
.nRow
, rParam
.nTab
, ScDBDataPortion::TOP_LEFT
);
538 pDestData
->GetArea(aOldDest
);
540 aData
.SetSize( nColSize
, nRowSize
);
541 aData
.SetFlags( rParam
.eFunction
, rParam
.bByCol
, rParam
.bByRow
, rParam
.bReferenceData
);
542 if ( rParam
.bByCol
|| rParam
.bByRow
)
543 for (nPos
=0; nPos
<rParam
.nDataAreaCount
; nPos
++)
545 ScArea
const & rArea
= rParam
.pDataAreas
[nPos
];
546 aData
.AddFields( m_pDocument
.get(), rArea
.nTab
, rArea
.nColStart
, rArea
.nRowStart
,
547 rArea
.nColEnd
, rArea
.nRowEnd
);
550 for (nPos
=0; nPos
<rParam
.nDataAreaCount
; nPos
++)
552 ScArea
const & rArea
= rParam
.pDataAreas
[nPos
];
553 aData
.AddData( m_pDocument
.get(), rArea
.nTab
, rArea
.nColStart
, rArea
.nRowStart
,
554 rArea
.nColEnd
, rArea
.nRowEnd
);
555 aData
.AddName( lcl_GetAreaName(m_pDocument
.get(), &rArea
) );
558 aData
.GetSize( nColSize
, nRowSize
);
559 if (bRecord
&& nColSize
> 0 && nRowSize
> 0)
561 std::unique_ptr
<ScDBData
> pUndoData(pDestData
? new ScDBData(*pDestData
) : nullptr);
563 SCTAB nDestTab
= rParam
.nTab
;
564 ScArea
aDestArea( rParam
.nTab
, rParam
.nCol
, rParam
.nRow
,
565 rParam
.nCol
+nColSize
-1, rParam
.nRow
+nRowSize
-1 );
566 if (rParam
.bByCol
) ++aDestArea
.nColEnd
;
567 if (rParam
.bByRow
) ++aDestArea
.nRowEnd
;
569 if (rParam
.bReferenceData
)
571 SCTAB nTabCount
= m_pDocument
->GetTableCount();
572 SCROW nInsertCount
= aData
.GetInsertCount();
575 ScOutlineTable
* pTable
= m_pDocument
->GetOutlineTable( nDestTab
);
576 std::unique_ptr
<ScOutlineTable
> pUndoTab(pTable
? new ScOutlineTable( *pTable
) : nullptr);
578 ScDocumentUniquePtr
pUndoDoc(new ScDocument( SCDOCMODE_UNDO
));
579 pUndoDoc
->InitUndo( *m_pDocument
, 0, nTabCount
-1, false, true );
582 m_pDocument
->CopyToDocument(0, 0, nDestTab
, m_pDocument
->MaxCol(), m_pDocument
->MaxRow(), nDestTab
,
583 InsertDeleteFlags::NONE
, false, *pUndoDoc
);
586 m_pDocument
->CopyToDocument(0, 0, 0, m_pDocument
->MaxCol(), m_pDocument
->MaxRow(), nTabCount
-1,
587 InsertDeleteFlags::FORMULA
, false, *pUndoDoc
);
589 // complete output rows
590 m_pDocument
->CopyToDocument(0, aDestArea
.nRowStart
, nDestTab
,
591 m_pDocument
->MaxCol(),aDestArea
.nRowEnd
, nDestTab
,
592 InsertDeleteFlags::ALL
, false, *pUndoDoc
);
596 m_pDocument
->CopyToDocument(aOldDest
, InsertDeleteFlags::ALL
, false, *pUndoDoc
);
598 GetUndoManager()->AddUndoAction(
599 std::make_unique
<ScUndoConsolidate
>( this, aDestArea
, rParam
, std::move(pUndoDoc
),
600 true, nInsertCount
, std::move(pUndoTab
), std::move(pUndoData
) ) );
604 ScDocumentUniquePtr
pUndoDoc(new ScDocument( SCDOCMODE_UNDO
));
605 pUndoDoc
->InitUndo( *m_pDocument
, aDestArea
.nTab
, aDestArea
.nTab
);
607 m_pDocument
->CopyToDocument(aDestArea
.nColStart
, aDestArea
.nRowStart
, aDestArea
.nTab
,
608 aDestArea
.nColEnd
, aDestArea
.nRowEnd
, aDestArea
.nTab
,
609 InsertDeleteFlags::ALL
, false, *pUndoDoc
);
613 m_pDocument
->CopyToDocument(aOldDest
, InsertDeleteFlags::ALL
, false, *pUndoDoc
);
615 GetUndoManager()->AddUndoAction(
616 std::make_unique
<ScUndoConsolidate
>( this, aDestArea
, rParam
, std::move(pUndoDoc
),
617 false, 0, nullptr, std::move(pUndoData
) ) );
621 if (pDestData
) // delete / adjust destination range
623 m_pDocument
->DeleteAreaTab(aOldDest
, InsertDeleteFlags::CONTENTS
);
624 pDestData
->SetArea( rParam
.nTab
, rParam
.nCol
, rParam
.nRow
,
625 rParam
.nCol
+ nColSize
- 1, rParam
.nRow
+ nRowSize
- 1 );
626 pDestData
->SetHeader( rParam
.bByRow
);
629 aData
.OutputToDocument( *m_pDocument
, rParam
.nCol
, rParam
.nRow
, rParam
.nTab
);
631 SCCOL nPaintStartCol
= rParam
.nCol
;
632 SCROW nPaintStartRow
= rParam
.nRow
;
633 SCCOL nPaintEndCol
= nPaintStartCol
+ nColSize
- 1;
634 SCROW nPaintEndRow
= nPaintStartRow
+ nRowSize
- 1;
635 PaintPartFlags nPaintFlags
= PaintPartFlags::Grid
;
640 if (rParam
.bReferenceData
)
643 nPaintEndCol
= m_pDocument
->MaxCol();
644 nPaintEndRow
= m_pDocument
->MaxRow();
645 nPaintFlags
|= PaintPartFlags::Left
| PaintPartFlags::Size
;
649 if ( aOldDest
.aEnd
.Col() > nPaintEndCol
)
650 nPaintEndCol
= aOldDest
.aEnd
.Col();
651 if ( aOldDest
.aEnd
.Row() > nPaintEndRow
)
652 nPaintEndRow
= aOldDest
.aEnd
.Row();
654 PostPaint( nPaintStartCol
, nPaintStartRow
, rParam
.nTab
,
655 nPaintEndCol
, nPaintEndRow
, rParam
.nTab
, nPaintFlags
);
656 aModificator
.SetDocumentModified();
659 void ScDocShell::UseScenario( SCTAB nTab
, const OUString
& rName
, bool bRecord
)
661 if (!m_pDocument
->IsScenario(nTab
))
663 SCTAB nTabCount
= m_pDocument
->GetTableCount();
664 SCTAB nSrcTab
= SCTAB_MAX
;
665 SCTAB nEndTab
= nTab
;
667 while ( nEndTab
+1 < nTabCount
&& m_pDocument
->IsScenario(nEndTab
+1) )
670 if (nSrcTab
> MAXTAB
) // still searching for the scenario?
672 m_pDocument
->GetName( nEndTab
, aCompare
);
673 if (aCompare
== rName
)
674 nSrcTab
= nEndTab
; // found
677 if (ValidTab(nSrcTab
))
679 if ( m_pDocument
->TestCopyScenario( nSrcTab
, nTab
) ) // test cell protection
681 ScDocShellModificator
aModificator( *this );
682 ScMarkData
aScenMark(m_pDocument
->GetSheetLimits());
683 m_pDocument
->MarkScenario( nSrcTab
, nTab
, aScenMark
);
684 const ScRange
& aMultiRange
= aScenMark
.GetMultiMarkArea();
685 SCCOL nStartCol
= aMultiRange
.aStart
.Col();
686 SCROW nStartRow
= aMultiRange
.aStart
.Row();
687 SCCOL nEndCol
= aMultiRange
.aEnd
.Col();
688 SCROW nEndRow
= aMultiRange
.aEnd
.Row();
692 ScDocumentUniquePtr
pUndoDoc(new ScDocument( SCDOCMODE_UNDO
));
693 pUndoDoc
->InitUndo( *m_pDocument
, nTab
,nEndTab
); // also all scenarios
695 m_pDocument
->CopyToDocument(nStartCol
, nStartRow
, nTab
,
696 nEndCol
, nEndRow
, nTab
, InsertDeleteFlags::ALL
,
697 true, *pUndoDoc
, &aScenMark
);
699 for (SCTAB i
=nTab
+1; i
<=nEndTab
; i
++)
701 pUndoDoc
->SetScenario( i
, true );
704 ScScenarioFlags nScenFlags
;
705 m_pDocument
->GetScenarioData( i
, aComment
, aColor
, nScenFlags
);
706 pUndoDoc
->SetScenarioData( i
, aComment
, aColor
, nScenFlags
);
707 bool bActive
= m_pDocument
->IsActiveScenario( i
);
708 pUndoDoc
->SetActiveScenario( i
, bActive
);
709 // At copy-back scenarios also contents
710 if ( nScenFlags
& ScScenarioFlags::TwoWay
)
711 m_pDocument
->CopyToDocument(0, 0, i
, m_pDocument
->MaxCol(), m_pDocument
->MaxRow(), i
,
712 InsertDeleteFlags::ALL
, false, *pUndoDoc
);
715 GetUndoManager()->AddUndoAction(
716 std::make_unique
<ScUndoUseScenario
>( this, aScenMark
,
717 ScArea( nTab
,nStartCol
,nStartRow
,nEndCol
,nEndRow
),
718 std::move(pUndoDoc
), rName
) );
721 m_pDocument
->CopyScenario( nSrcTab
, nTab
);
723 sc::SetFormulaDirtyContext aCxt
;
724 m_pDocument
->SetAllFormulasDirty(aCxt
);
726 // paint all, because the active scenario may be modified in other ranges;
727 //! only if there are visible frames?
728 PostPaint( 0,0,nTab
, m_pDocument
->MaxCol(),m_pDocument
->MaxRow(),nTab
, PaintPartFlags::Grid
);
729 aModificator
.SetDocumentModified();
733 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
734 VclMessageType::Info
, VclButtonsType::Ok
,
735 ScResId(STR_PROTECTIONERR
)));
741 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
742 VclMessageType::Info
, VclButtonsType::Ok
,
743 ScResId(STR_SCENARIO_NOTFOUND
)));
749 OSL_FAIL( "UseScenario on Scenario-Sheet" );
753 void ScDocShell::ModifyScenario( SCTAB nTab
, const OUString
& rName
, const OUString
& rComment
,
754 const Color
& rColor
, ScScenarioFlags nFlags
)
758 m_pDocument
->GetName( nTab
, aOldName
);
759 OUString aOldComment
;
761 ScScenarioFlags nOldFlags
;
762 m_pDocument
->GetScenarioData( nTab
, aOldComment
, aOldColor
, nOldFlags
);
763 GetUndoManager()->AddUndoAction(
764 std::make_unique
<ScUndoScenarioFlags
>(this, nTab
,
765 aOldName
, rName
, aOldComment
, rComment
,
766 aOldColor
, rColor
, nOldFlags
, nFlags
) );
769 ScDocShellModificator
aModificator( *this );
770 m_pDocument
->RenameTab( nTab
, rName
);
771 m_pDocument
->SetScenarioData( nTab
, rComment
, rColor
, nFlags
);
773 aModificator
.SetDocumentModified();
775 if (aOldName
!= rName
)
776 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged
) );
778 SfxBindings
* pBindings
= GetViewBindings();
780 pBindings
->Invalidate( SID_SELECT_SCENARIO
);
783 SCTAB
ScDocShell::MakeScenario( SCTAB nTab
, const OUString
& rName
, const OUString
& rComment
,
784 const Color
& rColor
, ScScenarioFlags nFlags
,
785 ScMarkData
& rMark
, bool bRecord
)
788 if (rMark
.IsMultiMarked())
790 SCTAB nNewTab
= nTab
+ 1;
791 while (m_pDocument
->IsScenario(nNewTab
))
794 bool bCopyAll
= ( (nFlags
& ScScenarioFlags::CopyAll
) != ScScenarioFlags::NONE
);
795 const ScMarkData
* pCopyMark
= nullptr;
799 ScDocShellModificator
aModificator( *this );
802 m_pDocument
->BeginDrawUndo(); // drawing layer must do its own undo actions
804 if (m_pDocument
->CopyTab( nTab
, nNewTab
, pCopyMark
))
808 GetUndoManager()->AddUndoAction(
809 std::make_unique
<ScUndoMakeScenario
>( this, nTab
, nNewTab
,
810 rName
, rComment
, rColor
, nFlags
, rMark
));
813 m_pDocument
->RenameTab( nNewTab
, rName
);
814 m_pDocument
->SetScenario( nNewTab
, true );
815 m_pDocument
->SetScenarioData( nNewTab
, rComment
, rColor
, nFlags
);
817 ScMarkData aDestMark
= rMark
;
818 aDestMark
.SelectOneTable( nNewTab
);
820 //! test for filter / buttons / merging
822 ScPatternAttr
aProtPattern( m_pDocument
->GetPool() );
823 aProtPattern
.GetItemSet().Put( ScProtectionAttr( true ) );
824 m_pDocument
->ApplyPatternAreaTab( 0,0, m_pDocument
->MaxCol(),m_pDocument
->MaxRow(), nNewTab
, aProtPattern
);
826 ScPatternAttr
aPattern( m_pDocument
->GetPool() );
827 aPattern
.GetItemSet().Put( ScMergeFlagAttr( ScMF::Scenario
) );
828 aPattern
.GetItemSet().Put( ScProtectionAttr( true ) );
829 m_pDocument
->ApplySelectionPattern( aPattern
, aDestMark
);
832 m_pDocument
->SetVisible( nNewTab
, false );
834 // this is the active scenario, then
835 m_pDocument
->CopyScenario( nNewTab
, nTab
, true ); // sal_True - don't copy anything from scenario
837 if (nFlags
& ScScenarioFlags::ShowFrame
)
838 PostPaint( 0,0,nTab
, m_pDocument
->MaxCol(),m_pDocument
->MaxRow(),nTab
, PaintPartFlags::Grid
); // paint frames
839 PostPaintExtras(); // table tab
840 aModificator
.SetDocumentModified();
842 // A scenario tab is like a hidden sheet, broadcasting also
843 // notifies ScTabViewShell to add an ScViewData::maTabData entry.
844 Broadcast( ScTablesHint( SC_TAB_INSERTED
, nNewTab
));
845 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged
) );
853 sal_uLong
ScDocShell::TransferTab( ScDocShell
& rSrcDocShell
, SCTAB nSrcPos
,
854 SCTAB nDestPos
, bool bInsertNew
,
855 bool bNotifyAndPaint
)
857 ScDocument
& rSrcDoc
= rSrcDocShell
.GetDocument();
859 // set the transferred area to the copyparam to make adjusting formulas possible
861 ScRange
aRange(0, 0, nSrcPos
, m_pDocument
->MaxCol(), m_pDocument
->MaxRow(), nSrcPos
);
862 aParam
.maRanges
.push_back(aRange
);
863 rSrcDoc
.SetClipParam(aParam
);
865 sal_uLong nErrVal
= m_pDocument
->TransferTab( rSrcDoc
, nSrcPos
, nDestPos
,
866 bInsertNew
); // no insert
868 // TransferTab doesn't copy drawing objects with bInsertNew=FALSE
869 if ( nErrVal
> 0 && !bInsertNew
)
870 m_pDocument
->TransferDrawPage( rSrcDoc
, nSrcPos
, nDestPos
);
872 if(nErrVal
>0 && rSrcDoc
.IsScenario( nSrcPos
))
876 ScScenarioFlags nFlags
;
878 rSrcDoc
.GetScenarioData( nSrcPos
, aComment
,aColor
, nFlags
);
879 m_pDocument
->SetScenario(nDestPos
,true);
880 m_pDocument
->SetScenarioData(nDestPos
,aComment
,aColor
,nFlags
);
881 bool bActive
= rSrcDoc
.IsActiveScenario(nSrcPos
);
882 m_pDocument
->SetActiveScenario(nDestPos
, bActive
);
884 bool bVisible
= rSrcDoc
.IsVisible(nSrcPos
);
885 m_pDocument
->SetVisible(nDestPos
,bVisible
);
889 if ( nErrVal
> 0 && rSrcDoc
.IsTabProtected( nSrcPos
) )
890 m_pDocument
->SetTabProtection(nDestPos
, rSrcDoc
.GetTabProtection(nSrcPos
));
891 if ( bNotifyAndPaint
)
893 Broadcast( ScTablesHint( SC_TAB_INSERTED
, nDestPos
) );
900 bool ScDocShell::MoveTable( SCTAB nSrcTab
, SCTAB nDestTab
, bool bCopy
, bool bRecord
)
902 ScDocShellModificator
aModificator( *this );
904 // #i92477# be consistent with ScDocFunc::InsertTable: any index past the last sheet means "append"
905 // #i101139# nDestTab must be the target position, not APPEND (for CopyTabProtection etc.)
906 if ( nDestTab
>= m_pDocument
->GetTableCount() )
907 nDestTab
= m_pDocument
->GetTableCount();
912 m_pDocument
->BeginDrawUndo(); // drawing layer must do its own undo actions
914 OUString sSrcCodeName
;
915 m_pDocument
->GetCodeName( nSrcTab
, sSrcCodeName
);
916 if (!m_pDocument
->CopyTab( nSrcTab
, nDestTab
))
923 SCTAB nAdjSource
= nSrcTab
;
924 if ( nDestTab
<= nSrcTab
)
925 ++nAdjSource
; // new position of source table after CopyTab
927 if ( m_pDocument
->IsTabProtected( nAdjSource
) )
928 m_pDocument
->CopyTabProtection(nAdjSource
, nDestTab
);
932 unique_ptr
< vector
<SCTAB
> > pSrcList(new vector
<SCTAB
>(1, nSrcTab
));
933 unique_ptr
< vector
<SCTAB
> > pDestList(new vector
<SCTAB
>(1, nDestTab
));
934 GetUndoManager()->AddUndoAction(
935 std::make_unique
<ScUndoCopyTab
>(this, std::move(pSrcList
), std::move(pDestList
)));
938 bool bVbaEnabled
= m_pDocument
->IsInVBAMode();
941 OUString
aLibName( "Standard" );
942 Reference
< XLibraryContainer
> xLibContainer
= GetBasicContainer();
943 Reference
< XVBACompatibility
> xVBACompat( xLibContainer
, UNO_QUERY
);
945 if ( xVBACompat
.is() )
947 aLibName
= xVBACompat
->getProjectName();
950 SCTAB nTabToUse
= nDestTab
;
951 if ( nDestTab
== SC_TAB_APPEND
)
952 nTabToUse
= m_pDocument
->GetMaxTableNumber() - 1;
956 Reference
< XNameContainer
> xLib
;
957 if( xLibContainer
.is() )
959 css::uno::Any aLibAny
= xLibContainer
->getByName( aLibName
);
964 xLib
->getByName( sSrcCodeName
) >>= sSource
;
967 catch ( const css::uno::Exception
& )
970 VBA_InsertModule( *m_pDocument
, nTabToUse
, sSource
);
973 Broadcast( ScTablesHint( SC_TAB_COPIED
, nSrcTab
, nDestTab
) );
977 if ( m_pDocument
->GetChangeTrack() )
980 if ( nSrcTab
<nDestTab
&& nDestTab
!=SC_TAB_APPEND
)
983 if ( nSrcTab
== nDestTab
)
985 //! allow only for api calls?
986 return true; // nothing to do, but valid
989 std::optional
<ScProgress
> pProgress(std::in_place
, this, ScResId(STR_UNDO_MOVE_TAB
),
990 m_pDocument
->GetCodeCount(), true);
991 bool bDone
= m_pDocument
->MoveTab( nSrcTab
, nDestTab
, &*pProgress
);
999 unique_ptr
< vector
<SCTAB
> > pSrcList(new vector
<SCTAB
>(1, nSrcTab
));
1000 unique_ptr
< vector
<SCTAB
> > pDestList(new vector
<SCTAB
>(1, nDestTab
));
1001 GetUndoManager()->AddUndoAction(
1002 std::make_unique
<ScUndoMoveTab
>(this, std::move(pSrcList
), std::move(pDestList
)));
1005 Broadcast( ScTablesHint( SC_TAB_MOVED
, nSrcTab
, nDestTab
) );
1010 aModificator
.SetDocumentModified();
1011 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged
) );
1016 IMPL_LINK( ScDocShell
, RefreshDBDataHdl
, Timer
*, pRefreshTimer
, void )
1018 ScDBDocFunc
aFunc(*this);
1020 ScDBData
* pDBData
= static_cast<ScDBData
*>(pRefreshTimer
);
1021 ScImportParam aImportParam
;
1022 pDBData
->GetImportParam( aImportParam
);
1023 if (aImportParam
.bImport
&& !pDBData
->HasImportSelection())
1026 pDBData
->GetArea( aRange
);
1027 bool bContinue
= aFunc
.DoImport( aRange
.aStart
.Tab(), aImportParam
, nullptr ); //! Api-Flag as parameter
1028 // internal operations (sort, query, subtotal) only if no error
1031 aFunc
.RepeatDB( pDBData
->GetName(), true, true );
1032 RefreshPivotTables(aRange
);
1037 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */