1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <scitems.hxx> 21 22 #include <comphelper/lok.hxx> 23 #include <o3tl/safeint.hxx> 24 #include <sfx2/app.hxx> 25 #include <editeng/editobj.hxx> 26 #include <editeng/justifyitem.hxx> 27 #include <sfx2/linkmgr.hxx> 28 #include <sfx2/bindings.hxx> 29 #include <vcl/weld.hxx> 30 #include <vcl/stdtext.hxx> 31 #include <vcl/svapp.hxx> 32 #include <svx/svdocapt.hxx> 33 #include <sal/log.hxx> 34 #include <unotools/charclass.hxx> 35 #include <osl/diagnose.h> 36 37 #include <com/sun/star/container/XNameContainer.hpp> 38 #include <com/sun/star/script/ModuleType.hpp> 39 #include <com/sun/star/script/XLibraryContainer.hpp> 40 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp> 41 42 #include <docfunc.hxx> 43 44 #include <sc.hrc> 45 #include <strings.hrc> 46 47 #include <arealink.hxx> 48 #include <attrib.hxx> 49 #include <dociter.hxx> 50 #include <autoform.hxx> 51 #include <formulacell.hxx> 52 #include <cellmergeoption.hxx> 53 #include <detdata.hxx> 54 #include <detfunc.hxx> 55 #include <docpool.hxx> 56 #include <docsh.hxx> 57 #include <drwlayer.hxx> 58 #include <editutil.hxx> 59 #include <globstr.hrc> 60 #include <olinetab.hxx> 61 #include <patattr.hxx> 62 #include <rangenam.hxx> 63 #include <refundo.hxx> 64 #include <scresid.hxx> 65 #include <stlpool.hxx> 66 #include <stlsheet.hxx> 67 #include <tablink.hxx> 68 #include <tabvwsh.hxx> 69 #include <uiitems.hxx> 70 #include <undoblk.hxx> 71 #include <undocell.hxx> 72 #include <undodraw.hxx> 73 #include <undotab.hxx> 74 #include <sizedev.hxx> 75 #include <scmod.hxx> 76 #include <inputhdl.hxx> 77 #include <editable.hxx> 78 #include <compiler.hxx> 79 #include <scui_def.hxx> 80 #include <tabprotection.hxx> 81 #include <clipparam.hxx> 82 #include <externalrefmgr.hxx> 83 #include <undorangename.hxx> 84 #include <progress.hxx> 85 #include <dpobject.hxx> 86 #include <stringutil.hxx> 87 #include <cellvalue.hxx> 88 #include <tokenarray.hxx> 89 #include <rowheightcontext.hxx> 90 #include <cellvalues.hxx> 91 #include <undoconvert.hxx> 92 #include <docfuncutil.hxx> 93 #include <sheetevents.hxx> 94 #include <conditio.hxx> 95 #include <columnspanset.hxx> 96 #include <validat.hxx> 97 #include <config_features.h> 98 99 #include <memory> 100 #include <utility> 101 #include <basic/basmgr.hxx> 102 #include <set> 103 #include <vector> 104 #include <sfx2/viewfrm.hxx> 105 106 using namespace com::sun::star; 107 using ::std::vector; 108 109 void ScDocFunc::NotifyDrawUndo( std::unique_ptr<SdrUndoAction> pUndoAction) 110 { 111 // #i101118# if drawing layer collects the undo actions, add it there 112 ScDrawLayer* pDrawLayer = rDocShell.GetDocument().GetDrawLayer(); 113 if( pDrawLayer && pDrawLayer->IsRecording() ) 114 pDrawLayer->AddCalcUndo( std::move(pUndoAction) ); 115 else 116 rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoDraw>( std::move(pUndoAction), &rDocShell ) ); 117 rDocShell.SetDrawModified(); 118 119 // the affected sheet isn't known, so all stream positions are invalidated 120 ScDocument& rDoc = rDocShell.GetDocument(); 121 SCTAB nTabCount = rDoc.GetTableCount(); 122 for (SCTAB nTab=0; nTab<nTabCount; nTab++) 123 rDoc.SetStreamValid(nTab, false); 124 } 125 126 // paint row above the range (because of lines after AdjustRowHeight) 127 128 static void lcl_PaintAbove( ScDocShell& rDocShell, const ScRange& rRange ) 129 { 130 SCROW nRow = rRange.aStart.Row(); 131 if ( nRow > 0 ) 132 { 133 SCTAB nTab = rRange.aStart.Tab(); //! all of them? 134 --nRow; 135 ScDocument& rDoc = rDocShell.GetDocument(); 136 rDocShell.PostPaint( ScRange(0,nRow,nTab,rDoc.MaxCol(),nRow,nTab), PaintPartFlags::Grid ); 137 } 138 } 139 140 bool ScDocFunc::AdjustRowHeight( const ScRange& rRange, bool bPaint, bool bApi ) 141 { 142 ScDocument& rDoc = rDocShell.GetDocument(); 143 SfxViewShell* pSomeViewForThisDoc = rDocShell.GetBestViewShell(false); 144 if ( rDoc.IsImportingXML() ) 145 { 146 // for XML import, all row heights are updated together after importing 147 return false; 148 } 149 if ( rDoc.IsAdjustHeightLocked() ) 150 { 151 return false; 152 } 153 154 SCTAB nTab = rRange.aStart.Tab(); 155 SCROW nStartRow = rRange.aStart.Row(); 156 SCROW nEndRow = rRange.aEnd.Row(); 157 158 ScSizeDeviceProvider aProv( &rDocShell ); 159 Fraction aOne(1,1); 160 161 sc::RowHeightContext aCxt(rDoc.MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice()); 162 bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab, bApi); 163 // tdf#76183: recalculate objects' positions 164 if (bChanged) 165 { 166 if (comphelper::LibreOfficeKit::isActive()) 167 { 168 SfxViewShell* pViewShell = SfxViewShell::GetFirst(); 169 while (pViewShell) 170 { 171 ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell); 172 if (pTabViewShell && pTabViewShell->GetDocId() == pSomeViewForThisDoc->GetDocId()) 173 { 174 if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nTab)) 175 pPosHelper->invalidateByIndex(nStartRow); 176 } 177 pViewShell = SfxViewShell::GetNext(*pViewShell); 178 } 179 } 180 rDoc.SetDrawPageSize(nTab); 181 } 182 183 if ( bPaint && bChanged ) 184 rDocShell.PostPaint(ScRange(0, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab), 185 PaintPartFlags::Grid | PaintPartFlags::Left); 186 187 if (comphelper::LibreOfficeKit::isActive()) 188 { 189 ScTabViewShell::notifyAllViewsHeaderInvalidation(pSomeViewForThisDoc, ROW_HEADER, nTab); 190 ScTabViewShell::notifyAllViewsSheetGeomInvalidation( 191 pSomeViewForThisDoc, false /* bColumns */, true /* bRows */, true /* bSizes*/, 192 false /* bHidden */, false /* bFiltered */, false /* bGroups */, nTab); 193 } 194 195 return bChanged; 196 } 197 198 bool ScDocFunc::DetectiveAddPred(const ScAddress& rPos) 199 { 200 ScDocShellModificator aModificator( rDocShell ); 201 202 rDocShell.MakeDrawLayer(); 203 ScDocument& rDoc = rDocShell.GetDocument(); 204 bool bUndo (rDoc.IsUndoEnabled()); 205 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 206 SCCOL nCol = rPos.Col(); 207 SCROW nRow = rPos.Row(); 208 SCTAB nTab = rPos.Tab(); 209 210 if (bUndo) 211 pModel->BeginCalcUndo(false); 212 bool bDone = ScDetectiveFunc(rDoc, nTab).ShowPred( nCol, nRow ); 213 std::unique_ptr<SdrUndoGroup> pUndo; 214 if (bUndo) 215 pUndo = pModel->GetCalcUndo(); 216 if (bDone) 217 { 218 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDPRED ); 219 rDoc.AddDetectiveOperation( aOperation ); 220 if (bUndo) 221 { 222 rDocShell.GetUndoManager()->AddUndoAction( 223 std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) ); 224 } 225 aModificator.SetDocumentModified(); 226 SfxBindings* pBindings = rDocShell.GetViewBindings(); 227 if (pBindings) 228 pBindings->Invalidate( SID_DETECTIVE_REFRESH ); 229 } 230 231 return bDone; 232 } 233 234 bool ScDocFunc::DetectiveDelPred(const ScAddress& rPos) 235 { 236 ScDocument& rDoc = rDocShell.GetDocument(); 237 238 bool bUndo(rDoc.IsUndoEnabled()); 239 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 240 if (!pModel) 241 return false; 242 243 ScDocShellModificator aModificator( rDocShell ); 244 245 SCCOL nCol = rPos.Col(); 246 SCROW nRow = rPos.Row(); 247 SCTAB nTab = rPos.Tab(); 248 249 if (bUndo) 250 pModel->BeginCalcUndo(false); 251 bool bDone = ScDetectiveFunc(rDoc, nTab).DeletePred( nCol, nRow ); 252 std::unique_ptr<SdrUndoGroup> pUndo; 253 if (bUndo) 254 pUndo = pModel->GetCalcUndo(); 255 if (bDone) 256 { 257 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELPRED ); 258 rDoc.AddDetectiveOperation( aOperation ); 259 if (bUndo) 260 { 261 rDocShell.GetUndoManager()->AddUndoAction( 262 std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) ); 263 } 264 aModificator.SetDocumentModified(); 265 SfxBindings* pBindings = rDocShell.GetViewBindings(); 266 if (pBindings) 267 pBindings->Invalidate( SID_DETECTIVE_REFRESH ); 268 } 269 270 return bDone; 271 } 272 273 bool ScDocFunc::DetectiveAddSucc(const ScAddress& rPos) 274 { 275 ScDocShellModificator aModificator( rDocShell ); 276 277 rDocShell.MakeDrawLayer(); 278 ScDocument& rDoc = rDocShell.GetDocument(); 279 280 bool bUndo(rDoc.IsUndoEnabled()); 281 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 282 SCCOL nCol = rPos.Col(); 283 SCROW nRow = rPos.Row(); 284 SCTAB nTab = rPos.Tab(); 285 286 if (bUndo) 287 pModel->BeginCalcUndo(false); 288 bool bDone = ScDetectiveFunc(rDoc, nTab).ShowSucc( nCol, nRow ); 289 std::unique_ptr<SdrUndoGroup> pUndo; 290 if (bUndo) 291 pUndo = pModel->GetCalcUndo(); 292 if (bDone) 293 { 294 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDSUCC ); 295 rDoc.AddDetectiveOperation( aOperation ); 296 if (bUndo) 297 { 298 rDocShell.GetUndoManager()->AddUndoAction( 299 std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) ); 300 } 301 aModificator.SetDocumentModified(); 302 SfxBindings* pBindings = rDocShell.GetViewBindings(); 303 if (pBindings) 304 pBindings->Invalidate( SID_DETECTIVE_REFRESH ); 305 } 306 307 return bDone; 308 } 309 310 bool ScDocFunc::DetectiveDelSucc(const ScAddress& rPos) 311 { 312 ScDocument& rDoc = rDocShell.GetDocument(); 313 314 bool bUndo (rDoc.IsUndoEnabled()); 315 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 316 if (!pModel) 317 return false; 318 319 ScDocShellModificator aModificator( rDocShell ); 320 321 SCCOL nCol = rPos.Col(); 322 SCROW nRow = rPos.Row(); 323 SCTAB nTab = rPos.Tab(); 324 325 if (bUndo) 326 pModel->BeginCalcUndo(false); 327 bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteSucc( nCol, nRow ); 328 std::unique_ptr<SdrUndoGroup> pUndo; 329 if (bUndo) 330 pUndo = pModel->GetCalcUndo(); 331 if (bDone) 332 { 333 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELSUCC ); 334 rDoc.AddDetectiveOperation( aOperation ); 335 if (bUndo) 336 { 337 rDocShell.GetUndoManager()->AddUndoAction( 338 std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) ); 339 } 340 aModificator.SetDocumentModified(); 341 SfxBindings* pBindings = rDocShell.GetViewBindings(); 342 if (pBindings) 343 pBindings->Invalidate( SID_DETECTIVE_REFRESH ); 344 } 345 346 return bDone; 347 } 348 349 bool ScDocFunc::DetectiveAddError(const ScAddress& rPos) 350 { 351 ScDocShellModificator aModificator( rDocShell ); 352 353 rDocShell.MakeDrawLayer(); 354 ScDocument& rDoc = rDocShell.GetDocument(); 355 356 bool bUndo (rDoc.IsUndoEnabled()); 357 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 358 SCCOL nCol = rPos.Col(); 359 SCROW nRow = rPos.Row(); 360 SCTAB nTab = rPos.Tab(); 361 362 if (bUndo) 363 pModel->BeginCalcUndo(false); 364 bool bDone = ScDetectiveFunc(rDoc, nTab).ShowError( nCol, nRow ); 365 std::unique_ptr<SdrUndoGroup> pUndo; 366 if (bUndo) 367 pUndo = pModel->GetCalcUndo(); 368 if (bDone) 369 { 370 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDERROR ); 371 rDoc.AddDetectiveOperation( aOperation ); 372 if (bUndo) 373 { 374 rDocShell.GetUndoManager()->AddUndoAction( 375 std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) ); 376 } 377 aModificator.SetDocumentModified(); 378 SfxBindings* pBindings = rDocShell.GetViewBindings(); 379 if (pBindings) 380 pBindings->Invalidate( SID_DETECTIVE_REFRESH ); 381 } 382 383 return bDone; 384 } 385 386 bool ScDocFunc::DetectiveMarkInvalid(SCTAB nTab) 387 { 388 ScDocShellModificator aModificator( rDocShell ); 389 390 rDocShell.MakeDrawLayer(); 391 ScDocument& rDoc = rDocShell.GetDocument(); 392 393 bool bUndo (rDoc.IsUndoEnabled()); 394 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 395 396 std::unique_ptr<weld::WaitObject> xWaitWin(new weld::WaitObject(ScDocShell::GetActiveDialogParent())); 397 if (bUndo) 398 pModel->BeginCalcUndo(false); 399 bool bOverflow; 400 bool bDone = ScDetectiveFunc(rDoc, nTab).MarkInvalid( bOverflow ); 401 std::unique_ptr<SdrUndoGroup> pUndo; 402 if (bUndo) 403 pUndo = pModel->GetCalcUndo(); 404 xWaitWin.reset(); 405 if (bDone) 406 { 407 if (pUndo && bUndo) 408 { 409 pUndo->SetComment( ScResId( STR_UNDO_DETINVALID ) ); 410 rDocShell.GetUndoManager()->AddUndoAction( std::move(pUndo) ); 411 } 412 aModificator.SetDocumentModified(); 413 if ( bOverflow ) 414 { 415 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr, 416 VclMessageType::Info, VclButtonsType::Ok, 417 ScResId(STR_DETINVALID_OVERFLOW))); 418 xInfoBox->run(); 419 } 420 } 421 422 return bDone; 423 } 424 425 bool ScDocFunc::DetectiveDelAll(SCTAB nTab) 426 { 427 ScDocument& rDoc = rDocShell.GetDocument(); 428 429 bool bUndo (rDoc.IsUndoEnabled()); 430 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 431 if (!pModel) 432 return false; 433 434 ScDocShellModificator aModificator( rDocShell ); 435 436 if (bUndo) 437 pModel->BeginCalcUndo(false); 438 bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteAll( ScDetectiveDelete::Detective ); 439 std::unique_ptr<SdrUndoGroup> pUndo; 440 if (bUndo) 441 pUndo = pModel->GetCalcUndo(); 442 if (bDone) 443 { 444 ScDetOpList* pOldList = rDoc.GetDetOpList(); 445 std::unique_ptr<ScDetOpList> pUndoList; 446 if (bUndo && pOldList) 447 pUndoList.reset(new ScDetOpList(*pOldList)); 448 449 rDoc.ClearDetectiveOperations(); 450 451 if (bUndo) 452 { 453 rDocShell.GetUndoManager()->AddUndoAction( 454 std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), nullptr, std::move(pUndoList) ) ); 455 } 456 aModificator.SetDocumentModified(); 457 SfxBindings* pBindings = rDocShell.GetViewBindings(); 458 if (pBindings) 459 pBindings->Invalidate( SID_DETECTIVE_REFRESH ); 460 } 461 462 return bDone; 463 } 464 465 bool ScDocFunc::DetectiveRefresh( bool bAutomatic ) 466 { 467 bool bDone = false; 468 ScDocument& rDoc = rDocShell.GetDocument(); 469 470 ScDetOpList* pList = rDoc.GetDetOpList(); 471 if ( pList && pList->Count() ) 472 { 473 rDocShell.MakeDrawLayer(); 474 ScDrawLayer* pModel = rDoc.GetDrawLayer(); 475 const bool bUndo (rDoc.IsUndoEnabled()); 476 if (bUndo) 477 pModel->BeginCalcUndo(false); 478 479 // Delete in all sheets 480 481 SCTAB nTabCount = rDoc.GetTableCount(); 482 for (SCTAB nTab=0; nTab<nTabCount; nTab++) 483 ScDetectiveFunc( rDoc,nTab ).DeleteAll( ScDetectiveDelete::Arrows ); // don't remove circles 484 485 // repeat 486 487 size_t nCount = pList->Count(); 488 for (size_t i=0; i < nCount; ++i) 489 { 490 const ScDetOpData& rData = pList->GetObject(i); 491 const ScAddress& aPos = rData.GetPos(); 492 ScDetectiveFunc aFunc( rDoc, aPos.Tab() ); 493 SCCOL nCol = aPos.Col(); 494 SCROW nRow = aPos.Row(); 495 switch (rData.GetOperation()) 496 { 497 case SCDETOP_ADDSUCC: 498 aFunc.ShowSucc( nCol, nRow ); 499 break; 500 case SCDETOP_DELSUCC: 501 aFunc.DeleteSucc( nCol, nRow ); 502 break; 503 case SCDETOP_ADDPRED: 504 aFunc.ShowPred( nCol, nRow ); 505 break; 506 case SCDETOP_DELPRED: 507 aFunc.DeletePred( nCol, nRow ); 508 break; 509 case SCDETOP_ADDERROR: 510 aFunc.ShowError( nCol, nRow ); 511 break; 512 default: 513 OSL_FAIL("wrong operation in DetectiveRefresh"); 514 } 515 } 516 517 if (bUndo) 518 { 519 std::unique_ptr<SdrUndoGroup> pUndo = pModel->GetCalcUndo(); 520 if (pUndo) 521 { 522 pUndo->SetComment( ScResId( STR_UNDO_DETREFRESH ) ); 523 // associate with the last action 524 rDocShell.GetUndoManager()->AddUndoAction( 525 std::make_unique<ScUndoDraw>( std::move(pUndo), &rDocShell ), 526 bAutomatic ); 527 } 528 } 529 rDocShell.SetDrawModified(); 530 bDone = true; 531 } 532 return bDone; 533 } 534 535 static void lcl_collectAllPredOrSuccRanges( 536 const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens, ScDocShell& rDocShell, 537 bool bPred) 538 { 539 ScDocument& rDoc = rDocShell.GetDocument(); 540 vector<ScTokenRef> aRefTokens; 541 if (rSrcRanges.empty()) 542 return; 543 ScRange const & rFrontRange = rSrcRanges.front(); 544 ScDetectiveFunc aDetFunc(rDoc, rFrontRange.aStart.Tab()); 545 for (size_t i = 0, n = rSrcRanges.size(); i < n; ++i) 546 { 547 ScRange const & r = rSrcRanges[i]; 548 if (bPred) 549 { 550 aDetFunc.GetAllPreds( 551 r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(), r.aEnd.Row(), aRefTokens); 552 } 553 else 554 { 555 aDetFunc.GetAllSuccs( 556 r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(), r.aEnd.Row(), aRefTokens); 557 } 558 } 559 rRefTokens.swap(aRefTokens); 560 } 561 562 void ScDocFunc::DetectiveCollectAllPreds(const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens) 563 { 564 lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, true); 565 } 566 567 void ScDocFunc::DetectiveCollectAllSuccs(const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens) 568 { 569 lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, false); 570 } 571 572 bool ScDocFunc::DeleteContents( 573 const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi ) 574 { 575 ScDocShellModificator aModificator( rDocShell ); 576 577 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) 578 { 579 OSL_FAIL("ScDocFunc::DeleteContents without markings"); 580 return false; 581 } 582 583 ScDocument& rDoc = rDocShell.GetDocument(); 584 585 if (bRecord && !rDoc.IsUndoEnabled()) 586 bRecord = false; 587 588 ScEditableTester aTester( rDoc, rMark ); 589 if (!aTester.IsEditable()) 590 { 591 if (!bApi) 592 rDocShell.ErrorMessage(aTester.GetMessageId()); 593 return false; 594 } 595 596 ScRange aMarkRange; 597 598 ScMarkData aMultiMark = rMark; 599 aMultiMark.SetMarking(false); // for MarkToMulti 600 601 ScDocumentUniquePtr pUndoDoc; 602 bool bMulti = aMultiMark.IsMultiMarked(); 603 aMultiMark.MarkToMulti(); 604 aMultiMark.GetMultiMarkArea( aMarkRange ); 605 ScRange aExtendedRange(aMarkRange); 606 if ( rDoc.ExtendMerge( aExtendedRange, true ) ) 607 bMulti = false; 608 609 // no objects on protected tabs 610 bool bObjects = (nFlags & InsertDeleteFlags::OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark); 611 612 sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted 613 if ( nFlags & InsertDeleteFlags::ATTRIB ) 614 rDocShell.UpdatePaintExt( nExtFlags, aMarkRange ); 615 616 // order of operations: 617 // 1) BeginDrawUndo 618 // 2) Delete objects (DrawUndo will be filled) 619 // 3) Copy content for undo and set up undo actions 620 // 4) Delete content 621 622 bool bDrawUndo = bObjects || (nFlags & InsertDeleteFlags::NOTE); 623 if (bRecord && bDrawUndo) 624 rDoc.BeginDrawUndo(); 625 626 if (bObjects) 627 { 628 if (bMulti) 629 rDoc.DeleteObjectsInSelection( aMultiMark ); 630 else 631 rDoc.DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), 632 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), 633 aMultiMark ); 634 } 635 636 // To keep track of all non-empty cells within the deleted area. 637 std::shared_ptr<ScSimpleUndo::DataSpansType> pDataSpans; 638 639 if ( bRecord ) 640 { 641 pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, aMultiMark, aMarkRange, nFlags, bMulti); 642 pDataSpans = sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, aMultiMark, aMarkRange); 643 } 644 645 rDoc.DeleteSelection( nFlags, aMultiMark ); 646 647 // add undo action after drawing undo is complete (objects and note captions) 648 if( bRecord ) 649 { 650 sc::DocFuncUtil::addDeleteContentsUndo( 651 rDocShell.GetUndoManager(), &rDocShell, aMultiMark, aExtendedRange, 652 std::move(pUndoDoc), nFlags, pDataSpans, bMulti, bDrawUndo); 653 } 654 655 if (!AdjustRowHeight( aExtendedRange, true, bApi )) 656 rDocShell.PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags ); 657 else if (nExtFlags & SC_PF_LINES) 658 lcl_PaintAbove( rDocShell, aExtendedRange ); // for lines above the range 659 660 aModificator.SetDocumentModified(); 661 662 return true; 663 } 664 665 bool ScDocFunc::DeleteCell( 666 const ScAddress& rPos, const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi ) 667 { 668 ScDocShellModificator aModificator(rDocShell); 669 670 ScDocument& rDoc = rDocShell.GetDocument(); 671 672 if (bRecord && !rDoc.IsUndoEnabled()) 673 bRecord = false; 674 675 ScEditableTester aTester(rDoc, rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark); 676 if (!aTester.IsEditable()) 677 { 678 rDocShell.ErrorMessage(aTester.GetMessageId()); 679 return false; 680 } 681 682 // no objects on protected tabs 683 bool bObjects = (nFlags & InsertDeleteFlags::OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark); 684 685 sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted 686 if (nFlags & InsertDeleteFlags::ATTRIB) 687 rDocShell.UpdatePaintExt(nExtFlags, rPos); 688 689 // order of operations: 690 // 1) BeginDrawUndo 691 // 2) delete objects (DrawUndo is filled) 692 // 3) copy contents for undo 693 // 4) delete contents 694 // 5) add undo-action 695 696 bool bDrawUndo = bObjects || (nFlags & InsertDeleteFlags::NOTE); // needed for shown notes 697 if (bDrawUndo && bRecord) 698 rDoc.BeginDrawUndo(); 699 700 if (bObjects) 701 rDoc.DeleteObjectsInArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark); 702 703 // To keep track of all non-empty cells within the deleted area. 704 std::shared_ptr<ScSimpleUndo::DataSpansType> pDataSpans; 705 706 ScDocumentUniquePtr pUndoDoc; 707 if (bRecord) 708 { 709 pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, rMark, rPos, nFlags, false); 710 pDataSpans = sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, rMark, rPos); 711 } 712 713 rDoc.DeleteArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark, nFlags); 714 715 if (bRecord) 716 { 717 sc::DocFuncUtil::addDeleteContentsUndo( 718 rDocShell.GetUndoManager(), &rDocShell, rMark, rPos, std::move(pUndoDoc), 719 nFlags, pDataSpans, false, bDrawUndo); 720 } 721 722 if (!AdjustRowHeight(rPos, true, bApi)) 723 rDocShell.PostPaint( 724 rPos.Col(), rPos.Row(), rPos.Tab(), rPos.Col(), rPos.Row(), rPos.Tab(), 725 PaintPartFlags::Grid, nExtFlags); 726 727 aModificator.SetDocumentModified(); 728 729 return true; 730 } 731 732 bool ScDocFunc::TransliterateText( const ScMarkData& rMark, TransliterationFlags nType, 733 bool bApi ) 734 { 735 ScDocShellModificator aModificator( rDocShell ); 736 737 ScDocument& rDoc = rDocShell.GetDocument(); 738 bool bRecord = true; 739 if (!rDoc.IsUndoEnabled()) 740 bRecord = false; 741 742 ScEditableTester aTester( rDoc, rMark ); 743 if (!aTester.IsEditable()) 744 { 745 if (!bApi) 746 rDocShell.ErrorMessage(aTester.GetMessageId()); 747 return false; 748 } 749 750 ScRange aMarkRange; 751 ScMarkData aMultiMark = rMark; 752 aMultiMark.SetMarking(false); // for MarkToMulti 753 aMultiMark.MarkToMulti(); 754 aMultiMark.GetMultiMarkArea( aMarkRange ); 755 756 if (bRecord) 757 { 758 SCTAB nStartTab = aMarkRange.aStart.Tab(); 759 SCTAB nTabCount = rDoc.GetTableCount(); 760 761 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); 762 pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab ); 763 for (const auto& rTab : rMark) 764 { 765 if (rTab >= nTabCount) 766 break; 767 768 if (rTab != nStartTab) 769 pUndoDoc->AddUndoTab( rTab, rTab ); 770 } 771 772 ScRange aCopyRange = aMarkRange; 773 aCopyRange.aStart.SetTab(0); 774 aCopyRange.aEnd.SetTab(nTabCount-1); 775 rDoc.CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, *pUndoDoc, &aMultiMark); 776 777 rDocShell.GetUndoManager()->AddUndoAction( 778 std::make_unique<ScUndoTransliterate>( &rDocShell, aMultiMark, std::move(pUndoDoc), nType ) ); 779 } 780 781 rDoc.TransliterateText( aMultiMark, nType ); 782 783 if (!AdjustRowHeight( aMarkRange, true, true )) 784 rDocShell.PostPaint( aMarkRange, PaintPartFlags::Grid ); 785 786 aModificator.SetDocumentModified(); 787 788 return true; 789 } 790 791 bool ScDocFunc::SetNormalString( bool& o_rbNumFmtSet, const ScAddress& rPos, const OUString& rText, bool bApi ) 792 { 793 ScDocShellModificator aModificator( rDocShell ); 794 ScDocument& rDoc = rDocShell.GetDocument(); 795 796 bool bUndo(rDoc.IsUndoEnabled()); 797 ScEditableTester aTester( rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); 798 if (!aTester.IsEditable()) 799 { 800 if (!bApi) 801 rDocShell.ErrorMessage(aTester.GetMessageId()); 802 return false; 803 } 804 805 bool bEditDeleted = (rDoc.GetCellType(rPos) == CELLTYPE_EDIT); 806 ScUndoEnterData::ValuesType aOldValues; 807 808 if (bUndo) 809 { 810 ScUndoEnterData::Value aOldValue; 811 812 aOldValue.mnTab = rPos.Tab(); 813 aOldValue.maCell.assign(rDoc, rPos); 814 815 const SfxPoolItem* pItem; 816 const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(),rPos.Row(),rPos.Tab() ); 817 if ( SfxItemState::SET == pPattern->GetItemSet().GetItemState( 818 ATTR_VALUE_FORMAT,false,&pItem) ) 819 { 820 aOldValue.mbHasFormat = true; 821 aOldValue.mnFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue(); 822 } 823 else 824 aOldValue.mbHasFormat = false; 825 826 aOldValues.push_back(aOldValue); 827 } 828 829 o_rbNumFmtSet = rDoc.SetString( rPos.Col(), rPos.Row(), rPos.Tab(), rText ); 830 831 if (bUndo) 832 { 833 // because of ChangeTracking, UndoAction can be created only after SetString was called 834 rDocShell.GetUndoManager()->AddUndoAction( 835 std::make_unique<ScUndoEnterData>(&rDocShell, rPos, aOldValues, rText, nullptr)); 836 } 837 838 if ( bEditDeleted || rDoc.HasAttrib( ScRange(rPos), HasAttrFlags::NeedHeight ) ) 839 AdjustRowHeight( ScRange(rPos), true, bApi ); 840 841 rDocShell.PostPaintCell( rPos ); 842 aModificator.SetDocumentModified(); 843 844 // notify input handler here the same way as in PutCell 845 if (bApi) 846 NotifyInputHandler( rPos ); 847 848 const SfxUInt32Item* pItem = rDoc.GetAttr(rPos, ATTR_VALIDDATA); 849 const ScValidationData* pData = rDoc.GetValidationEntry(pItem->GetValue()); 850 if (pData) 851 { 852 ScRefCellValue aCell(rDoc, rPos); 853 if (pData->IsDataValid(aCell, rPos)) 854 ScDetectiveFunc(rDoc, rPos.Tab()).DeleteCirclesAt(rPos.Col(), rPos.Row()); 855 } 856 857 return true; 858 } 859 860 bool ScDocFunc::SetValueCell( const ScAddress& rPos, double fVal, bool bInteraction ) 861 { 862 ScDocShellModificator aModificator( rDocShell ); 863 ScDocument& rDoc = rDocShell.GetDocument(); 864 bool bUndo = rDoc.IsUndoEnabled(); 865 866 bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight); 867 868 ScCellValue aOldVal; 869 if (bUndo) 870 aOldVal.assign(rDoc, rPos); 871 872 rDoc.SetValue(rPos, fVal); 873 874 if (bUndo) 875 { 876 SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager(); 877 ScCellValue aNewVal; 878 aNewVal.assign(rDoc, rPos); 879 pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal)); 880 } 881 882 if (bHeight) 883 AdjustRowHeight(rPos, true, !bInteraction); 884 885 rDocShell.PostPaintCell( rPos ); 886 aModificator.SetDocumentModified(); 887 888 // #103934#; notify editline and cell in edit mode 889 if (!bInteraction) 890 NotifyInputHandler( rPos ); 891 892 return true; 893 } 894 895 void ScDocFunc::SetValueCells( const ScAddress& rPos, const std::vector<double>& aVals, bool bInteraction ) 896 { 897 ScDocument& rDoc = rDocShell.GetDocument(); 898 899 // Check for invalid range. 900 SCROW nLastRow = rPos.Row() + aVals.size() - 1; 901 if (nLastRow > rDoc.MaxRow()) 902 // out of bound. 903 return; 904 905 ScRange aRange(rPos); 906 aRange.aEnd.SetRow(nLastRow); 907 908 ScDocShellModificator aModificator(rDocShell); 909 910 if (rDoc.IsUndoEnabled()) 911 { 912 std::unique_ptr<sc::UndoSetCells> pUndoObj(new sc::UndoSetCells(&rDocShell, rPos)); 913 rDoc.TransferCellValuesTo(rPos, aVals.size(), pUndoObj->GetOldValues()); 914 pUndoObj->SetNewValues(aVals); 915 SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager(); 916 pUndoMgr->AddUndoAction(std::move(pUndoObj)); 917 } 918 919 rDoc.SetValues(rPos, aVals); 920 921 rDocShell.PostPaint(aRange, PaintPartFlags::Grid); 922 aModificator.SetDocumentModified(); 923 924 // #103934#; notify editline and cell in edit mode 925 if (!bInteraction) 926 NotifyInputHandler(rPos); 927 } 928 929 bool ScDocFunc::SetStringCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction ) 930 { 931 ScDocShellModificator aModificator( rDocShell ); 932 ScDocument& rDoc = rDocShell.GetDocument(); 933 bool bUndo = rDoc.IsUndoEnabled(); 934 935 bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight); 936 937 ScCellValue aOldVal; 938 if (bUndo) 939 aOldVal.assign(rDoc, rPos); 940 941 ScSetStringParam aParam; 942 aParam.setTextInput(); 943 rDoc.SetString(rPos, rStr, &aParam); 944 945 if (bUndo) 946 { 947 SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager(); 948 ScCellValue aNewVal; 949 aNewVal.assign(rDoc, rPos); 950 pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal)); 951 } 952 953 if (bHeight) 954 AdjustRowHeight(rPos, true, !bInteraction); 955 956 rDocShell.PostPaintCell( rPos ); 957 aModificator.SetDocumentModified(); 958 959 // #103934#; notify editline and cell in edit mode 960 if (!bInteraction) 961 NotifyInputHandler( rPos ); 962 963 return true; 964 } 965 966 bool ScDocFunc::SetEditCell( const ScAddress& rPos, const EditTextObject& rStr, bool bInteraction ) 967 { 968 ScDocShellModificator aModificator( rDocShell ); 969 ScDocument& rDoc = rDocShell.GetDocument(); 970 bool bUndo = rDoc.IsUndoEnabled(); 971 972 bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight); 973 974 ScCellValue aOldVal; 975 if (bUndo) 976 aOldVal.assign(rDoc, rPos); 977 978 rDoc.SetEditText(rPos, rStr.Clone()); 979 980 if (bUndo) 981 { 982 SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager(); 983 ScCellValue aNewVal; 984 aNewVal.assign(rDoc, rPos); 985 pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal)); 986 } 987 988 if (bHeight) 989 AdjustRowHeight(rPos, true, !bInteraction); 990 991 rDocShell.PostPaintCell( rPos ); 992 aModificator.SetDocumentModified(); 993 994 // #103934#; notify editline and cell in edit mode 995 if (!bInteraction) 996 NotifyInputHandler( rPos ); 997 998 return true; 999 } 1000 1001 bool ScDocFunc::SetStringOrEditCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction ) 1002 { 1003 ScDocument& rDoc = rDocShell.GetDocument(); 1004 1005 if (ScStringUtil::isMultiline(rStr)) 1006 { 1007 ScFieldEditEngine& rEngine = rDoc.GetEditEngine(); 1008 rEngine.SetTextCurrentDefaults(rStr); 1009 std::unique_ptr<EditTextObject> pEditText(rEngine.CreateTextObject()); 1010 return SetEditCell(rPos, *pEditText, bInteraction); 1011 } 1012 else 1013 return SetStringCell(rPos, rStr, bInteraction); 1014 } 1015 1016 bool ScDocFunc::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell, bool bInteraction ) 1017 { 1018 std::unique_ptr<ScFormulaCell> xCell(pCell); 1019 1020 ScDocShellModificator aModificator( rDocShell ); 1021 ScDocument& rDoc = rDocShell.GetDocument(); 1022 bool bUndo = rDoc.IsUndoEnabled(); 1023 1024 bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight); 1025 1026 ScCellValue aOldVal; 1027 if (bUndo) 1028 aOldVal.assign(rDoc, rPos); 1029 1030 pCell = rDoc.SetFormulaCell(rPos, xCell.release()); 1031 1032 // For performance reasons API calls may disable calculation while 1033 // operating and recalculate once when done. If through user interaction 1034 // and AutoCalc is disabled, calculate the formula (without its 1035 // dependencies) once so the result matches the current document's content. 1036 if (bInteraction && !rDoc.GetAutoCalc() && pCell) 1037 { 1038 // calculate just the cell once and set Dirty again 1039 pCell->Interpret(); 1040 pCell->SetDirtyVar(); 1041 rDoc.PutInFormulaTree( pCell); 1042 } 1043 1044 if (bUndo) 1045 { 1046 SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager(); 1047 ScCellValue aNewVal; 1048 aNewVal.assign(rDoc, rPos); 1049 pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal)); 1050 } 1051 1052 if (bHeight) 1053 AdjustRowHeight(rPos, true, !bInteraction); 1054 1055 rDocShell.PostPaintCell( rPos ); 1056 aModificator.SetDocumentModified(); 1057 1058 // #103934#; notify editline and cell in edit mode 1059 if (!bInteraction) 1060 NotifyInputHandler( rPos ); 1061 1062 return true; 1063 } 1064 1065 bool ScDocFunc::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells, bool bInteraction ) 1066 { 1067 ScDocument& rDoc = rDocShell.GetDocument(); 1068 1069 const size_t nLength = rCells.size(); 1070 if (rPos.Row() + nLength - 1 > o3tl::make_unsigned(rDoc.MaxRow())) 1071 // out of bound 1072 return false; 1073 1074 ScRange aRange(rPos); 1075 aRange.aEnd.IncRow(nLength - 1); 1076 1077 ScDocShellModificator aModificator( rDocShell ); 1078 bool bUndo = rDoc.IsUndoEnabled(); 1079 1080 std::unique_ptr<sc::UndoSetCells> pUndoObj; 1081 if (bUndo) 1082 { 1083 pUndoObj.reset(new sc::UndoSetCells(&rDocShell, rPos)); 1084 rDoc.TransferCellValuesTo(rPos, nLength, pUndoObj->GetOldValues()); 1085 } 1086 1087 rDoc.SetFormulaCells(rPos, rCells); 1088 1089 // For performance reasons API calls may disable calculation while 1090 // operating and recalculate once when done. If through user interaction 1091 // and AutoCalc is disabled, calculate the formula (without its 1092 // dependencies) once so the result matches the current document's content. 1093 if (bInteraction && !rDoc.GetAutoCalc()) 1094 { 1095 for (auto* pCell : rCells) 1096 { 1097 // calculate just the cell once and set Dirty again 1098 pCell->Interpret(); 1099 pCell->SetDirtyVar(); 1100 rDoc.PutInFormulaTree( pCell); 1101 } 1102 } 1103 1104 if (bUndo) 1105 { 1106 pUndoObj->SetNewValues(rCells); 1107 SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager(); 1108 pUndoMgr->AddUndoAction(std::move(pUndoObj)); 1109 } 1110 1111 rDocShell.PostPaint(aRange, PaintPartFlags::Grid); 1112 aModificator.SetDocumentModified(); 1113 1114 // #103934#; notify editline and cell in edit mode 1115 if (!bInteraction) 1116 NotifyInputHandler( rPos ); 1117 1118 return true; 1119 } 1120 1121 void ScDocFunc::NotifyInputHandler( const ScAddress& rPos ) 1122 { 1123 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); 1124 if ( !(pViewSh && pViewSh->GetViewData().GetDocShell() == &rDocShell) ) 1125 return; 1126 1127 ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(); 1128 if ( pInputHdl && pInputHdl->GetCursorPos() == rPos ) 1129 { 1130 bool bIsEditMode(pInputHdl->IsEditMode()); 1131 1132 // set modified if in editmode, because so the string is not set in the InputWindow like in the cell 1133 // (the cell shows the same like the InputWindow) 1134 if (bIsEditMode) 1135 pInputHdl->SetModified(); 1136 pViewSh->UpdateInputHandler(false, !bIsEditMode); 1137 } 1138 } 1139 1140 namespace { 1141 1142 struct ScMyRememberItem 1143 { 1144 sal_Int32 nIndex; 1145 SfxItemSet aItemSet; 1146 1147 ScMyRememberItem(const SfxItemSet& rItemSet, sal_Int32 nTempIndex) : 1148 nIndex(nTempIndex), aItemSet(rItemSet) {} 1149 }; 1150 1151 } 1152 1153 void ScDocFunc::PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, bool bApi ) 1154 { 1155 // PutData calls PutCell or SetNormalString 1156 1157 bool bRet = false; 1158 ScDocument& rDoc = rDocShell.GetDocument(); 1159 ScEditAttrTester aTester( &rEngine ); 1160 bool bEditCell = aTester.NeedsObject(); 1161 if ( bEditCell ) 1162 { 1163 // #i61702# With bLoseContent set, the content of rEngine isn't restored 1164 // (used in loading XML, where after the removeActionLock call the API object's 1165 // EditEngine isn't accessed again. 1166 bool bLoseContent = rDoc.IsImportingXML(); 1167 1168 const bool bUpdateMode = rEngine.SetUpdateLayout(false); 1169 1170 std::vector<std::unique_ptr<ScMyRememberItem>> aRememberItems; 1171 1172 // All paragraph attributes must be removed before calling CreateTextObject, 1173 // not only alignment, so the object doesn't contain the cell attributes as 1174 // paragraph attributes. Before removing the attributes store them in a vector to 1175 // set them back to the EditEngine. 1176 sal_Int32 nCount = rEngine.GetParagraphCount(); 1177 for (sal_Int32 i=0; i<nCount; i++) 1178 { 1179 const SfxItemSet& rOld = rEngine.GetParaAttribs( i ); 1180 if ( rOld.Count() ) 1181 { 1182 if ( !bLoseContent ) 1183 { 1184 aRememberItems.push_back(std::make_unique<ScMyRememberItem>(rEngine.GetParaAttribs(i), i)); 1185 } 1186 rEngine.SetParaAttribs( i, SfxItemSet( *rOld.GetPool(), rOld.GetRanges() ) ); 1187 } 1188 } 1189 1190 // A copy of pNewData will be stored in the cell. 1191 std::unique_ptr<EditTextObject> pNewData(rEngine.CreateTextObject()); 1192 bRet = SetEditCell(rPos, *pNewData, !bApi); 1193 1194 // Set the paragraph attributes back to the EditEngine. 1195 for (const auto& rxItem : aRememberItems) 1196 { 1197 rEngine.SetParaAttribs(rxItem->nIndex, rxItem->aItemSet); 1198 } 1199 1200 // #i61702# if the content isn't accessed, there's no need to set the UpdateMode again 1201 if ( bUpdateMode && !bLoseContent ) 1202 rEngine.SetUpdateLayout(true); 1203 } 1204 else 1205 { 1206 OUString aText = rEngine.GetText(); 1207 if (aText.isEmpty()) 1208 { 1209 bool bNumFmtSet = false; 1210 bRet = SetNormalString( bNumFmtSet, rPos, aText, bApi ); 1211 } 1212 else 1213 bRet = SetStringCell(rPos, aText, !bApi); 1214 } 1215 1216 if ( !(bRet && aTester.NeedsCellAttr()) ) 1217 return; 1218 1219 const SfxItemSet& rEditAttr = aTester.GetAttribs(); 1220 ScPatternAttr aPattern( rDoc.GetPool() ); 1221 aPattern.GetFromEditItemSet( &rEditAttr ); 1222 aPattern.DeleteUnchanged( rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() ) ); 1223 aPattern.GetItemSet().ClearItem( ATTR_HOR_JUSTIFY ); // wasn't removed above if no edit object 1224 if ( aPattern.GetItemSet().Count() > 0 ) 1225 { 1226 ScMarkData aMark(rDoc.GetSheetLimits()); 1227 aMark.SelectTable( rPos.Tab(), true ); 1228 aMark.SetMarkArea( ScRange( rPos ) ); 1229 ApplyAttributes( aMark, aPattern, bApi ); 1230 } 1231 } 1232 1233 bool ScDocFunc::SetCellText( 1234 const ScAddress& rPos, const OUString& rText, bool bInterpret, bool bEnglish, bool bApi, 1235 const formula::FormulaGrammar::Grammar eGrammar ) 1236 { 1237 bool bSet = false; 1238 if ( bInterpret ) 1239 { 1240 if ( bEnglish ) 1241 { 1242 ScDocument& rDoc = rDocShell.GetDocument(); 1243 1244 ::std::unique_ptr<ScExternalRefManager::ApiGuard> pExtRefGuard; 1245 if (bApi) 1246 pExtRefGuard.reset(new ScExternalRefManager::ApiGuard(rDoc)); 1247 1248 ScInputStringType aRes = 1249 ScStringUtil::parseInputString(*rDoc.GetFormatTable(), rText, LANGUAGE_ENGLISH_US); 1250 1251 switch (aRes.meType) 1252 { 1253 case ScInputStringType::Formula: 1254 bSet = SetFormulaCell(rPos, new ScFormulaCell(rDoc, rPos, aRes.maText, eGrammar), !bApi); 1255 break; 1256 case ScInputStringType::Number: 1257 bSet = SetValueCell(rPos, aRes.mfValue, !bApi); 1258 break; 1259 case ScInputStringType::Text: 1260 bSet = SetStringOrEditCell(rPos, aRes.maText, !bApi); 1261 break; 1262 default: 1263 ; 1264 } 1265 } 1266 // otherwise keep Null -> SetString with local formulas/number formats 1267 } 1268 else if (!rText.isEmpty()) 1269 { 1270 bSet = SetStringOrEditCell(rPos, rText, !bApi); 1271 } 1272 1273 if (!bSet) 1274 { 1275 bool bNumFmtSet = false; 1276 bSet = SetNormalString( bNumFmtSet, rPos, rText, bApi ); 1277 } 1278 return bSet; 1279 } 1280 1281 bool ScDocFunc::ShowNote( const ScAddress& rPos, bool bShow ) 1282 { 1283 ScDocument& rDoc = rDocShell.GetDocument(); 1284 ScPostIt* pNote = rDoc.GetNote( rPos ); 1285 if( !pNote || (bShow == pNote->IsCaptionShown()) || 1286 (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations()) ) 1287 return false; 1288 1289 // move the caption to internal or hidden layer and create undo action 1290 pNote->ShowCaption( rPos, bShow ); 1291 if( rDoc.IsUndoEnabled() ) 1292 rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideNote>( rDocShell, rPos, bShow ) ); 1293 1294 rDoc.SetStreamValid(rPos.Tab(), false); 1295 1296 ScTabView::OnLOKNoteStateChanged(pNote); 1297 1298 if (ScViewData* pViewData = ScDocShell::GetViewData()) 1299 { 1300 if (ScDrawView* pDrawView = pViewData->GetScDrawView()) 1301 pDrawView->SyncForGrid( pNote->GetCaption()); 1302 } 1303 1304 rDocShell.SetDocumentModified(); 1305 1306 return true; 1307 } 1308 1309 void ScDocFunc::SetNoteText( const ScAddress& rPos, const OUString& rText, bool bApi ) 1310 { 1311 ScDocShellModificator aModificator( rDocShell ); 1312 1313 ScDocument& rDoc = rDocShell.GetDocument(); 1314 ScEditableTester aTester( rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); 1315 if (!aTester.IsEditable()) 1316 { 1317 if (!bApi) 1318 rDocShell.ErrorMessage(aTester.GetMessageId()); 1319 return; 1320 } 1321 1322 OUString aNewText = convertLineEnd(rText, GetSystemLineEnd()); //! is this necessary ??? 1323 1324 if( ScPostIt* pNote = (!aNewText.isEmpty()) ? rDoc.GetOrCreateNote( rPos ) : rDoc.GetNote(rPos) ) 1325 pNote->SetText( rPos, aNewText ); 1326 1327 //! Undo !!! 1328 1329 rDoc.SetStreamValid(rPos.Tab(), false); 1330 1331 rDocShell.PostPaintCell( rPos ); 1332 aModificator.SetDocumentModified(); 1333 } 1334 1335 void ScDocFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate, bool bApi ) 1336 { 1337 ScDocShellModificator aModificator( rDocShell ); 1338 ScDocument& rDoc = rDocShell.GetDocument(); 1339 ScEditableTester aTester( rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); 1340 if (aTester.IsEditable()) 1341 { 1342 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); 1343 SfxUndoManager* pUndoMgr = (pDrawLayer && rDoc.IsUndoEnabled()) ? rDocShell.GetUndoManager() : nullptr; 1344 1345 ScNoteData aOldData; 1346 std::unique_ptr<ScPostIt> pOldNote = rDoc.ReleaseNote( rPos ); 1347 sal_uInt32 nNoteId = 0; 1348 if( pOldNote ) 1349 { 1350 nNoteId = pOldNote->GetId(); 1351 // ensure existing caption object before draw undo tracking starts 1352 pOldNote->GetOrCreateCaption( rPos ); 1353 // rescue note data for undo 1354 aOldData = pOldNote->GetNoteData(); 1355 } 1356 1357 // collect drawing undo actions for deleting/inserting caption objects 1358 if( pUndoMgr ) 1359 pDrawLayer->BeginCalcUndo(false); 1360 1361 // delete the note (creates drawing undo action for the caption object) 1362 bool hadOldNote(pOldNote); 1363 pOldNote.reset(); 1364 1365 // create new note (creates drawing undo action for the new caption object) 1366 ScNoteData aNewData; 1367 ScPostIt* pNewNote = nullptr; 1368 if( (pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true, nNoteId )) ) 1369 { 1370 if( pAuthor ) pNewNote->SetAuthor( *pAuthor ); 1371 if( pDate ) pNewNote->SetDate( *pDate ); 1372 1373 // rescue note data for undo 1374 aNewData = pNewNote->GetNoteData(); 1375 } 1376 1377 // create the undo action 1378 if( pUndoMgr && (aOldData.mxCaption || aNewData.mxCaption) ) 1379 pUndoMgr->AddUndoAction( std::make_unique<ScUndoReplaceNote>( rDocShell, rPos, aOldData, aNewData, pDrawLayer->GetCalcUndo() ) ); 1380 1381 // repaint cell (to make note marker visible) 1382 rDocShell.PostPaintCell( rPos ); 1383 1384 rDoc.SetStreamValid(rPos.Tab(), false); 1385 1386 aModificator.SetDocumentModified(); 1387 1388 // Let our LOK clients know about the new/modified note 1389 if (pNewNote) 1390 { 1391 ScDocShell::LOKCommentNotify(hadOldNote ? LOKCommentNotificationType::Modify : LOKCommentNotificationType::Add, 1392 &rDoc, rPos, pNewNote); 1393 } 1394 } 1395 else if (!bApi) 1396 { 1397 rDocShell.ErrorMessage(aTester.GetMessageId()); 1398 } 1399 } 1400 1401 ScPostIt* ScDocFunc::ImportNote( const ScAddress& rPos, const OUString& rNoteText ) 1402 { 1403 ScDocShellModificator aModificator( rDocShell ); 1404 ScDocument& rDoc = rDocShell.GetDocument(); 1405 1406 std::unique_ptr<ScPostIt> pOldNote = rDoc.ReleaseNote( rPos ); 1407 SAL_WARN_IF(pOldNote, "sc.ui", "imported data has >1 notes on same cell? at pos " << rPos); 1408 1409 // create new note 1410 ScPostIt* pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true, /*nNoteId*/0 ); 1411 1412 rDoc.SetStreamValid(rPos.Tab(), false); 1413 1414 aModificator.SetDocumentModified(); 1415 1416 return pNewNote; 1417 } 1418 1419 bool ScDocFunc::ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern, 1420 bool bApi ) 1421 { 1422 ScDocument& rDoc = rDocShell.GetDocument(); 1423 bool bRecord = true; 1424 if ( !rDoc.IsUndoEnabled() ) 1425 bRecord = false; 1426 1427 bool bImportingXML = rDoc.IsImportingXML(); 1428 // Cell formats can still be set if the range isn't editable only because of matrix formulas. 1429 // #i62483# When loading XML, the check can be skipped altogether. 1430 bool bOnlyNotBecauseOfMatrix; 1431 if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix ) 1432 && !bOnlyNotBecauseOfMatrix ) 1433 { 1434 if (!bApi) 1435 rDocShell.ErrorMessage(STR_PROTECTIONERR); 1436 return false; 1437 } 1438 1439 ScDocShellModificator aModificator( rDocShell ); 1440 1441 //! Border 1442 1443 ScRange aMultiRange; 1444 bool bMulti = rMark.IsMultiMarked(); 1445 if ( bMulti ) 1446 rMark.GetMultiMarkArea( aMultiRange ); 1447 else 1448 rMark.GetMarkArea( aMultiRange ); 1449 1450 if ( bRecord ) 1451 { 1452 ScDocumentUniquePtr pUndoDoc( new ScDocument( SCDOCMODE_UNDO )); 1453 pUndoDoc->InitUndo( rDoc, aMultiRange.aStart.Tab(), aMultiRange.aEnd.Tab() ); 1454 rDoc.CopyToDocument(aMultiRange, InsertDeleteFlags::ATTRIB, bMulti, *pUndoDoc, &rMark); 1455 1456 rDocShell.GetUndoManager()->AddUndoAction( 1457 std::make_unique<ScUndoSelectionAttr>( 1458 &rDocShell, rMark, 1459 aMultiRange.aStart.Col(), aMultiRange.aStart.Row(), aMultiRange.aStart.Tab(), 1460 aMultiRange.aEnd.Col(), aMultiRange.aEnd.Row(), aMultiRange.aEnd.Tab(), 1461 std::move(pUndoDoc), bMulti, &rPattern ) ); 1462 } 1463 1464 // While loading XML it is not necessary to ask HasAttrib. It needs too much time. 1465 sal_uInt16 nExtFlags = 0; 1466 if ( !bImportingXML ) 1467 rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content before the change 1468 1469 bool bChanged = false; 1470 rDoc.ApplySelectionPattern( rPattern, rMark, nullptr, &bChanged ); 1471 1472 if(bChanged) 1473 { 1474 if ( !bImportingXML ) 1475 rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content after the change 1476 1477 if (!AdjustRowHeight( aMultiRange, true, bApi )) 1478 rDocShell.PostPaint( aMultiRange, PaintPartFlags::Grid, nExtFlags ); 1479 else if (nExtFlags & SC_PF_LINES) 1480 lcl_PaintAbove( rDocShell, aMultiRange ); // because of lines above the range 1481 1482 aModificator.SetDocumentModified(); 1483 } 1484 1485 return true; 1486 } 1487 1488 bool ScDocFunc::ApplyStyle( const ScMarkData& rMark, const OUString& rStyleName, 1489 bool bApi ) 1490 { 1491 ScDocument& rDoc = rDocShell.GetDocument(); 1492 bool bRecord = true; 1493 if ( !rDoc.IsUndoEnabled() ) 1494 bRecord = false; 1495 1496 bool bImportingXML = rDoc.IsImportingXML(); 1497 // Cell formats can still be set if the range isn't editable only because of matrix formulas. 1498 // #i62483# When loading XML, the check can be skipped altogether. 1499 bool bOnlyNotBecauseOfMatrix; 1500 if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix ) 1501 && !bOnlyNotBecauseOfMatrix ) 1502 { 1503 if (!bApi) 1504 rDocShell.ErrorMessage(STR_PROTECTIONERR); 1505 return false; 1506 } 1507 1508 ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( rDoc.GetStyleSheetPool()->Find( 1509 rStyleName, SfxStyleFamily::Para )); 1510 if (!pStyleSheet) 1511 return false; 1512 1513 ScDocShellModificator aModificator( rDocShell ); 1514 1515 ScRange aMultiRange; 1516 bool bMulti = rMark.IsMultiMarked(); 1517 if ( bMulti ) 1518 rMark.GetMultiMarkArea( aMultiRange ); 1519 else 1520 rMark.GetMarkArea( aMultiRange ); 1521 1522 if ( bRecord ) 1523 { 1524 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); 1525 SCTAB nStartTab = aMultiRange.aStart.Tab(); 1526 SCTAB nTabCount = rDoc.GetTableCount(); 1527 pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab ); 1528 for (const auto& rTab : rMark) 1529 { 1530 if (rTab >= nTabCount) 1531 break; 1532 1533 if (rTab != nStartTab) 1534 pUndoDoc->AddUndoTab( rTab, rTab ); 1535 } 1536 1537 ScRange aCopyRange = aMultiRange; 1538 aCopyRange.aStart.SetTab(0); 1539 aCopyRange.aEnd.SetTab(nTabCount-1); 1540 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, *pUndoDoc, &rMark ); 1541 1542 rDocShell.GetUndoManager()->AddUndoAction( 1543 std::make_unique<ScUndoSelectionStyle>( 1544 &rDocShell, rMark, aMultiRange, rStyleName, std::move(pUndoDoc) ) ); 1545 1546 } 1547 1548 rDoc.ApplySelectionStyle( *pStyleSheet, rMark ); 1549 1550 if (!AdjustRowHeight( aMultiRange, true, bApi )) 1551 rDocShell.PostPaint( aMultiRange, PaintPartFlags::Grid ); 1552 1553 aModificator.SetDocumentModified(); 1554 1555 return true; 1556 } 1557 1558 namespace { 1559 1560 /** 1561 * Check if this insertion attempt would end up cutting one or more pivot 1562 * tables in half, which is not desirable. 1563 * 1564 * @return true if this insertion can be done safely without shearing any 1565 * existing pivot tables, false otherwise. 1566 */ 1567 bool canInsertCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, InsCellCmd eCmd, const ScDocument& rDoc) 1568 { 1569 if (!rDoc.HasPivotTable()) 1570 // This document has no pivot tables. 1571 return true; 1572 1573 const ScDPCollection* pDPs = rDoc.GetDPCollection(); 1574 1575 ScRange aRange(rRange); // local copy 1576 switch (eCmd) 1577 { 1578 case INS_INSROWS_BEFORE: 1579 { 1580 aRange.aStart.SetCol(0); 1581 aRange.aEnd.SetCol(rDoc.MaxCol()); 1582 [[fallthrough]]; 1583 } 1584 case INS_CELLSDOWN: 1585 { 1586 auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) { 1587 return pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), rTab); }); 1588 if (bIntersects) 1589 // This column range cuts through at least one pivot table. Not good. 1590 return false; 1591 1592 // Start row must be either at the top or above any pivot tables. 1593 if (aRange.aStart.Row() < 0) 1594 // I don't know how to handle this case. 1595 return false; 1596 1597 if (aRange.aStart.Row() == 0) 1598 // First row is always allowed. 1599 return true; 1600 1601 ScRange aTest(aRange); 1602 aTest.aStart.IncRow(-1); // Test one row up. 1603 aTest.aEnd.SetRow(aTest.aStart.Row()); 1604 for (const auto& rTab : rMarkData) 1605 { 1606 aTest.aStart.SetTab(rTab); 1607 aTest.aEnd.SetTab(rTab); 1608 if (pDPs->HasTable(aTest)) 1609 return false; 1610 } 1611 } 1612 break; 1613 case INS_INSCOLS_BEFORE: 1614 { 1615 aRange.aStart.SetRow(0); 1616 aRange.aEnd.SetRow(rDoc.MaxRow()); 1617 [[fallthrough]]; 1618 } 1619 case INS_CELLSRIGHT: 1620 { 1621 auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) { 1622 return pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), rTab); }); 1623 if (bIntersects) 1624 // This column range cuts through at least one pivot table. Not good. 1625 return false; 1626 1627 // Start row must be either at the top or above any pivot tables. 1628 if (aRange.aStart.Col() < 0) 1629 // I don't know how to handle this case. 1630 return false; 1631 1632 if (aRange.aStart.Col() == 0) 1633 // First row is always allowed. 1634 return true; 1635 1636 ScRange aTest(aRange); 1637 aTest.aStart.IncCol(-1); // Test one column to the left. 1638 aTest.aEnd.SetCol(aTest.aStart.Col()); 1639 for (const auto& rTab : rMarkData) 1640 { 1641 aTest.aStart.SetTab(rTab); 1642 aTest.aEnd.SetTab(rTab); 1643 if (pDPs->HasTable(aTest)) 1644 return false; 1645 } 1646 } 1647 break; 1648 default: 1649 ; 1650 } 1651 return true; 1652 } 1653 1654 /** 1655 * Check if this deletion attempt would end up cutting one or more pivot 1656 * tables in half, which is not desirable. 1657 * 1658 * @return true if this deletion can be done safely without shearing any 1659 * existing pivot tables, false otherwise. 1660 */ 1661 bool canDeleteCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, DelCellCmd eCmd, const ScDocument& rDoc) 1662 { 1663 if (!rDoc.HasPivotTable()) 1664 // This document has no pivot tables. 1665 return true; 1666 1667 const ScDPCollection* pDPs = rDoc.GetDPCollection(); 1668 1669 ScRange aRange(rRange); // local copy 1670 1671 switch (eCmd) 1672 { 1673 case DelCellCmd::Rows: 1674 { 1675 aRange.aStart.SetCol(0); 1676 aRange.aEnd.SetCol(rDoc.MaxCol()); 1677 [[fallthrough]]; 1678 } 1679 case DelCellCmd::CellsUp: 1680 { 1681 auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) { 1682 return pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), rTab); }); 1683 if (bIntersects) 1684 // This column range cuts through at least one pivot table. Not good. 1685 return false; 1686 1687 ScRange aTest(aRange); 1688 for (const auto& rTab : rMarkData) 1689 { 1690 aTest.aStart.SetTab(rTab); 1691 aTest.aEnd.SetTab(rTab); 1692 if (pDPs->HasTable(aTest)) 1693 return false; 1694 } 1695 } 1696 break; 1697 case DelCellCmd::Cols: 1698 { 1699 aRange.aStart.SetRow(0); 1700 aRange.aEnd.SetRow(rDoc.MaxRow()); 1701 [[fallthrough]]; 1702 } 1703 case DelCellCmd::CellsLeft: 1704 { 1705 auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) { 1706 return pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), rTab); }); 1707 if (bIntersects) 1708 // This column range cuts through at least one pivot table. Not good. 1709 return false; 1710 1711 ScRange aTest(aRange); 1712 for (const auto& rTab : rMarkData) 1713 { 1714 aTest.aStart.SetTab(rTab); 1715 aTest.aEnd.SetTab(rTab); 1716 if (pDPs->HasTable(aTest)) 1717 return false; 1718 } 1719 } 1720 break; 1721 default: 1722 ; 1723 } 1724 return true; 1725 } 1726 1727 } 1728 1729 bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, InsCellCmd eCmd, 1730 bool bRecord, bool bApi, bool bPartOfPaste ) 1731 { 1732 ScDocShellModificator aModificator( rDocShell ); 1733 ScDocument& rDoc = rDocShell.GetDocument(); 1734 1735 if (rDocShell.GetDocument().GetChangeTrack() && 1736 ((eCmd == INS_CELLSDOWN && (rRange.aStart.Col() != 0 || rRange.aEnd.Col() != rDoc.MaxCol())) || 1737 (eCmd == INS_CELLSRIGHT && (rRange.aStart.Row() != 0 || rRange.aEnd.Row() != rDoc.MaxRow())))) 1738 { 1739 // We should not reach this via UI disabled slots. 1740 assert(bApi); 1741 SAL_WARN("sc.ui","ScDocFunc::InsertCells - no change-tracking of partial cell shift"); 1742 return false; 1743 } 1744 1745 ScRange aTargetRange( rRange ); 1746 1747 // If insertion is for full cols/rows and after the current 1748 // selection, then shift the range accordingly 1749 if ( eCmd == INS_INSROWS_AFTER ) 1750 { 1751 ScRange aErrorRange( ScAddress::UNINITIALIZED ); 1752 if (!aTargetRange.Move(0, rRange.aEnd.Row() - rRange.aStart.Row() + 1, 0, aErrorRange)) 1753 { 1754 return false; 1755 } 1756 } 1757 if ( eCmd == INS_INSCOLS_AFTER ) 1758 { 1759 ScRange aErrorRange( ScAddress::UNINITIALIZED ); 1760 if (!aTargetRange.Move(rRange.aEnd.Col() - rRange.aStart.Col() + 1, 0, 0, aErrorRange)) 1761 { 1762 return false; 1763 } 1764 } 1765 1766 SCCOL nStartCol = aTargetRange.aStart.Col(); 1767 SCROW nStartRow = aTargetRange.aStart.Row(); 1768 SCTAB nStartTab = aTargetRange.aStart.Tab(); 1769 SCCOL nEndCol = aTargetRange.aEnd.Col(); 1770 SCROW nEndRow = aTargetRange.aEnd.Row(); 1771 SCTAB nEndTab = aTargetRange.aEnd.Tab(); 1772 1773 if ( !rDoc.ValidRow(nStartRow) || !rDoc.ValidRow(nEndRow) ) 1774 { 1775 OSL_FAIL("invalid row in InsertCells"); 1776 return false; 1777 } 1778 1779 SCTAB nTabCount = rDoc.GetTableCount(); 1780 SCCOL nPaintStartCol = nStartCol; 1781 SCROW nPaintStartRow = nStartRow; 1782 SCCOL nPaintEndCol = nEndCol; 1783 SCROW nPaintEndRow = nEndRow; 1784 PaintPartFlags nPaintFlags = PaintPartFlags::Grid; 1785 bool bSuccess; 1786 1787 ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); //preserve current cursor position 1788 SCCOL nCursorCol = 0; 1789 SCROW nCursorRow = 0; 1790 if( pViewSh ) 1791 { 1792 nCursorCol = pViewSh->GetViewData().GetCurX(); 1793 nCursorRow = pViewSh->GetViewData().GetCurY(); 1794 } 1795 1796 if (bRecord && !rDoc.IsUndoEnabled()) 1797 bRecord = false; 1798 1799 ScMarkData aMark(rDoc.GetSheetLimits()); 1800 if (pTabMark) 1801 aMark = *pTabMark; 1802 else 1803 { 1804 SCTAB nCount = 0; 1805 for( SCTAB i=0; i<nTabCount; i++ ) 1806 { 1807 if( !rDoc.IsScenario(i) ) 1808 { 1809 nCount++; 1810 if( nCount == nEndTab+1 ) 1811 { 1812 aMark.SelectTable( i, true ); 1813 break; 1814 } 1815 } 1816 } 1817 } 1818 1819 ScMarkData aFullMark( aMark ); // including scenario sheets 1820 for (const auto& rTab : aMark) 1821 { 1822 if (rTab >= nTabCount) 1823 break; 1824 1825 for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 1826 aFullMark.SelectTable( j, true ); 1827 } 1828 1829 SCTAB nSelCount = aMark.GetSelectCount(); 1830 1831 // Adjust also related scenarios 1832 1833 SCCOL nMergeTestStartCol = nStartCol; 1834 SCROW nMergeTestStartRow = nStartRow; 1835 SCCOL nMergeTestEndCol = nEndCol; 1836 SCROW nMergeTestEndRow = nEndRow; 1837 1838 ScRange aExtendMergeRange( aTargetRange ); 1839 1840 if( aTargetRange.aStart == aTargetRange.aEnd && rDoc.HasAttrib(aTargetRange, HasAttrFlags::Merged) ) 1841 { 1842 rDoc.ExtendMerge( aExtendMergeRange ); 1843 rDoc.ExtendOverlapped( aExtendMergeRange ); 1844 nMergeTestEndCol = aExtendMergeRange.aEnd.Col(); 1845 nMergeTestEndRow = aExtendMergeRange.aEnd.Row(); 1846 nPaintEndCol = nMergeTestEndCol; 1847 nPaintEndRow = nMergeTestEndRow; 1848 } 1849 1850 if ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER ) 1851 { 1852 nMergeTestStartCol = 0; 1853 nMergeTestEndCol = rDoc.MaxCol(); 1854 } 1855 if ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER ) 1856 { 1857 nMergeTestStartRow = 0; 1858 nMergeTestEndRow = rDoc.MaxRow(); 1859 } 1860 if ( eCmd == INS_CELLSDOWN ) 1861 nMergeTestEndRow = rDoc.MaxRow(); 1862 if ( eCmd == INS_CELLSRIGHT ) 1863 nMergeTestEndCol = rDoc.MaxCol(); 1864 1865 bool bNeedRefresh = false; 1866 1867 SCCOL nEditTestEndCol = (eCmd==INS_INSCOLS_BEFORE || eCmd==INS_INSCOLS_AFTER) ? rDoc.MaxCol() : nMergeTestEndCol; 1868 SCROW nEditTestEndRow = (eCmd==INS_INSROWS_BEFORE || eCmd==INS_INSROWS_AFTER) ? rDoc.MaxRow() : nMergeTestEndRow; 1869 1870 ScEditableTester aTester; 1871 1872 switch (eCmd) 1873 { 1874 case INS_INSCOLS_BEFORE: 1875 aTester = ScEditableTester( 1876 rDoc, sc::ColRowEditAction::InsertColumnsBefore, nMergeTestStartCol, nMergeTestEndCol, aMark); 1877 break; 1878 case INS_INSCOLS_AFTER: 1879 aTester = ScEditableTester( 1880 rDoc, sc::ColRowEditAction::InsertColumnsAfter, nMergeTestStartCol, nMergeTestEndCol, aMark); 1881 break; 1882 case INS_INSROWS_BEFORE: 1883 aTester = ScEditableTester( 1884 rDoc, sc::ColRowEditAction::InsertRowsBefore, nMergeTestStartRow, nMergeTestEndRow, aMark); 1885 break; 1886 case INS_INSROWS_AFTER: 1887 aTester = ScEditableTester( 1888 rDoc, sc::ColRowEditAction::InsertRowsAfter, nMergeTestStartRow, nMergeTestEndRow, aMark); 1889 break; 1890 default: 1891 aTester = ScEditableTester( 1892 rDoc, nMergeTestStartCol, nMergeTestStartRow, nEditTestEndCol, nEditTestEndRow, aMark); 1893 } 1894 1895 if (!aTester.IsEditable()) 1896 { 1897 if (!bApi) 1898 rDocShell.ErrorMessage(aTester.GetMessageId()); 1899 return false; 1900 } 1901 1902 // Check if this insertion is allowed with respect to pivot table. 1903 if (!canInsertCellsByPivot(aTargetRange, aMark, eCmd, rDoc)) 1904 { 1905 if (!bApi) 1906 rDocShell.ErrorMessage(STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE); 1907 return false; 1908 } 1909 1910 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas at UpdateReference 1911 1912 ScDocumentUniquePtr pRefUndoDoc; 1913 std::unique_ptr<ScRefUndoData> pUndoData; 1914 if ( bRecord ) 1915 { 1916 pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 1917 pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 ); 1918 1919 // pRefUndoDoc is filled in InsertCol / InsertRow 1920 1921 pUndoData.reset(new ScRefUndoData( &rDoc )); 1922 1923 rDoc.BeginDrawUndo(); 1924 } 1925 1926 // #i8302 : we unmerge overwhelming ranges, before insertion all the actions are put in the same ListAction 1927 // the patch comes from mloiseleur and maoyg 1928 bool bInsertMerge = false; 1929 std::vector<ScRange> qIncreaseRange; 1930 OUString aUndo = ScResId( STR_UNDO_INSERTCELLS ); 1931 if (bRecord) 1932 { 1933 ViewShellId nViewShellId(-1); 1934 if (pViewSh) 1935 nViewShellId = pViewSh->GetViewShellId(); 1936 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId ); 1937 } 1938 std::unique_ptr<ScUndoRemoveMerge> pUndoRemoveMerge; 1939 1940 for (const SCTAB i : aMark) 1941 { 1942 if (i >= nTabCount) 1943 break; 1944 1945 if( rDoc.HasAttrib( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HasAttrFlags::Merged | HasAttrFlags::Overlapped ) ) 1946 { 1947 if (eCmd==INS_CELLSRIGHT) 1948 bNeedRefresh = true; 1949 1950 SCCOL nMergeStartCol = nMergeTestStartCol; 1951 SCROW nMergeStartRow = nMergeTestStartRow; 1952 SCCOL nMergeEndCol = nMergeTestEndCol; 1953 SCROW nMergeEndRow = nMergeTestEndRow; 1954 1955 rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); 1956 rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); 1957 1958 if(( eCmd == INS_CELLSDOWN && ( nMergeStartCol != nMergeTestStartCol || nMergeEndCol != nMergeTestEndCol )) || 1959 (eCmd == INS_CELLSRIGHT && ( nMergeStartRow != nMergeTestStartRow || nMergeEndRow != nMergeTestEndRow )) ) 1960 { 1961 if (!bApi) 1962 rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); 1963 rDocShell.GetUndoManager()->LeaveListAction(); 1964 return false; 1965 } 1966 1967 SCCOL nTestCol = -1; 1968 SCROW nTestRow1 = -1; 1969 SCROW nTestRow2 = -1; 1970 1971 ScDocAttrIterator aTestIter( rDoc, i, nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow ); 1972 ScRange aExtendRange( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i ); 1973 const ScPatternAttr* pPattern = nullptr; 1974 while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != nullptr ) 1975 { 1976 const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE); 1977 const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG); 1978 ScMF nNewFlags = rMergeFlagAttr.GetValue() & (ScMF::Hor | ScMF::Ver); 1979 if (rMergeFlag.IsMerged() || nNewFlags == ScMF::Hor || nNewFlags == ScMF::Ver) 1980 { 1981 ScRange aRange( nTestCol, nTestRow1, i ); 1982 rDoc.ExtendOverlapped(aRange); 1983 rDoc.ExtendMerge(aRange, true); 1984 1985 if( nTestRow1 < nTestRow2 && nNewFlags == ScMF::Hor ) 1986 { 1987 for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ ) 1988 { 1989 ScRange aTestRange( nTestCol, nTestRow, i ); 1990 rDoc.ExtendOverlapped( aTestRange ); 1991 rDoc.ExtendMerge( aTestRange, true); 1992 ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i ); 1993 if( !aExtendRange.Contains( aMergeRange ) ) 1994 { 1995 qIncreaseRange.push_back( aTestRange ); 1996 bInsertMerge = true; 1997 } 1998 } 1999 } 2000 else 2001 { 2002 ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i ); 2003 if( !aExtendRange.Contains( aMergeRange ) ) 2004 { 2005 qIncreaseRange.push_back( aRange ); 2006 } 2007 bInsertMerge = true; 2008 } 2009 } 2010 } 2011 2012 if( bInsertMerge ) 2013 { 2014 if( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN ) 2015 { 2016 nStartRow = aExtendMergeRange.aStart.Row(); 2017 nEndRow = aExtendMergeRange.aEnd.Row(); 2018 2019 if( eCmd == INS_CELLSDOWN ) 2020 nEndCol = nMergeTestEndCol; 2021 else 2022 { 2023 nStartCol = 0; 2024 nEndCol = rDoc.MaxCol(); 2025 } 2026 } 2027 else if( eCmd == INS_CELLSRIGHT || eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER ) 2028 { 2029 2030 nStartCol = aExtendMergeRange.aStart.Col(); 2031 nEndCol = aExtendMergeRange.aEnd.Col(); 2032 if( eCmd == INS_CELLSRIGHT ) 2033 { 2034 nEndRow = nMergeTestEndRow; 2035 } 2036 else 2037 { 2038 nStartRow = 0; 2039 nEndRow = rDoc.MaxRow(); 2040 } 2041 } 2042 2043 if( !qIncreaseRange.empty() ) 2044 { 2045 if (bRecord && !pUndoRemoveMerge) 2046 { 2047 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); 2048 pUndoDoc->InitUndo( rDoc, *aMark.begin(), *aMark.rbegin()); 2049 pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, rRange, std::move(pUndoDoc) )); 2050 } 2051 2052 for( const ScRange& aRange : qIncreaseRange ) 2053 { 2054 if( rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) ) 2055 { 2056 UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() ); 2057 } 2058 } 2059 } 2060 } 2061 else 2062 { 2063 if (!bApi) 2064 rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); 2065 rDocShell.GetUndoManager()->LeaveListAction(); 2066 return false; 2067 } 2068 } 2069 } 2070 2071 if (bRecord && pUndoRemoveMerge) 2072 { 2073 rDocShell.GetUndoManager()->AddUndoAction( std::move(pUndoRemoveMerge)); 2074 } 2075 2076 switch (eCmd) 2077 { 2078 case INS_CELLSDOWN: 2079 bSuccess = rDoc.InsertRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), &aFullMark ); 2080 nPaintEndRow = rDoc.MaxRow(); 2081 break; 2082 case INS_INSROWS_BEFORE: 2083 case INS_INSROWS_AFTER: 2084 bSuccess = rDoc.InsertRow( 0, 0, rDoc.MaxCol(), MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), &aFullMark ); 2085 nPaintStartCol = 0; 2086 nPaintEndCol = rDoc.MaxCol(); 2087 nPaintEndRow = rDoc.MaxRow(); 2088 nPaintFlags |= PaintPartFlags::Left; 2089 break; 2090 case INS_CELLSRIGHT: 2091 bSuccess = rDoc.InsertCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), &aFullMark ); 2092 nPaintEndCol = rDoc.MaxCol(); 2093 break; 2094 case INS_INSCOLS_BEFORE: 2095 case INS_INSCOLS_AFTER: 2096 bSuccess = rDoc.InsertCol( 0, 0, rDoc.MaxRow(), MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), &aFullMark ); 2097 nPaintStartRow = 0; 2098 nPaintEndRow = rDoc.MaxRow(); 2099 nPaintEndCol = rDoc.MaxCol(); 2100 nPaintFlags |= PaintPartFlags::Top; 2101 break; 2102 default: 2103 OSL_FAIL("Wrong code at inserting"); 2104 bSuccess = false; 2105 break; 2106 } 2107 2108 if ( bSuccess ) 2109 { 2110 SCTAB nUndoPos = 0; 2111 2112 if ( bRecord ) 2113 { 2114 std::unique_ptr<SCTAB[]> pTabs(new SCTAB[nSelCount]); 2115 std::unique_ptr<SCTAB[]> pScenarios(new SCTAB[nSelCount]); 2116 nUndoPos = 0; 2117 for (const auto& rTab : aMark) 2118 { 2119 if (rTab >= nTabCount) 2120 break; 2121 2122 SCTAB nCount = 0; 2123 for( SCTAB j=rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 2124 nCount ++; 2125 2126 pScenarios[nUndoPos] = nCount; 2127 pTabs[nUndoPos] = rTab; 2128 nUndoPos ++; 2129 } 2130 2131 if( !bInsertMerge ) 2132 { 2133 rDocShell.GetUndoManager()->LeaveListAction(); 2134 } 2135 2136 rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoInsertCells>( 2137 &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ), 2138 nUndoPos, std::move(pTabs), std::move(pScenarios), eCmd, std::move(pRefUndoDoc), std::move(pUndoData), bPartOfPaste ) ); 2139 } 2140 2141 // #i8302 : we remerge growing ranges, with the new part inserted 2142 2143 while( !qIncreaseRange.empty() ) 2144 { 2145 ScRange aRange = qIncreaseRange.back(); 2146 if( !rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) ) 2147 { 2148 switch (eCmd) 2149 { 2150 case INS_CELLSDOWN: 2151 case INS_INSROWS_BEFORE: 2152 case INS_INSROWS_AFTER: 2153 aRange.aEnd.IncRow(static_cast<SCCOL>(nEndRow-nStartRow+1)); 2154 break; 2155 case INS_CELLSRIGHT: 2156 case INS_INSCOLS_BEFORE: 2157 case INS_INSCOLS_AFTER: 2158 aRange.aEnd.IncCol(static_cast<SCCOL>(nEndCol-nStartCol+1)); 2159 break; 2160 default: 2161 break; 2162 } 2163 ScCellMergeOption aMergeOption( 2164 aRange.aStart.Col(), aRange.aStart.Row(), 2165 aRange.aEnd.Col(), aRange.aEnd.Row() ); 2166 aMergeOption.maTabs.insert(aRange.aStart.Tab()); 2167 MergeCells(aMergeOption, false, true, true); 2168 } 2169 qIncreaseRange.pop_back(); 2170 } 2171 2172 if( bInsertMerge ) 2173 rDocShell.GetUndoManager()->LeaveListAction(); 2174 2175 for (const SCTAB i : aMark) 2176 { 2177 if (i >= nTabCount) 2178 break; 2179 2180 rDoc.SetDrawPageSize(i); 2181 2182 if (bNeedRefresh) 2183 rDoc.ExtendMerge( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i, true ); 2184 else 2185 rDoc.RefreshAutoFilter( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i ); 2186 2187 if ( eCmd == INS_INSROWS_BEFORE ||eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSROWS_AFTER ||eCmd == INS_INSCOLS_AFTER ) 2188 rDoc.UpdatePageBreaks( i ); 2189 2190 sal_uInt16 nExtFlags = 0; 2191 rDocShell.UpdatePaintExt( nExtFlags, nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i ); 2192 2193 SCTAB nScenarioCount = 0; 2194 2195 for( SCTAB j = i+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 2196 nScenarioCount ++; 2197 2198 bool bAdjusted = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER ) ? 2199 AdjustRowHeight(ScRange(0, nStartRow, i, rDoc.MaxCol(), nEndRow, i+nScenarioCount ), true, bApi) : 2200 AdjustRowHeight(ScRange(0, nPaintStartRow, i, rDoc.MaxCol(), nPaintEndRow, i+nScenarioCount ), true, bApi); 2201 if (bAdjusted) 2202 { 2203 // paint only what is not done by AdjustRowHeight 2204 if (nPaintFlags & PaintPartFlags::Top) 2205 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i+nScenarioCount, PaintPartFlags::Top ); 2206 } 2207 else 2208 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i+nScenarioCount, nPaintFlags, nExtFlags ); 2209 } 2210 } 2211 else 2212 { 2213 if( bInsertMerge ) 2214 { 2215 while( !qIncreaseRange.empty() ) 2216 { 2217 ScRange aRange = qIncreaseRange.back(); 2218 ScCellMergeOption aMergeOption( 2219 aRange.aStart.Col(), aRange.aStart.Row(), 2220 aRange.aEnd.Col(), aRange.aEnd.Row() ); 2221 MergeCells(aMergeOption, false, true, true); 2222 qIncreaseRange.pop_back(); 2223 } 2224 2225 if( pViewSh ) 2226 { 2227 pViewSh->MarkRange( aTargetRange, false ); 2228 pViewSh->SetCursor( nCursorCol, nCursorRow ); 2229 } 2230 } 2231 2232 rDocShell.GetUndoManager()->LeaveListAction(); 2233 rDocShell.GetUndoManager()->RemoveLastUndoAction(); 2234 2235 pRefUndoDoc.reset(); 2236 if (!bApi) 2237 rDocShell.ErrorMessage(STR_INSERT_FULL); // column/row full 2238 } 2239 2240 // The cursor position needs to be modified earlier than updating 2241 // any enabled edit view which is triggered by SetDocumentModified below. 2242 if (bSuccess) 2243 { 2244 bool bInsertCols = ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER); 2245 bool bInsertRows = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER ); 2246 2247 if (bInsertCols) 2248 { 2249 pViewSh->OnLOKInsertDeleteColumn(rRange.aStart.Col(), 1); 2250 } 2251 2252 if (bInsertRows) 2253 { 2254 pViewSh->OnLOKInsertDeleteRow(rRange.aStart.Row(), 1); 2255 } 2256 } 2257 2258 aModificator.SetDocumentModified(); 2259 2260 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); 2261 return bSuccess; 2262 } 2263 2264 bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, DelCellCmd eCmd, 2265 bool bApi ) 2266 { 2267 ScDocShellModificator aModificator( rDocShell ); 2268 ScDocument& rDoc = rDocShell.GetDocument(); 2269 2270 if (rDocShell.GetDocument().GetChangeTrack() && 2271 ((eCmd == DelCellCmd::CellsUp && (rRange.aStart.Col() != 0 || rRange.aEnd.Col() != rDoc.MaxCol())) || 2272 (eCmd == DelCellCmd::CellsLeft && (rRange.aStart.Row() != 0 || rRange.aEnd.Row() != rDoc.MaxRow())))) 2273 { 2274 // We should not reach this via UI disabled slots. 2275 assert(bApi); 2276 SAL_WARN("sc.ui","ScDocFunc::DeleteCells - no change-tracking of partial cell shift"); 2277 return false; 2278 } 2279 2280 SCCOL nStartCol = rRange.aStart.Col(); 2281 SCROW nStartRow = rRange.aStart.Row(); 2282 SCTAB nStartTab = rRange.aStart.Tab(); 2283 SCCOL nEndCol = rRange.aEnd.Col(); 2284 SCROW nEndRow = rRange.aEnd.Row(); 2285 SCTAB nEndTab = rRange.aEnd.Tab(); 2286 2287 if ( !rDoc.ValidRow(nStartRow) || !rDoc.ValidRow(nEndRow) ) 2288 { 2289 OSL_FAIL("invalid row in DeleteCells"); 2290 return false; 2291 } 2292 2293 SCTAB nTabCount = rDoc.GetTableCount(); 2294 SCCOL nPaintStartCol = nStartCol; 2295 SCROW nPaintStartRow = nStartRow; 2296 SCCOL nPaintEndCol = nEndCol; 2297 SCROW nPaintEndRow = nEndRow; 2298 PaintPartFlags nPaintFlags = PaintPartFlags::Grid; 2299 2300 bool bRecord = true; 2301 if (!rDoc.IsUndoEnabled()) 2302 bRecord = false; 2303 2304 ScMarkData aMark(rDoc.GetSheetLimits()); 2305 if (pTabMark) 2306 aMark = *pTabMark; 2307 else 2308 { 2309 SCTAB nCount = 0; 2310 for(SCTAB i=0; i<nTabCount; i++ ) 2311 { 2312 if( !rDoc.IsScenario(i) ) 2313 { 2314 nCount++; 2315 if( nCount == nEndTab+1 ) 2316 { 2317 aMark.SelectTable(i, true); 2318 break; 2319 } 2320 } 2321 } 2322 } 2323 2324 ScMarkData aFullMark( aMark ); // including scenario sheets 2325 for (const auto& rTab : aMark) 2326 { 2327 if (rTab >= nTabCount) 2328 break; 2329 2330 for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 2331 aFullMark.SelectTable( j, true ); 2332 } 2333 2334 SCTAB nSelCount = aMark.GetSelectCount(); 2335 2336 SCCOL nUndoStartCol = nStartCol; 2337 SCROW nUndoStartRow = nStartRow; 2338 SCCOL nUndoEndCol = nEndCol; 2339 SCROW nUndoEndRow = nEndRow; 2340 2341 ScRange aExtendMergeRange( rRange ); 2342 2343 if( rRange.aStart == rRange.aEnd && rDoc.HasAttrib(rRange, HasAttrFlags::Merged) ) 2344 { 2345 rDoc.ExtendMerge( aExtendMergeRange ); 2346 rDoc.ExtendOverlapped( aExtendMergeRange ); 2347 nUndoEndCol = aExtendMergeRange.aEnd.Col(); 2348 nUndoEndRow = aExtendMergeRange.aEnd.Row(); 2349 nPaintEndCol = nUndoEndCol; 2350 nPaintEndRow = nUndoEndRow; 2351 } 2352 2353 if (eCmd==DelCellCmd::Rows) 2354 { 2355 nUndoStartCol = 0; 2356 nUndoEndCol = rDoc.MaxCol(); 2357 } 2358 if (eCmd==DelCellCmd::Cols) 2359 { 2360 nUndoStartRow = 0; 2361 nUndoEndRow = rDoc.MaxRow(); 2362 } 2363 // Test for cell protection 2364 2365 SCCOL nEditTestEndX = nUndoEndCol; 2366 if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft ) 2367 nEditTestEndX = rDoc.MaxCol(); 2368 SCROW nEditTestEndY = nUndoEndRow; 2369 if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp ) 2370 nEditTestEndY = rDoc.MaxRow(); 2371 2372 ScEditableTester aTester; 2373 2374 switch (eCmd) 2375 { 2376 case DelCellCmd::Cols: 2377 aTester = ScEditableTester( 2378 rDoc, sc::ColRowEditAction::DeleteColumns, nUndoStartCol, nUndoEndCol, aMark); 2379 break; 2380 case DelCellCmd::Rows: 2381 aTester = ScEditableTester( 2382 rDoc, sc::ColRowEditAction::DeleteRows, nUndoStartRow, nUndoEndRow, aMark); 2383 break; 2384 default: 2385 aTester = ScEditableTester( 2386 rDoc, nUndoStartCol, nUndoStartRow, nEditTestEndX, nEditTestEndY, aMark); 2387 } 2388 2389 if (!aTester.IsEditable()) 2390 { 2391 if (!bApi) 2392 rDocShell.ErrorMessage(aTester.GetMessageId()); 2393 return false; 2394 } 2395 2396 if (!canDeleteCellsByPivot(rRange, aMark, eCmd, rDoc)) 2397 { 2398 if (!bApi) 2399 rDocShell.ErrorMessage(STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE); 2400 return false; 2401 } 2402 // Test for merged cells 2403 2404 SCCOL nMergeTestEndCol = (eCmd==DelCellCmd::CellsLeft) ? rDoc.MaxCol() : nUndoEndCol; 2405 SCROW nMergeTestEndRow = (eCmd==DelCellCmd::CellsUp) ? rDoc.MaxRow() : nUndoEndRow; 2406 SCCOL nExtendStartCol = nUndoStartCol; 2407 SCROW nExtendStartRow = nUndoStartRow; 2408 bool bNeedRefresh = false; 2409 2410 //Issue 8302 want to be able to insert into the middle of merged cells 2411 //the patch comes from maoyg 2412 ::std::vector<ScRange> qDecreaseRange; 2413 bool bDeletingMerge = false; 2414 OUString aUndo = ScResId( STR_UNDO_DELETECELLS ); 2415 if (bRecord) 2416 { 2417 ViewShellId nViewShellId(-1); 2418 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell()) 2419 nViewShellId = pViewSh->GetViewShellId(); 2420 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId ); 2421 } 2422 std::unique_ptr<ScUndoRemoveMerge> pUndoRemoveMerge; 2423 2424 for (const SCTAB i : aMark) 2425 { 2426 if (i >= nTabCount) 2427 break; 2428 2429 if ( rDoc.HasAttrib( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HasAttrFlags::Merged | HasAttrFlags::Overlapped )) 2430 { 2431 SCCOL nMergeStartCol = nUndoStartCol; 2432 SCROW nMergeStartRow = nUndoStartRow; 2433 SCCOL nMergeEndCol = nMergeTestEndCol; 2434 SCROW nMergeEndRow = nMergeTestEndRow; 2435 2436 rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); 2437 rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); 2438 if( ( eCmd == DelCellCmd::CellsUp && ( nMergeStartCol != nUndoStartCol || nMergeEndCol != nMergeTestEndCol))|| 2439 ( eCmd == DelCellCmd::CellsLeft && ( nMergeStartRow != nUndoStartRow || nMergeEndRow != nMergeTestEndRow))) 2440 { 2441 if (!bApi) 2442 rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0); 2443 rDocShell.GetUndoManager()->LeaveListAction(); 2444 return false; 2445 } 2446 2447 nExtendStartCol = nMergeStartCol; 2448 nExtendStartRow = nMergeStartRow; 2449 SCCOL nTestCol = -1; 2450 SCROW nTestRow1 = -1; 2451 SCROW nTestRow2 = -1; 2452 2453 ScDocAttrIterator aTestIter( rDoc, i, nUndoStartCol, nUndoStartRow, nMergeTestEndCol, nMergeTestEndRow ); 2454 ScRange aExtendRange( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i ); 2455 const ScPatternAttr* pPattern = nullptr; 2456 while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != nullptr ) 2457 { 2458 const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE); 2459 const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG); 2460 ScMF nNewFlags = rMergeFlagAttr.GetValue() & (ScMF::Hor | ScMF::Ver); 2461 if (rMergeFlag.IsMerged() || nNewFlags == ScMF::Hor || nNewFlags == ScMF::Ver) 2462 { 2463 ScRange aRange( nTestCol, nTestRow1, i ); 2464 rDoc.ExtendOverlapped( aRange ); 2465 rDoc.ExtendMerge( aRange, true ); 2466 2467 if( nTestRow1 < nTestRow2 && nNewFlags == ScMF::Hor ) 2468 { 2469 for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ ) 2470 { 2471 ScRange aTestRange( nTestCol, nTestRow, i ); 2472 rDoc.ExtendOverlapped( aTestRange ); 2473 rDoc.ExtendMerge( aTestRange, true ); 2474 ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i ); 2475 if( !aExtendRange.Contains( aMergeRange ) ) 2476 { 2477 qDecreaseRange.push_back( aTestRange ); 2478 bDeletingMerge = true; 2479 } 2480 } 2481 } 2482 else 2483 { 2484 ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i ); 2485 if( !aExtendRange.Contains( aMergeRange ) ) 2486 { 2487 qDecreaseRange.push_back( aRange ); 2488 } 2489 bDeletingMerge = true; 2490 } 2491 } 2492 } 2493 2494 if( bDeletingMerge ) 2495 { 2496 2497 if( eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp ) 2498 { 2499 nStartRow = aExtendMergeRange.aStart.Row(); 2500 nEndRow = aExtendMergeRange.aEnd.Row(); 2501 bNeedRefresh = true; 2502 2503 if( eCmd == DelCellCmd::CellsUp ) 2504 { 2505 nEndCol = aExtendMergeRange.aEnd.Col(); 2506 } 2507 else 2508 { 2509 nStartCol = 0; 2510 nEndCol = rDoc.MaxCol(); 2511 } 2512 } 2513 else if( eCmd == DelCellCmd::CellsLeft || eCmd == DelCellCmd::Cols ) 2514 { 2515 2516 nStartCol = aExtendMergeRange.aStart.Col(); 2517 nEndCol = aExtendMergeRange.aEnd.Col(); 2518 if( eCmd == DelCellCmd::CellsLeft ) 2519 { 2520 nEndRow = aExtendMergeRange.aEnd.Row(); 2521 bNeedRefresh = true; 2522 } 2523 else 2524 { 2525 nStartRow = 0; 2526 nEndRow = rDoc.MaxRow(); 2527 } 2528 } 2529 2530 if( !qDecreaseRange.empty() ) 2531 { 2532 if (bRecord && !pUndoRemoveMerge) 2533 { 2534 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); 2535 pUndoDoc->InitUndo( rDoc, *aMark.begin(), *aMark.rbegin()); 2536 pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, rRange, std::move(pUndoDoc) )); 2537 } 2538 2539 for( const ScRange& aRange : qDecreaseRange ) 2540 { 2541 if( rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) ) 2542 { 2543 UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() ); 2544 } 2545 } 2546 } 2547 } 2548 else 2549 { 2550 if (!bApi) 2551 rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0); 2552 rDocShell.GetUndoManager()->LeaveListAction(); 2553 return false; 2554 } 2555 } 2556 } 2557 2558 if (bRecord && pUndoRemoveMerge) 2559 { 2560 rDocShell.GetUndoManager()->AddUndoAction( std::move(pUndoRemoveMerge)); 2561 } 2562 2563 // do it 2564 2565 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference 2566 2567 ScDocumentUniquePtr pUndoDoc; 2568 std::unique_ptr<ScDocument> pRefUndoDoc; 2569 std::unique_ptr<ScRefUndoData> pUndoData; 2570 if ( bRecord ) 2571 { 2572 // With the fix for #101329#, UpdateRef always puts cells into pRefUndoDoc at their old position, 2573 // so it's no longer necessary to copy more than the deleted range into pUndoDoc. 2574 2575 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 2576 pUndoDoc->InitUndo( rDoc, 0, nTabCount-1, (eCmd==DelCellCmd::Cols), (eCmd==DelCellCmd::Rows) ); 2577 for (const auto& rTab : aMark) 2578 { 2579 if (rTab >= nTabCount) 2580 break; 2581 2582 SCTAB nScenarioCount = 0; 2583 2584 for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 2585 nScenarioCount ++; 2586 2587 rDoc.CopyToDocument( nUndoStartCol, nUndoStartRow, rTab, nUndoEndCol, nUndoEndRow, rTab+nScenarioCount, 2588 InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc ); 2589 } 2590 2591 pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 2592 pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 ); 2593 2594 pUndoData.reset(new ScRefUndoData( &rDoc )); 2595 2596 rDoc.BeginDrawUndo(); 2597 } 2598 2599 sal_uInt16 nExtFlags = 0; 2600 for (const auto& rTab : aMark) 2601 { 2602 if (rTab >= nTabCount) 2603 break; 2604 2605 rDocShell.UpdatePaintExt( nExtFlags, nStartCol, nStartRow, rTab, nEndCol, nEndRow, rTab ); 2606 } 2607 2608 switch (eCmd) 2609 { 2610 case DelCellCmd::CellsUp: 2611 case DelCellCmd::CellsLeft: 2612 rDoc.DeleteObjectsInArea(nStartCol, nStartRow, nEndCol, nEndRow, aMark, true); 2613 break; 2614 case DelCellCmd::Rows: 2615 rDoc.DeleteObjectsInArea(0, nStartRow, rDoc.MaxCol(), nEndRow, aMark, true); 2616 break; 2617 case DelCellCmd::Cols: 2618 rDoc.DeleteObjectsInArea(nStartCol, 0, nEndCol, rDoc.MaxRow(), aMark, true); 2619 break; 2620 default: 2621 break; 2622 } 2623 2624 2625 bool bUndoOutline = false; 2626 switch (eCmd) 2627 { 2628 case DelCellCmd::CellsUp: 2629 rDoc.DeleteRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), nullptr, &aFullMark ); 2630 nPaintEndRow = rDoc.MaxRow(); 2631 break; 2632 case DelCellCmd::Rows: 2633 rDoc.DeleteRow( 0, 0, rDoc.MaxCol(), MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), &bUndoOutline, &aFullMark ); 2634 nPaintStartCol = 0; 2635 nPaintEndCol = rDoc.MaxCol(); 2636 nPaintEndRow = rDoc.MaxRow(); 2637 nPaintFlags |= PaintPartFlags::Left; 2638 break; 2639 case DelCellCmd::CellsLeft: 2640 rDoc.DeleteCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), nullptr, &aFullMark ); 2641 nPaintEndCol = rDoc.MaxCol(); 2642 break; 2643 case DelCellCmd::Cols: 2644 rDoc.DeleteCol( 0, 0, rDoc.MaxRow(), MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), &bUndoOutline, &aFullMark ); 2645 nPaintStartRow = 0; 2646 nPaintEndRow = rDoc.MaxRow(); 2647 nPaintEndCol = rDoc.MaxCol(); 2648 nPaintFlags |= PaintPartFlags::Top; 2649 break; 2650 default: 2651 OSL_FAIL("Wrong code at deleting"); 2652 break; 2653 } 2654 2655 //! Test if the size of outline has changed 2656 2657 if ( bRecord ) 2658 { 2659 for (const auto& rTab : aFullMark) 2660 { 2661 if (rTab >= nTabCount) 2662 break; 2663 2664 pRefUndoDoc->DeleteAreaTab(nUndoStartCol,nUndoStartRow,nUndoEndCol,nUndoEndRow, rTab, InsertDeleteFlags::ALL); 2665 } 2666 2667 // for all sheets, so that formulas can be copied 2668 pUndoDoc->AddUndoTab( 0, nTabCount-1 ); 2669 2670 // copy with bColRowFlags=false (#54194#) 2671 pRefUndoDoc->CopyToDocument(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB,InsertDeleteFlags::FORMULA,false,*pUndoDoc,nullptr,false); 2672 pRefUndoDoc.reset(); 2673 2674 std::unique_ptr<SCTAB[]> pTabs( new SCTAB[nSelCount]); 2675 std::unique_ptr<SCTAB[]> pScenarios( new SCTAB[nSelCount]); 2676 SCTAB nUndoPos = 0; 2677 2678 for (const auto& rTab : aMark) 2679 { 2680 if (rTab >= nTabCount) 2681 break; 2682 2683 SCTAB nCount = 0; 2684 for( SCTAB j=rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 2685 nCount ++; 2686 2687 pScenarios[nUndoPos] = nCount; 2688 pTabs[nUndoPos] = rTab; 2689 nUndoPos ++; 2690 } 2691 2692 if( !bDeletingMerge ) 2693 { 2694 rDocShell.GetUndoManager()->LeaveListAction(); 2695 } 2696 2697 rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoDeleteCells>( 2698 &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ), 2699 nUndoPos, std::move(pTabs), std::move(pScenarios), 2700 eCmd, std::move(pUndoDoc), std::move(pUndoData) ) ); 2701 } 2702 2703 // #i8302 want to be able to insert into the middle of merged cells 2704 // the patch comes from maoyg 2705 2706 while( !qDecreaseRange.empty() ) 2707 { 2708 ScRange aRange = qDecreaseRange.back(); 2709 2710 sal_Int32 nDecreaseRowCount = 0; 2711 sal_Int32 nDecreaseColCount = 0; 2712 if( eCmd == DelCellCmd::CellsUp || eCmd == DelCellCmd::Rows ) 2713 { 2714 if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() ) 2715 nDecreaseRowCount = nEndRow-nStartRow+1; 2716 else if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow >= aRange.aStart.Row() && nEndRow >= aRange.aEnd.Row() ) 2717 nDecreaseRowCount = aRange.aEnd.Row()-nStartRow+1; 2718 else if( nStartRow >= aRange.aStart.Row() && nStartRow >= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() ) 2719 nDecreaseRowCount = aRange.aEnd.Row()-nEndRow+1; 2720 } 2721 else if( eCmd == DelCellCmd::CellsLeft || eCmd == DelCellCmd::Cols ) 2722 { 2723 if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() ) 2724 nDecreaseColCount = nEndCol-nStartCol+1; 2725 else if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol >= aRange.aStart.Col() && nEndCol >= aRange.aEnd.Col() ) 2726 nDecreaseColCount = aRange.aEnd.Col()-nStartCol+1; 2727 else if( nStartCol >= aRange.aStart.Col() && nStartCol >= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() ) 2728 nDecreaseColCount = aRange.aEnd.Col()-nEndCol+1; 2729 } 2730 2731 switch (eCmd) 2732 { 2733 case DelCellCmd::CellsUp: 2734 case DelCellCmd::Rows: 2735 aRange.aEnd.SetRow(static_cast<SCCOL>( aRange.aEnd.Row()-nDecreaseRowCount)); 2736 break; 2737 case DelCellCmd::CellsLeft: 2738 case DelCellCmd::Cols: 2739 aRange.aEnd.SetCol(static_cast<SCCOL>( aRange.aEnd.Col()-nDecreaseColCount)); 2740 break; 2741 default: 2742 break; 2743 } 2744 2745 if( !rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) ) 2746 { 2747 ScCellMergeOption aMergeOption(aRange); 2748 MergeCells( aMergeOption, false, true, true ); 2749 } 2750 qDecreaseRange.pop_back(); 2751 } 2752 2753 if( bDeletingMerge ) 2754 rDocShell.GetUndoManager()->LeaveListAction(); 2755 2756 if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft ) 2757 nMergeTestEndCol = rDoc.MaxCol(); 2758 if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp ) 2759 nMergeTestEndRow = rDoc.MaxRow(); 2760 if ( bNeedRefresh ) 2761 { 2762 // #i51445# old merge flag attributes must be deleted also for single cells, 2763 // not only for whole columns/rows 2764 2765 ScPatternAttr aPattern( rDoc.GetPool() ); 2766 aPattern.GetItemSet().Put( ScMergeFlagAttr() ); 2767 2768 rDoc.ApplyPatternArea( nExtendStartCol, nExtendStartRow, nMergeTestEndCol, nMergeTestEndRow, aMark, aPattern ); 2769 2770 for (const auto& rTab : aMark) 2771 { 2772 if (rTab >= nTabCount) 2773 break; 2774 2775 SCTAB nScenarioCount = 0; 2776 2777 for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 2778 nScenarioCount ++; 2779 2780 ScRange aMergedRange( nExtendStartCol, nExtendStartRow, rTab, nMergeTestEndCol, nMergeTestEndRow, rTab+nScenarioCount ); 2781 rDoc.ExtendMerge( aMergedRange, true ); 2782 } 2783 } 2784 2785 for (const auto& rTab : aMark) 2786 { 2787 if (rTab >= nTabCount) 2788 break; 2789 2790 rDoc.RefreshAutoFilter( nExtendStartCol, nExtendStartRow, nMergeTestEndCol, nMergeTestEndRow, rTab ); 2791 } 2792 2793 for (const auto& rTab : aMark) 2794 { 2795 if (rTab >= nTabCount) 2796 break; 2797 2798 rDoc.SetDrawPageSize(rTab); 2799 2800 if ( eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::Rows ) 2801 rDoc.UpdatePageBreaks( rTab ); 2802 2803 rDocShell.UpdatePaintExt( nExtFlags, nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab ); 2804 2805 SCTAB nScenarioCount = 0; 2806 2807 for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ ) 2808 nScenarioCount ++; 2809 2810 // delete entire rows: do not adjust 2811 if ( eCmd == DelCellCmd::Rows || !AdjustRowHeight(ScRange( 0, nPaintStartRow, rTab, rDoc.MaxCol(), nPaintEndRow, rTab+nScenarioCount ), true, bApi) ) 2812 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab+nScenarioCount, nPaintFlags, nExtFlags ); 2813 else 2814 { 2815 // paint only what is not done by AdjustRowHeight 2816 if (nExtFlags & SC_PF_LINES) 2817 lcl_PaintAbove( rDocShell, ScRange( nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab+nScenarioCount) ); 2818 if (nPaintFlags & PaintPartFlags::Top) 2819 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab+nScenarioCount, PaintPartFlags::Top ); 2820 } 2821 } 2822 2823 // The cursor position needs to be modified earlier than updating 2824 // any enabled edit view which is triggered by SetDocumentModified below. 2825 ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); 2826 if (pViewSh) 2827 { 2828 if (eCmd == DelCellCmd::Cols) 2829 { 2830 pViewSh->OnLOKInsertDeleteColumn(rRange.aStart.Col(), -1); 2831 } 2832 if (eCmd == DelCellCmd::Rows) 2833 { 2834 pViewSh->OnLOKInsertDeleteRow(rRange.aStart.Row(), -1); 2835 } 2836 } 2837 2838 aModificator.SetDocumentModified(); 2839 2840 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); 2841 2842 return true; 2843 } 2844 2845 bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos, 2846 bool bCut, bool bRecord, bool bPaint, bool bApi ) 2847 { 2848 ScDocShellModificator aModificator( rDocShell ); 2849 2850 SCCOL nStartCol = rSource.aStart.Col(); 2851 SCROW nStartRow = rSource.aStart.Row(); 2852 SCTAB nStartTab = rSource.aStart.Tab(); 2853 SCCOL nEndCol = rSource.aEnd.Col(); 2854 SCROW nEndRow = rSource.aEnd.Row(); 2855 SCTAB nEndTab = rSource.aEnd.Tab(); 2856 SCCOL nDestCol = rDestPos.Col(); 2857 SCROW nDestRow = rDestPos.Row(); 2858 SCTAB nDestTab = rDestPos.Tab(); 2859 2860 ScDocument& rDoc = rDocShell.GetDocument(); 2861 if ( !rDoc.ValidRow(nStartRow) || !rDoc.ValidRow(nEndRow) || !rDoc.ValidRow(nDestRow) ) 2862 { 2863 OSL_FAIL("invalid row in MoveBlock"); 2864 return false; 2865 } 2866 2867 // adjust related scenarios too - but only when moved within one sheet 2868 bool bScenariosAdded = false; 2869 if (bRecord && !rDoc.IsUndoEnabled()) 2870 bRecord = false; 2871 2872 SCTAB nTabCount = rDoc.GetTableCount(); 2873 if ( nDestTab == nStartTab && !rDoc.IsScenario(nEndTab) ) 2874 while ( nEndTab+1 < nTabCount && rDoc.IsScenario(nEndTab+1) ) 2875 { 2876 ++nEndTab; 2877 bScenariosAdded = true; 2878 } 2879 2880 SCTAB nSrcTabCount = nEndTab-nStartTab+1; 2881 SCTAB nDestEndTab = nDestTab+nSrcTabCount-1; 2882 SCTAB nTab; 2883 2884 ScDocumentUniquePtr pClipDoc(new ScDocument(SCDOCMODE_CLIP)); 2885 2886 ScMarkData aSourceMark(rDoc.GetSheetLimits()); 2887 for (nTab=nStartTab; nTab<=nEndTab; nTab++) 2888 aSourceMark.SelectTable( nTab, true ); // select source 2889 aSourceMark.SetMarkArea( rSource ); 2890 2891 ScDocShellRef aDragShellRef; 2892 if ( rDoc.HasOLEObjectsInArea( rSource ) ) 2893 { 2894 aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately 2895 aDragShellRef->DoInitNew(); 2896 } 2897 ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() ); 2898 2899 ScClipParam aClipParam(ScRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nStartTab), bCut); 2900 rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bScenariosAdded, true); 2901 2902 ScDrawLayer::SetGlobalDrawPersist(nullptr); 2903 2904 SCCOL nOldEndCol = nEndCol; 2905 SCROW nOldEndRow = nEndRow; 2906 bool bClipOver = false; 2907 for (nTab=nStartTab; nTab<=nEndTab; nTab++) 2908 { 2909 SCCOL nTmpEndCol = nOldEndCol; 2910 SCROW nTmpEndRow = nOldEndRow; 2911 if (rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab )) 2912 bClipOver = true; 2913 if ( nTmpEndCol > nEndCol ) nEndCol = nTmpEndCol; 2914 if ( nTmpEndRow > nEndRow ) nEndRow = nTmpEndRow; 2915 } 2916 2917 SCCOL nDestEndCol = nDestCol + ( nOldEndCol-nStartCol ); 2918 SCROW nDestEndRow = nDestRow + ( nOldEndRow-nStartRow ); 2919 2920 SCCOL nUndoEndCol = nDestCol + ( nEndCol-nStartCol ); // extended in destination block 2921 SCROW nUndoEndRow = nDestRow + ( nEndRow-nStartRow ); 2922 2923 bool bIncludeFiltered = bCut; 2924 if ( !bIncludeFiltered ) 2925 { 2926 // adjust sizes to include only non-filtered rows 2927 2928 SCCOL nClipX; 2929 SCROW nClipY; 2930 pClipDoc->GetClipArea( nClipX, nClipY, false ); 2931 SCROW nUndoAdd = nUndoEndRow - nDestEndRow; 2932 nDestEndRow = nDestRow + nClipY; 2933 nUndoEndRow = nDestEndRow + nUndoAdd; 2934 } 2935 2936 if (!rDoc.ValidCol(nUndoEndCol) || !rDoc.ValidRow(nUndoEndRow)) 2937 { 2938 if (!bApi) 2939 rDocShell.ErrorMessage(STR_PASTE_FULL); 2940 return false; 2941 } 2942 2943 // Test for cell protection 2944 2945 ScEditableTester aTester; 2946 for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) 2947 aTester.TestBlock( rDoc, nTab, nDestCol,nDestRow, nUndoEndCol,nUndoEndRow ); 2948 if (bCut) 2949 for (nTab=nStartTab; nTab<=nEndTab; nTab++) 2950 aTester.TestBlock( rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow ); 2951 2952 if (!aTester.IsEditable()) 2953 { 2954 if (!bApi) 2955 rDocShell.ErrorMessage(aTester.GetMessageId()); 2956 return false; 2957 } 2958 2959 // Test for merged cells- when moving after delete 2960 2961 if (bClipOver && !bCut) 2962 if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab, nUndoEndCol,nUndoEndRow,nDestEndTab, 2963 HasAttrFlags::Merged | HasAttrFlags::Overlapped )) 2964 { // "Merge of already merged cells not possible" 2965 if (!bApi) 2966 rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0); 2967 return false; 2968 } 2969 2970 // Are there borders in the cells? (for painting) 2971 2972 sal_uInt16 nSourceExt = 0; 2973 rDocShell.UpdatePaintExt( nSourceExt, nStartCol,nStartRow,nStartTab, nEndCol,nEndRow,nEndTab ); 2974 sal_uInt16 nDestExt = 0; 2975 rDocShell.UpdatePaintExt( nDestExt, nDestCol,nDestRow,nDestTab, nDestEndCol,nDestEndRow,nDestEndTab ); 2976 2977 // do it 2978 2979 ScDocumentUniquePtr pUndoDoc; 2980 2981 if (bRecord) 2982 { 2983 bool bWholeCols = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() ); 2984 bool bWholeRows = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() ); 2985 InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS; 2986 2987 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 2988 pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab, bWholeCols, bWholeRows ); 2989 2990 if (bCut) 2991 { 2992 rDoc.CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab, 2993 nUndoFlags, false, *pUndoDoc ); 2994 } 2995 2996 if ( nDestTab != nStartTab ) 2997 pUndoDoc->AddUndoTab( nDestTab, nDestEndTab, bWholeCols, bWholeRows ); 2998 rDoc.CopyToDocument( nDestCol, nDestRow, nDestTab, 2999 nDestEndCol, nDestEndRow, nDestEndTab, 3000 nUndoFlags, false, *pUndoDoc ); 3001 rDoc.BeginDrawUndo(); 3002 } 3003 3004 bool bSourceHeight = false; // adjust heights? 3005 if (bCut) 3006 { 3007 ScMarkData aDelMark(rDoc.GetSheetLimits()); // only for tables 3008 for (nTab=nStartTab; nTab<=nEndTab; nTab++) 3009 { 3010 rDoc.DeleteAreaTab( nStartCol,nStartRow, nOldEndCol,nOldEndRow, nTab, InsertDeleteFlags::ALL ); 3011 aDelMark.SelectTable( nTab, true ); 3012 } 3013 rDoc.DeleteObjectsInArea( nStartCol,nStartRow, nOldEndCol,nOldEndRow, aDelMark ); 3014 3015 // Test for merged cells 3016 3017 if (bClipOver) 3018 if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab, 3019 nUndoEndCol,nUndoEndRow,nDestEndTab, 3020 HasAttrFlags::Merged | HasAttrFlags::Overlapped )) 3021 { 3022 rDoc.CopyFromClip( rSource, aSourceMark, InsertDeleteFlags::ALL, nullptr, pClipDoc.get() ); 3023 for (nTab=nStartTab; nTab<=nEndTab; nTab++) 3024 { 3025 SCCOL nTmpEndCol = nEndCol; 3026 SCROW nTmpEndRow = nEndRow; 3027 rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab, true ); 3028 } 3029 3030 // Report error only after restoring content 3031 if (!bApi) // "Merge of already merged cells not possible" 3032 rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0); 3033 3034 return false; 3035 } 3036 3037 bSourceHeight = AdjustRowHeight( rSource, false, bApi ); 3038 } 3039 3040 ScRange aPasteDest( nDestCol, nDestRow, nDestTab, nDestEndCol, nDestEndRow, nDestEndTab ); 3041 3042 ScMarkData aDestMark(rDoc.GetSheetLimits()); 3043 for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) 3044 aDestMark.SelectTable( nTab, true ); // select destination 3045 aDestMark.SetMarkArea( aPasteDest ); 3046 3047 /* Do not copy drawing objects here. While pasting, the 3048 function ScDocument::UpdateReference() is called which calls 3049 ScDrawLayer::MoveCells() which may move away inserted objects to wrong 3050 positions (e.g. if source and destination range overlaps).*/ 3051 3052 rDoc.CopyFromClip( 3053 aPasteDest, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, 3054 pUndoDoc.get(), pClipDoc.get(), true, false, bIncludeFiltered); 3055 3056 // skipped rows and merged cells don't mix 3057 if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() ) 3058 UnmergeCells( aPasteDest, false, nullptr ); 3059 3060 bool bDestHeight = AdjustRowHeight( 3061 ScRange( 0,nDestRow,nDestTab, rDoc.MaxCol(),nDestEndRow,nDestEndTab ), 3062 false, bApi ); 3063 3064 /* Paste drawing objects after adjusting formula references 3065 and row heights. There are no cell notes or drawing objects, if the 3066 clipdoc does not contain a drawing layer.*/ 3067 if ( pClipDoc->GetDrawLayer() ) 3068 rDoc.CopyFromClip( aPasteDest, aDestMark, InsertDeleteFlags::OBJECTS, 3069 nullptr, pClipDoc.get(), true, false, bIncludeFiltered ); 3070 3071 if (bRecord) 3072 { 3073 ScRange aUndoRange(nStartCol, nStartRow, nStartTab, nOldEndCol, nOldEndRow, nEndTab); 3074 ScAddress aDestPos(nDestCol, nDestRow, nDestTab); 3075 3076 rDocShell.GetUndoManager()->AddUndoAction( 3077 std::make_unique<ScUndoDragDrop>( 3078 &rDocShell, aUndoRange, aDestPos, bCut, std::move(pUndoDoc), bScenariosAdded)); 3079 } 3080 3081 SCCOL nDestPaintEndCol = nDestEndCol; 3082 SCROW nDestPaintEndRow = nDestEndRow; 3083 for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) 3084 { 3085 SCCOL nTmpEndCol = nDestEndCol; 3086 SCROW nTmpEndRow = nDestEndRow; 3087 rDoc.ExtendMerge( nDestCol, nDestRow, nTmpEndCol, nTmpEndRow, nTab, true ); 3088 if (nTmpEndCol > nDestPaintEndCol) nDestPaintEndCol = nTmpEndCol; 3089 if (nTmpEndRow > nDestPaintEndRow) nDestPaintEndRow = nTmpEndRow; 3090 } 3091 3092 if (bCut) 3093 for (nTab=nStartTab; nTab<=nEndTab; nTab++) 3094 rDoc.RefreshAutoFilter( nStartCol, nStartRow, nEndCol, nEndRow, nTab ); 3095 3096 if (bPaint) 3097 { 3098 // destination range: 3099 3100 SCCOL nPaintStartX = nDestCol; 3101 SCROW nPaintStartY = nDestRow; 3102 SCCOL nPaintEndX = nDestPaintEndCol; 3103 SCROW nPaintEndY = nDestPaintEndRow; 3104 PaintPartFlags nFlags = PaintPartFlags::Grid; 3105 3106 if ( nStartRow==0 && nEndRow==rDoc.MaxRow() ) // copy widths too? 3107 { 3108 nPaintEndX = rDoc.MaxCol(); 3109 nPaintStartY = 0; 3110 nPaintEndY = rDoc.MaxRow(); 3111 nFlags |= PaintPartFlags::Top; 3112 } 3113 if ( bDestHeight || ( nStartCol == 0 && nEndCol == rDoc.MaxCol() ) ) 3114 { 3115 nPaintEndY = rDoc.MaxRow(); 3116 nPaintStartX = 0; 3117 nPaintEndX = rDoc.MaxCol(); 3118 nFlags |= PaintPartFlags::Left; 3119 } 3120 if ( bScenariosAdded ) 3121 { 3122 nPaintStartX = 0; 3123 nPaintStartY = 0; 3124 nPaintEndX = rDoc.MaxCol(); 3125 nPaintEndY = rDoc.MaxRow(); 3126 } 3127 3128 rDocShell.PostPaint( nPaintStartX,nPaintStartY,nDestTab, 3129 nPaintEndX,nPaintEndY,nDestEndTab, nFlags, nSourceExt | nDestExt ); 3130 3131 if ( bCut ) 3132 { 3133 // source range: 3134 3135 nPaintStartX = nStartCol; 3136 nPaintStartY = nStartRow; 3137 nPaintEndX = nEndCol; 3138 nPaintEndY = nEndRow; 3139 nFlags = PaintPartFlags::Grid; 3140 3141 if ( bSourceHeight ) 3142 { 3143 nPaintEndY = rDoc.MaxRow(); 3144 nPaintStartX = 0; 3145 nPaintEndX = rDoc.MaxCol(); 3146 nFlags |= PaintPartFlags::Left; 3147 } 3148 if ( bScenariosAdded ) 3149 { 3150 nPaintStartX = 0; 3151 nPaintStartY = 0; 3152 nPaintEndX = rDoc.MaxCol(); 3153 nPaintEndY = rDoc.MaxRow(); 3154 } 3155 3156 rDocShell.PostPaint( nPaintStartX,nPaintStartY,nStartTab, 3157 nPaintEndX,nPaintEndY,nEndTab, nFlags, nSourceExt ); 3158 } 3159 } 3160 3161 aModificator.SetDocumentModified(); 3162 3163 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); 3164 3165 return true; 3166 } 3167 3168 static uno::Reference< uno::XInterface > GetDocModuleObject( const SfxObjectShell& rDocSh, const OUString& sCodeName ) 3169 { 3170 uno::Reference< lang::XMultiServiceFactory> xSF(rDocSh.GetModel(), uno::UNO_QUERY); 3171 uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess; 3172 uno::Reference< uno::XInterface > xDocModuleApiObject; 3173 if ( xSF.is() ) 3174 { 3175 xVBACodeNamedObjectAccess.set( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY ); 3176 xDocModuleApiObject.set( xVBACodeNamedObjectAccess->getByName( sCodeName ), uno::UNO_QUERY ); 3177 } 3178 return xDocModuleApiObject; 3179 3180 } 3181 3182 static script::ModuleInfo lcl_InitModuleInfo( const SfxObjectShell& rDocSh, const OUString& sModule ) 3183 { 3184 script::ModuleInfo sModuleInfo; 3185 sModuleInfo.ModuleType = script::ModuleType::DOCUMENT; 3186 sModuleInfo.ModuleObject = GetDocModuleObject( rDocSh, sModule ); 3187 return sModuleInfo; 3188 } 3189 3190 void VBA_InsertModule( ScDocument& rDoc, SCTAB nTab, const OUString& sSource ) 3191 { 3192 SfxObjectShell& rDocSh = *rDoc.GetDocumentShell(); 3193 uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer(); 3194 OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" ); 3195 3196 uno::Reference< container::XNameContainer > xLib; 3197 if( xLibContainer.is() ) 3198 { 3199 OUString aLibName( "Standard" ); 3200 #if HAVE_FEATURE_SCRIPTING 3201 if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() ) 3202 { 3203 aLibName = rDocSh.GetBasicManager()->GetName(); 3204 } 3205 #endif 3206 uno::Any aLibAny = xLibContainer->getByName( aLibName ); 3207 aLibAny >>= xLib; 3208 } 3209 if( !xLib.is() ) 3210 return; 3211 3212 // if the Module with codename exists then find a new name 3213 sal_Int32 nNum = 1; 3214 OUString genModuleName = "Sheet1"; 3215 while( xLib->hasByName( genModuleName ) ) 3216 genModuleName = "Sheet" + OUString::number( ++nNum ); 3217 3218 uno::Any aSourceAny; 3219 OUString sTmpSource = sSource; 3220 if ( sTmpSource.isEmpty() ) 3221 sTmpSource = "Rem Attribute VBA_ModuleType=VBADocumentModule\nOption VBASupport 1\n"; 3222 aSourceAny <<= sTmpSource; 3223 uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY ); 3224 if ( xVBAModuleInfo.is() ) 3225 { 3226 rDoc.SetCodeName( nTab, genModuleName ); 3227 script::ModuleInfo sModuleInfo = lcl_InitModuleInfo( rDocSh, genModuleName ); 3228 xVBAModuleInfo->insertModuleInfo( genModuleName, sModuleInfo ); 3229 xLib->insertByName( genModuleName, aSourceAny ); 3230 } 3231 } 3232 3233 void VBA_DeleteModule( ScDocShell& rDocSh, const OUString& sModuleName ) 3234 { 3235 uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer(); 3236 OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" ); 3237 3238 uno::Reference< container::XNameContainer > xLib; 3239 if( xLibContainer.is() ) 3240 { 3241 OUString aLibName( "Standard" ); 3242 #if HAVE_FEATURE_SCRIPTING 3243 if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() ) 3244 { 3245 aLibName = rDocSh.GetBasicManager()->GetName(); 3246 } 3247 #endif 3248 uno::Any aLibAny = xLibContainer->getByName( aLibName ); 3249 aLibAny >>= xLib; 3250 } 3251 if( xLib.is() ) 3252 { 3253 uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY ); 3254 if( xLib->hasByName( sModuleName ) ) 3255 xLib->removeByName( sModuleName ); 3256 if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo(sModuleName) ) 3257 xVBAModuleInfo->removeModuleInfo( sModuleName ); 3258 3259 } 3260 } 3261 3262 bool ScDocFunc::InsertTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi ) 3263 { 3264 bool bSuccess = false; 3265 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 3266 3267 ScDocShellModificator aModificator( rDocShell ); 3268 3269 ScDocument& rDoc = rDocShell.GetDocument(); 3270 3271 // Strange loop, also basic is loaded too early ( InsertTable ) 3272 // is called via the xml import for sheets in described in ODF 3273 bool bInsertDocModule = false; 3274 3275 if( !rDocShell.GetDocument().IsImportingXML() ) 3276 { 3277 bInsertDocModule = rDoc.IsInVBAMode(); 3278 } 3279 if ( bInsertDocModule || ( bRecord && !rDoc.IsUndoEnabled() ) ) 3280 bRecord = false; 3281 3282 if (bRecord) 3283 rDoc.BeginDrawUndo(); // InsertTab generates SdrUndoNewPage 3284 3285 SCTAB nTabCount = rDoc.GetTableCount(); 3286 bool bAppend = ( nTab >= nTabCount ); 3287 if ( bAppend ) 3288 nTab = nTabCount; // important for Undo 3289 3290 if (rDoc.InsertTab( nTab, rName )) 3291 { 3292 if (bRecord) 3293 rDocShell.GetUndoManager()->AddUndoAction( 3294 std::make_unique<ScUndoInsertTab>( &rDocShell, nTab, bAppend, rName)); 3295 // Update views: 3296 // Only insert vba modules if vba mode ( and not currently importing XML ) 3297 if( bInsertDocModule ) 3298 { 3299 VBA_InsertModule( rDoc, nTab, OUString() ); 3300 } 3301 rDocShell.Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab ) ); 3302 3303 rDocShell.PostPaintExtras(); 3304 aModificator.SetDocumentModified(); 3305 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); 3306 bSuccess = true; 3307 } 3308 else if (!bApi) 3309 rDocShell.ErrorMessage(STR_TABINSERT_ERROR); 3310 3311 return bSuccess; 3312 } 3313 3314 bool ScDocFunc::DeleteTable( SCTAB nTab, bool bRecord ) 3315 { 3316 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 3317 3318 ScDocShellModificator aModificator( rDocShell ); 3319 3320 bool bSuccess = false; 3321 ScDocument& rDoc = rDocShell.GetDocument(); 3322 bool bVbaEnabled = rDoc.IsInVBAMode(); 3323 if (bRecord && !rDoc.IsUndoEnabled()) 3324 bRecord = false; 3325 if ( bVbaEnabled ) 3326 bRecord = false; 3327 bool bWasLinked = rDoc.IsLinked(nTab); 3328 ScDocumentUniquePtr pUndoDoc; 3329 std::unique_ptr<ScRefUndoData> pUndoData; 3330 if (bRecord) 3331 { 3332 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 3333 SCTAB nCount = rDoc.GetTableCount(); 3334 3335 pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true ); // only nTab with Flags 3336 pUndoDoc->AddUndoTab( 0, nCount-1 ); // all sheets for references 3337 3338 rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::ALL,false, *pUndoDoc ); 3339 OUString aOldName; 3340 rDoc.GetName( nTab, aOldName ); 3341 pUndoDoc->RenameTab( nTab, aOldName ); 3342 if (bWasLinked) 3343 pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab), 3344 rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab), 3345 rDoc.GetLinkTab(nTab), 3346 rDoc.GetLinkRefreshDelay(nTab) ); 3347 3348 if ( rDoc.IsScenario(nTab) ) 3349 { 3350 pUndoDoc->SetScenario( nTab, true ); 3351 OUString aComment; 3352 Color aColor; 3353 ScScenarioFlags nScenFlags; 3354 rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags ); 3355 pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags ); 3356 bool bActive = rDoc.IsActiveScenario( nTab ); 3357 pUndoDoc->SetActiveScenario( nTab, bActive ); 3358 } 3359 pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) ); 3360 pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) ); 3361 auto pSheetEvents = rDoc.GetSheetEvents( nTab ); 3362 pUndoDoc->SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) ); 3363 3364 // Drawing-Layer has to take care of its own undo!!! 3365 rDoc.BeginDrawUndo(); // DeleteTab generates SdrUndoDelPage 3366 3367 pUndoData.reset(new ScRefUndoData( &rDoc )); 3368 } 3369 3370 if (rDoc.DeleteTab(nTab)) 3371 { 3372 if (bRecord) 3373 { 3374 vector<SCTAB> theTabs; 3375 theTabs.push_back(nTab); 3376 rDocShell.GetUndoManager()->AddUndoAction( 3377 std::make_unique<ScUndoDeleteTab>( &rDocShell, theTabs, std::move(pUndoDoc), std::move(pUndoData) )); 3378 } 3379 // Update views: 3380 if( bVbaEnabled ) 3381 { 3382 OUString sCodeName; 3383 if( rDoc.GetCodeName( nTab, sCodeName ) ) 3384 { 3385 VBA_DeleteModule( rDocShell, sCodeName ); 3386 } 3387 } 3388 rDocShell.Broadcast( ScTablesHint( SC_TAB_DELETED, nTab ) ); 3389 3390 if (bWasLinked) 3391 { 3392 rDocShell.UpdateLinks(); // update Link-Manager 3393 SfxBindings* pBindings = rDocShell.GetViewBindings(); 3394 if (pBindings) 3395 pBindings->Invalidate(SID_LINKS); 3396 } 3397 3398 rDocShell.PostPaintExtras(); 3399 aModificator.SetDocumentModified(); 3400 3401 SfxApplication* pSfxApp = SfxGetpApp(); // Navigator 3402 pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); 3403 pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) ); 3404 pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); 3405 3406 bSuccess = true; 3407 } 3408 return bSuccess; 3409 } 3410 3411 void ScDocFunc::SetTableVisible( SCTAB nTab, bool bVisible, bool bApi ) 3412 { 3413 ScDocument& rDoc = rDocShell.GetDocument(); 3414 bool bUndo(rDoc.IsUndoEnabled()); 3415 if ( rDoc.IsVisible( nTab ) == bVisible ) 3416 return; // nothing to do - ok 3417 3418 if ( !rDoc.IsDocEditable() ) 3419 { 3420 if (!bApi) 3421 rDocShell.ErrorMessage(STR_PROTECTIONERR); 3422 return; 3423 } 3424 3425 ScDocShellModificator aModificator( rDocShell ); 3426 3427 if ( !bVisible && !rDoc.IsImportingXML() ) // #i57869# allow hiding in any order for loading 3428 { 3429 // do not disable all sheets 3430 3431 sal_uInt16 nVisCount = 0; 3432 SCTAB nCount = rDoc.GetTableCount(); 3433 for (SCTAB i=0; i<nCount && nVisCount<2; i++) 3434 if (rDoc.IsVisible(i)) 3435 ++nVisCount; 3436 3437 if (nVisCount <= 1) 3438 { 3439 if (!bApi) 3440 rDocShell.ErrorMessage(STR_PROTECTIONERR); //! separate error message? 3441 return; 3442 } 3443 } 3444 3445 rDoc.SetVisible( nTab, bVisible ); 3446 if (bUndo) 3447 { 3448 std::vector<SCTAB> undoTabs { nTab }; 3449 rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( &rDocShell, std::move(undoTabs), bVisible ) ); 3450 } 3451 3452 // update views 3453 if (!bVisible) 3454 rDocShell.Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) ); 3455 3456 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); 3457 rDocShell.PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras); 3458 aModificator.SetDocumentModified(); 3459 } 3460 3461 bool ScDocFunc::SetLayoutRTL( SCTAB nTab, bool bRTL ) 3462 { 3463 ScDocument& rDoc = rDocShell.GetDocument(); 3464 bool bUndo(rDoc.IsUndoEnabled()); 3465 if ( rDoc.IsLayoutRTL( nTab ) == bRTL ) 3466 return true; // nothing to do - ok 3467 3468 //! protection (sheet or document?) 3469 3470 ScDocShellModificator aModificator( rDocShell ); 3471 3472 rDoc.SetLayoutRTL( nTab, bRTL, ScObjectHandling::MirrorRTLMode); 3473 3474 if (bUndo) 3475 { 3476 rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoLayoutRTL>( &rDocShell, nTab, bRTL ) ); 3477 } 3478 3479 rDocShell.PostPaint( 0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::All ); 3480 aModificator.SetDocumentModified(); 3481 3482 SfxBindings* pBindings = rDocShell.GetViewBindings(); 3483 if (pBindings) 3484 { 3485 pBindings->Invalidate( FID_TAB_RTL ); 3486 pBindings->Invalidate( SID_ATTR_SIZE ); 3487 } 3488 3489 return true; 3490 } 3491 3492 bool ScDocFunc::RenameTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi ) 3493 { 3494 ScDocument& rDoc = rDocShell.GetDocument(); 3495 if (bRecord && !rDoc.IsUndoEnabled()) 3496 bRecord = false; 3497 if ( !rDoc.IsDocEditable() ) 3498 { 3499 if (!bApi) 3500 rDocShell.ErrorMessage(STR_PROTECTIONERR); 3501 return false; 3502 } 3503 3504 ScDocShellModificator aModificator( rDocShell ); 3505 3506 bool bSuccess = false; 3507 OUString sOldName; 3508 rDoc.GetName(nTab, sOldName); 3509 if (rDoc.RenameTab( nTab, rName )) 3510 { 3511 if (bRecord) 3512 { 3513 rDocShell.GetUndoManager()->AddUndoAction( 3514 std::make_unique<ScUndoRenameTab>( &rDocShell, nTab, sOldName, rName)); 3515 } 3516 rDocShell.PostPaintExtras(); 3517 aModificator.SetDocumentModified(); 3518 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); 3519 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesRenamed ) ); 3520 3521 bSuccess = true; 3522 } 3523 return bSuccess; 3524 } 3525 3526 bool ScDocFunc::SetTabBgColor( SCTAB nTab, const Color& rColor, bool bRecord, bool bApi ) 3527 { 3528 3529 ScDocument& rDoc = rDocShell.GetDocument(); 3530 if (bRecord && !rDoc.IsUndoEnabled()) 3531 bRecord = false; 3532 if ( !rDoc.IsDocEditable() || rDoc.IsTabProtected(nTab) ) 3533 { 3534 if (!bApi) 3535 rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Check to see what this string is... 3536 return false; 3537 } 3538 3539 Color aOldTabBgColor = rDoc.GetTabBgColor(nTab); 3540 3541 bool bSuccess = false; 3542 rDoc.SetTabBgColor(nTab, rColor); 3543 if ( rDoc.GetTabBgColor(nTab) == rColor) 3544 bSuccess = true; 3545 if (bSuccess) 3546 { 3547 if (bRecord) 3548 { 3549 rDocShell.GetUndoManager()->AddUndoAction( 3550 std::make_unique<ScUndoTabColor>( &rDocShell, nTab, aOldTabBgColor, rColor)); 3551 } 3552 rDocShell.PostPaintExtras(); 3553 ScDocShellModificator aModificator( rDocShell ); 3554 aModificator.SetDocumentModified(); 3555 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); 3556 3557 bSuccess = true; 3558 } 3559 return bSuccess; 3560 } 3561 3562 bool ScDocFunc::SetTabBgColor( 3563 ScUndoTabColorInfo::List& rUndoTabColorList, bool bApi ) 3564 { 3565 ScDocument& rDoc = rDocShell.GetDocument(); 3566 bool bRecord = true; 3567 if (!rDoc.IsUndoEnabled()) 3568 bRecord = false; 3569 3570 if ( !rDoc.IsDocEditable() ) 3571 { 3572 if (!bApi) 3573 rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error... 3574 return false; 3575 } 3576 3577 sal_uInt16 nTab; 3578 Color aNewTabBgColor; 3579 bool bSuccess = true; 3580 size_t nTabProtectCount = 0; 3581 size_t nTabListCount = rUndoTabColorList.size(); 3582 for ( size_t i = 0; i < nTabListCount; ++i ) 3583 { 3584 ScUndoTabColorInfo& rInfo = rUndoTabColorList[i]; 3585 nTab = rInfo.mnTabId; 3586 if ( !rDoc.IsTabProtected(nTab) ) 3587 { 3588 aNewTabBgColor = rInfo.maNewTabBgColor; 3589 rInfo.maOldTabBgColor = rDoc.GetTabBgColor(nTab); 3590 rDoc.SetTabBgColor(nTab, aNewTabBgColor); 3591 if ( rDoc.GetTabBgColor(nTab) != aNewTabBgColor) 3592 { 3593 bSuccess = false; 3594 break; 3595 } 3596 } 3597 else 3598 { 3599 nTabProtectCount++; 3600 } 3601 } 3602 3603 if ( nTabProtectCount == nTabListCount ) 3604 { 3605 if (!bApi) 3606 rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error... 3607 return false; 3608 } 3609 3610 if (bSuccess) 3611 { 3612 if (bRecord) 3613 { 3614 rDocShell.GetUndoManager()->AddUndoAction( 3615 std::make_unique<ScUndoTabColor>( &rDocShell, std::vector(rUndoTabColorList))); 3616 } 3617 rDocShell.PostPaintExtras(); 3618 ScDocShellModificator aModificator( rDocShell ); 3619 aModificator.SetDocumentModified(); 3620 } 3621 return bSuccess; 3622 } 3623 3624 //! SetWidthOrHeight - duplicated in ViewFunc !!!!!! 3625 //! Problems: 3626 //! - Optimal height of text cells is different for a printer and a screen 3627 //! - Optimal width needs a selection in order to take only selected cells into account 3628 3629 static sal_uInt16 lcl_GetOptimalColWidth( ScDocShell& rDocShell, SCCOL nCol, SCTAB nTab ) 3630 { 3631 ScSizeDeviceProvider aProv(&rDocShell); 3632 OutputDevice* pDev = aProv.GetDevice(); // has pixel MapMode 3633 double nPPTX = aProv.GetPPTX(); 3634 double nPPTY = aProv.GetPPTY(); 3635 3636 ScDocument& rDoc = rDocShell.GetDocument(); 3637 Fraction aOne(1,1); 3638 sal_uInt16 nTwips = rDoc.GetOptimalColWidth( nCol, nTab, pDev, nPPTX, nPPTY, aOne, aOne, 3639 false/*bFormula*/ ); 3640 3641 return nTwips; 3642 } 3643 3644 bool ScDocFunc::SetWidthOrHeight( 3645 bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, SCTAB nTab, 3646 ScSizeMode eMode, sal_uInt16 nSizeTwips, bool bRecord, bool bApi ) 3647 { 3648 ScDocShellModificator aModificator( rDocShell ); 3649 3650 if (rRanges.empty()) 3651 return true; 3652 3653 ScDocument& rDoc = rDocShell.GetDocument(); 3654 if ( bRecord && !rDoc.IsUndoEnabled() ) 3655 bRecord = false; 3656 3657 // import into read-only document is possible 3658 if ( !rDoc.IsChangeReadOnlyEnabled() && !rDocShell.IsEditable() ) 3659 { 3660 if (!bApi) 3661 rDocShell.ErrorMessage(STR_PROTECTIONERR); //! separate error message? 3662 return false; 3663 } 3664 3665 SCCOLROW nStart = rRanges[0].mnStart; 3666 SCCOLROW nEnd = rRanges[0].mnEnd; 3667 3668 if ( eMode == SC_SIZE_OPTIMAL ) 3669 { 3670 //! Option "Show formulas" - but where to get them from? 3671 } 3672 3673 ScDocumentUniquePtr pUndoDoc; 3674 std::unique_ptr<ScOutlineTable> pUndoTab; 3675 std::vector<sc::ColRowSpan> aUndoRanges; 3676 3677 if ( bRecord ) 3678 { 3679 rDoc.BeginDrawUndo(); // Drawing Updates 3680 3681 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 3682 if (bWidth) 3683 { 3684 pUndoDoc->InitUndo( rDoc, nTab, nTab, true ); 3685 rDoc.CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc ); 3686 } 3687 else 3688 { 3689 pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true ); 3690 rDoc.CopyToDocument( 0, static_cast<SCROW>(nStart), nTab, rDoc.MaxCol(), static_cast<SCROW>(nEnd), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc ); 3691 } 3692 3693 aUndoRanges = rRanges; 3694 3695 ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab ); 3696 if (pTable) 3697 pUndoTab.reset(new ScOutlineTable( *pTable )); 3698 } 3699 3700 bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT; 3701 bool bOutline = false; 3702 3703 for (const sc::ColRowSpan& rRange : rRanges) 3704 { 3705 SCCOLROW nStartNo = rRange.mnStart; 3706 SCCOLROW nEndNo = rRange.mnEnd; 3707 3708 if ( !bWidth ) // deal with heights always in blocks 3709 { 3710 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT ) 3711 { 3712 bool bAll = ( eMode==SC_SIZE_OPTIMAL ); 3713 if (!bAll) 3714 { 3715 // delete for all that have CRFlags::ManualSize enabled 3716 // then SetOptimalHeight with bShrink = FALSE 3717 for (SCROW nRow=nStartNo; nRow<=nEndNo; nRow++) 3718 { 3719 CRFlags nOld = rDoc.GetRowFlags(nRow,nTab); 3720 SCROW nLastRow = -1; 3721 bool bHidden = rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow); 3722 if ( !bHidden && ( nOld & CRFlags::ManualSize ) ) 3723 rDoc.SetRowFlags( nRow, nTab, nOld & ~CRFlags::ManualSize ); 3724 } 3725 } 3726 3727 ScSizeDeviceProvider aProv( &rDocShell ); 3728 Fraction aOne(1,1); 3729 sc::RowHeightContext aCxt(rDoc.MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice()); 3730 aCxt.setForceAutoSize(bAll); 3731 rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab, bApi); 3732 3733 if (bAll) 3734 rDoc.ShowRows( nStartNo, nEndNo, nTab, true ); 3735 3736 // Manual flag will be set already in SetOptimalHeight if bAll=true 3737 // (it is on when Extra-Height, otherwise off). 3738 } 3739 else if ( eMode==SC_SIZE_DIRECT || eMode==SC_SIZE_ORIGINAL ) 3740 { 3741 if (nSizeTwips) 3742 { 3743 rDoc.SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips ); 3744 rDoc.SetManualHeight( nStartNo, nEndNo, nTab, true ); // height was set manually 3745 } 3746 if ( eMode != SC_SIZE_ORIGINAL ) 3747 rDoc.ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 ); 3748 } 3749 else if ( eMode==SC_SIZE_SHOW ) 3750 { 3751 rDoc.ShowRows( nStartNo, nEndNo, nTab, true ); 3752 } 3753 } 3754 else // Column widths 3755 { 3756 for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++) 3757 { 3758 if ( eMode != SC_SIZE_VISOPT || !rDoc.ColHidden(nCol, nTab) ) 3759 { 3760 sal_uInt16 nThisSize = nSizeTwips; 3761 3762 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT ) 3763 nThisSize = nSizeTwips + 3764 lcl_GetOptimalColWidth( rDocShell, nCol, nTab ); 3765 if ( nThisSize ) 3766 rDoc.SetColWidth( nCol, nTab, nThisSize ); 3767 3768 if ( eMode != SC_SIZE_ORIGINAL ) 3769 rDoc.ShowCol( nCol, nTab, bShow ); 3770 } 3771 } 3772 } 3773 3774 // adjust outlines 3775 3776 if ( eMode != SC_SIZE_ORIGINAL ) 3777 { 3778 if (bWidth) 3779 bOutline = bOutline || rDoc.UpdateOutlineCol( 3780 static_cast<SCCOL>(nStartNo), 3781 static_cast<SCCOL>(nEndNo), nTab, bShow ); 3782 else 3783 bOutline = bOutline || rDoc.UpdateOutlineRow( 3784 static_cast<SCROW>(nStartNo), 3785 static_cast<SCROW>(nEndNo), nTab, bShow ); 3786 } 3787 } 3788 rDoc.SetDrawPageSize(nTab); 3789 3790 if (!bOutline) 3791 pUndoTab.reset(); 3792 3793 if (bRecord) 3794 { 3795 ScMarkData aMark(rDoc.GetSheetLimits()); 3796 aMark.SelectOneTable( nTab ); 3797 rDocShell.GetUndoManager()->AddUndoAction( 3798 std::make_unique<ScUndoWidthOrHeight>( 3799 &rDocShell, aMark, nStart, nTab, nEnd, nTab, std::move(pUndoDoc), 3800 std::move(aUndoRanges), std::move(pUndoTab), eMode, nSizeTwips, bWidth)); 3801 } 3802 3803 rDoc.UpdatePageBreaks( nTab ); 3804 3805 ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); 3806 if (pViewSh) 3807 pViewSh->OnLOKSetWidthOrHeight(nStart, bWidth); 3808 3809 rDocShell.PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::All); 3810 aModificator.SetDocumentModified(); 3811 3812 return false; 3813 } 3814 3815 bool ScDocFunc::InsertPageBreak( bool bColumn, const ScAddress& rPos, 3816 bool bRecord, bool bSetModified ) 3817 { 3818 ScDocShellModificator aModificator( rDocShell ); 3819 3820 ScDocument& rDoc = rDocShell.GetDocument(); 3821 if (bRecord && !rDoc.IsUndoEnabled()) 3822 bRecord = false; 3823 SCTAB nTab = rPos.Tab(); 3824 SfxBindings* pBindings = rDocShell.GetViewBindings(); 3825 3826 SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) : 3827 static_cast<SCCOLROW>(rPos.Row()); 3828 if (nPos == 0) 3829 return false; // first column / row 3830 3831 ScBreakType nBreak = bColumn ? 3832 rDoc.HasColBreak(static_cast<SCCOL>(nPos), nTab) : 3833 rDoc.HasRowBreak(static_cast<SCROW>(nPos), nTab); 3834 if (nBreak & ScBreakType::Manual) 3835 return true; 3836 3837 if (bRecord) 3838 rDocShell.GetUndoManager()->AddUndoAction( 3839 std::make_unique<ScUndoPageBreak>( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, true ) ); 3840 3841 if (bColumn) 3842 rDoc.SetColBreak(static_cast<SCCOL>(nPos), nTab, false, true); 3843 else 3844 rDoc.SetRowBreak(static_cast<SCROW>(nPos), nTab, false, true); 3845 3846 rDoc.InvalidatePageBreaks(nTab); 3847 rDoc.UpdatePageBreaks( nTab ); 3848 3849 rDoc.SetStreamValid(nTab, false); 3850 3851 if (bColumn) 3852 { 3853 rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid ); 3854 if (pBindings) 3855 { 3856 pBindings->Invalidate( FID_INS_COLBRK ); 3857 pBindings->Invalidate( FID_DEL_COLBRK ); 3858 } 3859 } 3860 else 3861 { 3862 rDocShell.PostPaint( 0, static_cast<SCROW>(nPos)-1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid ); 3863 if (pBindings) 3864 { 3865 pBindings->Invalidate( FID_INS_ROWBRK ); 3866 pBindings->Invalidate( FID_DEL_ROWBRK ); 3867 } 3868 } 3869 if (pBindings) 3870 pBindings->Invalidate( FID_DEL_MANUALBREAKS ); 3871 3872 if (bSetModified) 3873 aModificator.SetDocumentModified(); 3874 3875 return true; 3876 } 3877 3878 bool ScDocFunc::RemovePageBreak( bool bColumn, const ScAddress& rPos, 3879 bool bRecord, bool bSetModified ) 3880 { 3881 ScDocShellModificator aModificator( rDocShell ); 3882 3883 ScDocument& rDoc = rDocShell.GetDocument(); 3884 if (bRecord && !rDoc.IsUndoEnabled()) 3885 bRecord = false; 3886 SCTAB nTab = rPos.Tab(); 3887 SfxBindings* pBindings = rDocShell.GetViewBindings(); 3888 3889 SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) : 3890 static_cast<SCCOLROW>(rPos.Row()); 3891 3892 ScBreakType nBreak; 3893 if (bColumn) 3894 nBreak = rDoc.HasColBreak(static_cast<SCCOL>(nPos), nTab); 3895 else 3896 nBreak = rDoc.HasRowBreak(static_cast<SCROW>(nPos), nTab); 3897 if (!(nBreak & ScBreakType::Manual)) 3898 // There is no manual break. 3899 return false; 3900 3901 if (bRecord) 3902 rDocShell.GetUndoManager()->AddUndoAction( 3903 std::make_unique<ScUndoPageBreak>( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, false ) ); 3904 3905 if (bColumn) 3906 rDoc.RemoveColBreak(static_cast<SCCOL>(nPos), nTab, false, true); 3907 else 3908 rDoc.RemoveRowBreak(static_cast<SCROW>(nPos), nTab, false, true); 3909 3910 rDoc.UpdatePageBreaks( nTab ); 3911 3912 rDoc.SetStreamValid(nTab, false); 3913 3914 if (bColumn) 3915 { 3916 rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid ); 3917 if (pBindings) 3918 { 3919 pBindings->Invalidate( FID_INS_COLBRK ); 3920 pBindings->Invalidate( FID_DEL_COLBRK ); 3921 } 3922 } 3923 else 3924 { 3925 rDocShell.PostPaint( 0, nPos-1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid ); 3926 if (pBindings) 3927 { 3928 pBindings->Invalidate( FID_INS_ROWBRK ); 3929 pBindings->Invalidate( FID_DEL_ROWBRK ); 3930 } 3931 } 3932 if (pBindings) 3933 pBindings->Invalidate( FID_DEL_MANUALBREAKS ); 3934 3935 if (bSetModified) 3936 aModificator.SetDocumentModified(); 3937 3938 return true; 3939 } 3940 3941 void ScDocFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect ) 3942 { 3943 ScDocument& rDoc = rDocShell.GetDocument(); 3944 3945 std::unique_ptr<ScTableProtection> p; 3946 if (!rProtect.isProtected() && rDoc.IsUndoEnabled()) 3947 { 3948 // In case of unprotecting, use a copy of passed ScTableProtection object for undo 3949 p = std::make_unique<ScTableProtection>(rProtect); 3950 } 3951 rDoc.SetTabProtection(nTab, &rProtect); 3952 if (rDoc.IsUndoEnabled()) 3953 { 3954 if (!p) 3955 { 3956 // For protection case, use a copy of resulting ScTableProtection for undo 3957 const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); 3958 p = std::make_unique<ScTableProtection>(*pProtect); 3959 } 3960 rDocShell.GetUndoManager()->AddUndoAction( 3961 std::make_unique<ScUndoTabProtect>(&rDocShell, nTab, std::move(p))); 3962 // ownership of unique_ptr now transferred to ScUndoTabProtect. 3963 } 3964 for (SfxViewFrame* fr = SfxViewFrame::GetFirst(&rDocShell); fr; 3965 fr = SfxViewFrame::GetNext(*fr, &rDocShell)) 3966 if (ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(fr->GetViewShell())) 3967 pTabViewShell->SetTabProtectionSymbol(nTab, rProtect.isProtected()); 3968 rDocShell.PostPaintGridAll(); 3969 ScDocShellModificator aModificator(rDocShell); 3970 aModificator.SetDocumentModified(); 3971 } 3972 3973 void ScDocFunc::ProtectDocument(const ScDocProtection& rProtect) 3974 { 3975 ScDocument& rDoc = rDocShell.GetDocument(); 3976 3977 std::unique_ptr<ScDocProtection> p; 3978 if (!rProtect.isProtected() && rDoc.IsUndoEnabled()) 3979 { 3980 // In case of unprotecting, use a copy of passed ScTableProtection object for undo 3981 p = std::make_unique<ScDocProtection>(rProtect); 3982 } 3983 rDoc.SetDocProtection(&rProtect); 3984 if (rDoc.IsUndoEnabled()) 3985 { 3986 if (!p) 3987 { 3988 // For protection case, use a copy of resulting ScTableProtection for undo 3989 ScDocProtection* pProtect = rDoc.GetDocProtection(); 3990 p = std::make_unique<ScDocProtection>(*pProtect); 3991 } 3992 rDocShell.GetUndoManager()->AddUndoAction( 3993 std::make_unique<ScUndoDocProtect>(&rDocShell, std::move(p))); 3994 // ownership of unique_ptr now transferred to ScUndoTabProtect. 3995 } 3996 3997 rDocShell.PostPaintGridAll(); 3998 ScDocShellModificator aModificator(rDocShell); 3999 aModificator.SetDocumentModified(); 4000 } 4001 4002 bool ScDocFunc::Protect( SCTAB nTab, const OUString& rPassword ) 4003 { 4004 if (nTab == TABLEID_DOC) 4005 { 4006 // document protection 4007 ScDocProtection aProtection; 4008 aProtection.setProtected(true); 4009 aProtection.setPassword(rPassword); 4010 ProtectDocument(aProtection); 4011 4012 } 4013 else 4014 { 4015 // sheet protection 4016 4017 const ScTableProtection* pOldProtection = rDocShell.GetDocument().GetTabProtection(nTab); 4018 ::std::unique_ptr<ScTableProtection> pNewProtection(pOldProtection ? new ScTableProtection(*pOldProtection) : new ScTableProtection()); 4019 pNewProtection->setProtected(true); 4020 pNewProtection->setPassword(rPassword); 4021 ProtectSheet(nTab, *pNewProtection); 4022 } 4023 return true; 4024 } 4025 4026 bool ScDocFunc::Unprotect( SCTAB nTab, const OUString& rPassword, bool bApi ) 4027 { 4028 ScDocument& rDoc = rDocShell.GetDocument(); 4029 4030 if (nTab == TABLEID_DOC) 4031 { 4032 // document protection 4033 4034 ScDocProtection* pDocProtect = rDoc.GetDocProtection(); 4035 if (!pDocProtect || !pDocProtect->isProtected()) 4036 // already unprotected (should not happen)! 4037 return true; 4038 4039 if (!pDocProtect->verifyPassword(rPassword)) 4040 { 4041 if (!bApi) 4042 { 4043 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(), 4044 VclMessageType::Info, VclButtonsType::Ok, 4045 ScResId(SCSTR_WRONGPASSWORD))); 4046 xInfoBox->run(); 4047 } 4048 return false; 4049 } 4050 4051 ScDocProtection aNewProtection(*pDocProtect); 4052 aNewProtection.setProtected(false); 4053 ProtectDocument(aNewProtection); 4054 4055 } 4056 else 4057 { 4058 // sheet protection 4059 4060 const ScTableProtection* pTabProtect = rDoc.GetTabProtection(nTab); 4061 if (!pTabProtect || !pTabProtect->isProtected()) 4062 // already unprotected (should not happen)! 4063 return true; 4064 if (!pTabProtect->verifyPassword(rPassword)) 4065 { 4066 if (!bApi) 4067 { 4068 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(), 4069 VclMessageType::Info, VclButtonsType::Ok, 4070 ScResId(SCSTR_WRONGPASSWORD))); 4071 xInfoBox->run(); 4072 } 4073 return false; 4074 } 4075 4076 ScTableProtection aNewProtection(*pTabProtect); 4077 aNewProtection.setProtected(false); 4078 ProtectSheet(nTab, aNewProtection); 4079 } 4080 4081 return true; 4082 } 4083 4084 void ScDocFunc::ClearItems( const ScMarkData& rMark, const sal_uInt16* pWhich, bool bApi ) 4085 { 4086 ScDocShellModificator aModificator( rDocShell ); 4087 4088 ScDocument& rDoc = rDocShell.GetDocument(); 4089 bool bUndo (rDoc.IsUndoEnabled()); 4090 ScEditableTester aTester( rDoc, rMark ); 4091 if (!aTester.IsEditable()) 4092 { 4093 if (!bApi) 4094 rDocShell.ErrorMessage(aTester.GetMessageId()); 4095 return; 4096 } 4097 4098 // #i12940# ClearItems is called (from setPropertyToDefault) directly with uno object's cached 4099 // MarkData (GetMarkData), so rMark must be changed to multi selection for ClearSelectionItems 4100 // here. 4101 4102 ScRange aMarkRange; 4103 ScMarkData aMultiMark = rMark; 4104 aMultiMark.SetMarking(false); // for MarkToMulti 4105 aMultiMark.MarkToMulti(); 4106 aMultiMark.GetMultiMarkArea( aMarkRange ); 4107 4108 if (bUndo) 4109 { 4110 SCTAB nStartTab = aMarkRange.aStart.Tab(); 4111 SCTAB nEndTab = aMarkRange.aEnd.Tab(); 4112 4113 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); 4114 pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab ); 4115 rDoc.CopyToDocument( aMarkRange, InsertDeleteFlags::ATTRIB, true, *pUndoDoc, &aMultiMark ); 4116 4117 rDocShell.GetUndoManager()->AddUndoAction( 4118 std::make_unique<ScUndoClearItems>( &rDocShell, aMultiMark, std::move(pUndoDoc), pWhich ) ); 4119 } 4120 4121 rDoc.ClearSelectionItems( pWhich, aMultiMark ); 4122 4123 rDocShell.PostPaint( aMarkRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); 4124 aModificator.SetDocumentModified(); 4125 4126 //! Bindings-Invalidate etc.? 4127 } 4128 4129 bool ScDocFunc::ChangeIndent( const ScMarkData& rMark, bool bIncrement, bool bApi ) 4130 { 4131 ScDocShellModificator aModificator( rDocShell ); 4132 4133 ScDocument& rDoc = rDocShell.GetDocument(); 4134 bool bUndo(rDoc.IsUndoEnabled()); 4135 ScEditableTester aTester( rDoc, rMark ); 4136 if (!aTester.IsEditable()) 4137 { 4138 if (!bApi) 4139 rDocShell.ErrorMessage(aTester.GetMessageId()); 4140 return false; 4141 } 4142 4143 ScRange aMarkRange; 4144 rMark.GetMultiMarkArea( aMarkRange ); 4145 4146 if (bUndo) 4147 { 4148 SCTAB nStartTab = aMarkRange.aStart.Tab(); 4149 SCTAB nTabCount = rDoc.GetTableCount(); 4150 4151 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); 4152 pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab ); 4153 for (const auto& rTab : rMark) 4154 { 4155 if (rTab >= nTabCount) 4156 break; 4157 4158 if (rTab != nStartTab) 4159 pUndoDoc->AddUndoTab( rTab, rTab ); 4160 } 4161 4162 ScRange aCopyRange = aMarkRange; 4163 aCopyRange.aStart.SetTab(0); 4164 aCopyRange.aEnd.SetTab(nTabCount-1); 4165 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, true, *pUndoDoc, &rMark ); 4166 4167 rDocShell.GetUndoManager()->AddUndoAction( 4168 std::make_unique<ScUndoIndent>( &rDocShell, rMark, std::move(pUndoDoc), bIncrement ) ); 4169 } 4170 4171 rDoc.ChangeSelectionIndent( bIncrement, rMark ); 4172 4173 rDocShell.PostPaint( aMarkRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); 4174 aModificator.SetDocumentModified(); 4175 4176 SfxBindings* pBindings = rDocShell.GetViewBindings(); 4177 if (pBindings) 4178 { 4179 pBindings->Invalidate( SID_ALIGNLEFT ); // ChangeIndent aligns left 4180 pBindings->Invalidate( SID_ALIGNRIGHT ); 4181 pBindings->Invalidate( SID_ALIGNBLOCK ); 4182 pBindings->Invalidate( SID_ALIGNCENTERHOR ); 4183 pBindings->Invalidate( SID_ATTR_LRSPACE ); 4184 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_LEFT ); 4185 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_RIGHT ); 4186 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_BLOCK ); 4187 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_CENTER); 4188 // pseudo slots for Format menu 4189 pBindings->Invalidate( SID_ALIGN_ANY_HDEFAULT ); 4190 pBindings->Invalidate( SID_ALIGN_ANY_LEFT ); 4191 pBindings->Invalidate( SID_ALIGN_ANY_HCENTER ); 4192 pBindings->Invalidate( SID_ALIGN_ANY_RIGHT ); 4193 pBindings->Invalidate( SID_ALIGN_ANY_JUSTIFIED ); 4194 } 4195 4196 return true; 4197 } 4198 4199 bool ScDocFunc::AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark, 4200 sal_uInt16 nFormatNo, bool bApi ) 4201 { 4202 ScDocShellModificator aModificator( rDocShell ); 4203 4204 ScDocument& rDoc = rDocShell.GetDocument(); 4205 SCCOL nStartCol = rRange.aStart.Col(); 4206 SCROW nStartRow = rRange.aStart.Row(); 4207 SCTAB nStartTab = rRange.aStart.Tab(); 4208 SCCOL nEndCol = rRange.aEnd.Col(); 4209 SCROW nEndRow = rRange.aEnd.Row(); 4210 SCTAB nEndTab = rRange.aEnd.Tab(); 4211 4212 bool bRecord = true; 4213 if (!rDoc.IsUndoEnabled()) 4214 bRecord = false; 4215 ScMarkData aMark(rDoc.GetSheetLimits()); 4216 if (pTabMark) 4217 aMark = *pTabMark; 4218 else 4219 { 4220 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) 4221 aMark.SelectTable( nTab, true ); 4222 } 4223 4224 ScAutoFormat* pAutoFormat = ScGlobal::GetOrCreateAutoFormat(); 4225 ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); 4226 if ( nFormatNo < pAutoFormat->size() && aTester.IsEditable() ) 4227 { 4228 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 4229 4230 bool bSize = pAutoFormat->findByIndex(nFormatNo)->GetIncludeWidthHeight(); 4231 4232 SCTAB nTabCount = rDoc.GetTableCount(); 4233 ScDocumentUniquePtr pUndoDoc; 4234 if ( bRecord ) 4235 { 4236 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 4237 pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab, bSize, bSize ); 4238 for (const auto& rTab : aMark) 4239 { 4240 if (rTab >= nTabCount) 4241 break; 4242 4243 if (rTab != nStartTab) 4244 pUndoDoc->AddUndoTab( rTab, rTab, bSize, bSize ); 4245 } 4246 4247 ScRange aCopyRange = rRange; 4248 aCopyRange.aStart.SetTab(0); 4249 aCopyRange.aStart.SetTab(nTabCount-1); 4250 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc, &aMark ); 4251 if (bSize) 4252 { 4253 rDoc.CopyToDocument( nStartCol,0,0, nEndCol,rDoc.MaxRow(),nTabCount-1, 4254 InsertDeleteFlags::NONE, false, *pUndoDoc, &aMark ); 4255 rDoc.CopyToDocument( 0,nStartRow,0, rDoc.MaxCol(),nEndRow,nTabCount-1, 4256 InsertDeleteFlags::NONE, false, *pUndoDoc, &aMark ); 4257 } 4258 rDoc.BeginDrawUndo(); 4259 } 4260 4261 rDoc.AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo, aMark ); 4262 4263 if (bSize) 4264 { 4265 std::vector<sc::ColRowSpan> aCols(1, sc::ColRowSpan(nStartCol,nEndCol)); 4266 std::vector<sc::ColRowSpan> aRows(1, sc::ColRowSpan(nStartRow,nEndRow)); 4267 4268 for (const auto& rTab : aMark) 4269 { 4270 if (rTab >= nTabCount) 4271 break; 4272 4273 SetWidthOrHeight(true, aCols, rTab, SC_SIZE_VISOPT, STD_EXTRA_WIDTH, false, true); 4274 SetWidthOrHeight(false, aRows, rTab, SC_SIZE_VISOPT, 0, false, false); 4275 rDocShell.PostPaint( 0,0,rTab, rDoc.MaxCol(),rDoc.MaxRow(),rTab, 4276 PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top ); 4277 } 4278 } 4279 else 4280 { 4281 for (const auto& rTab : aMark) 4282 { 4283 if (rTab >= nTabCount) 4284 break; 4285 4286 bool bAdj = AdjustRowHeight( ScRange(nStartCol, nStartRow, rTab, 4287 nEndCol, nEndRow, rTab), false, bApi ); 4288 if (bAdj) 4289 rDocShell.PostPaint( 0,nStartRow,rTab, rDoc.MaxCol(),rDoc.MaxRow(),rTab, 4290 PaintPartFlags::Grid | PaintPartFlags::Left ); 4291 else 4292 rDocShell.PostPaint( nStartCol, nStartRow, rTab, 4293 nEndCol, nEndRow, rTab, PaintPartFlags::Grid ); 4294 } 4295 } 4296 4297 if ( bRecord ) // only now is Draw-Undo available 4298 { 4299 rDocShell.GetUndoManager()->AddUndoAction( 4300 std::make_unique<ScUndoAutoFormat>( &rDocShell, rRange, std::move(pUndoDoc), aMark, bSize, nFormatNo ) ); 4301 } 4302 4303 aModificator.SetDocumentModified(); 4304 } 4305 else if (!bApi) 4306 rDocShell.ErrorMessage(aTester.GetMessageId()); 4307 4308 return false; 4309 } 4310 4311 bool ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark, 4312 const ScTokenArray* pTokenArray, const OUString& rString, bool bApi, bool bEnglish, 4313 const OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) 4314 { 4315 if (ScViewData::SelectionFillDOOM( rRange )) 4316 return false; 4317 4318 ScDocShellModificator aModificator( rDocShell ); 4319 4320 bool bSuccess = false; 4321 ScDocument& rDoc = rDocShell.GetDocument(); 4322 SCCOL nStartCol = rRange.aStart.Col(); 4323 SCROW nStartRow = rRange.aStart.Row(); 4324 SCTAB nStartTab = rRange.aStart.Tab(); 4325 SCCOL nEndCol = rRange.aEnd.Col(); 4326 SCROW nEndRow = rRange.aEnd.Row(); 4327 SCTAB nEndTab = rRange.aEnd.Tab(); 4328 4329 ScMarkData aMark(rDoc.GetSheetLimits()); 4330 if (pTabMark) 4331 aMark = *pTabMark; 4332 else 4333 { 4334 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) 4335 aMark.SelectTable( nTab, true ); 4336 } 4337 4338 ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); 4339 if ( aTester.IsEditable() ) 4340 { 4341 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 4342 4343 ScDocumentUniquePtr pUndoDoc; 4344 4345 const bool bUndo(rDoc.IsUndoEnabled()); 4346 if (bUndo) 4347 { 4348 //! take selected sheets into account also when undoing 4349 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 4350 pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab ); 4351 rDoc.CopyToDocument( rRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc ); 4352 } 4353 4354 // use TokenArray if given, string (and flags) otherwise 4355 if ( pTokenArray ) 4356 { 4357 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, 4358 aMark, OUString(), pTokenArray, eGrammar); 4359 } 4360 else if ( rDoc.IsImportingXML() ) 4361 { 4362 ScTokenArray aCode(rDoc); 4363 aCode.AssignXMLString( rString, 4364 ((eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) ? rFormulaNmsp : OUString())); 4365 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, 4366 aMark, OUString(), &aCode, eGrammar); 4367 rDoc.IncXMLImportedFormulaCount( rString.getLength() ); 4368 } 4369 else if (bEnglish) 4370 { 4371 ScCompiler aComp( rDoc, rRange.aStart, eGrammar); 4372 std::unique_ptr<ScTokenArray> pCode = aComp.CompileString( rString ); 4373 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, 4374 aMark, OUString(), pCode.get(), eGrammar); 4375 } 4376 else 4377 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, 4378 aMark, rString, nullptr, eGrammar); 4379 4380 if (bUndo) 4381 { 4382 //! take selected sheets into account also when undoing 4383 rDocShell.GetUndoManager()->AddUndoAction( 4384 std::make_unique<ScUndoEnterMatrix>( &rDocShell, rRange, std::move(pUndoDoc), rString ) ); 4385 } 4386 4387 // Err522 painting of DDE-Formulas will be intercepted during interpreting 4388 rDocShell.PostPaint( nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab, PaintPartFlags::Grid ); 4389 aModificator.SetDocumentModified(); 4390 4391 bSuccess = true; 4392 } 4393 else if (!bApi) 4394 rDocShell.ErrorMessage(aTester.GetMessageId()); 4395 4396 return bSuccess; 4397 } 4398 4399 bool ScDocFunc::TabOp( const ScRange& rRange, const ScMarkData* pTabMark, 4400 const ScTabOpParam& rParam, bool bRecord, bool bApi ) 4401 { 4402 ScDocShellModificator aModificator( rDocShell ); 4403 4404 bool bSuccess = false; 4405 ScDocument& rDoc = rDocShell.GetDocument(); 4406 SCCOL nStartCol = rRange.aStart.Col(); 4407 SCROW nStartRow = rRange.aStart.Row(); 4408 SCTAB nStartTab = rRange.aStart.Tab(); 4409 SCCOL nEndCol = rRange.aEnd.Col(); 4410 SCROW nEndRow = rRange.aEnd.Row(); 4411 SCTAB nEndTab = rRange.aEnd.Tab(); 4412 4413 if (bRecord && !rDoc.IsUndoEnabled()) 4414 bRecord = false; 4415 4416 ScMarkData aMark(rDoc.GetSheetLimits()); 4417 if (pTabMark) 4418 aMark = *pTabMark; 4419 else 4420 { 4421 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) 4422 aMark.SelectTable( nTab, true ); 4423 } 4424 4425 ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); 4426 if ( aTester.IsEditable() ) 4427 { 4428 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 4429 rDoc.SetDirty( rRange, false ); 4430 if ( bRecord ) 4431 { 4432 //! take selected sheets into account also when undoing 4433 ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); 4434 pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab ); 4435 rDoc.CopyToDocument( rRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc ); 4436 4437 rDocShell.GetUndoManager()->AddUndoAction( 4438 std::make_unique<ScUndoTabOp>( &rDocShell, 4439 nStartCol, nStartRow, nStartTab, 4440 nEndCol, nEndRow, nEndTab, std::move(pUndoDoc), 4441 rParam.aRefFormulaCell, 4442 rParam.aRefFormulaEnd, 4443 rParam.aRefRowCell, 4444 rParam.aRefColCell, 4445 rParam.meMode) ); 4446 } 4447 rDoc.InsertTableOp(rParam, nStartCol, nStartRow, nEndCol, nEndRow, aMark); 4448 rDocShell.PostPaintGridAll(); 4449 aModificator.SetDocumentModified(); 4450 bSuccess = true; 4451 } 4452 else if (!bApi) 4453 rDocShell.ErrorMessage(aTester.GetMessageId()); 4454 4455 return bSuccess; 4456 } 4457 4458 static ScDirection DirFromFillDir( FillDir eDir ) 4459 { 4460 if (eDir==FILL_TO_BOTTOM) 4461 return DIR_BOTTOM; 4462 else if (eDir==FILL_TO_RIGHT) 4463 return DIR_RIGHT; 4464 else if (eDir==FILL_TO_TOP) 4465 return DIR_TOP; 4466 else // if (eDir==FILL_TO_LEFT) 4467 return DIR_LEFT; 4468 } 4469 4470 namespace { 4471 4472 /** 4473 * Expand the fill range as necessary, to allow copying of adjacent cell(s) 4474 * even when those cells are not in the original range. 4475 */ 4476 void adjustFillRangeForAdjacentCopy(const ScDocument &rDoc, ScRange& rRange, FillDir eDir) 4477 { 4478 switch (eDir) 4479 { 4480 case FILL_TO_BOTTOM: 4481 { 4482 if (rRange.aStart.Row() == 0) 4483 return; 4484 4485 if (rRange.aStart.Row() != rRange.aEnd.Row()) 4486 return; 4487 4488 // Include the above row. 4489 ScAddress& s = rRange.aStart; 4490 s.SetRow(s.Row()-1); 4491 } 4492 break; 4493 case FILL_TO_TOP: 4494 { 4495 if (rRange.aStart.Row() == rDoc.MaxRow()) 4496 return; 4497 4498 if (rRange.aStart.Row() != rRange.aEnd.Row()) 4499 return; 4500 4501 // Include the row below. 4502 ScAddress& e = rRange.aEnd; 4503 e.SetRow(e.Row()+1); 4504 } 4505 break; 4506 case FILL_TO_LEFT: 4507 { 4508 if (rRange.aStart.Col() == rDoc.MaxCol()) 4509 return; 4510 4511 if (rRange.aStart.Col() != rRange.aEnd.Col()) 4512 return; 4513 4514 // Include the column to the right. 4515 ScAddress& e = rRange.aEnd; 4516 e.SetCol(e.Col()+1); 4517 } 4518 break; 4519 case FILL_TO_RIGHT: 4520 { 4521 if (rRange.aStart.Col() == 0) 4522 return; 4523 4524 if (rRange.aStart.Col() != rRange.aEnd.Col()) 4525 return; 4526 4527 // Include the column to the left. 4528 ScAddress& s = rRange.aStart; 4529 s.SetCol(s.Col()-1); 4530 } 4531 break; 4532 default: 4533 ; 4534 } 4535 } 4536 4537 } 4538 4539 bool ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMark, 4540 FillDir eDir, bool bApi ) 4541 { 4542 ScDocShellModificator aModificator( rDocShell ); 4543 ScDocument& rDoc = rDocShell.GetDocument(); 4544 4545 bool bSuccess = false; 4546 ScRange aRange = rRange; 4547 adjustFillRangeForAdjacentCopy(rDoc, aRange, eDir); 4548 4549 SCCOL nStartCol = aRange.aStart.Col(); 4550 SCROW nStartRow = aRange.aStart.Row(); 4551 SCTAB nStartTab = aRange.aStart.Tab(); 4552 SCCOL nEndCol = aRange.aEnd.Col(); 4553 SCROW nEndRow = aRange.aEnd.Row(); 4554 SCTAB nEndTab = aRange.aEnd.Tab(); 4555 4556 bool bRecord = true; 4557 if (!rDoc.IsUndoEnabled()) 4558 bRecord = false; 4559 4560 ScMarkData aMark(rDoc.GetSheetLimits()); 4561 if (pTabMark) 4562 aMark = *pTabMark; 4563 else 4564 { 4565 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) 4566 aMark.SelectTable( nTab, true ); 4567 } 4568 4569 ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); 4570 if ( aTester.IsEditable() ) 4571 { 4572 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 4573 4574 ScRange aSourceArea = aRange; 4575 ScRange aDestArea = aRange; 4576 4577 SCCOLROW nCount = 0; 4578 switch (eDir) 4579 { 4580 case FILL_TO_BOTTOM: 4581 nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row(); 4582 aSourceArea.aEnd.SetRow( aSourceArea.aStart.Row() ); 4583 break; 4584 case FILL_TO_RIGHT: 4585 nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col(); 4586 aSourceArea.aEnd.SetCol( aSourceArea.aStart.Col() ); 4587 break; 4588 case FILL_TO_TOP: 4589 nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row(); 4590 aSourceArea.aStart.SetRow( aSourceArea.aEnd.Row() ); 4591 break; 4592 case FILL_TO_LEFT: 4593 nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col(); 4594 aSourceArea.aStart.SetCol( aSourceArea.aEnd.Col() ); 4595 break; 4596 } 4597 4598 ScDocumentUniquePtr pUndoDoc; 4599 if ( bRecord ) 4600 { 4601 SCTAB nTabCount = rDoc.GetTableCount(); 4602 SCTAB nDestStartTab = aDestArea.aStart.Tab(); 4603 4604 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 4605 pUndoDoc->InitUndo( rDoc, nDestStartTab, nDestStartTab ); 4606 for (const auto& rTab : aMark) 4607 { 4608 if (rTab >= nTabCount) 4609 break; 4610 4611 if (rTab != nDestStartTab) 4612 pUndoDoc->AddUndoTab( rTab, rTab ); 4613 } 4614 4615 ScRange aCopyRange = aDestArea; 4616 aCopyRange.aStart.SetTab(0); 4617 aCopyRange.aEnd.SetTab(nTabCount-1); 4618 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::AUTOFILL, false, *pUndoDoc, &aMark ); 4619 } 4620 4621 sal_uLong nProgCount; 4622 if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP) 4623 nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1; 4624 else 4625 nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1; 4626 nProgCount *= nCount; 4627 ScProgress aProgress( rDoc.GetDocumentShell(), 4628 ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true ); 4629 4630 rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), 4631 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress, 4632 aMark, nCount, eDir, FILL_SIMPLE ); 4633 AdjustRowHeight(aRange, true, bApi); 4634 4635 if ( bRecord ) // only now is Draw-Undo available 4636 { 4637 rDocShell.GetUndoManager()->AddUndoAction( 4638 std::make_unique<ScUndoAutoFill>( &rDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), aMark, 4639 eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307) ); 4640 } 4641 4642 rDocShell.PostPaintGridAll(); 4643 aModificator.SetDocumentModified(); 4644 4645 bSuccess = true; 4646 } 4647 else if (!bApi) 4648 rDocShell.ErrorMessage(aTester.GetMessageId()); 4649 4650 return bSuccess; 4651 } 4652 4653 bool ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark, 4654 FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, 4655 double fStart, double fStep, double fMax, 4656 bool bApi ) 4657 { 4658 ScDocShellModificator aModificator( rDocShell ); 4659 4660 bool bSuccess = false; 4661 ScDocument& rDoc = rDocShell.GetDocument(); 4662 SCCOL nStartCol = rRange.aStart.Col(); 4663 SCROW nStartRow = rRange.aStart.Row(); 4664 SCTAB nStartTab = rRange.aStart.Tab(); 4665 SCCOL nEndCol = rRange.aEnd.Col(); 4666 SCROW nEndRow = rRange.aEnd.Row(); 4667 SCTAB nEndTab = rRange.aEnd.Tab(); 4668 4669 bool bRecord = true; 4670 if (!rDoc.IsUndoEnabled()) 4671 bRecord = false; 4672 4673 ScMarkData aMark(rDoc.GetSheetLimits()); 4674 if (pTabMark) 4675 aMark = *pTabMark; 4676 else 4677 { 4678 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) 4679 aMark.SelectTable( nTab, true ); 4680 } 4681 4682 ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); 4683 if ( aTester.IsEditable() ) 4684 { 4685 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 4686 4687 ScRange aSourceArea = rRange; 4688 ScRange aDestArea = rRange; 4689 4690 SCSIZE nCount = rDoc.GetEmptyLinesInBlock( 4691 aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aStart.Tab(), 4692 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aSourceArea.aEnd.Tab(), 4693 DirFromFillDir(eDir) ); 4694 4695 // keep at least one row/column as source range 4696 SCSIZE nTotLines = ( eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP ) ? 4697 static_cast<SCSIZE>( aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1 ) : 4698 static_cast<SCSIZE>( aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1 ); 4699 if ( nCount >= nTotLines ) 4700 nCount = nTotLines - 1; 4701 4702 switch (eDir) 4703 { 4704 case FILL_TO_BOTTOM: 4705 aSourceArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() - nCount ) ); 4706 break; 4707 case FILL_TO_RIGHT: 4708 aSourceArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() - nCount ) ); 4709 break; 4710 case FILL_TO_TOP: 4711 aSourceArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() + nCount ) ); 4712 break; 4713 case FILL_TO_LEFT: 4714 aSourceArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() + nCount ) ); 4715 break; 4716 } 4717 4718 ScDocumentUniquePtr pUndoDoc; 4719 if ( bRecord ) 4720 { 4721 SCTAB nTabCount = rDoc.GetTableCount(); 4722 SCTAB nDestStartTab = aDestArea.aStart.Tab(); 4723 4724 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 4725 pUndoDoc->InitUndo( rDoc, nDestStartTab, nDestStartTab ); 4726 for (const auto& rTab : aMark) 4727 { 4728 if (rTab >= nTabCount) 4729 break; 4730 4731 if (rTab != nDestStartTab) 4732 pUndoDoc->AddUndoTab( rTab, rTab ); 4733 } 4734 4735 rDoc.CopyToDocument( 4736 aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0, 4737 aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1, 4738 InsertDeleteFlags::AUTOFILL, false, *pUndoDoc, &aMark ); 4739 } 4740 4741 if (aDestArea.aStart.Col() <= aDestArea.aEnd.Col() && 4742 aDestArea.aStart.Row() <= aDestArea.aEnd.Row()) 4743 { 4744 if ( fStart != MAXDOUBLE ) 4745 { 4746 SCCOL nValX = (eDir == FILL_TO_LEFT) ? aDestArea.aEnd.Col() : aDestArea.aStart.Col(); 4747 SCROW nValY = (eDir == FILL_TO_TOP ) ? aDestArea.aEnd.Row() : aDestArea.aStart.Row(); 4748 SCTAB nTab = aDestArea.aStart.Tab(); 4749 rDoc.SetValue( nValX, nValY, nTab, fStart ); 4750 } 4751 4752 sal_uLong nProgCount; 4753 if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP) 4754 nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1; 4755 else 4756 nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1; 4757 nProgCount *= nCount; 4758 ScProgress aProgress( rDoc.GetDocumentShell(), 4759 ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true ); 4760 4761 rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), 4762 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress, 4763 aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax ); 4764 AdjustRowHeight(rRange, true, bApi); 4765 4766 rDocShell.PostPaintGridAll(); 4767 aModificator.SetDocumentModified(); 4768 } 4769 4770 if ( bRecord ) // only now is Draw-Undo available 4771 { 4772 rDocShell.GetUndoManager()->AddUndoAction( 4773 std::make_unique<ScUndoAutoFill>( &rDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), aMark, 4774 eDir, eCmd, eDateCmd, fStart, fStep, fMax) ); 4775 } 4776 4777 bSuccess = true; 4778 } 4779 else if (!bApi) 4780 rDocShell.ErrorMessage(aTester.GetMessageId()); 4781 4782 return bSuccess; 4783 } 4784 4785 bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, 4786 FillDir eDir, sal_uLong nCount, bool bApi ) 4787 { 4788 return FillAuto( rRange, pTabMark, eDir, FILL_AUTO, FILL_DAY, nCount, 1.0/*fStep*/, MAXDOUBLE/*fMax*/, true/*bRecord*/, bApi ); 4789 } 4790 4791 bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, sal_uLong nCount, double fStep, double fMax, bool bRecord, bool bApi ) 4792 { 4793 ScDocShellModificator aModificator( rDocShell ); 4794 4795 ScDocument& rDoc = rDocShell.GetDocument(); 4796 SCCOL nStartCol = rRange.aStart.Col(); 4797 SCROW nStartRow = rRange.aStart.Row(); 4798 SCTAB nStartTab = rRange.aStart.Tab(); 4799 SCCOL nEndCol = rRange.aEnd.Col(); 4800 SCROW nEndRow = rRange.aEnd.Row(); 4801 SCTAB nEndTab = rRange.aEnd.Tab(); 4802 4803 if (bRecord && !rDoc.IsUndoEnabled()) 4804 bRecord = false; 4805 4806 ScMarkData aMark(rDoc.GetSheetLimits()); 4807 if (pTabMark) 4808 aMark = *pTabMark; 4809 else 4810 { 4811 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) 4812 aMark.SelectTable( nTab, true ); 4813 } 4814 4815 ScRange aSourceArea = rRange; 4816 ScRange aDestArea = rRange; 4817 4818 switch (eDir) 4819 { 4820 case FILL_TO_BOTTOM: 4821 aDestArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() + nCount ) ); 4822 break; 4823 case FILL_TO_TOP: 4824 if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Row() )) 4825 { 4826 OSL_FAIL("FillAuto: Row < 0"); 4827 nCount = aSourceArea.aStart.Row(); 4828 } 4829 aDestArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() - nCount ) ); 4830 break; 4831 case FILL_TO_RIGHT: 4832 aDestArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() + nCount ) ); 4833 break; 4834 case FILL_TO_LEFT: 4835 if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Col() )) 4836 { 4837 OSL_FAIL("FillAuto: Col < 0"); 4838 nCount = aSourceArea.aStart.Col(); 4839 } 4840 aDestArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() - nCount ) ); 4841 break; 4842 default: 4843 OSL_FAIL("Wrong direction with FillAuto"); 4844 break; 4845 } 4846 4847 // Test for cell protection 4848 //! Source range can be protected !!! 4849 //! but can't contain matrix fragments !!! 4850 4851 ScEditableTester aTester( rDoc, aDestArea ); 4852 if ( !aTester.IsEditable() ) 4853 { 4854 if (!bApi) 4855 rDocShell.ErrorMessage(aTester.GetMessageId()); 4856 return false; 4857 } 4858 4859 if ( rDoc.HasSelectedBlockMatrixFragment( nStartCol, nStartRow, 4860 nEndCol, nEndRow, aMark ) ) 4861 { 4862 if (!bApi) 4863 rDocShell.ErrorMessage(STR_MATRIXFRAGMENTERR); 4864 return false; 4865 } 4866 4867 // FID_FILL_... slots should already had been disabled, check here for API 4868 // calls, no message. 4869 if (ScViewData::SelectionFillDOOM( aDestArea)) 4870 return false; 4871 4872 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); 4873 4874 ScDocumentUniquePtr pUndoDoc; 4875 if ( bRecord ) 4876 { 4877 SCTAB nTabCount = rDoc.GetTableCount(); 4878 SCTAB nDestStartTab = aDestArea.aStart.Tab(); 4879 4880 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 4881 pUndoDoc->InitUndo( rDoc, nDestStartTab, nDestStartTab ); 4882 for (const auto& rTab : aMark) 4883 { 4884 if (rTab >= nTabCount) 4885 break; 4886 4887 if (rTab != nDestStartTab) 4888 pUndoDoc->AddUndoTab( rTab, rTab ); 4889 } 4890 4891 // do not clone note captions in undo document 4892 rDoc.CopyToDocument( 4893 aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0, 4894 aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1, 4895 InsertDeleteFlags::AUTOFILL, false, *pUndoDoc, &aMark ); 4896 } 4897 4898 sal_uLong nProgCount; 4899 if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP) 4900 nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1; 4901 else 4902 nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1; 4903 nProgCount *= nCount; 4904 ScProgress aProgress( rDoc.GetDocumentShell(), 4905 ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true ); 4906 4907 rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), 4908 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress, 4909 aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax ); 4910 4911 AdjustRowHeight(aDestArea, true, bApi); 4912 4913 if ( bRecord ) // only now is Draw-Undo available 4914 { 4915 rDocShell.GetUndoManager()->AddUndoAction( 4916 std::make_unique<ScUndoAutoFill>( &rDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), aMark, 4917 eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax) ); 4918 } 4919 4920 rDocShell.PostPaintGridAll(); 4921 aModificator.SetDocumentModified(); 4922 4923 rRange = aDestArea; // return destination range (for marking) 4924 return true; 4925 } 4926 4927 bool ScDocFunc::MergeCells( const ScCellMergeOption& rOption, bool bContents, bool bRecord, bool bApi, bool bEmptyMergedCells /*=false*/ ) 4928 { 4929 using ::std::set; 4930 4931 ScDocShellModificator aModificator( rDocShell ); 4932 4933 SCCOL nStartCol = rOption.mnStartCol; 4934 SCROW nStartRow = rOption.mnStartRow; 4935 SCCOL nEndCol = rOption.mnEndCol; 4936 SCROW nEndRow = rOption.mnEndRow; 4937 if ((nStartCol == nEndCol && nStartRow == nEndRow) || rOption.maTabs.empty()) 4938 { 4939 // Nothing to do. Bail out quickly 4940 return true; 4941 } 4942 4943 ScDocument& rDoc = rDocShell.GetDocument(); 4944 SCTAB nTab1 = *rOption.maTabs.begin(), nTab2 = *rOption.maTabs.rbegin(); 4945 4946 if (bRecord && !rDoc.IsUndoEnabled()) 4947 bRecord = false; 4948 4949 for (const auto& rTab : rOption.maTabs) 4950 { 4951 ScEditableTester aTester( rDoc, rTab, nStartCol, nStartRow, nEndCol, nEndRow ); 4952 if (!aTester.IsEditable()) 4953 { 4954 if (!bApi) 4955 rDocShell.ErrorMessage(aTester.GetMessageId()); 4956 return false; 4957 } 4958 4959 if ( rDoc.HasAttrib( nStartCol, nStartRow, rTab, nEndCol, nEndRow, rTab, 4960 HasAttrFlags::Merged | HasAttrFlags::Overlapped ) ) 4961 { 4962 // "Merge of already merged cells not possible" 4963 if (!bApi) 4964 rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0); 4965 return false; 4966 } 4967 } 4968 4969 ScDocumentUniquePtr pUndoDoc; 4970 bool bNeedContentsUndo = false; 4971 for (const SCTAB nTab : rOption.maTabs) 4972 { 4973 bool bIsBlockEmpty = ( nStartRow == nEndRow ) 4974 ? rDoc.IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) 4975 : rDoc.IsBlockEmpty( nTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) && 4976 rDoc.IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ); 4977 bool bNeedContents = bContents && !bIsBlockEmpty; 4978 bool bNeedEmpty = bEmptyMergedCells && !bIsBlockEmpty && !bNeedContents; // if DoMergeContents then cells are emptied 4979 4980 if (bRecord) 4981 { 4982 // test if the range contains other notes which also implies that we need an undo document 4983 bool bHasNotes = rDoc.HasNote(nTab, nStartCol, nStartRow, nEndCol, nEndRow); 4984 if (!pUndoDoc) 4985 { 4986 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 4987 pUndoDoc->InitUndo(rDoc, nTab1, nTab2); 4988 } 4989 // note captions are collected by drawing undo 4990 rDoc.CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, 4991 InsertDeleteFlags::ALL|InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc ); 4992 if( bHasNotes ) 4993 rDoc.BeginDrawUndo(); 4994 } 4995 4996 if (bNeedContents) 4997 rDoc.DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); 4998 else if ( bNeedEmpty ) 4999 rDoc.DoEmptyBlock( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); 5000 rDoc.DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); 5001 5002 if (rOption.mbCenter) 5003 { 5004 rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxHorJustifyItem( SvxCellHorJustify::Center, ATTR_HOR_JUSTIFY ) ); 5005 rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxVerJustifyItem( SvxCellVerJustify::Center, ATTR_VER_JUSTIFY ) ); 5006 } 5007 5008 if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, rDoc.MaxCol(),nEndRow,nTab ), true, bApi ) ) 5009 rDocShell.PostPaint( nStartCol, nStartRow, nTab, 5010 nEndCol, nEndRow, nTab, PaintPartFlags::Grid ); 5011 if (bNeedContents || rOption.mbCenter) 5012 { 5013 ScRange aRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab); 5014 rDoc.SetDirty(aRange, true); 5015 } 5016 5017 bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteAll( ScDetectiveDelete::Circles ); 5018 if(bDone) 5019 DetectiveMarkInvalid(nTab); 5020 5021 bNeedContentsUndo |= bNeedContents; 5022 } 5023 5024 if (pUndoDoc) 5025 { 5026 std::unique_ptr<SdrUndoGroup> pDrawUndo = rDoc.GetDrawLayer() ? rDoc.GetDrawLayer()->GetCalcUndo() : nullptr; 5027 rDocShell.GetUndoManager()->AddUndoAction( 5028 std::make_unique<ScUndoMerge>(&rDocShell, rOption, bNeedContentsUndo, std::move(pUndoDoc), std::move(pDrawUndo)) ); 5029 } 5030 5031 aModificator.SetDocumentModified(); 5032 5033 SfxBindings* pBindings = rDocShell.GetViewBindings(); 5034 if (pBindings) 5035 { 5036 pBindings->Invalidate( FID_MERGE_ON ); 5037 pBindings->Invalidate( FID_MERGE_OFF ); 5038 pBindings->Invalidate( FID_MERGE_TOGGLE ); 5039 } 5040 5041 return true; 5042 } 5043 5044 bool ScDocFunc::UnmergeCells( const ScRange& rRange, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge ) 5045 { 5046 ScCellMergeOption aOption(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); 5047 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab(); 5048 for (SCTAB i = nTab1; i <= nTab2; ++i) 5049 aOption.maTabs.insert(i); 5050 5051 return UnmergeCells(aOption, bRecord, pUndoRemoveMerge); 5052 } 5053 5054 bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge ) 5055 { 5056 using ::std::set; 5057 5058 if (rOption.maTabs.empty()) 5059 // Nothing to unmerge. 5060 return true; 5061 5062 ScDocShellModificator aModificator( rDocShell ); 5063 ScDocument& rDoc = rDocShell.GetDocument(); 5064 5065 if (bRecord && !rDoc.IsUndoEnabled()) 5066 bRecord = false; 5067 5068 ScDocument* pUndoDoc = (pUndoRemoveMerge ? pUndoRemoveMerge->GetUndoDoc() : nullptr); 5069 assert( pUndoDoc || !pUndoRemoveMerge ); 5070 for (const SCTAB nTab : rOption.maTabs) 5071 { 5072 ScRange aRange = rOption.getSingleRange(nTab); 5073 if ( !rDoc.HasAttrib(aRange, HasAttrFlags::Merged) ) 5074 continue; 5075 5076 ScRange aExtended = aRange; 5077 rDoc.ExtendMerge(aExtended); 5078 ScRange aRefresh = aExtended; 5079 rDoc.ExtendOverlapped(aRefresh); 5080 5081 if (bRecord) 5082 { 5083 if (!pUndoDoc) 5084 { 5085 pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); 5086 pUndoDoc->InitUndo(rDoc, *rOption.maTabs.begin(), *rOption.maTabs.rbegin()); 5087 } 5088 rDoc.CopyToDocument(aExtended, InsertDeleteFlags::ATTRIB, false, *pUndoDoc); 5089 } 5090 5091 const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE ); 5092 ScPatternAttr aPattern( rDoc.GetPool() ); 5093 aPattern.GetItemSet().Put( rDefAttr ); 5094 rDoc.ApplyPatternAreaTab( aRange.aStart.Col(), aRange.aStart.Row(), 5095 aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, 5096 aPattern ); 5097 5098 rDoc.RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(), 5099 aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab, 5100 ScMF::Hor | ScMF::Ver ); 5101 5102 rDoc.ExtendMerge( aRefresh, true ); 5103 5104 if ( !AdjustRowHeight( aExtended, true, true ) ) 5105 rDocShell.PostPaint( aExtended, PaintPartFlags::Grid ); 5106 5107 bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteAll( ScDetectiveDelete::Circles ); 5108 if(bDone) 5109 DetectiveMarkInvalid(nTab); 5110 } 5111 5112 if (bRecord) 5113 { 5114 if (pUndoRemoveMerge) 5115 { 5116 // If pUndoRemoveMerge was passed, the caller is responsible for 5117 // adding it to Undo. Just add the current option. 5118 pUndoRemoveMerge->AddCellMergeOption( rOption); 5119 } 5120 else 5121 { 5122 rDocShell.GetUndoManager()->AddUndoAction( 5123 std::make_unique<ScUndoRemoveMerge>( &rDocShell, rOption, ScDocumentUniquePtr(pUndoDoc) ) ); 5124 } 5125 } 5126 aModificator.SetDocumentModified(); 5127 5128 return true; 5129 } 5130 5131 void ScDocFunc::ModifyRangeNames( const ScRangeName& rNewRanges, SCTAB nTab ) 5132 { 5133 SetNewRangeNames( std::unique_ptr<ScRangeName>(new ScRangeName(rNewRanges)), true, nTab ); 5134 } 5135 5136 void ScDocFunc::SetNewRangeNames( std::unique_ptr<ScRangeName> pNewRanges, bool bModifyDoc, SCTAB nTab ) // takes ownership of pNewRanges 5137 { 5138 ScDocShellModificator aModificator( rDocShell ); 5139 5140 OSL_ENSURE( pNewRanges, "pNewRanges is 0" ); 5141 ScDocument& rDoc = rDocShell.GetDocument(); 5142 bool bUndo(rDoc.IsUndoEnabled()); 5143 5144 if (bUndo) 5145 { 5146 ScRangeName* pOld; 5147 if (nTab >=0) 5148 { 5149 pOld = rDoc.GetRangeName(nTab); 5150 } 5151 else 5152 { 5153 pOld = rDoc.GetRangeName(); 5154 } 5155 std::unique_ptr<ScRangeName> pUndoRanges(new ScRangeName(*pOld)); 5156 std::unique_ptr<ScRangeName> pRedoRanges(new ScRangeName(*pNewRanges)); 5157 rDocShell.GetUndoManager()->AddUndoAction( 5158 std::make_unique<ScUndoRangeNames>( &rDocShell, std::move(pUndoRanges), std::move(pRedoRanges), nTab ) ); 5159 } 5160 5161 // #i55926# While loading XML, formula cells only have a single string token, 5162 // so CompileNameFormula would never find any name (index) tokens, and would 5163 // unnecessarily loop through all cells. 5164 bool bCompile = ( !rDoc.IsImportingXML() && rDoc.GetNamedRangesLockCount() == 0 ); 5165 5166 if ( bCompile ) 5167 rDoc.PreprocessRangeNameUpdate(); 5168 if (nTab >= 0) 5169 rDoc.SetRangeName( nTab, std::move(pNewRanges) ); // takes ownership 5170 else 5171 rDoc.SetRangeName( std::move(pNewRanges) ); // takes ownership 5172 if ( bCompile ) 5173 rDoc.CompileHybridFormula(); 5174 5175 if (bModifyDoc) 5176 { 5177 aModificator.SetDocumentModified(); 5178 SfxGetpApp()->Broadcast( SfxHint(SfxHintId::ScAreasChanged) ); 5179 } 5180 } 5181 5182 void ScDocFunc::ModifyAllRangeNames(const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap) 5183 { 5184 ScDocShellModificator aModificator(rDocShell); 5185 ScDocument& rDoc = rDocShell.GetDocument(); 5186 5187 if (rDoc.IsUndoEnabled()) 5188 { 5189 std::map<OUString, ScRangeName*> aOldRangeMap; 5190 rDoc.GetRangeNameMap(aOldRangeMap); 5191 rDocShell.GetUndoManager()->AddUndoAction( 5192 std::make_unique<ScUndoAllRangeNames>(&rDocShell, aOldRangeMap, rRangeMap)); 5193 } 5194 5195 rDoc.PreprocessAllRangeNamesUpdate(rRangeMap); 5196 rDoc.SetAllRangeNames(rRangeMap); 5197 rDoc.CompileHybridFormula(); 5198 5199 aModificator.SetDocumentModified(); 5200 SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged)); 5201 } 5202 5203 void ScDocFunc::CreateOneName( ScRangeName& rList, 5204 SCCOL nPosX, SCROW nPosY, SCTAB nTab, 5205 SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, 5206 bool& rCancel, bool bApi ) 5207 { 5208 if (rCancel) 5209 return; 5210 5211 ScDocument& rDoc = rDocShell.GetDocument(); 5212 if (rDoc.HasValueData( nPosX, nPosY, nTab )) 5213 return; 5214 5215 OUString aName = rDoc.GetString(nPosX, nPosY, nTab); 5216 ScRangeData::MakeValidName(rDoc, aName); 5217 if (aName.isEmpty()) 5218 return; 5219 5220 OUString aContent( ScRange( nX1, nY1, nTab, nX2, nY2, nTab ).Format( 5221 rDoc, ScRefFlags::RANGE_ABS_3D, ScAddress::Details( rDoc.GetAddressConvention(), nPosY, nPosX))); 5222 5223 bool bInsert = false; 5224 ScRangeData* pOld = rList.findByUpperName(ScGlobal::getCharClass().uppercase(aName)); 5225 if (pOld) 5226 { 5227 OUString aOldStr = pOld->GetSymbol(); 5228 if (aOldStr != aContent) 5229 { 5230 if (bApi) 5231 bInsert = true; // don't check via API 5232 else 5233 { 5234 OUString aTemplate = ScResId( STR_CREATENAME_REPLACE ); 5235 OUString aMessage = aTemplate.getToken( 0, '#' ) + aName + aTemplate.getToken( 1, '#' ); 5236 5237 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(), 5238 VclMessageType::Question, VclButtonsType::YesNo, 5239 aMessage)); 5240 xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); 5241 xQueryBox->set_default_response(RET_YES); 5242 5243 short nResult = xQueryBox->run(); 5244 if ( nResult == RET_YES ) 5245 { 5246 rList.erase(*pOld); 5247 bInsert = true; 5248 } 5249 else if ( nResult == RET_CANCEL ) 5250 rCancel = true; 5251 } 5252 } 5253 } 5254 else 5255 bInsert = true; 5256 5257 if (bInsert) 5258 { 5259 ScRangeData* pData = new ScRangeData( rDoc, aName, aContent, 5260 ScAddress( nPosX, nPosY, nTab)); 5261 if (!rList.insert(pData)) 5262 { 5263 OSL_FAIL("nanu?"); 5264 } 5265 } 5266 } 5267 5268 bool ScDocFunc::CreateNames( const ScRange& rRange, CreateNameFlags nFlags, bool bApi, SCTAB aTab ) 5269 { 5270 if (nFlags == CreateNameFlags::NONE) 5271 return false; // was nothing 5272 5273 ScDocShellModificator aModificator( rDocShell ); 5274 5275 bool bDone = false; 5276 SCCOL nStartCol = rRange.aStart.Col(); 5277 SCROW nStartRow = rRange.aStart.Row(); 5278 SCCOL nEndCol = rRange.aEnd.Col(); 5279 SCROW nEndRow = rRange.aEnd.Row(); 5280 SCTAB nTab = rRange.aStart.Tab(); 5281 OSL_ENSURE(rRange.aEnd.Tab() == nTab, "CreateNames: multiple tables not possible"); 5282 5283 bool bValid = true; 5284 if ( nFlags & ( CreateNameFlags::Top | CreateNameFlags::Bottom ) ) 5285 if ( nStartRow == nEndRow ) 5286 bValid = false; 5287 if ( nFlags & ( CreateNameFlags::Left | CreateNameFlags::Right ) ) 5288 if ( nStartCol == nEndCol ) 5289 bValid = false; 5290 5291 if (bValid) 5292 { 5293 ScDocument& rDoc = rDocShell.GetDocument(); 5294 ScRangeName* pNames; 5295 if (aTab >=0) 5296 pNames = rDoc.GetRangeName(nTab); 5297 else 5298 pNames = rDoc.GetRangeName(); 5299 5300 if (!pNames) 5301 return false; // shouldn't happen 5302 ScRangeName aNewRanges( *pNames ); 5303 5304 bool bTop ( nFlags & CreateNameFlags::Top ); 5305 bool bLeft ( nFlags & CreateNameFlags::Left ); 5306 bool bBottom( nFlags & CreateNameFlags::Bottom ); 5307 bool bRight ( nFlags & CreateNameFlags::Right ); 5308 5309 SCCOL nContX1 = nStartCol; 5310 SCROW nContY1 = nStartRow; 5311 SCCOL nContX2 = nEndCol; 5312 SCROW nContY2 = nEndRow; 5313 5314 if ( bTop ) 5315 ++nContY1; 5316 if ( bLeft ) 5317 ++nContX1; 5318 if ( bBottom ) 5319 --nContY2; 5320 if ( bRight ) 5321 --nContX2; 5322 5323 bool bCancel = false; 5324 SCCOL i; 5325 SCROW j; 5326 5327 if ( bTop ) 5328 for (i=nContX1; i<=nContX2; i++) 5329 CreateOneName( aNewRanges, i,nStartRow,nTab, i,nContY1,i,nContY2, bCancel, bApi ); 5330 if ( bLeft ) 5331 for (j=nContY1; j<=nContY2; j++) 5332 CreateOneName( aNewRanges, nStartCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi ); 5333 if ( bBottom ) 5334 for (i=nContX1; i<=nContX2; i++) 5335 CreateOneName( aNewRanges, i,nEndRow,nTab, i,nContY1,i,nContY2, bCancel, bApi ); 5336 if ( bRight ) 5337 for (j=nContY1; j<=nContY2; j++) 5338 CreateOneName( aNewRanges, nEndCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi ); 5339 5340 if ( bTop && bLeft ) 5341 CreateOneName( aNewRanges, nStartCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); 5342 if ( bTop && bRight ) 5343 CreateOneName( aNewRanges, nEndCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); 5344 if ( bBottom && bLeft ) 5345 CreateOneName( aNewRanges, nStartCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); 5346 if ( bBottom && bRight ) 5347 CreateOneName( aNewRanges, nEndCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); 5348 5349 ModifyRangeNames( aNewRanges, aTab ); 5350 bDone = true; 5351 5352 } 5353 5354 return bDone; 5355 } 5356 5357 bool ScDocFunc::InsertNameList( const ScAddress& rStartPos, bool bApi ) 5358 { 5359 ScDocShellModificator aModificator( rDocShell ); 5360 5361 bool bDone = false; 5362 ScDocument& rDoc = rDocShell.GetDocument(); 5363 const bool bRecord = rDoc.IsUndoEnabled(); 5364 SCTAB nTab = rStartPos.Tab(); 5365 5366 //local names have higher priority than global names 5367 ScRangeName* pLocalList = rDoc.GetRangeName(nTab); 5368 sal_uInt16 nValidCount = 0; 5369 for (const auto& rEntry : *pLocalList) 5370 { 5371 const ScRangeData& r = *rEntry.second; 5372 if (!r.HasType(ScRangeData::Type::Database)) 5373 ++nValidCount; 5374 } 5375 ScRangeName* pList = rDoc.GetRangeName(); 5376 for (const auto& rEntry : *pList) 5377 { 5378 const ScRangeData& r = *rEntry.second; 5379 if (!r.HasType(ScRangeData::Type::Database) && !pLocalList->findByUpperName(r.GetUpperName())) 5380 ++nValidCount; 5381 } 5382 5383 if (nValidCount) 5384 { 5385 SCCOL nStartCol = rStartPos.Col(); 5386 SCROW nStartRow = rStartPos.Row(); 5387 SCCOL nEndCol = nStartCol + 1; 5388 SCROW nEndRow = nStartRow + static_cast<SCROW>(nValidCount) - 1; 5389 5390 ScEditableTester aTester( rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow ); 5391 if (aTester.IsEditable()) 5392 { 5393 ScDocumentUniquePtr pUndoDoc; 5394 5395 if (bRecord) 5396 { 5397 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); 5398 pUndoDoc->InitUndo( rDoc, nTab, nTab ); 5399 rDoc.CopyToDocument(nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, 5400 InsertDeleteFlags::ALL, false, *pUndoDoc); 5401 5402 rDoc.BeginDrawUndo(); // because of adjusting heights 5403 } 5404 5405 std::unique_ptr<ScRangeData*[]> ppSortArray(new ScRangeData* [ nValidCount ]); 5406 sal_uInt16 j = 0; 5407 for (const auto& rEntry : *pLocalList) 5408 { 5409 ScRangeData& r = *rEntry.second; 5410 if (!r.HasType(ScRangeData::Type::Database)) 5411 ppSortArray[j++] = &r; 5412 } 5413 for (const auto& [rName, rxData] : *pList) 5414 { 5415 ScRangeData& r = *rxData; 5416 if (!r.HasType(ScRangeData::Type::Database) && !pLocalList->findByUpperName(rName)) 5417 ppSortArray[j++] = &r; 5418 } 5419 qsort( static_cast<void*>(ppSortArray.get()), nValidCount, sizeof(ScRangeData*), 5420 &ScRangeData_QsortNameCompare ); 5421 OUString aName; 5422 OUStringBuffer aContent; 5423 OUString aFormula; 5424 SCROW nOutRow = nStartRow; 5425 for (j=0; j<nValidCount; j++) 5426 { 5427 ScRangeData* pData = ppSortArray[j]; 5428 pData->GetName(aName); 5429 // adjust relative references to the left column in Excel-compliant way: 5430 pData->UpdateSymbol(aContent, ScAddress( nStartCol, nOutRow, nTab )); 5431 aFormula = "=" + aContent; 5432 ScSetStringParam aParam; 5433 aParam.setTextInput(); 5434 rDoc.SetString(ScAddress(nStartCol,nOutRow,nTab), aName, &aParam); 5435 rDoc.SetString(ScAddress(nEndCol,nOutRow,nTab), aFormula, &aParam); 5436 ++nOutRow; 5437 } 5438 5439 ppSortArray.reset(); 5440 5441 if (bRecord) 5442 { 5443 ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO )); 5444 pRedoDoc->InitUndo( rDoc, nTab, nTab ); 5445 rDoc.CopyToDocument(nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, 5446 InsertDeleteFlags::ALL, false, *pRedoDoc); 5447 5448 rDocShell.GetUndoManager()->AddUndoAction( 5449 std::make_unique<ScUndoListNames>( &rDocShell, 5450 ScRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab ), 5451 std::move(pUndoDoc), std::move(pRedoDoc) ) ); 5452 } 5453 5454 if (!AdjustRowHeight(ScRange(0,nStartRow,nTab,rDoc.MaxCol(),nEndRow,nTab), true, true)) 5455 rDocShell.PostPaint( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, PaintPartFlags::Grid ); 5456 5457 aModificator.SetDocumentModified(); 5458 bDone = true; 5459 } 5460 else if (!bApi) 5461 rDocShell.ErrorMessage(aTester.GetMessageId()); 5462 } 5463 return bDone; 5464 } 5465 5466 void ScDocFunc::ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd ) 5467 { 5468 ScDocument& rDoc = rDocShell.GetDocument(); 5469 SCCOL nStartCol = rOldRange.aStart.Col(); 5470 SCROW nStartRow = rOldRange.aStart.Row(); 5471 SCTAB nTab = rOldRange.aStart.Tab(); 5472 5473 OUString aFormula = rDoc.GetFormula( nStartCol, nStartRow, nTab ); 5474 if ( !(aFormula.startsWith("{") && aFormula.endsWith("}")) ) 5475 return; 5476 5477 OUString aUndo = ScResId( STR_UNDO_RESIZEMATRIX ); 5478 bool bUndo(rDoc.IsUndoEnabled()); 5479 if (bUndo) 5480 { 5481 ViewShellId nViewShellId(1); 5482 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell()) 5483 nViewShellId = pViewSh->GetViewShellId(); 5484 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId ); 5485 } 5486 5487 aFormula = aFormula.copy(1, aFormula.getLength()-2); 5488 5489 ScMarkData aMark(rDoc.GetSheetLimits()); 5490 aMark.SetMarkArea( rOldRange ); 5491 aMark.SelectTable( nTab, true ); 5492 ScRange aNewRange( rOldRange.aStart, rNewEnd ); 5493 5494 if ( DeleteContents( aMark, InsertDeleteFlags::CONTENTS, true, false/*bApi*/ ) ) 5495 { 5496 // GRAM_API for API compatibility. 5497 if (!EnterMatrix( aNewRange, &aMark, nullptr, aFormula, false/*bApi*/, false, OUString(), formula::FormulaGrammar::GRAM_API )) 5498 { 5499 // try to restore the previous state 5500 EnterMatrix( rOldRange, &aMark, nullptr, aFormula, false/*bApi*/, false, OUString(), formula::FormulaGrammar::GRAM_API ); 5501 } 5502 } 5503 5504 if (bUndo) 5505 rDocShell.GetUndoManager()->LeaveListAction(); 5506 } 5507 5508 void ScDocFunc::InsertAreaLink( const OUString& rFile, const OUString& rFilter, 5509 const OUString& rOptions, const OUString& rSource, 5510 const ScRange& rDestRange, sal_uLong nRefresh, 5511 bool bFitBlock, bool bApi ) 5512 { 5513 ScDocument& rDoc = rDocShell.GetDocument(); 5514 bool bUndo (rDoc.IsUndoEnabled()); 5515 5516 sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager(); 5517 5518 // #i52120# if other area links exist at the same start position, 5519 // remove them first (file format specifies only one link definition 5520 // for a cell) 5521 5522 sal_uInt16 nLinkCount = pLinkManager->GetLinks().size(); 5523 sal_uInt16 nRemoved = 0; 5524 sal_uInt16 nLinkPos = 0; 5525 while (nLinkPos<nLinkCount) 5526 { 5527 ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[nLinkPos].get(); 5528 ScAreaLink* pLink = dynamic_cast<ScAreaLink*>(pBase); 5529 if (pLink && pLink->GetDestArea().aStart == rDestRange.aStart) 5530 { 5531 if ( bUndo ) 5532 { 5533 if ( !nRemoved ) 5534 { 5535 // group all remove and the insert action 5536 OUString aUndo = ScResId( STR_UNDO_INSERTAREALINK ); 5537 ViewShellId nViewShellId(-1); 5538 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell()) 5539 nViewShellId = pViewSh->GetViewShellId(); 5540 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId ); 5541 } 5542 5543 ScAreaLink* pOldArea = static_cast<ScAreaLink*>(pBase); 5544 rDocShell.GetUndoManager()->AddUndoAction( 5545 std::make_unique<ScUndoRemoveAreaLink>( &rDocShell, 5546 pOldArea->GetFile(), pOldArea->GetFilter(), pOldArea->GetOptions(), 5547 pOldArea->GetSource(), pOldArea->GetDestArea(), pOldArea->GetRefreshDelay() ) ); 5548 } 5549 pLinkManager->Remove( pBase ); 5550 nLinkCount = pLinkManager->GetLinks().size(); 5551 ++nRemoved; 5552 } 5553 else 5554 ++nLinkPos; 5555 } 5556 5557 OUString aFilterName = rFilter; 5558 OUString aNewOptions = rOptions; 5559 if (aFilterName.isEmpty()) 5560 ScDocumentLoader::GetFilterName( rFile, aFilterName, aNewOptions, true, !bApi ); 5561 5562 // remove application prefix from filter name here, so the filter options 5563 // aren't reset when the filter name is changed in ScAreaLink::DataChanged 5564 ScDocumentLoader::RemoveAppPrefix( aFilterName ); 5565 5566 ScAreaLink* pLink = new ScAreaLink( &rDocShell, rFile, aFilterName, 5567 aNewOptions, rSource, rDestRange, nRefresh ); 5568 OUString aTmp = aFilterName; 5569 pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, rFile, &aTmp, &rSource ); 5570 5571 // Undo for an empty link 5572 5573 if (bUndo) 5574 { 5575 rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoInsertAreaLink>( &rDocShell, 5576 rFile, aFilterName, aNewOptions, 5577 rSource, rDestRange, nRefresh ) ); 5578 if ( nRemoved ) 5579 rDocShell.GetUndoManager()->LeaveListAction(); // undo for link update is still separate 5580 } 5581 5582 // Update has its own undo 5583 if (rDoc.IsExecuteLinkEnabled()) 5584 { 5585 pLink->SetDoInsert(bFitBlock); // if applicable, don't insert anything on first update 5586 pLink->Update(); // no SetInCreate -> carry out update 5587 } 5588 pLink->SetDoInsert(true); // Default = true 5589 5590 SfxBindings* pBindings = rDocShell.GetViewBindings(); 5591 if (pBindings) 5592 pBindings->Invalidate( SID_LINKS ); 5593 5594 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator 5595 } 5596 5597 void ScDocFunc::ReplaceConditionalFormat( sal_uLong nOldFormat, std::unique_ptr<ScConditionalFormat> pFormat, SCTAB nTab, const ScRangeList& rRanges ) 5598 { 5599 ScDocShellModificator aModificator(rDocShell); 5600 ScDocument& rDoc = rDocShell.GetDocument(); 5601 if(rDoc.IsTabProtected(nTab)) 5602 return; 5603 5604 bool bUndo = rDoc.IsUndoEnabled(); 5605 ScDocumentUniquePtr pUndoDoc; 5606 ScRange aCombinedRange = rRanges.Combine(); 5607 ScRange aCompleteRange; 5608 if(bUndo) 5609 { 5610 pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO)); 5611 pUndoDoc->InitUndo( rDoc, nTab, nTab ); 5612 5613 if(pFormat) 5614 { 5615 aCompleteRange = aCombinedRange; 5616 } 5617 if(nOldFormat) 5618 { 5619 ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat); 5620 if(pOldFormat) 5621 aCompleteRange.ExtendTo(pOldFormat->GetRange().Combine()); 5622 } 5623 5624 rDoc.CopyToDocument(aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab, 5625 aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab, 5626 InsertDeleteFlags::ALL, false, *pUndoDoc); 5627 } 5628 5629 std::unique_ptr<ScRange> pRepaintRange; 5630 if(nOldFormat) 5631 { 5632 ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat); 5633 if(pOldFormat) 5634 { 5635 pRepaintRange.reset(new ScRange( pOldFormat->GetRange().Combine() )); 5636 rDoc.RemoveCondFormatData(pOldFormat->GetRange(), nTab, pOldFormat->GetKey()); 5637 } 5638 5639 rDoc.DeleteConditionalFormat(nOldFormat, nTab); 5640 rDoc.SetStreamValid(nTab, false); 5641 } 5642 if(pFormat) 5643 { 5644 if(pRepaintRange) 5645 pRepaintRange->ExtendTo(aCombinedRange); 5646 else 5647 pRepaintRange.reset(new ScRange(aCombinedRange)); 5648 5649 sal_uLong nIndex = rDoc.AddCondFormat(std::move(pFormat), nTab); 5650 5651 rDoc.AddCondFormatData(rRanges, nTab, nIndex); 5652 rDoc.SetStreamValid(nTab, false); 5653 } 5654 5655 if(bUndo) 5656 { 5657 ScDocumentUniquePtr pRedoDoc(new ScDocument(SCDOCMODE_UNDO)); 5658 pRedoDoc->InitUndo( rDoc, nTab, nTab ); 5659 rDoc.CopyToDocument(aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab, 5660 aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab, 5661 InsertDeleteFlags::ALL, false, *pRedoDoc); 5662 rDocShell.GetUndoManager()->AddUndoAction( 5663 std::make_unique<ScUndoConditionalFormat>(&rDocShell, std::move(pUndoDoc), std::move(pRedoDoc), aCompleteRange)); 5664 } 5665 5666 if(pRepaintRange) 5667 rDocShell.PostPaint(*pRepaintRange, PaintPartFlags::Grid); 5668 5669 aModificator.SetDocumentModified(); 5670 SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged)); 5671 } 5672 5673 void ScDocFunc::SetConditionalFormatList( ScConditionalFormatList* pList, SCTAB nTab ) 5674 { 5675 ScDocShellModificator aModificator(rDocShell); 5676 ScDocument& rDoc = rDocShell.GetDocument(); 5677 if(rDoc.IsTabProtected(nTab)) 5678 return; 5679 5680 bool bUndo = rDoc.IsUndoEnabled(); 5681 ScDocumentUniquePtr pUndoDoc; 5682 if (bUndo) 5683 { 5684 pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO)); 5685 pUndoDoc->InitUndo( rDoc, nTab, nTab ); 5686 5687 ScConditionalFormatList* pOld = rDoc.GetCondFormList(nTab); 5688 5689 if (pOld) 5690 pUndoDoc->SetCondFormList(new ScConditionalFormatList(*pUndoDoc, *pOld), nTab); 5691 else 5692 pUndoDoc->SetCondFormList(nullptr, nTab); 5693 5694 } 5695 5696 // first remove all old entries 5697 ScConditionalFormatList* pOldList = rDoc.GetCondFormList(nTab); 5698 pOldList->RemoveFromDocument(rDoc); 5699 5700 // then set new entries 5701 pList->AddToDocument(rDoc); 5702 5703 rDoc.SetCondFormList(pList, nTab); 5704 rDocShell.PostPaintGridAll(); 5705 5706 if(bUndo) 5707 { 5708 ScDocumentUniquePtr pRedoDoc(new ScDocument(SCDOCMODE_UNDO)); 5709 pRedoDoc->InitUndo( rDoc, nTab, nTab ); 5710 pRedoDoc->SetCondFormList(new ScConditionalFormatList(*pRedoDoc, *pList), nTab); 5711 5712 rDocShell.GetUndoManager()->AddUndoAction( 5713 std::make_unique<ScUndoConditionalFormatList>(&rDocShell, std::move(pUndoDoc), std::move(pRedoDoc), nTab)); 5714 } 5715 5716 rDoc.SetStreamValid(nTab, false); 5717 aModificator.SetDocumentModified(); 5718 SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged)); 5719 } 5720 5721 void ScDocFunc::ConvertFormulaToValue( const ScRange& rRange, bool bInteraction ) 5722 { 5723 ScDocShellModificator aModificator(rDocShell); 5724 ScDocument& rDoc = rDocShell.GetDocument(); 5725 bool bRecord = true; 5726 if (!rDoc.IsUndoEnabled()) 5727 bRecord = false; 5728 5729 ScEditableTester aTester(rDoc, rRange); 5730 if (!aTester.IsEditable()) 5731 { 5732 if (bInteraction) 5733 rDocShell.ErrorMessage(aTester.GetMessageId()); 5734 return; 5735 } 5736 5737 sc::TableValues aUndoVals(rRange); 5738 sc::TableValues* pUndoVals = bRecord ? &aUndoVals : nullptr; 5739 5740 rDoc.ConvertFormulaToValue(rRange, pUndoVals); 5741 5742 if (bRecord && pUndoVals) 5743 { 5744 rDocShell.GetUndoManager()->AddUndoAction( 5745 std::make_unique<sc::UndoFormulaToValue>(&rDocShell, *pUndoVals)); 5746 } 5747 5748 rDocShell.PostPaint(rRange, PaintPartFlags::Grid); 5749 rDocShell.PostDataChanged(); 5750 rDoc.BroadcastCells(rRange, SfxHintId::ScDataChanged); 5751 aModificator.SetDocumentModified(); 5752 } 5753 5754 void ScDocFunc::EnterListAction(TranslateId pNameResId) 5755 { 5756 OUString aUndo(ScResId(pNameResId)); 5757 ViewShellId nViewShellId(-1); 5758 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell()) 5759 nViewShellId = pViewSh->GetViewShellId(); 5760 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId ); 5761 } 5762 5763 void ScDocFunc::EndListAction() 5764 { 5765 rDocShell.GetUndoManager()->LeaveListAction(); 5766 } 5767 5768 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 5769
