| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| |
| |
| |
| // INCLUDE --------------------------------------------------------------- |
| |
| #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> |
| #include <com/sun/star/document/XDocumentProperties.hpp> |
| |
| #include "scitems.hxx" |
| #include "rangelst.hxx" |
| #include <editeng/flstitem.hxx> |
| #include <svx/pageitem.hxx> |
| #include <editeng/paperinf.hxx> |
| #include <svx/postattr.hxx> |
| #include <editeng/sizeitem.hxx> |
| #include <unotools/misccfg.hxx> |
| #include <sfx2/viewfrm.hxx> |
| #include <sfx2/app.hxx> |
| #include <sfx2/docfile.hxx> |
| #include <sfx2/printer.hxx> |
| #include <svtools/ctrltool.hxx> |
| #include <vcl/virdev.hxx> |
| #include <vcl/svapp.hxx> |
| #include <vcl/msgbox.hxx> |
| #include <unotools/localedatawrapper.hxx> |
| |
| #include "docsh.hxx" |
| #include "docshimp.hxx" |
| #include "scmod.hxx" |
| #include "tabvwsh.hxx" |
| #include "viewdata.hxx" |
| #include "docpool.hxx" |
| #include "stlpool.hxx" |
| #include "patattr.hxx" |
| #include "uiitems.hxx" |
| #include "hints.hxx" |
| #include "docoptio.hxx" |
| #include "viewopti.hxx" |
| #include "pntlock.hxx" |
| #include "chgtrack.hxx" |
| #include "docfunc.hxx" |
| #include "cell.hxx" |
| #include "chgviset.hxx" |
| #include "progress.hxx" |
| #include "redcom.hxx" |
| #include "sc.hrc" |
| #include "inputopt.hxx" |
| #include "drwlayer.hxx" |
| #include "inputhdl.hxx" |
| #include "conflictsdlg.hxx" |
| #include "globstr.hrc" |
| |
| #if DEBUG_CHANGETRACK |
| #include <stdio.h> |
| #endif // DEBUG_CHANGETRACK |
| |
| |
| //------------------------------------------------------------------ |
| |
| // |
| // Redraw - Benachrichtigungen |
| // |
| |
| |
| void ScDocShell::PostEditView( ScEditEngineDefaulter* pEditEngine, const ScAddress& rCursorPos ) |
| { |
| // Broadcast( ScEditViewHint( pEditEngine, rCursorPos ) ); |
| |
| // Test: nur aktive ViewShell |
| |
| ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); |
| if (pViewSh && pViewSh->GetViewData()->GetDocShell() == this) |
| { |
| ScEditViewHint aHint( pEditEngine, rCursorPos ); |
| pViewSh->Notify( *this, aHint ); |
| } |
| } |
| |
| void ScDocShell::PostDataChanged() |
| { |
| Broadcast( SfxSimpleHint( FID_DATACHANGED ) ); |
| aDocument.ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) ); |
| |
| SFX_APP()->Broadcast(SfxSimpleHint( FID_ANYDATACHANGED )); // Navigator |
| //! Navigator direkt benachrichtigen! |
| } |
| |
| void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, |
| SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, sal_uInt16 nPart, |
| sal_uInt16 nExtFlags ) |
| { |
| if (!ValidCol(nStartCol)) nStartCol = MAXCOL; |
| if (!ValidRow(nStartRow)) nStartRow = MAXROW; |
| if (!ValidCol(nEndCol)) nEndCol = MAXCOL; |
| if (!ValidRow(nEndRow)) nEndRow = MAXROW; |
| |
| if ( pPaintLockData ) |
| { |
| // #i54081# PAINT_EXTRAS still has to be brodcast because it changes the |
| // current sheet if it's invalid. All other flags added to pPaintLockData. |
| sal_uInt16 nLockPart = nPart & ~PAINT_EXTRAS; |
| if ( nLockPart ) |
| { |
| //! nExtFlags ??? |
| pPaintLockData->AddRange( ScRange( nStartCol, nStartRow, nStartTab, |
| nEndCol, nEndRow, nEndTab ), nLockPart ); |
| } |
| |
| nPart &= PAINT_EXTRAS; // for broadcasting |
| if ( !nPart ) |
| return; |
| } |
| |
| |
| if (nExtFlags & SC_PF_LINES) // Platz fuer Linien beruecksichtigen |
| { |
| //! Abfrage auf versteckte Spalten/Zeilen! |
| if (nStartCol>0) --nStartCol; |
| if (nEndCol<MAXCOL) ++nEndCol; |
| if (nStartRow>0) --nStartRow; |
| if (nEndRow<MAXROW) ++nEndRow; |
| } |
| |
| // um zusammengefasste erweitern |
| if (nExtFlags & SC_PF_TESTMERGE) |
| aDocument.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nStartTab ); |
| |
| if ( nStartCol != 0 || nEndCol != MAXCOL ) |
| { |
| // Extend to whole rows if SC_PF_WHOLEROWS is set, or rotated or non-left |
| // aligned cells are contained (see UpdatePaintExt). |
| // Special handling for RTL text (#i9731#) is unnecessary now with full |
| // support of right-aligned text. |
| |
| if ( ( nExtFlags & SC_PF_WHOLEROWS ) || |
| aDocument.HasAttrib( nStartCol,nStartRow,nStartTab, |
| MAXCOL,nEndRow,nEndTab, HASATTR_ROTATE | HASATTR_RIGHTORCENTER ) ) |
| { |
| nStartCol = 0; |
| nEndCol = MAXCOL; |
| } |
| } |
| |
| Broadcast( ScPaintHint( ScRange( nStartCol, nStartRow, nStartTab, |
| nEndCol, nEndRow, nEndTab ), nPart ) ); |
| |
| if ( nPart & PAINT_GRID ) |
| aDocument.ResetChanged( ScRange(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) ); |
| } |
| |
| void ScDocShell::PostPaint( const ScRange& rRange, sal_uInt16 nPart, sal_uInt16 nExtFlags ) |
| { |
| PostPaint( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(), |
| rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), |
| nPart, nExtFlags ); |
| } |
| |
| void ScDocShell::PostPaintGridAll() |
| { |
| PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID ); |
| } |
| |
| void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab ) |
| { |
| PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PAINT_GRID, SC_PF_TESTMERGE ); |
| } |
| |
| void ScDocShell::PostPaintCell( const ScAddress& rPos ) |
| { |
| PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab() ); |
| } |
| |
| void ScDocShell::PostPaintExtras() |
| { |
| PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS ); |
| } |
| |
| void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, const ScRange& rRange ) |
| { |
| if ( ( rExtFlags & SC_PF_LINES ) == 0 && aDocument.HasAttrib( rRange, HASATTR_PAINTEXT ) ) |
| { |
| // If the range contains lines, shadow or conditional formats, |
| // set SC_PF_LINES to include one extra cell in all directions. |
| |
| rExtFlags |= SC_PF_LINES; |
| } |
| |
| if ( ( rExtFlags & SC_PF_WHOLEROWS ) == 0 && |
| ( rRange.aStart.Col() != 0 || rRange.aEnd.Col() != MAXCOL ) && |
| aDocument.HasAttrib( rRange, HASATTR_ROTATE | HASATTR_RIGHTORCENTER ) ) |
| { |
| // If the range contains (logically) right- or center-aligned cells, |
| // or rotated cells, set SC_PF_WHOLEROWS to paint the whole rows. |
| // This test isn't needed after the cell changes, because it's also |
| // tested in PostPaint. UpdatePaintExt may later be changed to do this |
| // only if called before the changes. |
| |
| rExtFlags |= SC_PF_WHOLEROWS; |
| } |
| } |
| |
| void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, |
| SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab ) |
| { |
| UpdatePaintExt( rExtFlags, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) ); |
| } |
| |
| //------------------------------------------------------------------ |
| |
| void ScDocShell::LockPaint_Impl(sal_Bool bDoc) |
| { |
| if ( !pPaintLockData ) |
| pPaintLockData = new ScPaintLockData(0); //! Modus... |
| pPaintLockData->IncLevel(bDoc); |
| } |
| |
| void ScDocShell::UnlockPaint_Impl(sal_Bool bDoc) |
| { |
| if ( pPaintLockData ) |
| { |
| if ( pPaintLockData->GetLevel(bDoc) ) |
| pPaintLockData->DecLevel(bDoc); |
| if (!pPaintLockData->GetLevel(!bDoc) && !pPaintLockData->GetLevel(bDoc)) |
| { |
| // Paint jetzt ausfuehren |
| |
| ScPaintLockData* pPaint = pPaintLockData; |
| pPaintLockData = NULL; // nicht weitersammeln |
| |
| ScRangeListRef xRangeList = pPaint->GetRangeList(); |
| if (xRangeList) |
| { |
| sal_uInt16 nParts = pPaint->GetParts(); |
| sal_uLong nCount = xRangeList->Count(); |
| for ( sal_uLong i=0; i<nCount; i++ ) |
| { |
| //! nExtFlags ??? |
| ScRange aRange = *xRangeList->GetObject(i); |
| PostPaint( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), |
| aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), |
| nParts ); |
| } |
| } |
| |
| if ( pPaint->GetModified() ) |
| SetDocumentModified(); |
| |
| delete pPaint; |
| } |
| } |
| else |
| { |
| DBG_ERROR("UnlockPaint ohne LockPaint"); |
| } |
| } |
| |
| void ScDocShell::LockDocument_Impl(sal_uInt16 nNew) |
| { |
| if (!nDocumentLock) |
| { |
| ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); |
| if (pDrawLayer) |
| pDrawLayer->setLock(sal_True); |
| } |
| nDocumentLock = nNew; |
| } |
| |
| void ScDocShell::UnlockDocument_Impl(sal_uInt16 nNew) |
| { |
| nDocumentLock = nNew; |
| if (!nDocumentLock) |
| { |
| ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); |
| if (pDrawLayer) |
| pDrawLayer->setLock(sal_False); |
| } |
| } |
| |
| sal_uInt16 ScDocShell::GetLockCount() const |
| { |
| return nDocumentLock; |
| } |
| |
| void ScDocShell::SetLockCount(sal_uInt16 nNew) |
| { |
| if (nNew) // setzen |
| { |
| if ( !pPaintLockData ) |
| pPaintLockData = new ScPaintLockData(0); //! Modus... |
| pPaintLockData->SetLevel(nNew-1, sal_True); |
| LockDocument_Impl(nNew); |
| } |
| else if (pPaintLockData) // loeschen |
| { |
| pPaintLockData->SetLevel(0, sal_True); // bei Unlock sofort ausfuehren |
| UnlockPaint_Impl(sal_True); // jetzt |
| UnlockDocument_Impl(0); |
| } |
| } |
| |
| void ScDocShell::LockPaint() |
| { |
| LockPaint_Impl(sal_False); |
| } |
| |
| void ScDocShell::UnlockPaint() |
| { |
| UnlockPaint_Impl(sal_False); |
| } |
| |
| void ScDocShell::LockDocument() |
| { |
| LockPaint_Impl(sal_True); |
| LockDocument_Impl(nDocumentLock + 1); |
| } |
| |
| void ScDocShell::UnlockDocument() |
| { |
| if (nDocumentLock) |
| { |
| UnlockPaint_Impl(sal_True); |
| UnlockDocument_Impl(nDocumentLock - 1); |
| } |
| else |
| { |
| DBG_ERROR("UnlockDocument without LockDocument"); |
| } |
| } |
| |
| //------------------------------------------------------------------ |
| |
| void ScDocShell::SetInplace( sal_Bool bInplace ) |
| { |
| if (bIsInplace != bInplace) |
| { |
| bIsInplace = bInplace; |
| CalcOutputFactor(); |
| } |
| } |
| |
| void ScDocShell::CalcOutputFactor() |
| { |
| if (bIsInplace) |
| { |
| nPrtToScreenFactor = 1.0; // passt sonst nicht zur inaktiven Darstellung |
| return; |
| } |
| |
| sal_Bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg(); |
| if (bTextWysiwyg) |
| { |
| nPrtToScreenFactor = 1.0; |
| return; |
| } |
| |
| String aTestString = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789" )); |
| long nPrinterWidth = 0; |
| long nWindowWidth = 0; |
| const ScPatternAttr* pPattern = (const ScPatternAttr*)&aDocument.GetPool()-> |
| GetDefaultItem(ATTR_PATTERN); |
| |
| Font aDefFont; |
| OutputDevice* pRefDev = GetRefDevice(); |
| MapMode aOldMode = pRefDev->GetMapMode(); |
| Font aOldFont = pRefDev->GetFont(); |
| |
| pRefDev->SetMapMode(MAP_PIXEL); |
| pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, pRefDev); // font color doesn't matter here |
| pRefDev->SetFont(aDefFont); |
| nPrinterWidth = pRefDev->PixelToLogic( Size( pRefDev->GetTextWidth(aTestString), 0 ), MAP_100TH_MM ).Width(); |
| pRefDev->SetFont(aOldFont); |
| pRefDev->SetMapMode(aOldMode); |
| |
| VirtualDevice aVirtWindow( *Application::GetDefaultDevice() ); |
| aVirtWindow.SetMapMode(MAP_PIXEL); |
| pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, &aVirtWindow); // font color doesn't matter here |
| aVirtWindow.SetFont(aDefFont); |
| nWindowWidth = aVirtWindow.GetTextWidth(aTestString); |
| nWindowWidth = (long) ( nWindowWidth / ScGlobal::nScreenPPTX * HMM_PER_TWIPS ); |
| |
| if (nPrinterWidth && nWindowWidth) |
| nPrtToScreenFactor = nPrinterWidth / (double) nWindowWidth; |
| else |
| { |
| DBG_ERROR("GetTextSize gibt 0 ??"); |
| nPrtToScreenFactor = 1.0; |
| } |
| } |
| |
| double ScDocShell::GetOutputFactor() const |
| { |
| return nPrtToScreenFactor; |
| } |
| |
| //--------------------------------------------------------------------- |
| |
| void ScDocShell::InitOptions(bool bForLoading) // called from InitNew and Load |
| { |
| // Einstellungen aus dem SpellCheckCfg kommen in Doc- und ViewOptions |
| |
| sal_uInt16 nDefLang, nCjkLang, nCtlLang; |
| sal_Bool bAutoSpell; |
| ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang, bAutoSpell ); |
| ScModule* pScMod = SC_MOD(); |
| |
| ScDocOptions aDocOpt = pScMod->GetDocOptions(); |
| ScViewOptions aViewOpt = pScMod->GetViewOptions(); |
| aDocOpt.SetAutoSpell( bAutoSpell ); |
| |
| // zweistellige Jahreszahleneingabe aus Extras->Optionen->Allgemein->Sonstiges |
| aDocOpt.SetYear2000( sal::static_int_cast<sal_uInt16>( ::utl::MiscCfg().GetYear2000() ) ); |
| |
| if (bForLoading) |
| { |
| // #i112123# No style:decimal-places attribute means automatic decimals, not the configured default, |
| // so it must not be taken from the global options. |
| // Calculation settings are handled separately in ScXMLBodyContext::EndElement. |
| aDocOpt.SetStdPrecision( SvNumberFormatter::UNLIMITED_PRECISION ); |
| } |
| |
| aDocument.SetDocOptions( aDocOpt ); |
| aDocument.SetViewOptions( aViewOpt ); |
| |
| // Druck-Optionen werden jetzt direkt vor dem Drucken gesetzt |
| |
| aDocument.SetLanguage( (LanguageType) nDefLang, (LanguageType) nCjkLang, (LanguageType) nCtlLang ); |
| } |
| |
| //--------------------------------------------------------------------- |
| |
| Printer* ScDocShell::GetDocumentPrinter() // fuer OLE |
| { |
| return aDocument.GetPrinter(); |
| } |
| |
| SfxPrinter* ScDocShell::GetPrinter(sal_Bool bCreateIfNotExist) |
| { |
| return aDocument.GetPrinter(bCreateIfNotExist); |
| } |
| |
| void ScDocShell::UpdateFontList() |
| { |
| delete pImpl->pFontList; |
| // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() ); |
| pImpl->pFontList = new FontList( GetRefDevice(), NULL, sal_False ); // sal_False or sal_True??? |
| SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST ); |
| PutItem( aFontListItem ); |
| |
| CalcOutputFactor(); |
| } |
| |
| OutputDevice* ScDocShell::GetRefDevice() |
| { |
| return aDocument.GetRefDevice(); |
| } |
| |
| sal_uInt16 ScDocShell::SetPrinter( SfxPrinter* pNewPrinter, sal_uInt16 nDiffFlags ) |
| { |
| SfxPrinter *pOld = aDocument.GetPrinter( sal_False ); |
| if ( pOld && pOld->IsPrinting() ) |
| return SFX_PRINTERROR_BUSY; |
| |
| if (nDiffFlags & SFX_PRINTER_PRINTER) |
| { |
| if ( aDocument.GetPrinter() != pNewPrinter ) |
| { |
| aDocument.SetPrinter( pNewPrinter ); |
| aDocument.SetPrintOptions(); |
| |
| // MT: Use UpdateFontList: Will use Printer fonts only if needed! |
| /* |
| delete pImpl->pFontList; |
| pImpl->pFontList = new FontList( pNewPrinter, Application::GetDefaultDevice() ); |
| SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST ); |
| PutItem( aFontListItem ); |
| |
| CalcOutputFactor(); |
| */ |
| if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() ) |
| UpdateFontList(); |
| |
| ScModule* pScMod = SC_MOD(); |
| SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this ); |
| while (pFrame) |
| { |
| SfxViewShell* pSh = pFrame->GetViewShell(); |
| if (pSh && pSh->ISA(ScTabViewShell)) |
| { |
| ScTabViewShell* pViewSh = (ScTabViewShell*)pSh; |
| ScInputHandler* pInputHdl = pScMod->GetInputHdl(pViewSh); |
| if (pInputHdl) |
| pInputHdl->UpdateRefDevice(); |
| } |
| pFrame = SfxViewFrame::GetNext( *pFrame, this ); |
| } |
| } |
| } |
| else if (nDiffFlags & SFX_PRINTER_JOBSETUP) |
| { |
| SfxPrinter* pOldPrinter = aDocument.GetPrinter(); |
| if (pOldPrinter) |
| { |
| pOldPrinter->SetJobSetup( pNewPrinter->GetJobSetup() ); |
| |
| // #i6706# Call SetPrinter with the old printer again, so the drawing layer |
| // RefDevice is set (calling ReformatAllTextObjects and rebuilding charts), |
| // because the JobSetup (printer device settings) may affect text layout. |
| aDocument.SetPrinter( pOldPrinter ); |
| CalcOutputFactor(); // also with the new settings |
| } |
| } |
| |
| if (nDiffFlags & SFX_PRINTER_OPTIONS) |
| { |
| aDocument.SetPrintOptions(); //! aus neuem Printer ??? |
| } |
| |
| if (nDiffFlags & (SFX_PRINTER_CHG_ORIENTATION | SFX_PRINTER_CHG_SIZE)) |
| { |
| String aStyle = aDocument.GetPageStyle( GetCurTab() ); |
| ScStyleSheetPool* pStPl = aDocument.GetStyleSheetPool(); |
| SfxStyleSheet* pStyleSheet = (SfxStyleSheet*)pStPl->Find(aStyle, SFX_STYLE_FAMILY_PAGE); |
| if (pStyleSheet) |
| { |
| SfxItemSet& rSet = pStyleSheet->GetItemSet(); |
| |
| if (nDiffFlags & SFX_PRINTER_CHG_ORIENTATION) |
| { |
| const SvxPageItem& rOldItem = (const SvxPageItem&)rSet.Get(ATTR_PAGE); |
| sal_Bool bWasLand = rOldItem.IsLandscape(); |
| sal_Bool bNewLand = ( pNewPrinter->GetOrientation() == ORIENTATION_LANDSCAPE ); |
| if (bNewLand != bWasLand) |
| { |
| SvxPageItem aNewItem( rOldItem ); |
| aNewItem.SetLandscape( bNewLand ); |
| rSet.Put( aNewItem ); |
| |
| // Groesse umdrehen |
| Size aOldSize = ((const SvxSizeItem&)rSet.Get(ATTR_PAGE_SIZE)).GetSize(); |
| Size aNewSize(aOldSize.Height(),aOldSize.Width()); |
| SvxSizeItem aNewSItem(ATTR_PAGE_SIZE,aNewSize); |
| rSet.Put( aNewSItem ); |
| } |
| } |
| if (nDiffFlags & SFX_PRINTER_CHG_SIZE) |
| { |
| SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(pNewPrinter) ); |
| rSet.Put( aPaperSizeItem ); |
| } |
| } |
| } |
| |
| PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB,PAINT_ALL); |
| |
| return 0; |
| } |
| |
| //--------------------------------------------------------------------- |
| |
| ScChangeAction* ScDocShell::GetChangeAction( const ScAddress& rPos ) |
| { |
| ScChangeTrack* pTrack = GetDocument()->GetChangeTrack(); |
| if (!pTrack) |
| return NULL; |
| |
| SCTAB nTab = rPos.Tab(); |
| |
| const ScChangeAction* pFound = NULL; |
| const ScChangeAction* pFoundContent = NULL; |
| const ScChangeAction* pFoundMove = NULL; |
| long nModified = 0; |
| const ScChangeAction* pAction = pTrack->GetFirst(); |
| while (pAction) |
| { |
| ScChangeActionType eType = pAction->GetType(); |
| //! ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc )... |
| if ( pAction->IsVisible() && eType != SC_CAT_DELETE_TABS ) |
| { |
| const ScBigRange& rBig = pAction->GetBigRange(); |
| if ( rBig.aStart.Tab() == nTab ) |
| { |
| ScRange aRange = rBig.MakeRange(); |
| |
| if ( eType == SC_CAT_DELETE_ROWS ) |
| aRange.aEnd.SetRow( aRange.aStart.Row() ); |
| else if ( eType == SC_CAT_DELETE_COLS ) |
| aRange.aEnd.SetCol( aRange.aStart.Col() ); |
| |
| if ( aRange.In( rPos ) ) |
| { |
| pFound = pAction; // der letzte gewinnt |
| switch ( pAction->GetType() ) |
| { |
| case SC_CAT_CONTENT : |
| pFoundContent = pAction; |
| break; |
| case SC_CAT_MOVE : |
| pFoundMove = pAction; |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| ++nModified; |
| } |
| } |
| if ( pAction->GetType() == SC_CAT_MOVE ) |
| { |
| ScRange aRange = |
| ((const ScChangeActionMove*)pAction)-> |
| GetFromRange().MakeRange(); |
| if ( aRange.In( rPos ) ) |
| { |
| pFound = pAction; |
| ++nModified; |
| } |
| } |
| } |
| pAction = pAction->GetNext(); |
| } |
| |
| return (ScChangeAction*)pFound; |
| } |
| |
| void ScDocShell::SetChangeComment( ScChangeAction* pAction, const String& rComment ) |
| { |
| if (pAction) |
| { |
| pAction->SetComment( rComment ); |
| //! Undo ??? |
| SetDocumentModified(); |
| |
| // Dialog-Notify |
| ScChangeTrack* pTrack = GetDocument()->GetChangeTrack(); |
| if (pTrack) |
| { |
| sal_uLong nNumber = pAction->GetActionNumber(); |
| pTrack->NotifyModified( SC_CTM_CHANGE, nNumber, nNumber ); |
| } |
| } |
| } |
| |
| void ScDocShell::ExecuteChangeCommentDialog( ScChangeAction* pAction, Window* pParent,sal_Bool bPrevNext) |
| { |
| if (!pAction) return; // ohne Aktion ist nichts.. |
| |
| String aComment = pAction->GetComment(); |
| String aAuthor = pAction->GetUser(); |
| |
| DateTime aDT = pAction->GetDateTime(); |
| String aDate = ScGlobal::pLocaleData->getDate( aDT ); |
| aDate += ' '; |
| aDate += ScGlobal::pLocaleData->getTime( aDT, sal_False, sal_False ); |
| |
| SfxItemSet aSet( GetPool(), |
| SID_ATTR_POSTIT_AUTHOR, SID_ATTR_POSTIT_AUTHOR, |
| SID_ATTR_POSTIT_DATE, SID_ATTR_POSTIT_DATE, |
| SID_ATTR_POSTIT_TEXT, SID_ATTR_POSTIT_TEXT, |
| 0 ); |
| |
| aSet.Put( SvxPostItTextItem ( aComment, SID_ATTR_POSTIT_TEXT ) ); |
| aSet.Put( SvxPostItAuthorItem( aAuthor, SID_ATTR_POSTIT_AUTHOR ) ); |
| aSet.Put( SvxPostItDateItem ( aDate, SID_ATTR_POSTIT_DATE ) ); |
| |
| ScRedComDialog* pDlg = new ScRedComDialog( pParent, aSet,this,pAction,bPrevNext); |
| |
| pDlg->Execute(); |
| |
| delete pDlg; |
| } |
| |
| //--------------------------------------------------------------------- |
| |
| void ScDocShell::CompareDocument( ScDocument& rOtherDoc ) |
| { |
| ScChangeTrack* pTrack = aDocument.GetChangeTrack(); |
| if ( pTrack && pTrack->GetFirst() ) |
| { |
| //! Changes vorhanden -> Nachfrage ob geloescht werden soll |
| } |
| |
| aDocument.EndChangeTracking(); |
| aDocument.StartChangeTracking(); |
| |
| String aOldUser; |
| pTrack = aDocument.GetChangeTrack(); |
| if ( pTrack ) |
| { |
| aOldUser = pTrack->GetUser(); |
| |
| // check if comparing to same document |
| |
| String aThisFile; |
| const SfxMedium* pThisMed = GetMedium(); |
| if (pThisMed) |
| aThisFile = pThisMed->GetName(); |
| String aOtherFile; |
| SfxObjectShell* pOtherSh = rOtherDoc.GetDocumentShell(); |
| if (pOtherSh) |
| { |
| const SfxMedium* pOtherMed = pOtherSh->GetMedium(); |
| if (pOtherMed) |
| aOtherFile = pOtherMed->GetName(); |
| } |
| sal_Bool bSameDoc = ( aThisFile == aOtherFile && aThisFile.Len() ); |
| if ( !bSameDoc ) |
| { |
| // create change actions from comparing with the name of the user |
| // who last saved the document |
| // (only if comparing different documents) |
| |
| using namespace ::com::sun::star; |
| uno::Reference<document::XDocumentPropertiesSupplier> xDPS( |
| GetModel(), uno::UNO_QUERY_THROW); |
| uno::Reference<document::XDocumentProperties> xDocProps( |
| xDPS->getDocumentProperties()); |
| DBG_ASSERT(xDocProps.is(), "no DocumentProperties"); |
| String aDocUser = xDocProps->getModifiedBy(); |
| |
| if ( aDocUser.Len() ) |
| pTrack->SetUser( aDocUser ); |
| } |
| } |
| |
| aDocument.CompareDocument( rOtherDoc ); |
| |
| pTrack = aDocument.GetChangeTrack(); |
| if ( pTrack ) |
| pTrack->SetUser( aOldUser ); |
| |
| PostPaintGridAll(); |
| SetDocumentModified(); |
| } |
| |
| //--------------------------------------------------------------------- |
| // |
| // Merge (Aenderungen zusammenfuehren) |
| // |
| //--------------------------------------------------------------------- |
| |
| inline sal_Bool lcl_Equal( const ScChangeAction* pA, const ScChangeAction* pB, sal_Bool bIgnore100Sec ) |
| { |
| return pA && pB && |
| pA->GetActionNumber() == pB->GetActionNumber() && |
| pA->GetType() == pB->GetType() && |
| pA->GetUser() == pB->GetUser() && |
| (bIgnore100Sec ? |
| pA->GetDateTimeUTC().IsEqualIgnore100Sec( pB->GetDateTimeUTC() ) : |
| pA->GetDateTimeUTC() == pB->GetDateTimeUTC()); |
| // State nicht vergleichen, falls eine alte Aenderung akzeptiert wurde |
| } |
| |
| bool lcl_FindAction( ScDocument* pDoc, const ScChangeAction* pAction, ScDocument* pSearchDoc, const ScChangeAction* pFirstSearchAction, const ScChangeAction* pLastSearchAction, sal_Bool bIgnore100Sec ) |
| { |
| if ( !pDoc || !pAction || !pSearchDoc || !pFirstSearchAction || !pLastSearchAction ) |
| { |
| return false; |
| } |
| |
| sal_uLong nLastSearchAction = pLastSearchAction->GetActionNumber(); |
| const ScChangeAction* pA = pFirstSearchAction; |
| while ( pA && pA->GetActionNumber() <= nLastSearchAction ) |
| { |
| if ( pAction->GetType() == pA->GetType() && |
| pAction->GetUser() == pA->GetUser() && |
| (bIgnore100Sec ? |
| pAction->GetDateTimeUTC().IsEqualIgnore100Sec( pA->GetDateTimeUTC() ) : |
| pAction->GetDateTimeUTC() == pA->GetDateTimeUTC() ) && |
| pAction->GetBigRange() == pA->GetBigRange() ) |
| { |
| String aActionDesc; |
| pAction->GetDescription( aActionDesc, pDoc, sal_True ); |
| String aADesc; |
| pA->GetDescription( aADesc, pSearchDoc, sal_True ); |
| if ( aActionDesc.Equals( aADesc ) ) |
| { |
| DBG_ERROR( "lcl_FindAction(): found equal action!" ); |
| return true; |
| } |
| } |
| pA = pA->GetNext(); |
| } |
| |
| return false; |
| } |
| |
| void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheckDuplicates, sal_uLong nOffset, ScChangeActionMergeMap* pMergeMap, bool bInverseMap ) |
| { |
| ScTabViewShell* pViewSh = GetBestViewShell( sal_False ); //! Funktionen an die DocShell |
| if (!pViewSh) |
| return; |
| |
| ScChangeTrack* pSourceTrack = rOtherDoc.GetChangeTrack(); |
| if (!pSourceTrack) |
| return; //! nichts zu tun - Fehlermeldung? |
| |
| ScChangeTrack* pThisTrack = aDocument.GetChangeTrack(); |
| if ( !pThisTrack ) |
| { // anschalten |
| aDocument.StartChangeTracking(); |
| pThisTrack = aDocument.GetChangeTrack(); |
| DBG_ASSERT(pThisTrack,"ChangeTracking nicht angeschaltet?"); |
| if ( !bShared ) |
| { |
| // #51138# visuelles RedLining einschalten |
| ScChangeViewSettings aChangeViewSet; |
| aChangeViewSet.SetShowChanges(sal_True); |
| aDocument.SetChangeViewSettings(aChangeViewSet); |
| } |
| } |
| |
| // #97286# include 100th seconds in compare? |
| sal_Bool bIgnore100Sec = !pSourceTrack->IsTime100thSeconds() || |
| !pThisTrack->IsTime100thSeconds(); |
| |
| // gemeinsame Ausgangsposition suchen |
| sal_uLong nFirstNewNumber = 0; |
| const ScChangeAction* pSourceAction = pSourceTrack->GetFirst(); |
| const ScChangeAction* pThisAction = pThisTrack->GetFirst(); |
| // skip identical actions |
| while ( lcl_Equal( pSourceAction, pThisAction, bIgnore100Sec ) ) |
| { |
| nFirstNewNumber = pSourceAction->GetActionNumber() + 1; |
| pSourceAction = pSourceAction->GetNext(); |
| pThisAction = pThisAction->GetNext(); |
| } |
| // pSourceAction und pThisAction zeigen jetzt auf die ersten "eigenen" Aktionen |
| // Die gemeinsamen Aktionen davor interessieren ueberhaupt nicht |
| |
| //! Abfrage, ob die Dokumente vor dem Change-Tracking gleich waren !!! |
| |
| |
| const ScChangeAction* pFirstMergeAction = pSourceAction; |
| const ScChangeAction* pFirstSearchAction = pThisAction; |
| |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| const ScChangeAction* pLastSearchAction = pThisTrack->GetLast(); |
| |
| // MergeChangeData aus den folgenden Aktionen erzeugen |
| sal_uLong nNewActionCount = 0; |
| const ScChangeAction* pCount = pSourceAction; |
| while ( pCount ) |
| { |
| if ( bShared || !ScChangeTrack::MergeIgnore( *pCount, nFirstNewNumber ) ) |
| ++nNewActionCount; |
| pCount = pCount->GetNext(); |
| } |
| if (!nNewActionCount) |
| return; //! nichts zu tun - Fehlermeldung? |
| // ab hier kein return mehr |
| |
| ScProgress aProgress( this, |
| String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("...")), |
| nNewActionCount ); |
| |
| sal_uLong nLastMergeAction = pSourceTrack->GetLast()->GetActionNumber(); |
| // UpdateReference-Undo, gueltige Referenzen fuer den letzten gemeinsamen Zustand |
| pSourceTrack->MergePrepare( (ScChangeAction*) pFirstMergeAction, bShared ); |
| |
| // MergeChangeData an alle noch folgenden Aktionen in diesem Dokument anpassen |
| // -> Referenzen gueltig fuer dieses Dokument |
| while ( pThisAction ) |
| { |
| // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly |
| if ( !bShared || !ScChangeTrack::MergeIgnore( *pThisAction, nFirstNewNumber ) ) |
| { |
| ScChangeActionType eType = pThisAction->GetType(); |
| switch ( eType ) |
| { |
| case SC_CAT_INSERT_COLS : |
| case SC_CAT_INSERT_ROWS : |
| case SC_CAT_INSERT_TABS : |
| pSourceTrack->AppendInsert( pThisAction->GetBigRange().MakeRange() ); |
| break; |
| case SC_CAT_DELETE_COLS : |
| case SC_CAT_DELETE_ROWS : |
| case SC_CAT_DELETE_TABS : |
| { |
| const ScChangeActionDel* pDel = (const ScChangeActionDel*) pThisAction; |
| if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() ) |
| { // deleted Table enthaelt deleted Cols, die nicht |
| sal_uLong nStart, nEnd; |
| pSourceTrack->AppendDeleteRange( |
| pDel->GetOverAllRange().MakeRange(), NULL, nStart, nEnd ); |
| } |
| } |
| break; |
| case SC_CAT_MOVE : |
| { |
| const ScChangeActionMove* pMove = (const ScChangeActionMove*) pThisAction; |
| pSourceTrack->AppendMove( pMove->GetFromRange().MakeRange(), |
| pMove->GetBigRange().MakeRange(), NULL ); |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| pThisAction = pThisAction->GetNext(); |
| } |
| |
| LockPaint(); // #i73877# no repainting after each action |
| |
| // MergeChangeData in das aktuelle Dokument uebernehmen |
| sal_Bool bHasRejected = sal_False; |
| String aOldUser = pThisTrack->GetUser(); |
| pThisTrack->SetUseFixDateTime( sal_True ); |
| ScMarkData& rMarkData = pViewSh->GetViewData()->GetMarkData(); |
| ScMarkData aOldMarkData( rMarkData ); |
| pSourceAction = pFirstMergeAction; |
| while ( pSourceAction && pSourceAction->GetActionNumber() <= nLastMergeAction ) |
| { |
| bool bMergeAction = false; |
| if ( bShared ) |
| { |
| if ( !bCheckDuplicates || !lcl_FindAction( &rOtherDoc, pSourceAction, &aDocument, pFirstSearchAction, pLastSearchAction, bIgnore100Sec ) ) |
| { |
| bMergeAction = true; |
| } |
| } |
| else |
| { |
| if ( !ScChangeTrack::MergeIgnore( *pSourceAction, nFirstNewNumber ) ) |
| { |
| bMergeAction = true; |
| } |
| } |
| |
| if ( bMergeAction ) |
| { |
| ScChangeActionType eSourceType = pSourceAction->GetType(); |
| if ( !bShared && pSourceAction->IsDeletedIn() ) |
| { |
| //! muss hier noch festgestellt werden, ob wirklich in |
| //! _diesem_ Dokument geloescht? |
| |
| // liegt in einem Bereich, der in diesem Dokument geloescht wurde |
| // -> wird weggelassen |
| //! ??? Loesch-Aktion rueckgaengig machen ??? |
| //! ??? Aktion irgendwo anders speichern ??? |
| #ifdef DBG_UTIL |
| String aValue; |
| if ( eSourceType == SC_CAT_CONTENT ) |
| ((const ScChangeActionContent*)pSourceAction)->GetNewString( aValue ); |
| ByteString aError( aValue, gsl_getSystemTextEncoding() ); |
| aError += " weggelassen"; |
| DBG_ERROR( aError.GetBuffer() ); |
| #endif |
| } |
| else |
| { |
| //! Datum/Autor/Kommentar der Source-Aktion uebernehmen! |
| |
| pThisTrack->SetUser( pSourceAction->GetUser() ); |
| pThisTrack->SetFixDateTimeUTC( pSourceAction->GetDateTimeUTC() ); |
| sal_uLong nOldActionMax = pThisTrack->GetActionMax(); |
| |
| bool bExecute = true; |
| sal_uLong nReject = pSourceAction->GetRejectAction(); |
| if ( nReject ) |
| { |
| if ( bShared ) |
| { |
| if ( nReject >= nFirstNewNumber ) |
| { |
| nReject += nOffset; |
| } |
| ScChangeAction* pOldAction = pThisTrack->GetAction( nReject ); |
| if ( pOldAction && pOldAction->IsVirgin() ) |
| { |
| pThisTrack->Reject( pOldAction ); |
| bHasRejected = sal_True; |
| bExecute = false; |
| } |
| } |
| else |
| { |
| // alte Aktion (aus den gemeinsamen) ablehnen |
| ScChangeAction* pOldAction = pThisTrack->GetAction( nReject ); |
| if (pOldAction && pOldAction->GetState() == SC_CAS_VIRGIN) |
| { |
| //! was passiert bei Aktionen, die in diesem Dokument accepted worden sind??? |
| //! Fehlermeldung oder was??? |
| //! oder Reject-Aenderung normal ausfuehren |
| |
| pThisTrack->Reject(pOldAction); |
| bHasRejected = sal_True; // fuer Paint |
| } |
| bExecute = false; |
| } |
| } |
| |
| if ( bExecute ) |
| { |
| // normal ausfuehren |
| ScRange aSourceRange = pSourceAction->GetBigRange().MakeRange(); |
| rMarkData.SelectOneTable( aSourceRange.aStart.Tab() ); |
| switch ( eSourceType ) |
| { |
| case SC_CAT_CONTENT: |
| { |
| //! Test, ob es ganz unten im Dokument war, dann automatisches |
| //! Zeilen-Einfuegen ??? |
| |
| DBG_ASSERT( aSourceRange.aStart == aSourceRange.aEnd, "huch?" ); |
| ScAddress aPos = aSourceRange.aStart; |
| String aValue; |
| ((const ScChangeActionContent*)pSourceAction)->GetNewString( aValue ); |
| sal_uInt8 eMatrix = MM_NONE; |
| const ScBaseCell* pCell = ((const ScChangeActionContent*)pSourceAction)->GetNewCell(); |
| if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) |
| eMatrix = ((const ScFormulaCell*)pCell)->GetMatrixFlag(); |
| switch ( eMatrix ) |
| { |
| case MM_NONE : |
| pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue ); |
| break; |
| case MM_FORMULA : |
| { |
| SCCOL nCols; |
| SCROW nRows; |
| ((const ScFormulaCell*)pCell)->GetMatColsRows( nCols, nRows ); |
| aSourceRange.aEnd.SetCol( aPos.Col() + nCols - 1 ); |
| aSourceRange.aEnd.SetRow( aPos.Row() + nRows - 1 ); |
| aValue.Erase( 0, 1 ); |
| aValue.Erase( aValue.Len()-1, 1 ); |
| GetDocFunc().EnterMatrix( aSourceRange, |
| NULL, NULL, aValue, sal_False, sal_False, |
| EMPTY_STRING, formula::FormulaGrammar::GRAM_DEFAULT ); |
| } |
| break; |
| case MM_REFERENCE : // do nothing |
| break; |
| case MM_FAKE : |
| DBG_WARNING( "MergeDocument: MatrixFlag MM_FAKE" ); |
| pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue ); |
| break; |
| default: |
| DBG_ERROR( "MergeDocument: unknown MatrixFlag" ); |
| } |
| } |
| break; |
| case SC_CAT_INSERT_TABS : |
| { |
| String aName; |
| aDocument.CreateValidTabName( aName ); |
| GetDocFunc().InsertTable( aSourceRange.aStart.Tab(), aName, sal_True, sal_False ); |
| } |
| break; |
| case SC_CAT_INSERT_ROWS: |
| GetDocFunc().InsertCells( aSourceRange, NULL, INS_INSROWS, sal_True, sal_False ); |
| break; |
| case SC_CAT_INSERT_COLS: |
| GetDocFunc().InsertCells( aSourceRange, NULL, INS_INSCOLS, sal_True, sal_False ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| GetDocFunc().DeleteTable( aSourceRange.aStart.Tab(), sal_True, sal_False ); |
| break; |
| case SC_CAT_DELETE_ROWS: |
| { |
| const ScChangeActionDel* pDel = (const ScChangeActionDel*) pSourceAction; |
| if ( pDel->IsTopDelete() ) |
| { |
| aSourceRange = pDel->GetOverAllRange().MakeRange(); |
| GetDocFunc().DeleteCells( aSourceRange, NULL, DEL_DELROWS, sal_True, sal_False ); |
| |
| // #i101099# [Collaboration] Changes are not correctly shown |
| if ( bShared ) |
| { |
| ScChangeAction* pAct = pThisTrack->GetLast(); |
| if ( pAct && pAct->GetType() == eSourceType && pAct->IsDeletedIn() && !pSourceAction->IsDeletedIn() ) |
| { |
| pAct->RemoveAllDeletedIn(); |
| } |
| } |
| } |
| } |
| break; |
| case SC_CAT_DELETE_COLS: |
| { |
| const ScChangeActionDel* pDel = (const ScChangeActionDel*) pSourceAction; |
| if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() ) |
| { // deleted Table enthaelt deleted Cols, die nicht |
| aSourceRange = pDel->GetOverAllRange().MakeRange(); |
| GetDocFunc().DeleteCells( aSourceRange, NULL, DEL_DELCOLS, sal_True, sal_False ); |
| } |
| } |
| break; |
| case SC_CAT_MOVE : |
| { |
| const ScChangeActionMove* pMove = (const ScChangeActionMove*) pSourceAction; |
| ScRange aFromRange( pMove->GetFromRange().MakeRange() ); |
| GetDocFunc().MoveBlock( aFromRange, |
| aSourceRange.aStart, sal_True, sal_True, sal_False, sal_False ); |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| const String& rComment = pSourceAction->GetComment(); |
| if ( rComment.Len() ) |
| { |
| ScChangeAction* pAct = pThisTrack->GetLast(); |
| if ( pAct && pAct->GetActionNumber() > nOldActionMax ) |
| pAct->SetComment( rComment ); |
| #ifdef DBG_UTIL |
| else |
| DBG_ERROR( "MergeDocument: wohin mit dem Kommentar?!?" ); |
| #endif |
| } |
| |
| // Referenzen anpassen |
| pSourceTrack->MergeOwn( (ScChangeAction*) pSourceAction, nFirstNewNumber, bShared ); |
| |
| // merge action state |
| if ( bShared && !pSourceAction->IsRejected() ) |
| { |
| ScChangeAction* pAct = pThisTrack->GetLast(); |
| if ( pAct && pAct->GetActionNumber() > nOldActionMax ) |
| { |
| pThisTrack->MergeActionState( pAct, pSourceAction ); |
| } |
| } |
| |
| // fill merge map |
| if ( bShared && pMergeMap ) |
| { |
| ScChangeAction* pAct = pThisTrack->GetLast(); |
| if ( pAct && pAct->GetActionNumber() > nOldActionMax ) |
| { |
| sal_uLong nActionMax = pAct->GetActionNumber(); |
| sal_uLong nActionCount = nActionMax - nOldActionMax; |
| sal_uLong nAction = nActionMax - nActionCount + 1; |
| sal_uLong nSourceAction = pSourceAction->GetActionNumber() - nActionCount + 1; |
| while ( nAction <= nActionMax ) |
| { |
| if ( bInverseMap ) |
| { |
| (*pMergeMap)[ nAction++ ] = nSourceAction++; |
| } |
| else |
| { |
| (*pMergeMap)[ nSourceAction++ ] = nAction++; |
| } |
| } |
| } |
| } |
| } |
| aProgress.SetStateCountDown( --nNewActionCount ); |
| } |
| pSourceAction = pSourceAction->GetNext(); |
| } |
| |
| rMarkData = aOldMarkData; |
| pThisTrack->SetUser(aOldUser); |
| pThisTrack->SetUseFixDateTime( sal_False ); |
| |
| pSourceTrack->Clear(); //! der ist jetzt verhunzt |
| |
| if (bHasRejected) |
| PostPaintGridAll(); // Reject() paintet nicht selber |
| |
| UnlockPaint(); |
| } |
| |
| bool ScDocShell::MergeSharedDocument( ScDocShell* pSharedDocShell ) |
| { |
| if ( !pSharedDocShell ) |
| { |
| return false; |
| } |
| |
| ScChangeTrack* pThisTrack = aDocument.GetChangeTrack(); |
| if ( !pThisTrack ) |
| { |
| return false; |
| } |
| |
| ScDocument& rSharedDoc = *( pSharedDocShell->GetDocument() ); |
| ScChangeTrack* pSharedTrack = rSharedDoc.GetChangeTrack(); |
| if ( !pSharedTrack ) |
| { |
| return false; |
| } |
| |
| #if DEBUG_CHANGETRACK |
| ::rtl::OUString aMessage = ::rtl::OUString::createFromAscii( "\nbefore merge:\n" ); |
| aMessage += pThisTrack->ToString(); |
| ::rtl::OString aMsg = ::rtl::OUStringToOString( aMessage, RTL_TEXTENCODING_UTF8 ); |
| OSL_ENSURE( false, aMsg.getStr() ); |
| //fprintf( stdout, "%s ", aMsg.getStr() ); |
| //fflush( stdout ); |
| #endif // DEBUG_CHANGETRACK |
| |
| // reset show changes |
| ScChangeViewSettings aChangeViewSet; |
| aChangeViewSet.SetShowChanges( sal_False ); |
| aDocument.SetChangeViewSettings( aChangeViewSet ); |
| |
| // find first merge action in this document |
| sal_Bool bIgnore100Sec = !pThisTrack->IsTime100thSeconds() || !pSharedTrack->IsTime100thSeconds(); |
| ScChangeAction* pThisAction = pThisTrack->GetFirst(); |
| ScChangeAction* pSharedAction = pSharedTrack->GetFirst(); |
| while ( lcl_Equal( pThisAction, pSharedAction, bIgnore100Sec ) ) |
| { |
| pThisAction = pThisAction->GetNext(); |
| pSharedAction = pSharedAction->GetNext(); |
| } |
| |
| if ( pSharedAction ) |
| { |
| if ( pThisAction ) |
| { |
| // merge own changes into shared document |
| sal_uLong nActStartShared = pSharedAction->GetActionNumber(); |
| sal_uLong nActEndShared = pSharedTrack->GetActionMax(); |
| ScDocument* pTmpDoc = new ScDocument; |
| for ( sal_Int32 nIndex = 0; nIndex < aDocument.GetTableCount(); ++nIndex ) |
| { |
| String sTabName; |
| pTmpDoc->CreateValidTabName( sTabName ); |
| pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName ); |
| } |
| aDocument.GetChangeTrack()->Clone( pTmpDoc ); |
| ScChangeActionMergeMap aOwnInverseMergeMap; |
| pSharedDocShell->MergeDocument( *pTmpDoc, true, true, 0, &aOwnInverseMergeMap, true ); |
| delete pTmpDoc; |
| sal_uLong nActStartOwn = nActEndShared + 1; |
| sal_uLong nActEndOwn = pSharedTrack->GetActionMax(); |
| |
| // find conflicts |
| ScConflictsList aConflictsList; |
| ScConflictsFinder aFinder( pSharedTrack, nActStartShared, nActEndShared, nActStartOwn, nActEndOwn, aConflictsList ); |
| if ( aFinder.Find() ) |
| { |
| ScConflictsListHelper::TransformConflictsList( aConflictsList, NULL, &aOwnInverseMergeMap ); |
| bool bLoop = true; |
| while ( bLoop ) |
| { |
| bLoop = false; |
| ScConflictsDlg aDlg( GetActiveDialogParent(), GetViewData(), &rSharedDoc, aConflictsList ); |
| if ( aDlg.Execute() == RET_CANCEL ) |
| { |
| QueryBox aBox( GetActiveDialogParent(), WinBits( WB_YES_NO | WB_DEF_YES ), |
| ScGlobal::GetRscString( STR_DOC_WILLNOTBESAVED ) ); |
| if ( aBox.Execute() == RET_YES ) |
| { |
| return false; |
| } |
| else |
| { |
| bLoop = true; |
| } |
| } |
| } |
| } |
| |
| // undo own changes in shared document |
| pSharedTrack->Undo( nActStartOwn, nActEndOwn ); |
| |
| // clone change track for merging into own document |
| pTmpDoc = new ScDocument; |
| for ( sal_Int32 nIndex = 0; nIndex < aDocument.GetTableCount(); ++nIndex ) |
| { |
| String sTabName; |
| pTmpDoc->CreateValidTabName( sTabName ); |
| pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName ); |
| } |
| pThisTrack->Clone( pTmpDoc ); |
| |
| // undo own changes since last save in own document |
| sal_uLong nStartShared = pThisAction->GetActionNumber(); |
| ScChangeAction* pAction = pThisTrack->GetLast(); |
| while ( pAction && pAction->GetActionNumber() >= nStartShared ) |
| { |
| pThisTrack->Reject( pAction, true ); |
| pAction = pAction->GetPrev(); |
| } |
| |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| pThisTrack->Undo( nStartShared, pThisTrack->GetActionMax(), true ); |
| |
| // merge shared changes into own document |
| ScChangeActionMergeMap aSharedMergeMap; |
| MergeDocument( rSharedDoc, true, true, 0, &aSharedMergeMap ); |
| sal_uLong nEndShared = pThisTrack->GetActionMax(); |
| |
| // resolve conflicts for shared non-content actions |
| if ( !aConflictsList.empty() ) |
| { |
| ScConflictsListHelper::TransformConflictsList( aConflictsList, &aSharedMergeMap, NULL ); |
| ScConflictsResolver aResolver( pThisTrack, aConflictsList ); |
| pAction = pThisTrack->GetAction( nEndShared ); |
| while ( pAction && pAction->GetActionNumber() >= nStartShared ) |
| { |
| aResolver.HandleAction( pAction, true /*bIsSharedAction*/, |
| false /*bHandleContentAction*/, true /*bHandleNonContentAction*/ ); |
| pAction = pAction->GetPrev(); |
| } |
| } |
| nEndShared = pThisTrack->GetActionMax(); |
| |
| // only show changes from shared document |
| aChangeViewSet.SetShowChanges( sal_True ); |
| aChangeViewSet.SetShowAccepted( sal_True ); |
| aChangeViewSet.SetHasActionRange( true ); |
| aChangeViewSet.SetTheActionRange( nStartShared, nEndShared ); |
| aDocument.SetChangeViewSettings( aChangeViewSet ); |
| |
| // merge own changes back into own document |
| sal_uLong nStartOwn = nEndShared + 1; |
| ScChangeActionMergeMap aOwnMergeMap; |
| MergeDocument( *pTmpDoc, true, true, nEndShared - nStartShared + 1, &aOwnMergeMap ); |
| delete pTmpDoc; |
| sal_uLong nEndOwn = pThisTrack->GetActionMax(); |
| |
| // resolve conflicts for shared content actions and own actions |
| if ( !aConflictsList.empty() ) |
| { |
| ScConflictsListHelper::TransformConflictsList( aConflictsList, NULL, &aOwnMergeMap ); |
| ScConflictsResolver aResolver( pThisTrack, aConflictsList ); |
| pAction = pThisTrack->GetAction( nEndShared ); |
| while ( pAction && pAction->GetActionNumber() >= nStartShared ) |
| { |
| aResolver.HandleAction( pAction, true /*bIsSharedAction*/, |
| true /*bHandleContentAction*/, false /*bHandleNonContentAction*/ ); |
| pAction = pAction->GetPrev(); |
| } |
| |
| pAction = pThisTrack->GetAction( nEndOwn ); |
| while ( pAction && pAction->GetActionNumber() >= nStartOwn ) |
| { |
| aResolver.HandleAction( pAction, false /*bIsSharedAction*/, |
| true /*bHandleContentAction*/, true /*bHandleNonContentAction*/ ); |
| pAction = pAction->GetPrev(); |
| } |
| } |
| nEndOwn = pThisTrack->GetActionMax(); |
| } |
| else |
| { |
| // merge shared changes into own document |
| sal_uLong nStartShared = pThisTrack->GetActionMax() + 1; |
| MergeDocument( rSharedDoc, true, true ); |
| sal_uLong nEndShared = pThisTrack->GetActionMax(); |
| |
| // only show changes from shared document |
| aChangeViewSet.SetShowChanges( sal_True ); |
| aChangeViewSet.SetShowAccepted( sal_True ); |
| aChangeViewSet.SetHasActionRange( true ); |
| aChangeViewSet.SetTheActionRange( nStartShared, nEndShared ); |
| aDocument.SetChangeViewSettings( aChangeViewSet ); |
| } |
| |
| // update view |
| PostPaintExtras(); |
| PostPaintGridAll(); |
| |
| InfoBox aInfoBox( GetActiveDialogParent(), ScGlobal::GetRscString( STR_DOC_UPDATED ) ); |
| aInfoBox.Execute(); |
| } |
| |
| #if DEBUG_CHANGETRACK |
| aMessage = ::rtl::OUString::createFromAscii( "\nafter merge:\n" ); |
| aMessage += pThisTrack->ToString(); |
| aMsg = ::rtl::OUStringToOString( aMessage, RTL_TEXTENCODING_UTF8 ); |
| OSL_ENSURE( false, aMsg.getStr() ); |
| //fprintf( stdout, "%s ", aMsg.getStr() ); |
| //fflush( stdout ); |
| #endif // DEBUG_CHANGETRACK |
| |
| return ( pThisAction != NULL ); |
| } |