1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 32 33 // INCLUDE --------------------------------------------------------------- 34 35 #include <vcl/virdev.hxx> 36 37 #include "undobase.hxx" 38 #include "refundo.hxx" 39 #include "docsh.hxx" 40 #include "tabvwsh.hxx" 41 #include "undoolk.hxx" 42 #include "undodraw.hxx" 43 #include "dbcolect.hxx" 44 #include "attrib.hxx" 45 #include "queryparam.hxx" 46 #include "globstr.hrc" 47 48 // STATIC DATA ----------------------------------------------------------- 49 50 TYPEINIT1(ScSimpleUndo, SfxUndoAction); 51 TYPEINIT1(ScBlockUndo, ScSimpleUndo); 52 TYPEINIT1(ScMoveUndo, ScSimpleUndo); 53 TYPEINIT1(ScDBFuncUndo, ScSimpleUndo); 54 TYPEINIT1(ScUndoWrapper, SfxUndoAction); 55 56 // ----------------------------------------------------------------------- 57 58 ScSimpleUndo::ScSimpleUndo( ScDocShell* pDocSh ) : 59 pDocShell( pDocSh ), 60 pDetectiveUndo( NULL ) 61 { 62 } 63 64 __EXPORT ScSimpleUndo::~ScSimpleUndo() 65 { 66 delete pDetectiveUndo; 67 } 68 69 bool ScSimpleUndo::SetViewMarkData( const ScMarkData& rMarkData ) 70 { 71 if ( IsPaintLocked() ) 72 return false; 73 74 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 75 if ( !pViewShell ) 76 return false; 77 78 pViewShell->SetMarkData( rMarkData ); 79 return true; 80 } 81 82 sal_Bool __EXPORT ScSimpleUndo::Merge( SfxUndoAction *pNextAction ) 83 { 84 // Zu jeder Undo-Action kann eine SdrUndoGroup fuer das Aktualisieren 85 // der Detektiv-Pfeile gehoeren. 86 // DetectiveRefresh kommt immer hinterher, die SdrUndoGroup ist in 87 // eine ScUndoDraw Action verpackt. 88 // Nur beim automatischen Aktualisieren wird AddUndoAction mit 89 // bTryMerg=sal_True gerufen. 90 91 if ( !pDetectiveUndo && pNextAction->ISA(ScUndoDraw) ) 92 { 93 // SdrUndoAction aus der ScUndoDraw Action uebernehmen, 94 // ScUndoDraw wird dann vom UndoManager geloescht 95 96 ScUndoDraw* pCalcUndo = (ScUndoDraw*)pNextAction; 97 pDetectiveUndo = pCalcUndo->GetDrawUndo(); 98 pCalcUndo->ForgetDrawUndo(); 99 return sal_True; 100 } 101 102 return sal_False; 103 } 104 105 void ScSimpleUndo::BeginUndo() 106 { 107 pDocShell->SetInUndo( sal_True ); 108 109 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 110 if (pViewShell) 111 pViewShell->HideAllCursors(); // z.B. wegen zusammengefassten Zellen 112 113 // detective updates happened last, must be undone first 114 if (pDetectiveUndo) 115 pDetectiveUndo->Undo(); 116 } 117 118 void ScSimpleUndo::EndUndo() 119 { 120 pDocShell->SetDocumentModified(); 121 122 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 123 if (pViewShell) 124 { 125 pViewShell->UpdateAutoFillMark(); 126 pViewShell->UpdateInputHandler(); 127 pViewShell->ShowAllCursors(); 128 } 129 130 pDocShell->SetInUndo( sal_False ); 131 } 132 133 void ScSimpleUndo::BeginRedo() 134 { 135 pDocShell->SetInUndo( sal_True ); //! eigenes Flag fuer Redo? 136 137 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 138 if (pViewShell) 139 pViewShell->HideAllCursors(); // z.B. wegen zusammengefassten Zellen 140 } 141 142 void ScSimpleUndo::EndRedo() 143 { 144 if (pDetectiveUndo) 145 pDetectiveUndo->Redo(); 146 147 pDocShell->SetDocumentModified(); 148 149 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 150 if (pViewShell) 151 { 152 pViewShell->UpdateAutoFillMark(); 153 pViewShell->UpdateInputHandler(); 154 pViewShell->ShowAllCursors(); 155 } 156 157 pDocShell->SetInUndo( sal_False ); 158 } 159 160 void ScSimpleUndo::ShowTable( SCTAB nTab ) // static 161 { 162 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 163 if (pViewShell) 164 pViewShell->SetTabNo( nTab ); 165 } 166 167 void ScSimpleUndo::ShowTable( const ScRange& rRange ) // static 168 { 169 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 170 if (pViewShell) 171 { 172 SCTAB nStart = rRange.aStart.Tab(); 173 SCTAB nEnd = rRange.aEnd.Tab(); 174 SCTAB nTab = pViewShell->GetViewData()->GetTabNo(); 175 if ( nTab < nStart || nTab > nEnd ) // wenn nicht im Bereich: 176 pViewShell->SetTabNo( nStart ); // auf erste des Bereiches 177 } 178 } 179 180 181 // ----------------------------------------------------------------------- 182 183 ScBlockUndo::ScBlockUndo( ScDocShell* pDocSh, const ScRange& rRange, 184 ScBlockUndoMode eBlockMode ) : 185 ScSimpleUndo( pDocSh ), 186 aBlockRange( rRange ), 187 eMode( eBlockMode ) 188 { 189 pDrawUndo = GetSdrUndoAction( pDocShell->GetDocument() ); 190 } 191 192 __EXPORT ScBlockUndo::~ScBlockUndo() 193 { 194 DeleteSdrUndoAction( pDrawUndo ); 195 } 196 197 void ScBlockUndo::BeginUndo() 198 { 199 ScSimpleUndo::BeginUndo(); 200 EnableDrawAdjust( pDocShell->GetDocument(), sal_False ); 201 } 202 203 void ScBlockUndo::EndUndo() 204 { 205 if (eMode == SC_UNDO_AUTOHEIGHT) 206 AdjustHeight(); 207 208 EnableDrawAdjust( pDocShell->GetDocument(), sal_True ); 209 DoSdrUndoAction( pDrawUndo, pDocShell->GetDocument() ); 210 211 ShowBlock(); 212 ScSimpleUndo::EndUndo(); 213 } 214 215 /* 216 void ScBlockUndo::BeginRedo() 217 { 218 ScSimpleUndo::BeginRedo(); 219 } 220 */ 221 222 void ScBlockUndo::EndRedo() 223 { 224 if (eMode == SC_UNDO_AUTOHEIGHT) 225 AdjustHeight(); 226 227 ShowBlock(); 228 ScSimpleUndo::EndRedo(); 229 } 230 231 sal_Bool ScBlockUndo::AdjustHeight() 232 { 233 ScDocument* pDoc = pDocShell->GetDocument(); 234 235 VirtualDevice aVirtDev; 236 Fraction aZoomX( 1, 1 ); 237 Fraction aZoomY = aZoomX; 238 double nPPTX, nPPTY; 239 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 240 if (pViewShell) 241 { 242 ScViewData* pData = pViewShell->GetViewData(); 243 nPPTX = pData->GetPPTX(); 244 nPPTY = pData->GetPPTY(); 245 aZoomX = pData->GetZoomX(); 246 aZoomY = pData->GetZoomY(); 247 } 248 else 249 { 250 // Zoom auf 100 lassen 251 nPPTX = ScGlobal::nScreenPPTX; 252 nPPTY = ScGlobal::nScreenPPTY; 253 } 254 255 sal_Bool bRet = pDoc->SetOptimalHeight( aBlockRange.aStart.Row(), aBlockRange.aEnd.Row(), 256 /*!*/ aBlockRange.aStart.Tab(), 0, &aVirtDev, 257 nPPTX, nPPTY, aZoomX, aZoomY, sal_False ); 258 259 if (bRet) 260 pDocShell->PostPaint( 0, aBlockRange.aStart.Row(), aBlockRange.aStart.Tab(), 261 MAXCOL, MAXROW, aBlockRange.aEnd.Tab(), 262 PAINT_GRID | PAINT_LEFT ); 263 264 return bRet; 265 } 266 267 void ScBlockUndo::ShowBlock() 268 { 269 if ( IsPaintLocked() ) 270 return; 271 272 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); 273 if (pViewShell) 274 { 275 ShowTable( aBlockRange ); // bei mehreren Tabs im Range ist jede davon gut 276 pViewShell->MoveCursorAbs( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(), 277 SC_FOLLOW_JUMP, sal_False, sal_False ); 278 SCTAB nTab = pViewShell->GetViewData()->GetTabNo(); 279 ScRange aRange = aBlockRange; 280 aRange.aStart.SetTab( nTab ); 281 aRange.aEnd.SetTab( nTab ); 282 pViewShell->MarkRange( aRange ); 283 284 // nicht per SetMarkArea an MarkData, wegen evtl. fehlendem Paint 285 } 286 } 287 288 289 // ----------------------------------------------------------------------- 290 291 ScMoveUndo::ScMoveUndo( ScDocShell* pDocSh, ScDocument* pRefDoc, ScRefUndoData* pRefData, 292 ScMoveUndoMode eRefMode ) : 293 ScSimpleUndo( pDocSh ), 294 pRefUndoDoc( pRefDoc ), 295 pRefUndoData( pRefData ), 296 eMode( eRefMode ) 297 { 298 ScDocument* pDoc = pDocShell->GetDocument(); 299 if (pRefUndoData) 300 pRefUndoData->DeleteUnchanged(pDoc); 301 pDrawUndo = GetSdrUndoAction( pDoc ); 302 } 303 304 __EXPORT ScMoveUndo::~ScMoveUndo() 305 { 306 delete pRefUndoData; 307 delete pRefUndoDoc; 308 DeleteSdrUndoAction( pDrawUndo ); 309 } 310 311 void ScMoveUndo::UndoRef() 312 { 313 ScDocument* pDoc = pDocShell->GetDocument(); 314 ScRange aRange(0,0,0, MAXCOL,MAXROW,pRefUndoDoc->GetTableCount()-1); 315 pRefUndoDoc->CopyToDocument( aRange, IDF_FORMULA, sal_False, pDoc, NULL, sal_False ); 316 if (pRefUndoData) 317 pRefUndoData->DoUndo( pDoc, (eMode == SC_UNDO_REFFIRST) ); 318 // #65055# HACK: ScDragDropUndo ist der einzige mit REFFIRST. 319 // Falls nicht, resultiert daraus evtl. ein zu haeufiges Anpassen 320 // der ChartRefs, nicht schoen, aber auch nicht schlecht.. 321 } 322 323 void ScMoveUndo::BeginUndo() 324 { 325 ScSimpleUndo::BeginUndo(); 326 327 EnableDrawAdjust( pDocShell->GetDocument(), sal_False ); 328 329 if (pRefUndoDoc && eMode == SC_UNDO_REFFIRST) 330 UndoRef(); 331 } 332 333 void ScMoveUndo::EndUndo() 334 { 335 //@17.12.97 Reihenfolge der Fkt.s geaendert 336 DoSdrUndoAction( pDrawUndo, pDocShell->GetDocument() ); // #125875# must also be called when pointer is null 337 338 if (pRefUndoDoc && eMode == SC_UNDO_REFLAST) 339 UndoRef(); 340 341 EnableDrawAdjust( pDocShell->GetDocument(), sal_True ); 342 343 ScSimpleUndo::EndUndo(); 344 } 345 346 /* 347 void ScMoveUndo::BeginRedo() 348 { 349 ScSimpleUndo::BeginRedo(); 350 } 351 */ 352 353 /* 354 void ScMoveUndo::EndRedo() 355 { 356 ScSimpleUndo::EndRedo(); 357 } 358 */ 359 360 // ----------------------------------------------------------------------- 361 362 ScDBFuncUndo::ScDBFuncUndo( ScDocShell* pDocSh, const ScRange& rOriginal, SdrUndoAction* pDrawUndo ) : 363 ScSimpleUndo( pDocSh ), 364 aOriginalRange( rOriginal ), 365 mpDrawUndo( pDrawUndo ) 366 { 367 pAutoDBRange = pDocSh->GetOldAutoDBRange(); 368 } 369 370 ScDBFuncUndo::~ScDBFuncUndo() 371 { 372 DeleteSdrUndoAction( mpDrawUndo ); 373 delete pAutoDBRange; 374 } 375 376 void ScDBFuncUndo::SetDrawUndoAction( SdrUndoAction* pDrawUndo ) 377 { 378 DeleteSdrUndoAction( mpDrawUndo ); 379 mpDrawUndo = pDrawUndo; 380 } 381 382 void ScDBFuncUndo::BeginUndo() 383 { 384 ScSimpleUndo::BeginUndo(); 385 DoSdrUndoAction( mpDrawUndo, pDocShell->GetDocument() ); 386 } 387 388 void ScDBFuncUndo::EndUndo() 389 { 390 ScSimpleUndo::EndUndo(); 391 392 if ( pAutoDBRange ) 393 { 394 sal_uInt16 nNoNameIndex; 395 ScDocument* pDoc = pDocShell->GetDocument(); 396 ScDBCollection* pColl = pDoc->GetDBCollection(); 397 if ( pColl->SearchName( ScGlobal::GetRscString( STR_DB_NONAME ), nNoNameIndex ) ) 398 { 399 ScDBData* pNoNameData = (*pColl)[nNoNameIndex]; 400 401 SCCOL nRangeX1; 402 SCROW nRangeY1; 403 SCCOL nRangeX2; 404 SCROW nRangeY2; 405 SCTAB nRangeTab; 406 pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); 407 pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); 408 409 *pNoNameData = *pAutoDBRange; 410 411 if ( pAutoDBRange->HasAutoFilter() ) 412 { 413 // restore AutoFilter buttons 414 pAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); 415 pDoc->ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, SC_MF_AUTO ); 416 pDocShell->PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PAINT_GRID ); 417 } 418 } 419 } 420 } 421 422 void ScDBFuncUndo::BeginRedo() 423 { 424 RedoSdrUndoAction( mpDrawUndo ); 425 if ( pAutoDBRange ) 426 { 427 // move the database range to this function's position again (see ScDocShell::GetDBData) 428 429 sal_uInt16 nNoNameIndex; 430 ScDocument* pDoc = pDocShell->GetDocument(); 431 ScDBCollection* pColl = pDoc->GetDBCollection(); 432 if ( pColl->SearchName( ScGlobal::GetRscString( STR_DB_NONAME ), nNoNameIndex ) ) 433 { 434 ScDBData* pNoNameData = (*pColl)[nNoNameIndex]; 435 436 SCCOL nRangeX1; 437 SCROW nRangeY1; 438 SCCOL nRangeX2; 439 SCROW nRangeY2; 440 SCTAB nRangeTab; 441 pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); 442 pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); 443 444 pNoNameData->SetSortParam( ScSortParam() ); 445 pNoNameData->SetQueryParam( ScQueryParam() ); 446 pNoNameData->SetSubTotalParam( ScSubTotalParam() ); 447 448 pNoNameData->SetArea( aOriginalRange.aStart.Tab(), 449 aOriginalRange.aStart.Col(), aOriginalRange.aStart.Row(), 450 aOriginalRange.aEnd.Col(), aOriginalRange.aEnd.Row() ); 451 452 pNoNameData->SetByRow( sal_True ); 453 pNoNameData->SetAutoFilter( sal_False ); 454 // header is always set with the operation in redo 455 } 456 } 457 458 ScSimpleUndo::BeginRedo(); 459 } 460 461 void ScDBFuncUndo::EndRedo() 462 { 463 ScSimpleUndo::EndRedo(); 464 } 465 466 // ----------------------------------------------------------------------- 467 468 ScUndoWrapper::ScUndoWrapper( SfxUndoAction* pUndo ) : 469 pWrappedUndo( pUndo ) 470 { 471 } 472 473 ScUndoWrapper::~ScUndoWrapper() 474 { 475 delete pWrappedUndo; 476 } 477 478 void ScUndoWrapper::ForgetWrappedUndo() 479 { 480 pWrappedUndo = NULL; // don't delete in dtor - pointer must be stored outside 481 } 482 483 String ScUndoWrapper::GetComment() const 484 { 485 if (pWrappedUndo) 486 return pWrappedUndo->GetComment(); 487 else 488 return String(); 489 } 490 491 String ScUndoWrapper::GetRepeatComment(SfxRepeatTarget& rTarget) const 492 { 493 if (pWrappedUndo) 494 return pWrappedUndo->GetRepeatComment(rTarget); 495 else 496 return String(); 497 } 498 499 sal_uInt16 ScUndoWrapper::GetId() const 500 { 501 if (pWrappedUndo) 502 return pWrappedUndo->GetId(); 503 else 504 return 0; 505 } 506 507 sal_Bool ScUndoWrapper::IsLinked() 508 { 509 if (pWrappedUndo) 510 return pWrappedUndo->IsLinked(); 511 else 512 return sal_False; 513 } 514 515 void ScUndoWrapper::SetLinked( sal_Bool bIsLinked ) 516 { 517 if (pWrappedUndo) 518 pWrappedUndo->SetLinked(bIsLinked); 519 } 520 521 sal_Bool ScUndoWrapper::Merge( SfxUndoAction* pNextAction ) 522 { 523 if (pWrappedUndo) 524 return pWrappedUndo->Merge(pNextAction); 525 else 526 return sal_False; 527 } 528 529 void ScUndoWrapper::Undo() 530 { 531 if (pWrappedUndo) 532 pWrappedUndo->Undo(); 533 } 534 535 void ScUndoWrapper::Redo() 536 { 537 if (pWrappedUndo) 538 pWrappedUndo->Redo(); 539 } 540 541 void ScUndoWrapper::Repeat(SfxRepeatTarget& rTarget) 542 { 543 if (pWrappedUndo) 544 pWrappedUndo->Repeat(rTarget); 545 } 546 547 sal_Bool ScUndoWrapper::CanRepeat(SfxRepeatTarget& rTarget) const 548 { 549 if (pWrappedUndo) 550 return pWrappedUndo->CanRepeat(rTarget); 551 else 552 return sal_False; 553 } 554 555 556