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