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 <com/sun/star/document/XDocumentPropertiesSupplier.hpp> 36 #include <com/sun/star/document/XDocumentProperties.hpp> 37 38 #include "scitems.hxx" 39 #include "rangelst.hxx" 40 #include <editeng/flstitem.hxx> 41 #include <svx/pageitem.hxx> 42 #include <editeng/paperinf.hxx> 43 #include <svx/postattr.hxx> 44 #include <editeng/sizeitem.hxx> 45 #include <unotools/misccfg.hxx> 46 #include <sfx2/viewfrm.hxx> 47 #include <sfx2/app.hxx> 48 #include <sfx2/docfile.hxx> 49 #include <sfx2/printer.hxx> 50 #include <svtools/ctrltool.hxx> 51 #include <vcl/virdev.hxx> 52 #include <vcl/svapp.hxx> 53 #include <vcl/msgbox.hxx> 54 #include <unotools/localedatawrapper.hxx> 55 56 #include "docsh.hxx" 57 #include "docshimp.hxx" 58 #include "scmod.hxx" 59 #include "tabvwsh.hxx" 60 #include "viewdata.hxx" 61 #include "docpool.hxx" 62 #include "stlpool.hxx" 63 #include "patattr.hxx" 64 #include "uiitems.hxx" 65 #include "hints.hxx" 66 #include "docoptio.hxx" 67 #include "viewopti.hxx" 68 #include "pntlock.hxx" 69 #include "chgtrack.hxx" 70 #include "docfunc.hxx" 71 #include "cell.hxx" 72 #include "chgviset.hxx" 73 #include "progress.hxx" 74 #include "redcom.hxx" 75 #include "sc.hrc" 76 #include "inputopt.hxx" 77 #include "drwlayer.hxx" 78 #include "inputhdl.hxx" 79 #include "conflictsdlg.hxx" 80 #include "globstr.hrc" 81 82 #if DEBUG_CHANGETRACK 83 #include <stdio.h> 84 #endif // DEBUG_CHANGETRACK 85 86 87 //------------------------------------------------------------------ 88 89 // 90 // Redraw - Benachrichtigungen 91 // 92 93 94 void ScDocShell::PostEditView( ScEditEngineDefaulter* pEditEngine, const ScAddress& rCursorPos ) 95 { 96 // Broadcast( ScEditViewHint( pEditEngine, rCursorPos ) ); 97 98 // Test: nur aktive ViewShell 99 100 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); 101 if (pViewSh && pViewSh->GetViewData()->GetDocShell() == this) 102 { 103 ScEditViewHint aHint( pEditEngine, rCursorPos ); 104 pViewSh->Notify( *this, aHint ); 105 } 106 } 107 108 void ScDocShell::PostDataChanged() 109 { 110 Broadcast( SfxSimpleHint( FID_DATACHANGED ) ); 111 aDocument.ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) ); 112 113 SFX_APP()->Broadcast(SfxSimpleHint( FID_ANYDATACHANGED )); // Navigator 114 //! Navigator direkt benachrichtigen! 115 } 116 117 void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, 118 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, sal_uInt16 nPart, 119 sal_uInt16 nExtFlags ) 120 { 121 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 122 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 123 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 124 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 125 126 if ( pPaintLockData ) 127 { 128 // #i54081# PAINT_EXTRAS still has to be brodcast because it changes the 129 // current sheet if it's invalid. All other flags added to pPaintLockData. 130 sal_uInt16 nLockPart = nPart & ~PAINT_EXTRAS; 131 if ( nLockPart ) 132 { 133 //! nExtFlags ??? 134 pPaintLockData->AddRange( ScRange( nStartCol, nStartRow, nStartTab, 135 nEndCol, nEndRow, nEndTab ), nLockPart ); 136 } 137 138 nPart &= PAINT_EXTRAS; // for broadcasting 139 if ( !nPart ) 140 return; 141 } 142 143 144 if (nExtFlags & SC_PF_LINES) // Platz fuer Linien beruecksichtigen 145 { 146 //! Abfrage auf versteckte Spalten/Zeilen! 147 if (nStartCol>0) --nStartCol; 148 if (nEndCol<MAXCOL) ++nEndCol; 149 if (nStartRow>0) --nStartRow; 150 if (nEndRow<MAXROW) ++nEndRow; 151 } 152 153 // um zusammengefasste erweitern 154 if (nExtFlags & SC_PF_TESTMERGE) 155 aDocument.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nStartTab ); 156 157 if ( nStartCol != 0 || nEndCol != MAXCOL ) 158 { 159 // Extend to whole rows if SC_PF_WHOLEROWS is set, or rotated or non-left 160 // aligned cells are contained (see UpdatePaintExt). 161 // Special handling for RTL text (#i9731#) is unnecessary now with full 162 // support of right-aligned text. 163 164 if ( ( nExtFlags & SC_PF_WHOLEROWS ) || 165 aDocument.HasAttrib( nStartCol,nStartRow,nStartTab, 166 MAXCOL,nEndRow,nEndTab, HASATTR_ROTATE | HASATTR_RIGHTORCENTER ) ) 167 { 168 nStartCol = 0; 169 nEndCol = MAXCOL; 170 } 171 } 172 173 Broadcast( ScPaintHint( ScRange( nStartCol, nStartRow, nStartTab, 174 nEndCol, nEndRow, nEndTab ), nPart ) ); 175 176 if ( nPart & PAINT_GRID ) 177 aDocument.ResetChanged( ScRange(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) ); 178 } 179 180 void ScDocShell::PostPaint( const ScRange& rRange, sal_uInt16 nPart, sal_uInt16 nExtFlags ) 181 { 182 PostPaint( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(), 183 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), 184 nPart, nExtFlags ); 185 } 186 187 void ScDocShell::PostPaintGridAll() 188 { 189 PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID ); 190 } 191 192 void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab ) 193 { 194 PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PAINT_GRID, SC_PF_TESTMERGE ); 195 } 196 197 void ScDocShell::PostPaintCell( const ScAddress& rPos ) 198 { 199 PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab() ); 200 } 201 202 void ScDocShell::PostPaintExtras() 203 { 204 PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS ); 205 } 206 207 void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, const ScRange& rRange ) 208 { 209 if ( ( rExtFlags & SC_PF_LINES ) == 0 && aDocument.HasAttrib( rRange, HASATTR_PAINTEXT ) ) 210 { 211 // If the range contains lines, shadow or conditional formats, 212 // set SC_PF_LINES to include one extra cell in all directions. 213 214 rExtFlags |= SC_PF_LINES; 215 } 216 217 if ( ( rExtFlags & SC_PF_WHOLEROWS ) == 0 && 218 ( rRange.aStart.Col() != 0 || rRange.aEnd.Col() != MAXCOL ) && 219 aDocument.HasAttrib( rRange, HASATTR_ROTATE | HASATTR_RIGHTORCENTER ) ) 220 { 221 // If the range contains (logically) right- or center-aligned cells, 222 // or rotated cells, set SC_PF_WHOLEROWS to paint the whole rows. 223 // This test isn't needed after the cell changes, because it's also 224 // tested in PostPaint. UpdatePaintExt may later be changed to do this 225 // only if called before the changes. 226 227 rExtFlags |= SC_PF_WHOLEROWS; 228 } 229 } 230 231 void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, 232 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab ) 233 { 234 UpdatePaintExt( rExtFlags, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) ); 235 } 236 237 //------------------------------------------------------------------ 238 239 void ScDocShell::LockPaint_Impl(sal_Bool bDoc) 240 { 241 if ( !pPaintLockData ) 242 pPaintLockData = new ScPaintLockData(0); //! Modus... 243 pPaintLockData->IncLevel(bDoc); 244 } 245 246 void ScDocShell::UnlockPaint_Impl(sal_Bool bDoc) 247 { 248 if ( pPaintLockData ) 249 { 250 if ( pPaintLockData->GetLevel(bDoc) ) 251 pPaintLockData->DecLevel(bDoc); 252 if (!pPaintLockData->GetLevel(!bDoc) && !pPaintLockData->GetLevel(bDoc)) 253 { 254 // Paint jetzt ausfuehren 255 256 ScPaintLockData* pPaint = pPaintLockData; 257 pPaintLockData = NULL; // nicht weitersammeln 258 259 ScRangeListRef xRangeList = pPaint->GetRangeList(); 260 if (xRangeList) 261 { 262 sal_uInt16 nParts = pPaint->GetParts(); 263 sal_uLong nCount = xRangeList->Count(); 264 for ( sal_uLong i=0; i<nCount; i++ ) 265 { 266 //! nExtFlags ??? 267 ScRange aRange = *xRangeList->GetObject(i); 268 PostPaint( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), 269 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), 270 nParts ); 271 } 272 } 273 274 if ( pPaint->GetModified() ) 275 SetDocumentModified(); 276 277 delete pPaint; 278 } 279 } 280 else 281 { 282 DBG_ERROR("UnlockPaint ohne LockPaint"); 283 } 284 } 285 286 void ScDocShell::LockDocument_Impl(sal_uInt16 nNew) 287 { 288 if (!nDocumentLock) 289 { 290 ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); 291 if (pDrawLayer) 292 pDrawLayer->setLock(sal_True); 293 } 294 nDocumentLock = nNew; 295 } 296 297 void ScDocShell::UnlockDocument_Impl(sal_uInt16 nNew) 298 { 299 nDocumentLock = nNew; 300 if (!nDocumentLock) 301 { 302 ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); 303 if (pDrawLayer) 304 pDrawLayer->setLock(sal_False); 305 } 306 } 307 308 sal_uInt16 ScDocShell::GetLockCount() const 309 { 310 return nDocumentLock; 311 } 312 313 void ScDocShell::SetLockCount(sal_uInt16 nNew) 314 { 315 if (nNew) // setzen 316 { 317 if ( !pPaintLockData ) 318 pPaintLockData = new ScPaintLockData(0); //! Modus... 319 pPaintLockData->SetLevel(nNew-1, sal_True); 320 LockDocument_Impl(nNew); 321 } 322 else if (pPaintLockData) // loeschen 323 { 324 pPaintLockData->SetLevel(0, sal_True); // bei Unlock sofort ausfuehren 325 UnlockPaint_Impl(sal_True); // jetzt 326 UnlockDocument_Impl(0); 327 } 328 } 329 330 void ScDocShell::LockPaint() 331 { 332 LockPaint_Impl(sal_False); 333 } 334 335 void ScDocShell::UnlockPaint() 336 { 337 UnlockPaint_Impl(sal_False); 338 } 339 340 void ScDocShell::LockDocument() 341 { 342 LockPaint_Impl(sal_True); 343 LockDocument_Impl(nDocumentLock + 1); 344 } 345 346 void ScDocShell::UnlockDocument() 347 { 348 if (nDocumentLock) 349 { 350 UnlockPaint_Impl(sal_True); 351 UnlockDocument_Impl(nDocumentLock - 1); 352 } 353 else 354 { 355 DBG_ERROR("UnlockDocument without LockDocument"); 356 } 357 } 358 359 //------------------------------------------------------------------ 360 361 void ScDocShell::SetInplace( sal_Bool bInplace ) 362 { 363 if (bIsInplace != bInplace) 364 { 365 bIsInplace = bInplace; 366 CalcOutputFactor(); 367 } 368 } 369 370 void ScDocShell::CalcOutputFactor() 371 { 372 if (bIsInplace) 373 { 374 nPrtToScreenFactor = 1.0; // passt sonst nicht zur inaktiven Darstellung 375 return; 376 } 377 378 sal_Bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg(); 379 if (bTextWysiwyg) 380 { 381 nPrtToScreenFactor = 1.0; 382 return; 383 } 384 385 String aTestString = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( 386 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789" )); 387 long nPrinterWidth = 0; 388 long nWindowWidth = 0; 389 const ScPatternAttr* pPattern = (const ScPatternAttr*)&aDocument.GetPool()-> 390 GetDefaultItem(ATTR_PATTERN); 391 392 Font aDefFont; 393 OutputDevice* pRefDev = GetRefDevice(); 394 MapMode aOldMode = pRefDev->GetMapMode(); 395 Font aOldFont = pRefDev->GetFont(); 396 397 pRefDev->SetMapMode(MAP_PIXEL); 398 pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, pRefDev); // font color doesn't matter here 399 pRefDev->SetFont(aDefFont); 400 nPrinterWidth = pRefDev->PixelToLogic( Size( pRefDev->GetTextWidth(aTestString), 0 ), MAP_100TH_MM ).Width(); 401 pRefDev->SetFont(aOldFont); 402 pRefDev->SetMapMode(aOldMode); 403 404 VirtualDevice aVirtWindow( *Application::GetDefaultDevice() ); 405 aVirtWindow.SetMapMode(MAP_PIXEL); 406 pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, &aVirtWindow); // font color doesn't matter here 407 aVirtWindow.SetFont(aDefFont); 408 nWindowWidth = aVirtWindow.GetTextWidth(aTestString); 409 nWindowWidth = (long) ( nWindowWidth / ScGlobal::nScreenPPTX * HMM_PER_TWIPS ); 410 411 if (nPrinterWidth && nWindowWidth) 412 nPrtToScreenFactor = nPrinterWidth / (double) nWindowWidth; 413 else 414 { 415 DBG_ERROR("GetTextSize gibt 0 ??"); 416 nPrtToScreenFactor = 1.0; 417 } 418 } 419 420 double ScDocShell::GetOutputFactor() const 421 { 422 return nPrtToScreenFactor; 423 } 424 425 //--------------------------------------------------------------------- 426 427 void ScDocShell::InitOptions(bool bForLoading) // called from InitNew and Load 428 { 429 // Einstellungen aus dem SpellCheckCfg kommen in Doc- und ViewOptions 430 431 sal_uInt16 nDefLang, nCjkLang, nCtlLang; 432 sal_Bool bAutoSpell; 433 ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang, bAutoSpell ); 434 ScModule* pScMod = SC_MOD(); 435 436 ScDocOptions aDocOpt = pScMod->GetDocOptions(); 437 ScViewOptions aViewOpt = pScMod->GetViewOptions(); 438 aDocOpt.SetAutoSpell( bAutoSpell ); 439 440 // zweistellige Jahreszahleneingabe aus Extras->Optionen->Allgemein->Sonstiges 441 aDocOpt.SetYear2000( sal::static_int_cast<sal_uInt16>( ::utl::MiscCfg().GetYear2000() ) ); 442 443 if (bForLoading) 444 { 445 // #i112123# No style:decimal-places attribute means automatic decimals, not the configured default, 446 // so it must not be taken from the global options. 447 // Calculation settings are handled separately in ScXMLBodyContext::EndElement. 448 aDocOpt.SetStdPrecision( SvNumberFormatter::UNLIMITED_PRECISION ); 449 } 450 451 aDocument.SetDocOptions( aDocOpt ); 452 aDocument.SetViewOptions( aViewOpt ); 453 454 // Druck-Optionen werden jetzt direkt vor dem Drucken gesetzt 455 456 aDocument.SetLanguage( (LanguageType) nDefLang, (LanguageType) nCjkLang, (LanguageType) nCtlLang ); 457 } 458 459 //--------------------------------------------------------------------- 460 461 Printer* ScDocShell::GetDocumentPrinter() // fuer OLE 462 { 463 return aDocument.GetPrinter(); 464 } 465 466 SfxPrinter* ScDocShell::GetPrinter(sal_Bool bCreateIfNotExist) 467 { 468 return aDocument.GetPrinter(bCreateIfNotExist); 469 } 470 471 void ScDocShell::UpdateFontList() 472 { 473 delete pImpl->pFontList; 474 // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() ); 475 pImpl->pFontList = new FontList( GetRefDevice(), NULL, sal_False ); // sal_False or sal_True??? 476 SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST ); 477 PutItem( aFontListItem ); 478 479 CalcOutputFactor(); 480 } 481 482 OutputDevice* ScDocShell::GetRefDevice() 483 { 484 return aDocument.GetRefDevice(); 485 } 486 487 sal_uInt16 ScDocShell::SetPrinter( SfxPrinter* pNewPrinter, sal_uInt16 nDiffFlags ) 488 { 489 SfxPrinter *pOld = aDocument.GetPrinter( sal_False ); 490 if ( pOld && pOld->IsPrinting() ) 491 return SFX_PRINTERROR_BUSY; 492 493 if (nDiffFlags & SFX_PRINTER_PRINTER) 494 { 495 if ( aDocument.GetPrinter() != pNewPrinter ) 496 { 497 aDocument.SetPrinter( pNewPrinter ); 498 aDocument.SetPrintOptions(); 499 500 // MT: Use UpdateFontList: Will use Printer fonts only if needed! 501 /* 502 delete pImpl->pFontList; 503 pImpl->pFontList = new FontList( pNewPrinter, Application::GetDefaultDevice() ); 504 SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST ); 505 PutItem( aFontListItem ); 506 507 CalcOutputFactor(); 508 */ 509 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() ) 510 UpdateFontList(); 511 512 ScModule* pScMod = SC_MOD(); 513 SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this ); 514 while (pFrame) 515 { 516 SfxViewShell* pSh = pFrame->GetViewShell(); 517 if (pSh && pSh->ISA(ScTabViewShell)) 518 { 519 ScTabViewShell* pViewSh = (ScTabViewShell*)pSh; 520 ScInputHandler* pInputHdl = pScMod->GetInputHdl(pViewSh); 521 if (pInputHdl) 522 pInputHdl->UpdateRefDevice(); 523 } 524 pFrame = SfxViewFrame::GetNext( *pFrame, this ); 525 } 526 } 527 } 528 else if (nDiffFlags & SFX_PRINTER_JOBSETUP) 529 { 530 SfxPrinter* pOldPrinter = aDocument.GetPrinter(); 531 if (pOldPrinter) 532 { 533 pOldPrinter->SetJobSetup( pNewPrinter->GetJobSetup() ); 534 535 // #i6706# Call SetPrinter with the old printer again, so the drawing layer 536 // RefDevice is set (calling ReformatAllTextObjects and rebuilding charts), 537 // because the JobSetup (printer device settings) may affect text layout. 538 aDocument.SetPrinter( pOldPrinter ); 539 CalcOutputFactor(); // also with the new settings 540 } 541 } 542 543 if (nDiffFlags & SFX_PRINTER_OPTIONS) 544 { 545 aDocument.SetPrintOptions(); //! aus neuem Printer ??? 546 } 547 548 if (nDiffFlags & (SFX_PRINTER_CHG_ORIENTATION | SFX_PRINTER_CHG_SIZE)) 549 { 550 String aStyle = aDocument.GetPageStyle( GetCurTab() ); 551 ScStyleSheetPool* pStPl = aDocument.GetStyleSheetPool(); 552 SfxStyleSheet* pStyleSheet = (SfxStyleSheet*)pStPl->Find(aStyle, SFX_STYLE_FAMILY_PAGE); 553 if (pStyleSheet) 554 { 555 SfxItemSet& rSet = pStyleSheet->GetItemSet(); 556 557 if (nDiffFlags & SFX_PRINTER_CHG_ORIENTATION) 558 { 559 const SvxPageItem& rOldItem = (const SvxPageItem&)rSet.Get(ATTR_PAGE); 560 sal_Bool bWasLand = rOldItem.IsLandscape(); 561 sal_Bool bNewLand = ( pNewPrinter->GetOrientation() == ORIENTATION_LANDSCAPE ); 562 if (bNewLand != bWasLand) 563 { 564 SvxPageItem aNewItem( rOldItem ); 565 aNewItem.SetLandscape( bNewLand ); 566 rSet.Put( aNewItem ); 567 568 // Groesse umdrehen 569 Size aOldSize = ((const SvxSizeItem&)rSet.Get(ATTR_PAGE_SIZE)).GetSize(); 570 Size aNewSize(aOldSize.Height(),aOldSize.Width()); 571 SvxSizeItem aNewSItem(ATTR_PAGE_SIZE,aNewSize); 572 rSet.Put( aNewSItem ); 573 } 574 } 575 if (nDiffFlags & SFX_PRINTER_CHG_SIZE) 576 { 577 SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(pNewPrinter) ); 578 rSet.Put( aPaperSizeItem ); 579 } 580 } 581 } 582 583 PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB,PAINT_ALL); 584 585 return 0; 586 } 587 588 //--------------------------------------------------------------------- 589 590 ScChangeAction* ScDocShell::GetChangeAction( const ScAddress& rPos ) 591 { 592 ScChangeTrack* pTrack = GetDocument()->GetChangeTrack(); 593 if (!pTrack) 594 return NULL; 595 596 SCTAB nTab = rPos.Tab(); 597 598 const ScChangeAction* pFound = NULL; 599 const ScChangeAction* pFoundContent = NULL; 600 const ScChangeAction* pFoundMove = NULL; 601 long nModified = 0; 602 const ScChangeAction* pAction = pTrack->GetFirst(); 603 while (pAction) 604 { 605 ScChangeActionType eType = pAction->GetType(); 606 //! ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc )... 607 if ( pAction->IsVisible() && eType != SC_CAT_DELETE_TABS ) 608 { 609 const ScBigRange& rBig = pAction->GetBigRange(); 610 if ( rBig.aStart.Tab() == nTab ) 611 { 612 ScRange aRange = rBig.MakeRange(); 613 614 if ( eType == SC_CAT_DELETE_ROWS ) 615 aRange.aEnd.SetRow( aRange.aStart.Row() ); 616 else if ( eType == SC_CAT_DELETE_COLS ) 617 aRange.aEnd.SetCol( aRange.aStart.Col() ); 618 619 if ( aRange.In( rPos ) ) 620 { 621 pFound = pAction; // der letzte gewinnt 622 switch ( pAction->GetType() ) 623 { 624 case SC_CAT_CONTENT : 625 pFoundContent = pAction; 626 break; 627 case SC_CAT_MOVE : 628 pFoundMove = pAction; 629 break; 630 default: 631 { 632 // added to avoid warnings 633 } 634 } 635 ++nModified; 636 } 637 } 638 if ( pAction->GetType() == SC_CAT_MOVE ) 639 { 640 ScRange aRange = 641 ((const ScChangeActionMove*)pAction)-> 642 GetFromRange().MakeRange(); 643 if ( aRange.In( rPos ) ) 644 { 645 pFound = pAction; 646 ++nModified; 647 } 648 } 649 } 650 pAction = pAction->GetNext(); 651 } 652 653 return (ScChangeAction*)pFound; 654 } 655 656 void ScDocShell::SetChangeComment( ScChangeAction* pAction, const String& rComment ) 657 { 658 if (pAction) 659 { 660 pAction->SetComment( rComment ); 661 //! Undo ??? 662 SetDocumentModified(); 663 664 // Dialog-Notify 665 ScChangeTrack* pTrack = GetDocument()->GetChangeTrack(); 666 if (pTrack) 667 { 668 sal_uLong nNumber = pAction->GetActionNumber(); 669 pTrack->NotifyModified( SC_CTM_CHANGE, nNumber, nNumber ); 670 } 671 } 672 } 673 674 void ScDocShell::ExecuteChangeCommentDialog( ScChangeAction* pAction, Window* pParent,sal_Bool bPrevNext) 675 { 676 if (!pAction) return; // ohne Aktion ist nichts.. 677 678 String aComment = pAction->GetComment(); 679 String aAuthor = pAction->GetUser(); 680 681 DateTime aDT = pAction->GetDateTime(); 682 String aDate = ScGlobal::pLocaleData->getDate( aDT ); 683 aDate += ' '; 684 aDate += ScGlobal::pLocaleData->getTime( aDT, sal_False, sal_False ); 685 686 SfxItemSet aSet( GetPool(), 687 SID_ATTR_POSTIT_AUTHOR, SID_ATTR_POSTIT_AUTHOR, 688 SID_ATTR_POSTIT_DATE, SID_ATTR_POSTIT_DATE, 689 SID_ATTR_POSTIT_TEXT, SID_ATTR_POSTIT_TEXT, 690 0 ); 691 692 aSet.Put( SvxPostItTextItem ( aComment, SID_ATTR_POSTIT_TEXT ) ); 693 aSet.Put( SvxPostItAuthorItem( aAuthor, SID_ATTR_POSTIT_AUTHOR ) ); 694 aSet.Put( SvxPostItDateItem ( aDate, SID_ATTR_POSTIT_DATE ) ); 695 696 ScRedComDialog* pDlg = new ScRedComDialog( pParent, aSet,this,pAction,bPrevNext); 697 698 pDlg->Execute(); 699 700 delete pDlg; 701 } 702 703 //--------------------------------------------------------------------- 704 705 void ScDocShell::CompareDocument( ScDocument& rOtherDoc ) 706 { 707 ScChangeTrack* pTrack = aDocument.GetChangeTrack(); 708 if ( pTrack && pTrack->GetFirst() ) 709 { 710 //! Changes vorhanden -> Nachfrage ob geloescht werden soll 711 } 712 713 aDocument.EndChangeTracking(); 714 aDocument.StartChangeTracking(); 715 716 String aOldUser; 717 pTrack = aDocument.GetChangeTrack(); 718 if ( pTrack ) 719 { 720 aOldUser = pTrack->GetUser(); 721 722 // check if comparing to same document 723 724 String aThisFile; 725 const SfxMedium* pThisMed = GetMedium(); 726 if (pThisMed) 727 aThisFile = pThisMed->GetName(); 728 String aOtherFile; 729 SfxObjectShell* pOtherSh = rOtherDoc.GetDocumentShell(); 730 if (pOtherSh) 731 { 732 const SfxMedium* pOtherMed = pOtherSh->GetMedium(); 733 if (pOtherMed) 734 aOtherFile = pOtherMed->GetName(); 735 } 736 sal_Bool bSameDoc = ( aThisFile == aOtherFile && aThisFile.Len() ); 737 if ( !bSameDoc ) 738 { 739 // create change actions from comparing with the name of the user 740 // who last saved the document 741 // (only if comparing different documents) 742 743 using namespace ::com::sun::star; 744 uno::Reference<document::XDocumentPropertiesSupplier> xDPS( 745 GetModel(), uno::UNO_QUERY_THROW); 746 uno::Reference<document::XDocumentProperties> xDocProps( 747 xDPS->getDocumentProperties()); 748 DBG_ASSERT(xDocProps.is(), "no DocumentProperties"); 749 String aDocUser = xDocProps->getModifiedBy(); 750 751 if ( aDocUser.Len() ) 752 pTrack->SetUser( aDocUser ); 753 } 754 } 755 756 aDocument.CompareDocument( rOtherDoc ); 757 758 pTrack = aDocument.GetChangeTrack(); 759 if ( pTrack ) 760 pTrack->SetUser( aOldUser ); 761 762 PostPaintGridAll(); 763 SetDocumentModified(); 764 } 765 766 //--------------------------------------------------------------------- 767 // 768 // Merge (Aenderungen zusammenfuehren) 769 // 770 //--------------------------------------------------------------------- 771 772 inline sal_Bool lcl_Equal( const ScChangeAction* pA, const ScChangeAction* pB, sal_Bool bIgnore100Sec ) 773 { 774 return pA && pB && 775 pA->GetActionNumber() == pB->GetActionNumber() && 776 pA->GetType() == pB->GetType() && 777 pA->GetUser() == pB->GetUser() && 778 (bIgnore100Sec ? 779 pA->GetDateTimeUTC().IsEqualIgnore100Sec( pB->GetDateTimeUTC() ) : 780 pA->GetDateTimeUTC() == pB->GetDateTimeUTC()); 781 // State nicht vergleichen, falls eine alte Aenderung akzeptiert wurde 782 } 783 784 bool lcl_FindAction( ScDocument* pDoc, const ScChangeAction* pAction, ScDocument* pSearchDoc, const ScChangeAction* pFirstSearchAction, const ScChangeAction* pLastSearchAction, sal_Bool bIgnore100Sec ) 785 { 786 if ( !pDoc || !pAction || !pSearchDoc || !pFirstSearchAction || !pLastSearchAction ) 787 { 788 return false; 789 } 790 791 sal_uLong nLastSearchAction = pLastSearchAction->GetActionNumber(); 792 const ScChangeAction* pA = pFirstSearchAction; 793 while ( pA && pA->GetActionNumber() <= nLastSearchAction ) 794 { 795 if ( pAction->GetType() == pA->GetType() && 796 pAction->GetUser() == pA->GetUser() && 797 (bIgnore100Sec ? 798 pAction->GetDateTimeUTC().IsEqualIgnore100Sec( pA->GetDateTimeUTC() ) : 799 pAction->GetDateTimeUTC() == pA->GetDateTimeUTC() ) && 800 pAction->GetBigRange() == pA->GetBigRange() ) 801 { 802 String aActionDesc; 803 pAction->GetDescription( aActionDesc, pDoc, sal_True ); 804 String aADesc; 805 pA->GetDescription( aADesc, pSearchDoc, sal_True ); 806 if ( aActionDesc.Equals( aADesc ) ) 807 { 808 DBG_ERROR( "lcl_FindAction(): found equal action!" ); 809 return true; 810 } 811 } 812 pA = pA->GetNext(); 813 } 814 815 return false; 816 } 817 818 void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheckDuplicates, sal_uLong nOffset, ScChangeActionMergeMap* pMergeMap, bool bInverseMap ) 819 { 820 ScTabViewShell* pViewSh = GetBestViewShell( sal_False ); //! Funktionen an die DocShell 821 if (!pViewSh) 822 return; 823 824 ScChangeTrack* pSourceTrack = rOtherDoc.GetChangeTrack(); 825 if (!pSourceTrack) 826 return; //! nichts zu tun - Fehlermeldung? 827 828 ScChangeTrack* pThisTrack = aDocument.GetChangeTrack(); 829 if ( !pThisTrack ) 830 { // anschalten 831 aDocument.StartChangeTracking(); 832 pThisTrack = aDocument.GetChangeTrack(); 833 DBG_ASSERT(pThisTrack,"ChangeTracking nicht angeschaltet?"); 834 if ( !bShared ) 835 { 836 // #51138# visuelles RedLining einschalten 837 ScChangeViewSettings aChangeViewSet; 838 aChangeViewSet.SetShowChanges(sal_True); 839 aDocument.SetChangeViewSettings(aChangeViewSet); 840 } 841 } 842 843 // #97286# include 100th seconds in compare? 844 sal_Bool bIgnore100Sec = !pSourceTrack->IsTime100thSeconds() || 845 !pThisTrack->IsTime100thSeconds(); 846 847 // gemeinsame Ausgangsposition suchen 848 sal_uLong nFirstNewNumber = 0; 849 const ScChangeAction* pSourceAction = pSourceTrack->GetFirst(); 850 const ScChangeAction* pThisAction = pThisTrack->GetFirst(); 851 // skip identical actions 852 while ( lcl_Equal( pSourceAction, pThisAction, bIgnore100Sec ) ) 853 { 854 nFirstNewNumber = pSourceAction->GetActionNumber() + 1; 855 pSourceAction = pSourceAction->GetNext(); 856 pThisAction = pThisAction->GetNext(); 857 } 858 // pSourceAction und pThisAction zeigen jetzt auf die ersten "eigenen" Aktionen 859 // Die gemeinsamen Aktionen davor interessieren ueberhaupt nicht 860 861 //! Abfrage, ob die Dokumente vor dem Change-Tracking gleich waren !!! 862 863 864 const ScChangeAction* pFirstMergeAction = pSourceAction; 865 const ScChangeAction* pFirstSearchAction = pThisAction; 866 867 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 868 const ScChangeAction* pLastSearchAction = pThisTrack->GetLast(); 869 870 // MergeChangeData aus den folgenden Aktionen erzeugen 871 sal_uLong nNewActionCount = 0; 872 const ScChangeAction* pCount = pSourceAction; 873 while ( pCount ) 874 { 875 if ( bShared || !ScChangeTrack::MergeIgnore( *pCount, nFirstNewNumber ) ) 876 ++nNewActionCount; 877 pCount = pCount->GetNext(); 878 } 879 if (!nNewActionCount) 880 return; //! nichts zu tun - Fehlermeldung? 881 // ab hier kein return mehr 882 883 ScProgress aProgress( this, 884 String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("...")), 885 nNewActionCount ); 886 887 sal_uLong nLastMergeAction = pSourceTrack->GetLast()->GetActionNumber(); 888 // UpdateReference-Undo, gueltige Referenzen fuer den letzten gemeinsamen Zustand 889 pSourceTrack->MergePrepare( (ScChangeAction*) pFirstMergeAction, bShared ); 890 891 // MergeChangeData an alle noch folgenden Aktionen in diesem Dokument anpassen 892 // -> Referenzen gueltig fuer dieses Dokument 893 while ( pThisAction ) 894 { 895 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly 896 if ( !bShared || !ScChangeTrack::MergeIgnore( *pThisAction, nFirstNewNumber ) ) 897 { 898 ScChangeActionType eType = pThisAction->GetType(); 899 switch ( eType ) 900 { 901 case SC_CAT_INSERT_COLS : 902 case SC_CAT_INSERT_ROWS : 903 case SC_CAT_INSERT_TABS : 904 pSourceTrack->AppendInsert( pThisAction->GetBigRange().MakeRange() ); 905 break; 906 case SC_CAT_DELETE_COLS : 907 case SC_CAT_DELETE_ROWS : 908 case SC_CAT_DELETE_TABS : 909 { 910 const ScChangeActionDel* pDel = (const ScChangeActionDel*) pThisAction; 911 if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() ) 912 { // deleted Table enthaelt deleted Cols, die nicht 913 sal_uLong nStart, nEnd; 914 pSourceTrack->AppendDeleteRange( 915 pDel->GetOverAllRange().MakeRange(), NULL, nStart, nEnd ); 916 } 917 } 918 break; 919 case SC_CAT_MOVE : 920 { 921 const ScChangeActionMove* pMove = (const ScChangeActionMove*) pThisAction; 922 pSourceTrack->AppendMove( pMove->GetFromRange().MakeRange(), 923 pMove->GetBigRange().MakeRange(), NULL ); 924 } 925 break; 926 default: 927 { 928 // added to avoid warnings 929 } 930 } 931 } 932 pThisAction = pThisAction->GetNext(); 933 } 934 935 LockPaint(); // #i73877# no repainting after each action 936 937 // MergeChangeData in das aktuelle Dokument uebernehmen 938 sal_Bool bHasRejected = sal_False; 939 String aOldUser = pThisTrack->GetUser(); 940 pThisTrack->SetUseFixDateTime( sal_True ); 941 ScMarkData& rMarkData = pViewSh->GetViewData()->GetMarkData(); 942 ScMarkData aOldMarkData( rMarkData ); 943 pSourceAction = pFirstMergeAction; 944 while ( pSourceAction && pSourceAction->GetActionNumber() <= nLastMergeAction ) 945 { 946 bool bMergeAction = false; 947 if ( bShared ) 948 { 949 if ( !bCheckDuplicates || !lcl_FindAction( &rOtherDoc, pSourceAction, &aDocument, pFirstSearchAction, pLastSearchAction, bIgnore100Sec ) ) 950 { 951 bMergeAction = true; 952 } 953 } 954 else 955 { 956 if ( !ScChangeTrack::MergeIgnore( *pSourceAction, nFirstNewNumber ) ) 957 { 958 bMergeAction = true; 959 } 960 } 961 962 if ( bMergeAction ) 963 { 964 ScChangeActionType eSourceType = pSourceAction->GetType(); 965 if ( !bShared && pSourceAction->IsDeletedIn() ) 966 { 967 //! muss hier noch festgestellt werden, ob wirklich in 968 //! _diesem_ Dokument geloescht? 969 970 // liegt in einem Bereich, der in diesem Dokument geloescht wurde 971 // -> wird weggelassen 972 //! ??? Loesch-Aktion rueckgaengig machen ??? 973 //! ??? Aktion irgendwo anders speichern ??? 974 #ifdef DBG_UTIL 975 String aValue; 976 if ( eSourceType == SC_CAT_CONTENT ) 977 ((const ScChangeActionContent*)pSourceAction)->GetNewString( aValue ); 978 ByteString aError( aValue, gsl_getSystemTextEncoding() ); 979 aError += " weggelassen"; 980 DBG_ERROR( aError.GetBuffer() ); 981 #endif 982 } 983 else 984 { 985 //! Datum/Autor/Kommentar der Source-Aktion uebernehmen! 986 987 pThisTrack->SetUser( pSourceAction->GetUser() ); 988 pThisTrack->SetFixDateTimeUTC( pSourceAction->GetDateTimeUTC() ); 989 sal_uLong nOldActionMax = pThisTrack->GetActionMax(); 990 991 bool bExecute = true; 992 sal_uLong nReject = pSourceAction->GetRejectAction(); 993 if ( nReject ) 994 { 995 if ( bShared ) 996 { 997 if ( nReject >= nFirstNewNumber ) 998 { 999 nReject += nOffset; 1000 } 1001 ScChangeAction* pOldAction = pThisTrack->GetAction( nReject ); 1002 if ( pOldAction && pOldAction->IsVirgin() ) 1003 { 1004 pThisTrack->Reject( pOldAction ); 1005 bHasRejected = sal_True; 1006 bExecute = false; 1007 } 1008 } 1009 else 1010 { 1011 // alte Aktion (aus den gemeinsamen) ablehnen 1012 ScChangeAction* pOldAction = pThisTrack->GetAction( nReject ); 1013 if (pOldAction && pOldAction->GetState() == SC_CAS_VIRGIN) 1014 { 1015 //! was passiert bei Aktionen, die in diesem Dokument accepted worden sind??? 1016 //! Fehlermeldung oder was??? 1017 //! oder Reject-Aenderung normal ausfuehren 1018 1019 pThisTrack->Reject(pOldAction); 1020 bHasRejected = sal_True; // fuer Paint 1021 } 1022 bExecute = false; 1023 } 1024 } 1025 1026 if ( bExecute ) 1027 { 1028 // normal ausfuehren 1029 ScRange aSourceRange = pSourceAction->GetBigRange().MakeRange(); 1030 rMarkData.SelectOneTable( aSourceRange.aStart.Tab() ); 1031 switch ( eSourceType ) 1032 { 1033 case SC_CAT_CONTENT: 1034 { 1035 //! Test, ob es ganz unten im Dokument war, dann automatisches 1036 //! Zeilen-Einfuegen ??? 1037 1038 DBG_ASSERT( aSourceRange.aStart == aSourceRange.aEnd, "huch?" ); 1039 ScAddress aPos = aSourceRange.aStart; 1040 String aValue; 1041 ((const ScChangeActionContent*)pSourceAction)->GetNewString( aValue ); 1042 sal_uInt8 eMatrix = MM_NONE; 1043 const ScBaseCell* pCell = ((const ScChangeActionContent*)pSourceAction)->GetNewCell(); 1044 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 1045 eMatrix = ((const ScFormulaCell*)pCell)->GetMatrixFlag(); 1046 switch ( eMatrix ) 1047 { 1048 case MM_NONE : 1049 pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue ); 1050 break; 1051 case MM_FORMULA : 1052 { 1053 SCCOL nCols; 1054 SCROW nRows; 1055 ((const ScFormulaCell*)pCell)->GetMatColsRows( nCols, nRows ); 1056 aSourceRange.aEnd.SetCol( aPos.Col() + nCols - 1 ); 1057 aSourceRange.aEnd.SetRow( aPos.Row() + nRows - 1 ); 1058 aValue.Erase( 0, 1 ); 1059 aValue.Erase( aValue.Len()-1, 1 ); 1060 GetDocFunc().EnterMatrix( aSourceRange, 1061 NULL, NULL, aValue, sal_False, sal_False, 1062 EMPTY_STRING, formula::FormulaGrammar::GRAM_DEFAULT ); 1063 } 1064 break; 1065 case MM_REFERENCE : // do nothing 1066 break; 1067 case MM_FAKE : 1068 DBG_WARNING( "MergeDocument: MatrixFlag MM_FAKE" ); 1069 pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue ); 1070 break; 1071 default: 1072 DBG_ERROR( "MergeDocument: unknown MatrixFlag" ); 1073 } 1074 } 1075 break; 1076 case SC_CAT_INSERT_TABS : 1077 { 1078 String aName; 1079 aDocument.CreateValidTabName( aName ); 1080 GetDocFunc().InsertTable( aSourceRange.aStart.Tab(), aName, sal_True, sal_False ); 1081 } 1082 break; 1083 case SC_CAT_INSERT_ROWS: 1084 GetDocFunc().InsertCells( aSourceRange, NULL, INS_INSROWS, sal_True, sal_False ); 1085 break; 1086 case SC_CAT_INSERT_COLS: 1087 GetDocFunc().InsertCells( aSourceRange, NULL, INS_INSCOLS, sal_True, sal_False ); 1088 break; 1089 case SC_CAT_DELETE_TABS : 1090 GetDocFunc().DeleteTable( aSourceRange.aStart.Tab(), sal_True, sal_False ); 1091 break; 1092 case SC_CAT_DELETE_ROWS: 1093 { 1094 const ScChangeActionDel* pDel = (const ScChangeActionDel*) pSourceAction; 1095 if ( pDel->IsTopDelete() ) 1096 { 1097 aSourceRange = pDel->GetOverAllRange().MakeRange(); 1098 GetDocFunc().DeleteCells( aSourceRange, NULL, DEL_DELROWS, sal_True, sal_False ); 1099 1100 // #i101099# [Collaboration] Changes are not correctly shown 1101 if ( bShared ) 1102 { 1103 ScChangeAction* pAct = pThisTrack->GetLast(); 1104 if ( pAct && pAct->GetType() == eSourceType && pAct->IsDeletedIn() && !pSourceAction->IsDeletedIn() ) 1105 { 1106 pAct->RemoveAllDeletedIn(); 1107 } 1108 } 1109 } 1110 } 1111 break; 1112 case SC_CAT_DELETE_COLS: 1113 { 1114 const ScChangeActionDel* pDel = (const ScChangeActionDel*) pSourceAction; 1115 if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() ) 1116 { // deleted Table enthaelt deleted Cols, die nicht 1117 aSourceRange = pDel->GetOverAllRange().MakeRange(); 1118 GetDocFunc().DeleteCells( aSourceRange, NULL, DEL_DELCOLS, sal_True, sal_False ); 1119 } 1120 } 1121 break; 1122 case SC_CAT_MOVE : 1123 { 1124 const ScChangeActionMove* pMove = (const ScChangeActionMove*) pSourceAction; 1125 ScRange aFromRange( pMove->GetFromRange().MakeRange() ); 1126 GetDocFunc().MoveBlock( aFromRange, 1127 aSourceRange.aStart, sal_True, sal_True, sal_False, sal_False ); 1128 } 1129 break; 1130 default: 1131 { 1132 // added to avoid warnings 1133 } 1134 } 1135 } 1136 const String& rComment = pSourceAction->GetComment(); 1137 if ( rComment.Len() ) 1138 { 1139 ScChangeAction* pAct = pThisTrack->GetLast(); 1140 if ( pAct && pAct->GetActionNumber() > nOldActionMax ) 1141 pAct->SetComment( rComment ); 1142 #ifdef DBG_UTIL 1143 else 1144 DBG_ERROR( "MergeDocument: wohin mit dem Kommentar?!?" ); 1145 #endif 1146 } 1147 1148 // Referenzen anpassen 1149 pSourceTrack->MergeOwn( (ScChangeAction*) pSourceAction, nFirstNewNumber, bShared ); 1150 1151 // merge action state 1152 if ( bShared && !pSourceAction->IsRejected() ) 1153 { 1154 ScChangeAction* pAct = pThisTrack->GetLast(); 1155 if ( pAct && pAct->GetActionNumber() > nOldActionMax ) 1156 { 1157 pThisTrack->MergeActionState( pAct, pSourceAction ); 1158 } 1159 } 1160 1161 // fill merge map 1162 if ( bShared && pMergeMap ) 1163 { 1164 ScChangeAction* pAct = pThisTrack->GetLast(); 1165 if ( pAct && pAct->GetActionNumber() > nOldActionMax ) 1166 { 1167 sal_uLong nActionMax = pAct->GetActionNumber(); 1168 sal_uLong nActionCount = nActionMax - nOldActionMax; 1169 sal_uLong nAction = nActionMax - nActionCount + 1; 1170 sal_uLong nSourceAction = pSourceAction->GetActionNumber() - nActionCount + 1; 1171 while ( nAction <= nActionMax ) 1172 { 1173 if ( bInverseMap ) 1174 { 1175 (*pMergeMap)[ nAction++ ] = nSourceAction++; 1176 } 1177 else 1178 { 1179 (*pMergeMap)[ nSourceAction++ ] = nAction++; 1180 } 1181 } 1182 } 1183 } 1184 } 1185 aProgress.SetStateCountDown( --nNewActionCount ); 1186 } 1187 pSourceAction = pSourceAction->GetNext(); 1188 } 1189 1190 rMarkData = aOldMarkData; 1191 pThisTrack->SetUser(aOldUser); 1192 pThisTrack->SetUseFixDateTime( sal_False ); 1193 1194 pSourceTrack->Clear(); //! der ist jetzt verhunzt 1195 1196 if (bHasRejected) 1197 PostPaintGridAll(); // Reject() paintet nicht selber 1198 1199 UnlockPaint(); 1200 } 1201 1202 bool ScDocShell::MergeSharedDocument( ScDocShell* pSharedDocShell ) 1203 { 1204 if ( !pSharedDocShell ) 1205 { 1206 return false; 1207 } 1208 1209 ScChangeTrack* pThisTrack = aDocument.GetChangeTrack(); 1210 if ( !pThisTrack ) 1211 { 1212 return false; 1213 } 1214 1215 ScDocument& rSharedDoc = *( pSharedDocShell->GetDocument() ); 1216 ScChangeTrack* pSharedTrack = rSharedDoc.GetChangeTrack(); 1217 if ( !pSharedTrack ) 1218 { 1219 return false; 1220 } 1221 1222 #if DEBUG_CHANGETRACK 1223 ::rtl::OUString aMessage = ::rtl::OUString::createFromAscii( "\nbefore merge:\n" ); 1224 aMessage += pThisTrack->ToString(); 1225 ::rtl::OString aMsg = ::rtl::OUStringToOString( aMessage, RTL_TEXTENCODING_UTF8 ); 1226 OSL_ENSURE( false, aMsg.getStr() ); 1227 //fprintf( stdout, "%s ", aMsg.getStr() ); 1228 //fflush( stdout ); 1229 #endif // DEBUG_CHANGETRACK 1230 1231 // reset show changes 1232 ScChangeViewSettings aChangeViewSet; 1233 aChangeViewSet.SetShowChanges( sal_False ); 1234 aDocument.SetChangeViewSettings( aChangeViewSet ); 1235 1236 // find first merge action in this document 1237 sal_Bool bIgnore100Sec = !pThisTrack->IsTime100thSeconds() || !pSharedTrack->IsTime100thSeconds(); 1238 ScChangeAction* pThisAction = pThisTrack->GetFirst(); 1239 ScChangeAction* pSharedAction = pSharedTrack->GetFirst(); 1240 while ( lcl_Equal( pThisAction, pSharedAction, bIgnore100Sec ) ) 1241 { 1242 pThisAction = pThisAction->GetNext(); 1243 pSharedAction = pSharedAction->GetNext(); 1244 } 1245 1246 if ( pSharedAction ) 1247 { 1248 if ( pThisAction ) 1249 { 1250 // merge own changes into shared document 1251 sal_uLong nActStartShared = pSharedAction->GetActionNumber(); 1252 sal_uLong nActEndShared = pSharedTrack->GetActionMax(); 1253 ScDocument* pTmpDoc = new ScDocument; 1254 for ( sal_Int32 nIndex = 0; nIndex < aDocument.GetTableCount(); ++nIndex ) 1255 { 1256 String sTabName; 1257 pTmpDoc->CreateValidTabName( sTabName ); 1258 pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName ); 1259 } 1260 aDocument.GetChangeTrack()->Clone( pTmpDoc ); 1261 ScChangeActionMergeMap aOwnInverseMergeMap; 1262 pSharedDocShell->MergeDocument( *pTmpDoc, true, true, 0, &aOwnInverseMergeMap, true ); 1263 delete pTmpDoc; 1264 sal_uLong nActStartOwn = nActEndShared + 1; 1265 sal_uLong nActEndOwn = pSharedTrack->GetActionMax(); 1266 1267 // find conflicts 1268 ScConflictsList aConflictsList; 1269 ScConflictsFinder aFinder( pSharedTrack, nActStartShared, nActEndShared, nActStartOwn, nActEndOwn, aConflictsList ); 1270 if ( aFinder.Find() ) 1271 { 1272 ScConflictsListHelper::TransformConflictsList( aConflictsList, NULL, &aOwnInverseMergeMap ); 1273 bool bLoop = true; 1274 while ( bLoop ) 1275 { 1276 bLoop = false; 1277 ScConflictsDlg aDlg( GetActiveDialogParent(), GetViewData(), &rSharedDoc, aConflictsList ); 1278 if ( aDlg.Execute() == RET_CANCEL ) 1279 { 1280 QueryBox aBox( GetActiveDialogParent(), WinBits( WB_YES_NO | WB_DEF_YES ), 1281 ScGlobal::GetRscString( STR_DOC_WILLNOTBESAVED ) ); 1282 if ( aBox.Execute() == RET_YES ) 1283 { 1284 return false; 1285 } 1286 else 1287 { 1288 bLoop = true; 1289 } 1290 } 1291 } 1292 } 1293 1294 // undo own changes in shared document 1295 pSharedTrack->Undo( nActStartOwn, nActEndOwn ); 1296 1297 // clone change track for merging into own document 1298 pTmpDoc = new ScDocument; 1299 for ( sal_Int32 nIndex = 0; nIndex < aDocument.GetTableCount(); ++nIndex ) 1300 { 1301 String sTabName; 1302 pTmpDoc->CreateValidTabName( sTabName ); 1303 pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName ); 1304 } 1305 pThisTrack->Clone( pTmpDoc ); 1306 1307 // undo own changes since last save in own document 1308 sal_uLong nStartShared = pThisAction->GetActionNumber(); 1309 ScChangeAction* pAction = pThisTrack->GetLast(); 1310 while ( pAction && pAction->GetActionNumber() >= nStartShared ) 1311 { 1312 pThisTrack->Reject( pAction, true ); 1313 pAction = pAction->GetPrev(); 1314 } 1315 1316 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 1317 pThisTrack->Undo( nStartShared, pThisTrack->GetActionMax(), true ); 1318 1319 // merge shared changes into own document 1320 ScChangeActionMergeMap aSharedMergeMap; 1321 MergeDocument( rSharedDoc, true, true, 0, &aSharedMergeMap ); 1322 sal_uLong nEndShared = pThisTrack->GetActionMax(); 1323 1324 // resolve conflicts for shared non-content actions 1325 if ( !aConflictsList.empty() ) 1326 { 1327 ScConflictsListHelper::TransformConflictsList( aConflictsList, &aSharedMergeMap, NULL ); 1328 ScConflictsResolver aResolver( pThisTrack, aConflictsList ); 1329 pAction = pThisTrack->GetAction( nEndShared ); 1330 while ( pAction && pAction->GetActionNumber() >= nStartShared ) 1331 { 1332 aResolver.HandleAction( pAction, true /*bIsSharedAction*/, 1333 false /*bHandleContentAction*/, true /*bHandleNonContentAction*/ ); 1334 pAction = pAction->GetPrev(); 1335 } 1336 } 1337 nEndShared = pThisTrack->GetActionMax(); 1338 1339 // only show changes from shared document 1340 aChangeViewSet.SetShowChanges( sal_True ); 1341 aChangeViewSet.SetShowAccepted( sal_True ); 1342 aChangeViewSet.SetHasActionRange( true ); 1343 aChangeViewSet.SetTheActionRange( nStartShared, nEndShared ); 1344 aDocument.SetChangeViewSettings( aChangeViewSet ); 1345 1346 // merge own changes back into own document 1347 sal_uLong nStartOwn = nEndShared + 1; 1348 ScChangeActionMergeMap aOwnMergeMap; 1349 MergeDocument( *pTmpDoc, true, true, nEndShared - nStartShared + 1, &aOwnMergeMap ); 1350 delete pTmpDoc; 1351 sal_uLong nEndOwn = pThisTrack->GetActionMax(); 1352 1353 // resolve conflicts for shared content actions and own actions 1354 if ( !aConflictsList.empty() ) 1355 { 1356 ScConflictsListHelper::TransformConflictsList( aConflictsList, NULL, &aOwnMergeMap ); 1357 ScConflictsResolver aResolver( pThisTrack, aConflictsList ); 1358 pAction = pThisTrack->GetAction( nEndShared ); 1359 while ( pAction && pAction->GetActionNumber() >= nStartShared ) 1360 { 1361 aResolver.HandleAction( pAction, true /*bIsSharedAction*/, 1362 true /*bHandleContentAction*/, false /*bHandleNonContentAction*/ ); 1363 pAction = pAction->GetPrev(); 1364 } 1365 1366 pAction = pThisTrack->GetAction( nEndOwn ); 1367 while ( pAction && pAction->GetActionNumber() >= nStartOwn ) 1368 { 1369 aResolver.HandleAction( pAction, false /*bIsSharedAction*/, 1370 true /*bHandleContentAction*/, true /*bHandleNonContentAction*/ ); 1371 pAction = pAction->GetPrev(); 1372 } 1373 } 1374 nEndOwn = pThisTrack->GetActionMax(); 1375 } 1376 else 1377 { 1378 // merge shared changes into own document 1379 sal_uLong nStartShared = pThisTrack->GetActionMax() + 1; 1380 MergeDocument( rSharedDoc, true, true ); 1381 sal_uLong nEndShared = pThisTrack->GetActionMax(); 1382 1383 // only show changes from shared document 1384 aChangeViewSet.SetShowChanges( sal_True ); 1385 aChangeViewSet.SetShowAccepted( sal_True ); 1386 aChangeViewSet.SetHasActionRange( true ); 1387 aChangeViewSet.SetTheActionRange( nStartShared, nEndShared ); 1388 aDocument.SetChangeViewSettings( aChangeViewSet ); 1389 } 1390 1391 // update view 1392 PostPaintExtras(); 1393 PostPaintGridAll(); 1394 1395 InfoBox aInfoBox( GetActiveDialogParent(), ScGlobal::GetRscString( STR_DOC_UPDATED ) ); 1396 aInfoBox.Execute(); 1397 } 1398 1399 #if DEBUG_CHANGETRACK 1400 aMessage = ::rtl::OUString::createFromAscii( "\nafter merge:\n" ); 1401 aMessage += pThisTrack->ToString(); 1402 aMsg = ::rtl::OUStringToOString( aMessage, RTL_TEXTENCODING_UTF8 ); 1403 OSL_ENSURE( false, aMsg.getStr() ); 1404 //fprintf( stdout, "%s ", aMsg.getStr() ); 1405 //fflush( stdout ); 1406 #endif // DEBUG_CHANGETRACK 1407 1408 return ( pThisAction != NULL ); 1409 } 1410