tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / docshell / docsh5.cxx
blob52fdbfada36ac280fa415133ab00932f0e9193dd
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 <dociter.hxx>
35 #include <docsh.hxx>
36 #include <global.hxx>
37 #include <globstr.hrc>
38 #include <scresid.hxx>
39 #include <globalnames.hxx>
40 #include <undodat.hxx>
41 #include <undotab.hxx>
42 #include <undoblk.hxx>
43 #include <dpobject.hxx>
44 #include <dpshttab.hxx>
45 #include <dbdocfun.hxx>
46 #include <consoli.hxx>
47 #include <dbdata.hxx>
48 #include <progress.hxx>
49 #include <olinetab.hxx>
50 #include <patattr.hxx>
51 #include <attrib.hxx>
52 #include <docpool.hxx>
53 #include <uiitems.hxx>
54 #include <sc.hrc>
55 #include <sizedev.hxx>
56 #include <clipparam.hxx>
57 #include <rowheightcontext.hxx>
58 #include <refupdatecontext.hxx>
60 using com::sun::star::script::XLibraryContainer;
61 using com::sun::star::script::vba::XVBACompatibility;
62 using com::sun::star::container::XNameContainer;
63 using com::sun::star::uno::Reference;
64 using com::sun::star::uno::UNO_QUERY;
66 using ::std::unique_ptr;
67 using ::std::vector;
69 // former viewfunc/dbfunc methods
71 void ScDocShell::ErrorMessage(TranslateId pGlobStrId)
73 //! StopMarking at the (active) view?
75 weld::Window* pParent = GetActiveDialogParent();
76 weld::WaitObject aWaitOff( pParent );
77 bool bFocus = pParent && pParent->has_focus();
79 if (pGlobStrId && pGlobStrId == STR_PROTECTIONERR)
81 if (IsReadOnly())
83 pGlobStrId = STR_READONLYERR;
87 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
88 VclMessageType::Info, VclButtonsType::Ok,
89 ScResId(pGlobStrId)));
90 xInfoBox->run();
92 if (bFocus)
93 pParent->grab_focus();
96 bool ScDocShell::IsEditable() const
98 // import into read-only document is possible - must be extended if other filters use api
99 // #i108547# MSOOXML filter uses "IsChangeReadOnlyEnabled" property
101 return !IsReadOnly() || m_pDocument->IsImportingXML() || m_pDocument->IsChangeReadOnlyEnabled();
104 void ScDocShell::DBAreaDeleted( SCTAB nTab, SCCOL nX1, SCROW nY1, SCCOL nX2 )
106 ScDocShellModificator aModificator( *this );
107 // the auto-filter is in the first row of the area
108 m_pDocument->RemoveFlagsTab( nX1, nY1, nX2, nY1, nTab, ScMF::Auto );
109 PostPaint( nX1, nY1, nTab, nX2, nY1, nTab, PaintPartFlags::Grid );
110 // No SetDocumentModified, as the unnamed database range might have to be restored later.
111 // The UNO hint is broadcast directly instead, to keep UNO objects in valid state.
112 m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
115 ScDBData* ScDocShell::GetDBData( const ScRange& rMarked, ScGetDBMode eMode, ScGetDBSelection eSel )
117 SCCOL nCol = rMarked.aStart.Col();
118 SCROW nRow = rMarked.aStart.Row();
119 SCTAB nTab = rMarked.aStart.Tab();
121 SCCOL nStartCol = nCol;
122 SCROW nStartRow = nRow;
123 SCTAB nStartTab = nTab;
124 SCCOL nEndCol = rMarked.aEnd.Col();
125 SCROW nEndRow = rMarked.aEnd.Row();
126 // Not simply GetDBAtCursor: The continuous data range for "unnamed" (GetDataArea) may be
127 // located next to the cursor; so a named DB range needs to be searched for there as well.
128 ScDBCollection* pColl = m_pDocument->GetDBCollection();
129 ScDBData* pData = m_pDocument->GetDBAtArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
130 if (!pData)
131 pData = pColl->GetDBNearCursor(nCol, nRow, nTab );
133 bool bSelected = ( eSel == ScGetDBSelection::ForceMark ||
134 (rMarked.aStart != rMarked.aEnd && eSel != ScGetDBSelection::RowDown) );
135 bool bOnlyDown = (!bSelected && eSel == ScGetDBSelection::RowDown && rMarked.aStart.Row() == rMarked.aEnd.Row());
137 bool bUseThis = false;
138 if (pData)
140 // take range, if nothing else is marked
142 SCTAB nDummy;
143 SCCOL nOldCol1;
144 SCROW nOldRow1;
145 SCCOL nOldCol2;
146 SCROW nOldRow2;
147 pData->GetArea( nDummy, nOldCol1,nOldRow1, nOldCol2,nOldRow2 );
148 bool bIsNoName = ( pData->GetName() == STR_DB_LOCAL_NONAME );
150 if (!bSelected)
152 bUseThis = true;
153 if ( bIsNoName && (eMode == SC_DB_MAKE || eMode == SC_DB_AUTOFILTER) )
155 // If nothing marked or only one row marked, adapt
156 // "unnamed" to contiguous area.
157 nStartCol = nCol;
158 nStartRow = nRow;
159 if (bOnlyDown)
161 nEndCol = rMarked.aEnd.Col();
162 nEndRow = rMarked.aEnd.Row();
164 else
166 nEndCol = nStartCol;
167 nEndRow = nStartRow;
169 m_pDocument->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, bOnlyDown );
170 if ( nOldCol1 != nStartCol || nOldCol2 != nEndCol || nOldRow1 != nStartRow )
171 bUseThis = false; // doesn't fit at all
172 else if ( nOldRow2 != nEndRow )
174 // extend range to new end row
175 pData->SetArea( nTab, nOldCol1,nOldRow1, nOldCol2,nEndRow );
179 else
181 if ( nOldCol1 == nStartCol && nOldRow1 == nStartRow &&
182 nOldCol2 == nEndCol && nOldRow2 == nEndRow ) // marked precisely?
183 bUseThis = true;
184 else
185 bUseThis = false; // always take marking (Bug 11964)
188 // never take "unnamed" for import
190 if ( bUseThis && eMode == SC_DB_IMPORT && bIsNoName )
191 bUseThis = false;
194 if ( bUseThis )
196 pData->GetArea( nStartTab, nStartCol,nStartRow, nEndCol,nEndRow );
198 else if ( eMode == SC_DB_OLD )
200 pData = nullptr; // nothing found
202 else
204 if ( !bSelected )
205 { // continuous range
206 nStartCol = nCol;
207 nStartRow = nRow;
208 if (bOnlyDown)
210 nEndCol = rMarked.aEnd.Col();
211 nEndRow = rMarked.aEnd.Row();
213 else
215 nEndCol = nStartCol;
216 nEndRow = nStartRow;
218 m_pDocument->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, bOnlyDown );
221 bool bHasHeader = m_pDocument->HasColHeader( nStartCol,nStartRow, nEndCol,nEndRow, nTab );
223 ScDBData* pNoNameData = m_pDocument->GetAnonymousDBData(nTab);
224 if ( eMode != SC_DB_IMPORT && pNoNameData)
226 // Do not reset AutoFilter range during temporary operations on
227 // other ranges, use the document global temporary anonymous range
228 // instead. But, if AutoFilter is to be toggled then do use the
229 // sheet-local DB range.
230 bool bSheetLocal = true;
231 if (eMode != SC_DB_AUTOFILTER && pNoNameData->HasAutoFilter())
233 bSheetLocal = false;
234 pNoNameData = m_pDocument->GetAnonymousDBData();
235 if (!pNoNameData)
237 m_pDocument->SetAnonymousDBData( std::unique_ptr<ScDBData>(new ScDBData( STR_DB_LOCAL_NONAME,
238 nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, bHasHeader) ) );
239 pNoNameData = m_pDocument->GetAnonymousDBData();
241 // ScDocShell::CancelAutoDBRange() would restore the
242 // sheet-local anonymous DBData from pOldAutoDBRange, unset so
243 // that won't happen with data of a previous sheet-local
244 // DBData.
245 m_pOldAutoDBRange.reset();
247 else if (!m_pOldAutoDBRange)
249 // store the old unnamed database range with its settings for undo
250 // (store at the first change, get the state before all changes)
251 m_pOldAutoDBRange.reset( new ScDBData( *pNoNameData ) );
253 else if (m_pOldAutoDBRange->GetTab() != pNoNameData->GetTab())
255 // Different sheet-local unnamed DB range than the previous one.
256 *m_pOldAutoDBRange = *pNoNameData;
259 SCCOL nOldX1; // take old range away cleanly
260 SCROW nOldY1; //! (UNDO ???)
261 SCCOL nOldX2;
262 SCROW nOldY2;
263 SCTAB nOldTab;
264 pNoNameData->GetArea( nOldTab, nOldX1, nOldY1, nOldX2, nOldY2 );
266 // If previously bHasHeader was set and the new range starts on the
267 // same row and intersects the old column range, then don't reset
268 // bHasHeader but assume that the new range still has headers, just
269 // some are empty or numeric.
270 if (!bHasHeader && pNoNameData->HasHeader() && nTab == nOldTab && nStartRow == nOldY1 &&
271 nStartCol <= nOldY2 && nOldY1 <= nEndCol)
272 bHasHeader = true;
274 // Remove AutoFilter button flags only for sheet-local DB range,
275 // not if a temporary is used.
276 if (bSheetLocal)
277 DBAreaDeleted( nOldTab, nOldX1, nOldY1, nOldX2 );
279 pNoNameData->SetSortParam( ScSortParam() ); // reset parameter
280 pNoNameData->SetQueryParam( ScQueryParam() );
281 pNoNameData->SetSubTotalParam( ScSubTotalParam() );
283 pNoNameData->SetArea( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); // set anew
284 pNoNameData->SetByRow( true );
285 pNoNameData->SetHeader( bHasHeader );
286 pNoNameData->SetAutoFilter( false );
288 else
290 std::unique_ptr<ScDBCollection> pUndoColl;
292 if (eMode==SC_DB_IMPORT)
294 m_pDocument->PreprocessDBDataUpdate();
295 pUndoColl.reset( new ScDBCollection( *pColl ) ); // Undo for import range
297 OUString aImport = ScResId( STR_DBNAME_IMPORT );
298 tools::Long nCount = 0;
299 const ScDBData* pDummy = nullptr;
300 ScDBCollection::NamedDBs& rDBs = pColl->getNamedDBs();
301 OUString aNewName;
304 ++nCount;
305 aNewName = aImport + OUString::number( nCount );
306 pDummy = rDBs.findByUpperName(ScGlobal::getCharClass().uppercase(aNewName));
308 while (pDummy);
309 pNoNameData = new ScDBData( aNewName, nTab,
310 nStartCol,nStartRow, nEndCol,nEndRow,
311 true, bHasHeader );
312 bool ins = rDBs.insert(std::unique_ptr<ScDBData>(pNoNameData));
313 assert(ins); (void)ins;
315 else
317 pNoNameData = new ScDBData(STR_DB_LOCAL_NONAME, nTab,
318 nStartCol,nStartRow, nEndCol,nEndRow,
319 true, bHasHeader );
320 m_pDocument->SetAnonymousDBData(nTab, std::unique_ptr<ScDBData>(pNoNameData));
323 if ( pUndoColl )
325 m_pDocument->CompileHybridFormula();
327 GetUndoManager()->AddUndoAction( std::make_unique<ScUndoDBData>( this,
328 std::move(pUndoColl),
329 std::make_unique<ScDBCollection>( *pColl ) ) );
332 // no longer needed to register new range at the Sba
334 // announce "Import1", etc., at the Navigator
335 if (eMode==SC_DB_IMPORT)
336 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
338 pData = pNoNameData;
341 return pData;
344 ScDBData* ScDocShell::GetAnonymousDBData(const ScRange& rRange)
346 ScDBCollection* pColl = m_pDocument->GetDBCollection();
347 if (!pColl)
348 return nullptr;
350 ScDBData* pData = pColl->getAnonDBs().getByRange(rRange);
351 if (!pData)
352 return nullptr;
354 if (!pData->HasHeader())
356 bool bHasHeader = m_pDocument->HasColHeader(
357 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab());
358 pData->SetHeader(bHasHeader);
361 return pData;
364 std::unique_ptr<ScDBData> ScDocShell::GetOldAutoDBRange()
366 return std::move(m_pOldAutoDBRange);
369 void ScDocShell::CancelAutoDBRange()
371 // called when dialog is cancelled
372 //moggi:TODO
373 if ( !m_pOldAutoDBRange )
374 return;
376 SCTAB nTab = GetCurTab();
377 ScDBData* pDBData = m_pDocument->GetAnonymousDBData(nTab);
378 if ( pDBData )
380 SCCOL nRangeX1;
381 SCROW nRangeY1;
382 SCCOL nRangeX2;
383 SCROW nRangeY2;
384 SCTAB nRangeTab;
385 pDBData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
386 DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
388 *pDBData = *m_pOldAutoDBRange; // restore old settings
390 if ( m_pOldAutoDBRange->HasAutoFilter() )
392 // restore AutoFilter buttons
393 m_pOldAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
394 m_pDocument->ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
395 PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
399 m_pOldAutoDBRange.reset();
402 // adjust height
403 //! merge with docfunc
405 bool ScDocShell::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab )
407 ScSizeDeviceProvider aProv(this);
408 Fraction aZoom(1,1);
409 sc::RowHeightContext aCxt(m_pDocument->MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aZoom, aZoom, aProv.GetDevice());
410 bool bChange = m_pDocument->SetOptimalHeight(aCxt, nStartRow,nEndRow, nTab, true);
412 if (bChange)
414 // tdf#76183: recalculate objects' positions
415 m_pDocument->SetDrawPageSize(nTab);
417 PostPaint( 0,nStartRow,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid|PaintPartFlags::Left );
420 return bChange;
423 void ScDocShell::UpdateAllRowHeights( const ScMarkData* pTabMark )
425 // update automatic row heights
427 ScSizeDeviceProvider aProv(this);
428 Fraction aZoom(1,1);
429 sc::RowHeightContext aCxt(m_pDocument->MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aZoom, aZoom, aProv.GetDevice());
430 m_pDocument->UpdateAllRowHeights(aCxt, pTabMark);
433 void ScDocShell::UpdateAllRowHeights(const bool bOnlyUsedRows)
435 // update automatic row heights on all sheets using the newer ScDocRowHeightUpdater
436 ScSizeDeviceProvider aProv(this);
437 ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(),
438 aProv.GetPPTY(), nullptr);
439 aUpdater.update(bOnlyUsedRows);
442 void ScDocShell::UpdatePendingRowHeights( SCTAB nUpdateTab, bool bBefore )
444 bool bIsUndoEnabled = m_pDocument->IsUndoEnabled();
445 m_pDocument->EnableUndo( false );
446 m_pDocument->LockStreamValid( true ); // ignore draw page size (but not formula results)
447 if ( bBefore ) // check all sheets up to nUpdateTab
449 SCTAB nTabCount = m_pDocument->GetTableCount();
450 if ( nUpdateTab >= nTabCount )
451 nUpdateTab = nTabCount-1; // nUpdateTab is inclusive
453 ScMarkData aUpdateSheets(m_pDocument->GetSheetLimits());
454 SCTAB nTab;
455 for (nTab=0; nTab<=nUpdateTab; ++nTab)
456 if ( m_pDocument->IsPendingRowHeights( nTab ) )
457 aUpdateSheets.SelectTable( nTab, true );
459 if (aUpdateSheets.GetSelectCount())
460 UpdateAllRowHeights(&aUpdateSheets); // update with a single progress bar
462 for (nTab=0; nTab<=nUpdateTab; ++nTab)
463 if ( aUpdateSheets.GetTableSelect( nTab ) )
465 m_pDocument->UpdatePageBreaks( nTab );
466 m_pDocument->SetPendingRowHeights( nTab, false );
469 else // only nUpdateTab
471 if ( m_pDocument->IsPendingRowHeights( nUpdateTab ) )
473 AdjustRowHeight( 0, m_pDocument->MaxRow(), nUpdateTab );
474 m_pDocument->UpdatePageBreaks( nUpdateTab );
475 m_pDocument->SetPendingRowHeights( nUpdateTab, false );
478 m_pDocument->LockStreamValid( false );
479 m_pDocument->EnableUndo( bIsUndoEnabled );
482 void ScDocShell::RefreshPivotTables( const ScRange& rSource )
484 ScDPCollection* pColl = m_pDocument->GetDPCollection();
485 if (!pColl)
486 return;
488 ScDBDocFunc aFunc(*this);
489 for (size_t i = 0, n = pColl->GetCount(); i < n; ++i)
491 ScDPObject& rOld = (*pColl)[i];
493 const ScSheetSourceDesc* pSheetDesc = rOld.GetSheetDesc();
494 if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rSource))
495 aFunc.UpdatePivotTable(rOld, true, false);
499 static OUString lcl_GetAreaName( ScDocument* pDoc, const ScArea* pArea )
501 ScDBData* pData = pDoc->GetDBAtArea( pArea->nTab, pArea->nColStart, pArea->nRowStart,
502 pArea->nColEnd, pArea->nRowEnd );
503 if (pData)
504 return pData->GetName();
506 OUString aName;
507 pDoc->GetName( pArea->nTab, aName );
508 return aName;
511 static ScDBData* getUndoData(ScDBData* pDestData)
513 if (!pDestData)
514 return nullptr;
515 return new ScDBData(*pDestData);
518 void ScDocShell::DoConsolidate( const ScConsolidateParam& rParam, bool bRecord )
520 ScConsData aData;
522 sal_uInt16 nPos;
523 SCCOL nColSize = 0;
524 SCROW nRowSize = 0;
525 bool bErr = false;
526 for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
528 ScArea const & rArea = rParam.pDataAreas[nPos];
529 nColSize = std::max( nColSize, SCCOL( rArea.nColEnd - rArea.nColStart + 1 ) );
530 nRowSize = std::max( nRowSize, SCROW( rArea.nRowEnd - rArea.nRowStart + 1 ) );
532 // test if source data were moved
533 if (rParam.bReferenceData)
534 if (rArea.nTab == rParam.nTab && rArea.nRowEnd >= rParam.nRow)
535 bErr = true;
538 if (bErr)
540 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
541 VclMessageType::Info, VclButtonsType::Ok,
542 ScResId(STR_CONSOLIDATE_ERR1)));
543 xInfoBox->run();
544 return;
547 // execute
549 weld::WaitObject aWait( GetActiveDialogParent() );
550 ScDocShellModificator aModificator( *this );
552 ScRange aOldDest;
553 ScDBData* pDestData = m_pDocument->GetDBAtCursor( rParam.nCol, rParam.nRow, rParam.nTab, ScDBDataPortion::TOP_LEFT );
554 if (pDestData)
555 pDestData->GetArea(aOldDest);
557 aData.SetSize( nColSize, nRowSize );
558 aData.SetFlags( rParam.eFunction, rParam.bByCol, rParam.bByRow, rParam.bReferenceData );
559 if ( rParam.bByCol || rParam.bByRow )
560 for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
562 ScArea const & rArea = rParam.pDataAreas[nPos];
563 aData.AddFields( m_pDocument.get(), rArea.nTab, rArea.nColStart, rArea.nRowStart,
564 rArea.nColEnd, rArea.nRowEnd );
566 aData.DoneFields();
567 for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
569 ScArea const & rArea = rParam.pDataAreas[nPos];
570 aData.AddData( m_pDocument.get(), rArea.nTab, rArea.nColStart, rArea.nRowStart,
571 rArea.nColEnd, rArea.nRowEnd );
572 aData.AddName( lcl_GetAreaName(m_pDocument.get(), &rArea) );
575 aData.GetSize( nColSize, nRowSize );
576 if (bRecord && nColSize > 0 && nRowSize > 0)
578 std::unique_ptr<ScDBData> pUndoData(getUndoData(pDestData));
580 SCTAB nDestTab = rParam.nTab;
581 ScArea aDestArea( rParam.nTab, rParam.nCol, rParam.nRow,
582 rParam.nCol+nColSize-1, rParam.nRow+nRowSize-1 );
583 if (rParam.bByCol) ++aDestArea.nColEnd;
584 if (rParam.bByRow) ++aDestArea.nRowEnd;
586 if (rParam.bReferenceData)
588 SCTAB nTabCount = m_pDocument->GetTableCount();
589 SCROW nInsertCount = aData.GetInsertCount();
591 // old outlines
592 ScOutlineTable* pTable = m_pDocument->GetOutlineTable( nDestTab );
593 std::unique_ptr<ScOutlineTable> pUndoTab(pTable ? new ScOutlineTable( *pTable ) : nullptr);
595 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
596 pUndoDoc->InitUndo( *m_pDocument, 0, nTabCount-1, false, true );
598 // row state
599 m_pDocument->CopyToDocument(0, 0, nDestTab, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nDestTab,
600 InsertDeleteFlags::NONE, false, *pUndoDoc);
602 // all formulas
603 m_pDocument->CopyToDocument(0, 0, 0, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nTabCount-1,
604 InsertDeleteFlags::FORMULA, false, *pUndoDoc);
606 // complete output rows
607 m_pDocument->CopyToDocument(0, aDestArea.nRowStart, nDestTab,
608 m_pDocument->MaxCol(),aDestArea.nRowEnd, nDestTab,
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 true, nInsertCount, std::move(pUndoTab), std::move(pUndoData) ) );
619 else
621 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
622 pUndoDoc->InitUndo( *m_pDocument, aDestArea.nTab, aDestArea.nTab );
624 m_pDocument->CopyToDocument(aDestArea.nColStart, aDestArea.nRowStart, aDestArea.nTab,
625 aDestArea.nColEnd, aDestArea.nRowEnd, aDestArea.nTab,
626 InsertDeleteFlags::ALL, false, *pUndoDoc);
628 // old output range
629 if (pDestData)
630 m_pDocument->CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, *pUndoDoc);
632 GetUndoManager()->AddUndoAction(
633 std::make_unique<ScUndoConsolidate>( this, aDestArea, rParam, std::move(pUndoDoc),
634 false, 0, nullptr, std::move(pUndoData) ) );
638 if (pDestData) // delete / adjust destination range
640 m_pDocument->DeleteAreaTab(aOldDest, InsertDeleteFlags::CONTENTS);
641 pDestData->SetArea( rParam.nTab, rParam.nCol, rParam.nRow,
642 rParam.nCol + nColSize - 1, rParam.nRow + nRowSize - 1 );
643 pDestData->SetHeader( rParam.bByRow );
646 aData.OutputToDocument( *m_pDocument, rParam.nCol, rParam.nRow, rParam.nTab );
648 SCCOL nPaintStartCol = rParam.nCol;
649 SCROW nPaintStartRow = rParam.nRow;
650 SCCOL nPaintEndCol = nPaintStartCol + nColSize - 1;
651 SCROW nPaintEndRow = nPaintStartRow + nRowSize - 1;
652 PaintPartFlags nPaintFlags = PaintPartFlags::Grid;
653 if (rParam.bByCol)
654 ++nPaintEndRow;
655 if (rParam.bByRow)
656 ++nPaintEndCol;
657 if (rParam.bReferenceData)
659 nPaintStartCol = 0;
660 nPaintEndCol = m_pDocument->MaxCol();
661 nPaintEndRow = m_pDocument->MaxRow();
662 nPaintFlags |= PaintPartFlags::Left | PaintPartFlags::Size;
664 if (pDestData)
666 if ( aOldDest.aEnd.Col() > nPaintEndCol )
667 nPaintEndCol = aOldDest.aEnd.Col();
668 if ( aOldDest.aEnd.Row() > nPaintEndRow )
669 nPaintEndRow = aOldDest.aEnd.Row();
671 PostPaint( nPaintStartCol, nPaintStartRow, rParam.nTab,
672 nPaintEndCol, nPaintEndRow, rParam.nTab, nPaintFlags );
673 aModificator.SetDocumentModified();
676 void ScDocShell::UseScenario( SCTAB nTab, const OUString& rName, bool bRecord )
678 if (!m_pDocument->IsScenario(nTab))
680 SCTAB nTabCount = m_pDocument->GetTableCount();
681 SCTAB nSrcTab = SCTAB_MAX;
682 SCTAB nEndTab = nTab;
683 OUString aCompare;
684 while ( nEndTab+1 < nTabCount && m_pDocument->IsScenario(nEndTab+1) )
686 ++nEndTab;
687 if (nSrcTab > MAXTAB) // still searching for the scenario?
689 m_pDocument->GetName( nEndTab, aCompare );
690 if (aCompare == rName)
691 nSrcTab = nEndTab; // found
694 if (ValidTab(nSrcTab))
696 if ( m_pDocument->TestCopyScenario( nSrcTab, nTab ) ) // test cell protection
698 ScDocShellModificator aModificator( *this );
699 ScMarkData aScenMark(m_pDocument->GetSheetLimits());
700 m_pDocument->MarkScenario( nSrcTab, nTab, aScenMark );
701 const ScRange& aMultiRange = aScenMark.GetMultiMarkArea();
702 SCCOL nStartCol = aMultiRange.aStart.Col();
703 SCROW nStartRow = aMultiRange.aStart.Row();
704 SCCOL nEndCol = aMultiRange.aEnd.Col();
705 SCROW nEndRow = aMultiRange.aEnd.Row();
707 if (bRecord)
709 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
710 pUndoDoc->InitUndo( *m_pDocument, nTab,nEndTab ); // also all scenarios
711 // shown table:
712 m_pDocument->CopyToDocument(nStartCol, nStartRow, nTab,
713 nEndCol, nEndRow, nTab, InsertDeleteFlags::ALL,
714 true, *pUndoDoc, &aScenMark);
715 // scenarios
716 for (SCTAB i=nTab+1; i<=nEndTab; i++)
718 pUndoDoc->SetScenario( i, true );
719 OUString aComment;
720 Color aColor;
721 ScScenarioFlags nScenFlags;
722 m_pDocument->GetScenarioData( i, aComment, aColor, nScenFlags );
723 pUndoDoc->SetScenarioData( i, aComment, aColor, nScenFlags );
724 bool bActive = m_pDocument->IsActiveScenario( i );
725 pUndoDoc->SetActiveScenario( i, bActive );
726 // At copy-back scenarios also contents
727 if ( nScenFlags & ScScenarioFlags::TwoWay )
728 m_pDocument->CopyToDocument(0, 0, i, m_pDocument->MaxCol(), m_pDocument->MaxRow(), i,
729 InsertDeleteFlags::ALL, false, *pUndoDoc );
732 GetUndoManager()->AddUndoAction(
733 std::make_unique<ScUndoUseScenario>( this, aScenMark,
734 ScArea( nTab,nStartCol,nStartRow,nEndCol,nEndRow ),
735 std::move(pUndoDoc), rName ) );
738 m_pDocument->CopyScenario( nSrcTab, nTab );
740 sc::SetFormulaDirtyContext aCxt;
741 m_pDocument->SetAllFormulasDirty(aCxt);
743 // paint all, because the active scenario may be modified in other ranges;
744 //! only if there are visible frames?
745 PostPaint( 0,0,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid );
746 aModificator.SetDocumentModified();
748 else
750 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
751 VclMessageType::Info, VclButtonsType::Ok,
752 ScResId(STR_PROTECTIONERR)));
753 xInfoBox->run();
756 else
758 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
759 VclMessageType::Info, VclButtonsType::Ok,
760 ScResId(STR_SCENARIO_NOTFOUND)));
761 xInfoBox->run();
764 else
766 OSL_FAIL( "UseScenario on Scenario-Sheet" );
770 void ScDocShell::ModifyScenario( SCTAB nTab, const OUString& rName, const OUString& rComment,
771 const Color& rColor, ScScenarioFlags nFlags )
773 // Undo
774 OUString aOldName;
775 m_pDocument->GetName( nTab, aOldName );
776 OUString aOldComment;
777 Color aOldColor;
778 ScScenarioFlags nOldFlags;
779 m_pDocument->GetScenarioData( nTab, aOldComment, aOldColor, nOldFlags );
780 GetUndoManager()->AddUndoAction(
781 std::make_unique<ScUndoScenarioFlags>(this, nTab,
782 aOldName, rName, aOldComment, rComment,
783 aOldColor, rColor, nOldFlags, nFlags) );
785 // execute
786 ScDocShellModificator aModificator( *this );
787 m_pDocument->RenameTab( nTab, rName );
788 m_pDocument->SetScenarioData( nTab, rComment, rColor, nFlags );
789 PostPaintGridAll();
790 aModificator.SetDocumentModified();
792 if (aOldName != rName)
793 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
795 SfxBindings* pBindings = GetViewBindings();
796 if (pBindings)
797 pBindings->Invalidate( SID_SELECT_SCENARIO );
800 SCTAB ScDocShell::MakeScenario( SCTAB nTab, const OUString& rName, const OUString& rComment,
801 const Color& rColor, ScScenarioFlags nFlags,
802 ScMarkData& rMark, bool bRecord )
804 rMark.MarkToMulti();
805 if (rMark.IsMultiMarked())
807 SCTAB nNewTab = nTab + 1;
808 while (m_pDocument->IsScenario(nNewTab))
809 ++nNewTab;
811 bool bCopyAll = ( (nFlags & ScScenarioFlags::CopyAll) != ScScenarioFlags::NONE );
812 const ScMarkData* pCopyMark = nullptr;
813 if (!bCopyAll)
814 pCopyMark = &rMark;
816 ScDocShellModificator aModificator( *this );
818 if (bRecord)
819 m_pDocument->BeginDrawUndo(); // drawing layer must do its own undo actions
821 if (m_pDocument->CopyTab( nTab, nNewTab, pCopyMark ))
823 if (bRecord)
825 GetUndoManager()->AddUndoAction(
826 std::make_unique<ScUndoMakeScenario>( this, nTab, nNewTab,
827 rName, rComment, rColor, nFlags, rMark ));
830 m_pDocument->RenameTab( nNewTab, rName);
831 m_pDocument->SetScenario( nNewTab, true );
832 m_pDocument->SetScenarioData( nNewTab, rComment, rColor, nFlags );
834 ScMarkData aDestMark = rMark;
835 aDestMark.SelectOneTable( nNewTab );
837 //! test for filter / buttons / merging
839 ScPatternAttr aProtPattern(m_pDocument->getCellAttributeHelper());
840 aProtPattern.GetItemSet().Put( ScProtectionAttr( true ) );
841 m_pDocument->ApplyPatternAreaTab( 0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(), nNewTab, aProtPattern );
843 ScPatternAttr aPattern(m_pDocument->getCellAttributeHelper());
844 aPattern.GetItemSet().Put( ScMergeFlagAttr( ScMF::Scenario ) );
845 aPattern.GetItemSet().Put( ScProtectionAttr( true ) );
846 m_pDocument->ApplySelectionPattern( aPattern, aDestMark );
848 if (!bCopyAll)
849 m_pDocument->SetVisible( nNewTab, false );
851 // this is the active scenario, then
852 m_pDocument->CopyScenario( nNewTab, nTab, true ); // sal_True - don't copy anything from scenario
854 if (nFlags & ScScenarioFlags::ShowFrame)
855 PostPaint( 0,0,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid ); // paint frames
856 PostPaintExtras(); // table tab
857 aModificator.SetDocumentModified();
859 // A scenario tab is like a hidden sheet, broadcasting also
860 // notifies ScTabViewShell to add an ScViewData::maTabData entry.
861 Broadcast( ScTablesHint( SC_TAB_INSERTED, nNewTab ));
862 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
864 return nNewTab;
867 return nTab;
870 bool ScDocShell::TransferTab( ScDocShell& rSrcDocShell, SCTAB nSrcPos,
871 SCTAB nDestPos, bool bInsertNew,
872 bool bNotifyAndPaint )
874 ScDocument& rSrcDoc = rSrcDocShell.GetDocument();
876 // set the transferred area to the copyparam to make adjusting formulas possible
877 ScClipParam aParam;
878 ScRange aRange(0, 0, nSrcPos, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nSrcPos);
879 aParam.maRanges.push_back(aRange);
880 rSrcDoc.SetClipParam(aParam);
882 bool bValid = m_pDocument->TransferTab( rSrcDoc, nSrcPos, nDestPos,
883 bInsertNew ); // no insert
885 // TransferTab doesn't copy drawing objects with bInsertNew=FALSE
886 if ( bValid && !bInsertNew)
887 m_pDocument->TransferDrawPage( rSrcDoc, nSrcPos, nDestPos );
889 if(bValid && rSrcDoc.IsScenario( nSrcPos ))
891 OUString aComment;
892 Color aColor;
893 ScScenarioFlags nFlags;
895 rSrcDoc.GetScenarioData( nSrcPos, aComment,aColor, nFlags);
896 m_pDocument->SetScenario(nDestPos,true);
897 m_pDocument->SetScenarioData(nDestPos,aComment,aColor,nFlags);
898 bool bActive = rSrcDoc.IsActiveScenario(nSrcPos);
899 m_pDocument->SetActiveScenario(nDestPos, bActive );
901 bool bVisible = rSrcDoc.IsVisible(nSrcPos);
902 m_pDocument->SetVisible(nDestPos,bVisible );
906 if ( bValid && rSrcDoc.IsTabProtected( nSrcPos ) )
907 m_pDocument->SetTabProtection(nDestPos, rSrcDoc.GetTabProtection(nSrcPos));
908 if ( bNotifyAndPaint )
910 Broadcast( ScTablesHint( SC_TAB_INSERTED, nDestPos ) );
911 PostPaintExtras();
912 PostPaintGridAll();
914 return bValid;
917 bool ScDocShell::MoveTable( SCTAB nSrcTab, SCTAB nDestTab, bool bCopy, bool bRecord )
919 ScDocShellModificator aModificator( *this );
921 // #i92477# be consistent with ScDocFunc::InsertTable: any index past the last sheet means "append"
922 // #i101139# nDestTab must be the target position, not APPEND (for CopyTabProtection etc.)
923 if ( nDestTab >= m_pDocument->GetTableCount() )
924 nDestTab = m_pDocument->GetTableCount();
926 if (bCopy)
928 if (bRecord)
929 m_pDocument->BeginDrawUndo(); // drawing layer must do its own undo actions
931 OUString sSrcCodeName;
932 m_pDocument->GetCodeName( nSrcTab, sSrcCodeName );
933 if (!m_pDocument->CopyTab( nSrcTab, nDestTab ))
935 //! EndDrawUndo?
936 return false;
938 else
940 SCTAB nAdjSource = nSrcTab;
941 if ( nDestTab <= nSrcTab )
942 ++nAdjSource; // new position of source table after CopyTab
944 if ( m_pDocument->IsTabProtected( nAdjSource ) )
945 m_pDocument->CopyTabProtection(nAdjSource, nDestTab);
947 if (bRecord)
949 unique_ptr< vector<SCTAB> > pSrcList(new vector<SCTAB>(1, nSrcTab));
950 unique_ptr< vector<SCTAB> > pDestList(new vector<SCTAB>(1, nDestTab));
951 GetUndoManager()->AddUndoAction(
952 std::make_unique<ScUndoCopyTab>(this, std::move(pSrcList), std::move(pDestList)));
955 bool bVbaEnabled = m_pDocument->IsInVBAMode();
956 if ( bVbaEnabled )
958 OUString aLibName( u"Standard"_ustr );
959 Reference< XLibraryContainer > xLibContainer = GetBasicContainer();
960 Reference< XVBACompatibility > xVBACompat( xLibContainer, UNO_QUERY );
962 if ( xVBACompat.is() )
964 aLibName = xVBACompat->getProjectName();
967 SCTAB nTabToUse = nDestTab;
968 if ( nDestTab == SC_TAB_APPEND )
969 nTabToUse = m_pDocument->GetMaxTableNumber() - 1;
970 OUString sSource;
973 Reference< XNameContainer > xLib;
974 if( xLibContainer.is() )
976 css::uno::Any aLibAny = xLibContainer->getByName( aLibName );
977 aLibAny >>= xLib;
979 if( xLib.is() )
981 xLib->getByName( sSrcCodeName ) >>= sSource;
984 catch ( const css::uno::Exception& )
987 VBA_InsertModule( *m_pDocument, nTabToUse, sSource );
990 Broadcast( ScTablesHint( SC_TAB_COPIED, nSrcTab, nDestTab ) );
992 else
994 if ( m_pDocument->GetChangeTrack() )
995 return false;
997 if ( nSrcTab<nDestTab && nDestTab!=SC_TAB_APPEND )
998 nDestTab--;
1000 if ( nSrcTab == nDestTab )
1002 //! allow only for api calls?
1003 return true; // nothing to do, but valid
1006 std::optional<ScProgress> pProgress(std::in_place, this, ScResId(STR_UNDO_MOVE_TAB),
1007 m_pDocument->GetCodeCount(), true);
1008 bool bDone = m_pDocument->MoveTab( nSrcTab, nDestTab, &*pProgress );
1009 pProgress.reset();
1010 if (!bDone)
1012 return false;
1014 else if (bRecord)
1016 unique_ptr< vector<SCTAB> > pSrcList(new vector<SCTAB>(1, nSrcTab));
1017 unique_ptr< vector<SCTAB> > pDestList(new vector<SCTAB>(1, nDestTab));
1018 GetUndoManager()->AddUndoAction(
1019 std::make_unique<ScUndoMoveTab>(this, std::move(pSrcList), std::move(pDestList)));
1022 Broadcast( ScTablesHint( SC_TAB_MOVED, nSrcTab, nDestTab ) );
1025 PostPaintGridAll();
1026 PostPaintExtras();
1027 aModificator.SetDocumentModified();
1028 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
1030 return true;
1033 IMPL_LINK( ScDocShell, RefreshDBDataHdl, Timer*, pRefreshTimer, void )
1035 ScDBDocFunc aFunc(*this);
1037 ScDBData* pDBData = static_cast<ScDBData*>(pRefreshTimer);
1038 ScImportParam aImportParam;
1039 pDBData->GetImportParam( aImportParam );
1040 if (aImportParam.bImport && !pDBData->HasImportSelection())
1042 ScRange aRange;
1043 pDBData->GetArea( aRange );
1044 bool bContinue = aFunc.DoImport( aRange.aStart.Tab(), aImportParam, nullptr ); //! Api-Flag as parameter
1045 // internal operations (sort, query, subtotal) only if no error
1046 if (bContinue)
1048 aFunc.RepeatDB( pDBData->GetName(), true, true );
1049 RefreshPivotTables(aRange);
1054 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */