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