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