calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / sc / source / ui / docshell / docsh5.cxx
blobd1749fee1e1b073060f089edec05626413ba2f64
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 <sal/config.h>
23 #include <cassert>
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>
34 #include <docsh.hxx>
35 #include <global.hxx>
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>
46 #include <dbdata.hxx>
47 #include <progress.hxx>
48 #include <olinetab.hxx>
49 #include <patattr.hxx>
50 #include <attrib.hxx>
51 #include <docpool.hxx>
52 #include <uiitems.hxx>
53 #include <sc.hrc>
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;
66 using ::std::vector;
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)
80 if (IsReadOnly())
82 pGlobStrId = STR_READONLYERR;
86 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
87 VclMessageType::Info, VclButtonsType::Ok,
88 ScResId(pGlobStrId)));
89 xInfoBox->run();
91 if (bFocus)
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 );
129 if (!pData)
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;
137 if (pData)
139 // take range, if nothing else is marked
141 SCTAB nDummy;
142 SCCOL nOldCol1;
143 SCROW nOldRow1;
144 SCCOL nOldCol2;
145 SCROW nOldRow2;
146 pData->GetArea( nDummy, nOldCol1,nOldRow1, nOldCol2,nOldRow2 );
147 bool bIsNoName = ( pData->GetName() == STR_DB_LOCAL_NONAME );
149 if (!bSelected)
151 bUseThis = true;
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.
156 nStartCol = nCol;
157 nStartRow = nRow;
158 if (bOnlyDown)
160 nEndCol = rMarked.aEnd.Col();
161 nEndRow = rMarked.aEnd.Row();
163 else
165 nEndCol = nStartCol;
166 nEndRow = nStartRow;
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 );
178 else
180 if ( nOldCol1 == nStartCol && nOldRow1 == nStartRow &&
181 nOldCol2 == nEndCol && nOldRow2 == nEndRow ) // marked precisely?
182 bUseThis = true;
183 else
184 bUseThis = false; // always take marking (Bug 11964)
187 // never take "unnamed" for import
189 if ( bUseThis && eMode == SC_DB_IMPORT && bIsNoName )
190 bUseThis = false;
193 if ( bUseThis )
195 pData->GetArea( nStartTab, nStartCol,nStartRow, nEndCol,nEndRow );
197 else if ( eMode == SC_DB_OLD )
199 pData = nullptr; // nothing found
201 else
203 if ( !bSelected )
204 { // continuous range
205 nStartCol = nCol;
206 nStartRow = nRow;
207 if (bOnlyDown)
209 nEndCol = rMarked.aEnd.Col();
210 nEndRow = rMarked.aEnd.Row();
212 else
214 nEndCol = nStartCol;
215 nEndRow = nStartRow;
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())
232 bSheetLocal = false;
233 pNoNameData = m_pDocument->GetAnonymousDBData();
234 if (!pNoNameData)
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
243 // DBData.
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 ???)
260 SCCOL nOldX2;
261 SCROW nOldY2;
262 SCTAB nOldTab;
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)
271 bHasHeader = true;
273 // Remove AutoFilter button flags only for sheet-local DB range,
274 // not if a temporary is used.
275 if (bSheetLocal)
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 );
287 else
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();
300 OUString aNewName;
303 ++nCount;
304 aNewName = aImport + OUString::number( nCount );
305 pDummy = rDBs.findByUpperName(ScGlobal::getCharClass().uppercase(aNewName));
307 while (pDummy);
308 pNoNameData = new ScDBData( aNewName, nTab,
309 nStartCol,nStartRow, nEndCol,nEndRow,
310 true, bHasHeader );
311 bool ins = rDBs.insert(std::unique_ptr<ScDBData>(pNoNameData));
312 assert(ins); (void)ins;
314 else
316 pNoNameData = new ScDBData(STR_DB_LOCAL_NONAME, nTab,
317 nStartCol,nStartRow, nEndCol,nEndRow,
318 true, bHasHeader );
319 m_pDocument->SetAnonymousDBData(nTab, std::unique_ptr<ScDBData>(pNoNameData));
322 if ( pUndoColl )
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 ) );
337 pData = pNoNameData;
340 return pData;
343 ScDBData* ScDocShell::GetAnonymousDBData(const ScRange& rRange)
345 ScDBCollection* pColl = m_pDocument->GetDBCollection();
346 if (!pColl)
347 return nullptr;
349 ScDBData* pData = pColl->getAnonDBs().getByRange(rRange);
350 if (!pData)
351 return nullptr;
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);
360 return pData;
363 std::unique_ptr<ScDBData> ScDocShell::GetOldAutoDBRange()
365 return std::move(m_pOldAutoDBRange);
368 void ScDocShell::CancelAutoDBRange()
370 // called when dialog is cancelled
371 //moggi:TODO
372 if ( !m_pOldAutoDBRange )
373 return;
375 SCTAB nTab = GetCurTab();
376 ScDBData* pDBData = m_pDocument->GetAnonymousDBData(nTab);
377 if ( pDBData )
379 SCCOL nRangeX1;
380 SCROW nRangeY1;
381 SCCOL nRangeX2;
382 SCROW nRangeY2;
383 SCTAB nRangeTab;
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();
401 // adjust height
402 //! merge with docfunc
404 bool ScDocShell::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab )
406 ScSizeDeviceProvider aProv(this);
407 Fraction aZoom(1,1);
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);
411 if (bChange)
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 );
419 return bChange;
422 void ScDocShell::UpdateAllRowHeights( const ScMarkData* pTabMark )
424 // update automatic row heights
426 ScSizeDeviceProvider aProv(this);
427 Fraction aZoom(1,1);
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());
444 SCTAB nTab;
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();
475 if (!pColl)
476 return;
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 );
493 if (pData)
494 return pData->GetName();
496 OUString aName;
497 pDoc->GetName( pArea->nTab, aName );
498 return aName;
501 void ScDocShell::DoConsolidate( const ScConsolidateParam& rParam, bool bRecord )
503 ScConsData aData;
505 sal_uInt16 nPos;
506 SCCOL nColSize = 0;
507 SCROW nRowSize = 0;
508 bool bErr = false;
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)
518 bErr = true;
521 if (bErr)
523 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
524 VclMessageType::Info, VclButtonsType::Ok,
525 ScResId(STR_CONSOLIDATE_ERR1)));
526 xInfoBox->run();
527 return;
530 // execute
532 weld::WaitObject aWait( GetActiveDialogParent() );
533 ScDocShellModificator aModificator( *this );
535 ScRange aOldDest;
536 ScDBData* pDestData = m_pDocument->GetDBAtCursor( rParam.nCol, rParam.nRow, rParam.nTab, ScDBDataPortion::TOP_LEFT );
537 if (pDestData)
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 );
549 aData.DoneFields();
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();
574 // old outlines
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 );
581 // row state
582 m_pDocument->CopyToDocument(0, 0, nDestTab, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nDestTab,
583 InsertDeleteFlags::NONE, false, *pUndoDoc);
585 // all formulas
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);
594 // old output range
595 if (pDestData)
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) ) );
602 else
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);
611 // old output range
612 if (pDestData)
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;
636 if (rParam.bByCol)
637 ++nPaintEndRow;
638 if (rParam.bByRow)
639 ++nPaintEndCol;
640 if (rParam.bReferenceData)
642 nPaintStartCol = 0;
643 nPaintEndCol = m_pDocument->MaxCol();
644 nPaintEndRow = m_pDocument->MaxRow();
645 nPaintFlags |= PaintPartFlags::Left | PaintPartFlags::Size;
647 if (pDestData)
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;
666 OUString aCompare;
667 while ( nEndTab+1 < nTabCount && m_pDocument->IsScenario(nEndTab+1) )
669 ++nEndTab;
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();
690 if (bRecord)
692 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
693 pUndoDoc->InitUndo( *m_pDocument, nTab,nEndTab ); // also all scenarios
694 // shown table:
695 m_pDocument->CopyToDocument(nStartCol, nStartRow, nTab,
696 nEndCol, nEndRow, nTab, InsertDeleteFlags::ALL,
697 true, *pUndoDoc, &aScenMark);
698 // scenarios
699 for (SCTAB i=nTab+1; i<=nEndTab; i++)
701 pUndoDoc->SetScenario( i, true );
702 OUString aComment;
703 Color aColor;
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();
731 else
733 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
734 VclMessageType::Info, VclButtonsType::Ok,
735 ScResId(STR_PROTECTIONERR)));
736 xInfoBox->run();
739 else
741 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
742 VclMessageType::Info, VclButtonsType::Ok,
743 ScResId(STR_SCENARIO_NOTFOUND)));
744 xInfoBox->run();
747 else
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 )
756 // Undo
757 OUString aOldName;
758 m_pDocument->GetName( nTab, aOldName );
759 OUString aOldComment;
760 Color aOldColor;
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) );
768 // execute
769 ScDocShellModificator aModificator( *this );
770 m_pDocument->RenameTab( nTab, rName );
771 m_pDocument->SetScenarioData( nTab, rComment, rColor, nFlags );
772 PostPaintGridAll();
773 aModificator.SetDocumentModified();
775 if (aOldName != rName)
776 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
778 SfxBindings* pBindings = GetViewBindings();
779 if (pBindings)
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 )
787 rMark.MarkToMulti();
788 if (rMark.IsMultiMarked())
790 SCTAB nNewTab = nTab + 1;
791 while (m_pDocument->IsScenario(nNewTab))
792 ++nNewTab;
794 bool bCopyAll = ( (nFlags & ScScenarioFlags::CopyAll) != ScScenarioFlags::NONE );
795 const ScMarkData* pCopyMark = nullptr;
796 if (!bCopyAll)
797 pCopyMark = &rMark;
799 ScDocShellModificator aModificator( *this );
801 if (bRecord)
802 m_pDocument->BeginDrawUndo(); // drawing layer must do its own undo actions
804 if (m_pDocument->CopyTab( nTab, nNewTab, pCopyMark ))
806 if (bRecord)
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 );
831 if (!bCopyAll)
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 ) );
847 return nNewTab;
850 return nTab;
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
860 ScClipParam aParam;
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 ))
874 OUString aComment;
875 Color aColor;
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 ) );
894 PostPaintExtras();
895 PostPaintGridAll();
897 return nErrVal;
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();
909 if (bCopy)
911 if (bRecord)
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 ))
918 //! EndDrawUndo?
919 return false;
921 else
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);
930 if (bRecord)
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();
939 if ( bVbaEnabled )
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;
953 OUString sSource;
956 Reference< XNameContainer > xLib;
957 if( xLibContainer.is() )
959 css::uno::Any aLibAny = xLibContainer->getByName( aLibName );
960 aLibAny >>= xLib;
962 if( xLib.is() )
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 ) );
975 else
977 if ( m_pDocument->GetChangeTrack() )
978 return false;
980 if ( nSrcTab<nDestTab && nDestTab!=SC_TAB_APPEND )
981 nDestTab--;
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 );
992 pProgress.reset();
993 if (!bDone)
995 return false;
997 else if (bRecord)
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 ) );
1008 PostPaintGridAll();
1009 PostPaintExtras();
1010 aModificator.SetDocumentModified();
1011 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
1013 return true;
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())
1025 ScRange aRange;
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
1029 if (bContinue)
1031 aFunc.RepeatDB( pDBData->GetName(), true, true );
1032 RefreshPivotTables(aRange);
1037 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */