tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / docshell / docsh3.cxx
blobcff0de59984388e76942bb6948d6b9b3e12d1d72
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
21 #include <com/sun/star/document/XDocumentProperties.hpp>
23 #include <scitems.hxx>
24 #include <rangelst.hxx>
25 #include <editeng/flstitem.hxx>
26 #include <editeng/paperinf.hxx>
27 #include <editeng/sizeitem.hxx>
28 #include <o3tl/unit_conversion.hxx>
29 #include <officecfg/Office/Common.hxx>
30 #include <sal/log.hxx>
31 #include <sfx2/viewfrm.hxx>
32 #include <sfx2/app.hxx>
33 #include <sfx2/docfile.hxx>
34 #include <sfx2/printer.hxx>
35 #include <svl/numformat.hxx>
36 #include <svx/pageitem.hxx>
37 #include <svx/postattr.hxx>
38 #include <svx/svxids.hrc>
39 #include <unotools/configmgr.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/virdev.hxx>
42 #include <vcl/weld.hxx>
43 #include <osl/diagnose.h>
45 #include <docsh.hxx>
46 #include "docshimp.hxx"
47 #include <scmod.hxx>
48 #include <tabvwsh.hxx>
49 #include <viewdata.hxx>
50 #include <docpool.hxx>
51 #include <stlpool.hxx>
52 #include <patattr.hxx>
53 #include <uiitems.hxx>
54 #include <hints.hxx>
55 #include <docoptio.hxx>
56 #include <viewopti.hxx>
57 #include <pntlock.hxx>
58 #include <chgtrack.hxx>
59 #include <docfunc.hxx>
60 #include <formulacell.hxx>
61 #include <chgviset.hxx>
62 #include <progress.hxx>
63 #include <redcom.hxx>
64 #include <inputopt.hxx>
65 #include <drwlayer.hxx>
66 #include <inputhdl.hxx>
67 #include <conflictsdlg.hxx>
68 #include <globstr.hrc>
69 #include <scresid.hxx>
70 #include <markdata.hxx>
71 #include <memory>
72 #include <formulaopt.hxx>
74 #include <comphelper/lok.hxx>
75 #include <sfx2/lokhelper.hxx>
77 // Redraw - Notifications
79 void ScDocShell::PostEditView( ScEditEngineDefaulter* pEditEngine, const ScAddress& rCursorPos )
81 // Broadcast( ScEditViewHint( pEditEngine, rCursorPos ) );
83 // Test: only active ViewShell
85 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
86 if (pViewSh && pViewSh->GetViewData().GetDocShell() == this)
88 ScEditViewHint aHint( pEditEngine, rCursorPos );
89 pViewSh->Notify( *this, aHint );
93 void ScDocShell::PostDataChanged()
95 Broadcast( SfxHint( SfxHintId::ScDataChanged ) );
96 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScAnyDataChanged )); // Navigator
97 m_pDocument->PrepareFormulaCalc();
98 //! notify navigator directly!
101 void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
102 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, PaintPartFlags nPart,
103 sal_uInt16 nExtFlags, tools::Long nMaxWidthAffectedHint )
105 ScRange aRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
106 PostPaint(aRange, nPart, nExtFlags, nMaxWidthAffectedHint);
109 void ScDocShell::PostPaint( const ScRangeList& rRanges, PaintPartFlags nPart, sal_uInt16 nExtFlags, tools::Long nMaxWidthAffectedHint )
111 ScRangeList aPaintRanges;
112 std::set<SCTAB> aTabsInvalidated;
113 const SCTAB nMaxTab = m_pDocument->GetTableCount() - 1;
114 for (size_t i = 0, n = rRanges.size(); i < n; ++i)
116 const ScRange& rRange = rRanges[i];
117 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
118 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
119 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = std::min<SCTAB>(nMaxTab, rRange.aEnd.Tab());
121 if (nTab1 < 0 || nTab2 < 0)
122 continue;
124 if (!m_pDocument->ValidCol(nCol1))
126 nMaxWidthAffectedHint = -1; // Hint no longer valid
127 nCol1 = m_pDocument->MaxCol();
129 if (!m_pDocument->ValidRow(nRow1)) nRow1 = m_pDocument->MaxRow();
130 if (!m_pDocument->ValidCol(nCol2))
132 nMaxWidthAffectedHint = -1; // Hint no longer valid
133 nCol2 = m_pDocument->MaxCol();
135 if (!m_pDocument->ValidRow(nRow2)) nRow2 = m_pDocument->MaxRow();
137 if ( m_pPaintLockData )
139 // #i54081# PaintPartFlags::Extras still has to be broadcast because it changes the
140 // current sheet if it's invalid. All other flags added to pPaintLockData.
141 PaintPartFlags nLockPart = nPart & ~PaintPartFlags::Extras;
142 if ( nLockPart != PaintPartFlags::NONE )
144 //! nExtFlags ???
145 m_pPaintLockData->AddRange( ScRange( nCol1, nRow1, nTab1,
146 nCol2, nRow2, nTab2 ), nLockPart );
149 nPart &= PaintPartFlags::Extras; // for broadcasting
150 if (nPart == PaintPartFlags::NONE)
151 continue;
154 if (nExtFlags & SC_PF_LINES) // respect space for lines
156 //! check for hidden columns/rows!
157 if (nCol1 > 0)
159 nMaxWidthAffectedHint = -1; // Hint no longer valid
160 --nCol1;
162 if (nCol2 < m_pDocument->MaxCol())
164 nMaxWidthAffectedHint = -1; // Hint no longer valid
165 ++nCol2;
167 if (nRow1>0) --nRow1;
168 if (nRow2<m_pDocument->MaxRow()) ++nRow2;
171 // expand for the merged ones
172 if (nExtFlags & SC_PF_TESTMERGE)
173 m_pDocument->ExtendMerge( nCol1, nRow1, nCol2, nRow2, nTab1 );
175 if ( nCol1 != 0 || nCol2 != m_pDocument->MaxCol() )
177 // Extend to whole rows if SC_PF_WHOLEROWS is set, or rotated or non-left
178 // aligned cells are contained (see UpdatePaintExt).
179 // Special handling for RTL text (#i9731#) is unnecessary now with full
180 // support of right-aligned text.
182 if ( ( nExtFlags & SC_PF_WHOLEROWS ) ||
183 m_pDocument->HasAttrib( nCol1,nRow1,nTab1,
184 m_pDocument->MaxCol(),nRow2,nTab2, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
186 nCol1 = 0;
187 nCol2 = m_pDocument->MaxCol();
188 nMaxWidthAffectedHint = -1; // Hint no longer valid
191 aPaintRanges.push_back(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
192 for (auto nTabNum = nTab1; nTabNum <= nTab2; ++nTabNum)
193 aTabsInvalidated.insert(nTabNum);
196 Broadcast(ScPaintHint(aPaintRanges.Combine(), nPart, nMaxWidthAffectedHint));
198 // LOK: we are supposed to update the row / columns headers (and actually
199 // the document size too - cell size affects that, obviously)
200 if ((nPart & (PaintPartFlags::Top | PaintPartFlags::Left)) && comphelper::LibreOfficeKit::isActive())
202 ScModelObj* pModel = GetModel();
203 for (auto nTab : aTabsInvalidated)
204 SfxLokHelper::notifyPartSizeChangedAllViews(pModel, nTab);
208 void ScDocShell::PostPaintGridAll()
210 PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Grid );
213 void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab, tools::Long nMaxWidthAffectedHint )
215 PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, SC_PF_TESTMERGE, nMaxWidthAffectedHint );
218 void ScDocShell::PostPaintCell( const ScAddress& rPos, tools::Long nMaxWidthAffectedHint )
220 PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab(), nMaxWidthAffectedHint );
223 void ScDocShell::PostPaintExtras()
225 PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Extras );
228 void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, const ScRange& rRange )
230 if ( ( rExtFlags & SC_PF_LINES ) == 0 &&
231 m_pDocument->HasAttrib( rRange, HasAttrFlags::Lines | HasAttrFlags::Shadow | HasAttrFlags::Conditional ) )
233 // If the range contains lines, shadow or conditional formats,
234 // set SC_PF_LINES to include one extra cell in all directions.
236 rExtFlags |= SC_PF_LINES;
239 if ( ( rExtFlags & SC_PF_WHOLEROWS ) == 0 &&
240 ( rRange.aStart.Col() != 0 || rRange.aEnd.Col() != m_pDocument->MaxCol() ) &&
241 m_pDocument->HasAttrib( rRange, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
243 // If the range contains (logically) right- or center-aligned cells,
244 // or rotated cells, set SC_PF_WHOLEROWS to paint the whole rows.
245 // This test isn't needed after the cell changes, because it's also
246 // tested in PostPaint. UpdatePaintExt may later be changed to do this
247 // only if called before the changes.
249 rExtFlags |= SC_PF_WHOLEROWS;
253 void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
254 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab )
256 UpdatePaintExt( rExtFlags, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) );
259 void ScDocShell::LockPaint_Impl(bool bDoc)
261 if ( !m_pPaintLockData )
262 m_pPaintLockData.reset( new ScPaintLockData );
263 m_pPaintLockData->IncLevel(bDoc);
266 void ScDocShell::UnlockPaint_Impl(bool bDoc)
268 if ( m_pPaintLockData )
270 if ( m_pPaintLockData->GetLevel(bDoc) )
271 m_pPaintLockData->DecLevel(bDoc);
272 if (!m_pPaintLockData->GetLevel(!bDoc) && !m_pPaintLockData->GetLevel(bDoc))
274 // Execute Paint now
276 // don't continue collecting
277 std::unique_ptr<ScPaintLockData> pPaint = std::move(m_pPaintLockData);
279 ScRangeListRef xRangeList = pPaint->GetRangeList();
280 if ( xRangeList.is() )
282 PaintPartFlags nParts = pPaint->GetParts();
283 for ( size_t i = 0, nCount = xRangeList->size(); i < nCount; i++ )
285 //! nExtFlags ???
286 ScRange const & rRange = (*xRangeList)[i];
287 PostPaint( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
288 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
289 nParts );
293 if ( pPaint->GetModified() )
294 SetDocumentModified();
297 else
299 OSL_FAIL("UnlockPaint without LockPaint");
303 void ScDocShell::LockDocument_Impl(sal_uInt16 nNew)
305 if (!m_nDocumentLock)
307 ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
308 if (pDrawLayer)
309 pDrawLayer->setLock(true);
311 m_nDocumentLock = nNew;
314 void ScDocShell::UnlockDocument_Impl(sal_uInt16 nNew)
316 m_nDocumentLock = nNew;
317 if (!m_nDocumentLock)
319 ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
320 if (pDrawLayer)
321 pDrawLayer->setLock(false);
325 void ScDocShell::SetLockCount(sal_uInt16 nNew)
327 if (nNew) // set
329 if ( !m_pPaintLockData )
330 m_pPaintLockData.reset( new ScPaintLockData );
331 m_pPaintLockData->SetDocLevel(nNew-1);
332 LockDocument_Impl(nNew);
334 else if (m_pPaintLockData) // delete
336 m_pPaintLockData->SetDocLevel(0); // at unlock, execute immediately
337 UnlockPaint_Impl(true); // now
338 UnlockDocument_Impl(0);
342 void ScDocShell::LockPaint()
344 LockPaint_Impl(false);
347 void ScDocShell::UnlockPaint()
349 UnlockPaint_Impl(false);
352 void ScDocShell::LockDocument()
354 LockPaint_Impl(true);
355 LockDocument_Impl(m_nDocumentLock + 1);
358 void ScDocShell::UnlockDocument()
360 if (m_nDocumentLock)
362 UnlockPaint_Impl(true);
363 UnlockDocument_Impl(m_nDocumentLock - 1);
365 else
367 OSL_FAIL("UnlockDocument without LockDocument");
371 void ScDocShell::SetInplace( bool bInplace )
373 if (m_bIsInplace != bInplace)
375 m_bIsInplace = bInplace;
376 CalcOutputFactor();
380 void ScDocShell::CalcOutputFactor()
382 if (m_bIsInplace)
384 m_nPrtToScreenFactor = 1.0; // otherwise it does not match the inactive display
385 return;
388 bool bTextWysiwyg = ScModule::get()->GetInputOptions().GetTextWysiwyg();
389 if (bTextWysiwyg)
391 m_nPrtToScreenFactor = 1.0;
392 return;
395 OUString aTestString(
396 u"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789"_ustr);
397 tools::Long nPrinterWidth = 0;
398 const ScPatternAttr& rPattern(m_pDocument->getCellAttributeHelper().getDefaultCellAttribute());
400 vcl::Font aDefFont;
401 OutputDevice* pRefDev = GetRefDevice();
402 MapMode aOldMode = pRefDev->GetMapMode();
403 vcl::Font aOldFont = pRefDev->GetFont();
405 pRefDev->SetMapMode(MapMode(MapUnit::MapPixel));
406 rPattern.fillFontOnly(aDefFont, pRefDev); // font color doesn't matter here
407 pRefDev->SetFont(aDefFont);
408 nPrinterWidth = pRefDev->PixelToLogic(Size(pRefDev->GetTextWidth(aTestString), 0), MapMode(MapUnit::Map100thMM)).Width();
409 pRefDev->SetFont(aOldFont);
410 pRefDev->SetMapMode(aOldMode);
412 ScopedVclPtrInstance< VirtualDevice > pVirtWindow( *Application::GetDefaultDevice() );
413 pVirtWindow->SetMapMode(MapMode(MapUnit::MapPixel));
414 rPattern.fillFontOnly(aDefFont, pVirtWindow); // font color doesn't matter here
415 pVirtWindow->SetFont(aDefFont);
416 double nWindowWidth = pVirtWindow->GetTextWidth(aTestString) / ScGlobal::nScreenPPTX;
417 nWindowWidth = o3tl::convert(nWindowWidth, o3tl::Length::twip, o3tl::Length::mm100);
419 if (nPrinterWidth && nWindowWidth)
420 m_nPrtToScreenFactor = nPrinterWidth / nWindowWidth;
421 else
423 OSL_FAIL("GetTextSize returns 0 ??");
424 m_nPrtToScreenFactor = 1.0;
428 void ScDocShell::InitOptions(bool bForLoading) // called from InitNew and Load
430 // Settings from the SpellCheckCfg get into Doc- and ViewOptions
432 LanguageType nDefLang, nCjkLang, nCtlLang;
433 ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang );
434 ScModule* pScMod = ScModule::get();
436 ScDocOptions aDocOpt = pScMod->GetDocOptions();
437 ScFormulaOptions aFormulaOpt = pScMod->GetFormulaOptions();
438 ScViewOptions aViewOpt = pScMod->GetViewOptions();
440 if (!comphelper::IsFuzzing())
442 // two-digit year entry from Tools->Options->General
443 aDocOpt.SetYear2000(officecfg::Office::Common::DateFormat::TwoDigitYear::get());
446 if (bForLoading)
448 // #i112123# No style:decimal-places attribute means automatic decimals, not the configured default,
449 // so it must not be taken from the global options.
450 // Calculation settings are handled separately in ScXMLBodyContext::EndElement.
451 aDocOpt.SetStdPrecision( SvNumberFormatter::UNLIMITED_PRECISION );
453 // fdo#78294 The default null-date if
454 // <table:null-date table:date-value='...' />
455 // is absent is 1899-12-30 regardless what the configuration is set to.
456 // Import filters may override this value.
457 aDocOpt.SetDate( 30, 12, 1899);
460 m_pDocument->SetDocOptions( aDocOpt );
461 m_pDocument->SetViewOptions( aViewOpt );
462 SetFormulaOptions( aFormulaOpt, bForLoading );
464 // print options are now set directly before the printing
466 m_pDocument->SetLanguage( nDefLang, nCjkLang, nCtlLang );
469 Printer* ScDocShell::GetDocumentPrinter() // for OLE
471 return m_pDocument->GetPrinter();
474 SfxPrinter* ScDocShell::GetPrinter(bool bCreateIfNotExist)
476 return m_pDocument->GetPrinter(bCreateIfNotExist);
479 void ScDocShell::UpdateFontList()
481 // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() );
482 m_pImpl->pFontList.reset(new FontList(GetRefDevice(), nullptr));
483 SvxFontListItem aFontListItem( m_pImpl->pFontList.get(), SID_ATTR_CHAR_FONTLIST );
484 PutItem( aFontListItem );
486 CalcOutputFactor();
489 OutputDevice* ScDocShell::GetRefDevice()
491 return m_pDocument->GetRefDevice();
494 sal_uInt16 ScDocShell::SetPrinter( VclPtr<SfxPrinter> const & pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
496 SfxPrinter *pOld = m_pDocument->GetPrinter( false );
497 if ( pOld && pOld->IsPrinting() )
498 return SFX_PRINTERROR_BUSY;
500 if (nDiffFlags & SfxPrinterChangeFlags::PRINTER)
502 if ( m_pDocument->GetPrinter() != pNewPrinter )
504 m_pDocument->SetPrinter( pNewPrinter );
505 m_pDocument->SetPrintOptions();
507 // MT: Use UpdateFontList: Will use Printer fonts only if needed!
509 delete pImpl->pFontList;
510 pImpl->pFontList = new FontList( pNewPrinter, Application::GetDefaultDevice() );
511 SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST );
512 PutItem( aFontListItem );
514 CalcOutputFactor();
516 ScModule* pScMod = ScModule::get();
517 if (pScMod->GetInputOptions().GetTextWysiwyg())
518 UpdateFontList();
520 SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this );
521 while (pFrame)
523 SfxViewShell* pSh = pFrame->GetViewShell();
524 if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pSh))
526 ScInputHandler* pInputHdl = pScMod->GetInputHdl(pViewSh);
527 if (pInputHdl)
528 pInputHdl->UpdateRefDevice();
530 pFrame = SfxViewFrame::GetNext( *pFrame, this );
534 else if (nDiffFlags & SfxPrinterChangeFlags::JOBSETUP)
536 SfxPrinter* pOldPrinter = m_pDocument->GetPrinter();
537 if (pOldPrinter)
539 pOldPrinter->SetJobSetup( pNewPrinter->GetJobSetup() );
541 // #i6706# Call SetPrinter with the old printer again, so the drawing layer
542 // RefDevice is set (calling ReformatAllTextObjects and rebuilding charts),
543 // because the JobSetup (printer device settings) may affect text layout.
544 m_pDocument->SetPrinter( pOldPrinter );
545 CalcOutputFactor(); // also with the new settings
549 if (nDiffFlags & SfxPrinterChangeFlags::OPTIONS)
551 m_pDocument->SetPrintOptions(); //! from new printer ???
554 if (nDiffFlags & (SfxPrinterChangeFlags::CHG_ORIENTATION | SfxPrinterChangeFlags::CHG_SIZE))
556 OUString aStyle = m_pDocument->GetPageStyle( GetCurTab() );
557 ScStyleSheetPool* pStPl = m_pDocument->GetStyleSheetPool();
558 SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(pStPl->Find(aStyle, SfxStyleFamily::Page));
559 if (pStyleSheet)
561 SfxItemSet& rSet = pStyleSheet->GetItemSet();
563 if (nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION)
565 const SvxPageItem& rOldItem = rSet.Get(ATTR_PAGE);
566 bool bWasLand = rOldItem.IsLandscape();
567 bool bNewLand = ( pNewPrinter->GetOrientation() == Orientation::Landscape );
568 if (bNewLand != bWasLand)
570 SvxPageItem aNewItem( rOldItem );
571 aNewItem.SetLandscape( bNewLand );
572 rSet.Put( aNewItem );
574 // flip size
575 Size aOldSize = rSet.Get(ATTR_PAGE_SIZE).GetSize();
576 // coverity[swapped_arguments : FALSE] - this is in the correct order
577 Size aNewSize(aOldSize.Height(),aOldSize.Width());
578 SvxSizeItem aNewSItem(ATTR_PAGE_SIZE,aNewSize);
579 rSet.Put( aNewSItem );
582 if (nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE)
584 SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(pNewPrinter) );
585 rSet.Put( aPaperSizeItem );
590 PostPaint(0,0,0,m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB,PaintPartFlags::All);
592 return 0;
595 ScChangeAction* ScDocShell::GetChangeAction( const ScAddress& rPos )
597 ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
598 if (!pTrack)
599 return nullptr;
601 SCTAB nTab = rPos.Tab();
603 const ScChangeAction* pFound = nullptr;
604 const ScChangeAction* pAction = pTrack->GetFirst();
605 while (pAction)
607 ScChangeActionType eType = pAction->GetType();
608 //! ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc )...
609 if ( pAction->IsVisible() && eType != SC_CAT_DELETE_TABS )
611 const ScBigRange& rBig = pAction->GetBigRange();
612 if ( rBig.aStart.Tab() == nTab )
614 ScRange aRange = rBig.MakeRange( GetDocument() );
616 if ( eType == SC_CAT_DELETE_ROWS )
617 aRange.aEnd.SetRow( aRange.aStart.Row() );
618 else if ( eType == SC_CAT_DELETE_COLS )
619 aRange.aEnd.SetCol( aRange.aStart.Col() );
621 if ( aRange.Contains( rPos ) )
623 pFound = pAction; // the last one wins
626 if ( pAction->GetType() == SC_CAT_MOVE )
628 ScRange aRange =
629 static_cast<const ScChangeActionMove*>(pAction)->
630 GetFromRange().MakeRange( GetDocument() );
631 if ( aRange.Contains( rPos ) )
633 pFound = pAction;
637 pAction = pAction->GetNext();
640 return const_cast<ScChangeAction*>(pFound);
643 void ScDocShell::SetChangeComment( ScChangeAction* pAction, const OUString& rComment )
645 if (!pAction)
646 return;
648 pAction->SetComment( rComment );
649 //! Undo ???
650 SetDocumentModified();
652 // Dialog-Notify
653 ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
654 if (pTrack)
656 sal_uLong nNumber = pAction->GetActionNumber();
657 pTrack->NotifyModified( ScChangeTrackMsgType::Change, nNumber, nNumber );
661 void ScDocShell::ExecuteChangeCommentDialog( ScChangeAction* pAction, weld::Window* pParent, bool bPrevNext)
663 if (!pAction) return; // without action is nothing...
665 OUString aComment = pAction->GetComment();
666 OUString aAuthor = pAction->GetUser();
668 DateTime aDT = pAction->GetDateTime();
669 OUString aDate = ScGlobal::getLocaleData().getDate( aDT ) + " " +
670 ScGlobal::getLocaleData().getTime( aDT, false );
672 SfxItemSetFixed<SID_ATTR_POSTIT_AUTHOR, SID_ATTR_POSTIT_TEXT> aSet( GetPool() );
674 aSet.Put( SvxPostItTextItem ( aComment, SID_ATTR_POSTIT_TEXT ) );
675 aSet.Put( SvxPostItAuthorItem( aAuthor, SID_ATTR_POSTIT_AUTHOR ) );
676 aSet.Put( SvxPostItDateItem ( aDate, SID_ATTR_POSTIT_DATE ) );
678 std::unique_ptr<ScRedComDialog> pDlg(new ScRedComDialog( pParent, aSet,this,pAction,bPrevNext));
680 pDlg->Execute();
683 void ScDocShell::CompareDocument( ScDocument& rOtherDoc )
685 ScChangeTrack* pTrack = m_pDocument->GetChangeTrack();
686 if ( pTrack && pTrack->GetFirst() )
688 //! there are changes -> inquiry if needs to be deleted
691 m_pDocument->EndChangeTracking();
692 m_pDocument->StartChangeTracking();
694 OUString aOldUser;
695 pTrack = m_pDocument->GetChangeTrack();
696 if ( pTrack )
698 aOldUser = pTrack->GetUser();
700 // check if comparing to same document
702 OUString aThisFile;
703 const SfxMedium* pThisMed = GetMedium();
704 if (pThisMed)
705 aThisFile = pThisMed->GetName();
706 OUString aOtherFile;
707 ScDocShell* pOtherSh = rOtherDoc.GetDocumentShell();
708 if (pOtherSh)
710 const SfxMedium* pOtherMed = pOtherSh->GetMedium();
711 if (pOtherMed)
712 aOtherFile = pOtherMed->GetName();
714 bool bSameDoc = ( aThisFile == aOtherFile && !aThisFile.isEmpty() );
715 if ( !bSameDoc )
717 // create change actions from comparing with the name of the user
718 // who last saved the document
719 // (only if comparing different documents)
721 using namespace ::com::sun::star;
722 uno::Reference<document::XDocumentProperties> xDocProps(
723 GetModel()->getDocumentProperties());
724 OSL_ENSURE(xDocProps.is(), "no DocumentProperties");
725 OUString aDocUser = xDocProps->getModifiedBy();
727 if ( !aDocUser.isEmpty() )
728 pTrack->SetUser( aDocUser );
732 m_pDocument->CompareDocument( rOtherDoc );
734 pTrack = m_pDocument->GetChangeTrack();
735 if ( pTrack )
736 pTrack->SetUser( aOldUser );
738 PostPaintGridAll();
739 SetDocumentModified();
742 // Merge (combine documents)
744 static bool lcl_Equal( const ScChangeAction* pA, const ScChangeAction* pB, bool bIgnore100Sec )
746 return pA && pB &&
747 pA->GetActionNumber() == pB->GetActionNumber() &&
748 pA->GetType() == pB->GetType() &&
749 pA->GetUser() == pB->GetUser() &&
750 (bIgnore100Sec ?
751 pA->GetDateTimeUTC().IsEqualIgnoreNanoSec( pB->GetDateTimeUTC() ) :
752 pA->GetDateTimeUTC() == pB->GetDateTimeUTC());
753 // don't compare state if an old change has been accepted
756 static bool lcl_FindAction( ScDocument& rDoc, const ScChangeAction* pAction, ScDocument& rSearchDoc, const ScChangeAction* pFirstSearchAction, const ScChangeAction* pLastSearchAction, bool bIgnore100Sec )
758 if ( !pAction || !pFirstSearchAction || !pLastSearchAction )
760 return false;
763 sal_uLong nLastSearchAction = pLastSearchAction->GetActionNumber();
764 const ScChangeAction* pA = pFirstSearchAction;
765 while ( pA && pA->GetActionNumber() <= nLastSearchAction )
767 if ( pAction->GetType() == pA->GetType() &&
768 pAction->GetUser() == pA->GetUser() &&
769 (bIgnore100Sec ?
770 pAction->GetDateTimeUTC().IsEqualIgnoreNanoSec( pA->GetDateTimeUTC() ) :
771 pAction->GetDateTimeUTC() == pA->GetDateTimeUTC() ) &&
772 pAction->GetBigRange() == pA->GetBigRange() )
774 OUString aActionDesc = pAction->GetDescription(rDoc, true);
775 OUString aADesc = pA->GetDescription(rSearchDoc, true);
776 if (aActionDesc == aADesc)
778 OSL_FAIL( "lcl_FindAction(): found equal action!" );
779 return true;
782 pA = pA->GetNext();
785 return false;
788 void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheckDuplicates, sal_uLong nOffset, ScChangeActionMergeMap* pMergeMap, bool bInverseMap )
790 ScTabViewShell* pViewSh = GetBestViewShell( false ); //! functions to the DocShell
791 if (!pViewSh)
792 return;
794 ScChangeTrack* pSourceTrack = rOtherDoc.GetChangeTrack();
795 if (!pSourceTrack)
796 return; //! nothing to do - error notification?
798 ScChangeTrack* pThisTrack = m_pDocument->GetChangeTrack();
799 if ( !pThisTrack )
800 { // turn on
801 m_pDocument->StartChangeTracking();
802 pThisTrack = m_pDocument->GetChangeTrack();
803 OSL_ENSURE(pThisTrack,"ChangeTracking not enabled?");
804 if ( !bShared )
806 // turn on visual RedLining
807 ScChangeViewSettings aChangeViewSet;
808 aChangeViewSet.SetShowChanges(true);
809 m_pDocument->SetChangeViewSettings(aChangeViewSet);
813 // include Nano seconds in compare?
814 bool bIgnore100Sec = !pSourceTrack->IsTimeNanoSeconds() ||
815 !pThisTrack->IsTimeNanoSeconds();
817 // find common initial position
818 sal_uLong nFirstNewNumber = 0;
819 const ScChangeAction* pSourceAction = pSourceTrack->GetFirst();
820 const ScChangeAction* pThisAction = pThisTrack->GetFirst();
821 // skip identical actions
822 while ( lcl_Equal( pSourceAction, pThisAction, bIgnore100Sec ) )
824 nFirstNewNumber = pSourceAction->GetActionNumber() + 1;
825 pSourceAction = pSourceAction->GetNext();
826 pThisAction = pThisAction->GetNext();
828 // pSourceAction and pThisAction now point to the first "own" actions
829 // The common actions before don't interest at all
831 //! Inquiry if the documents where equal before the change tracking !!!
833 const ScChangeAction* pFirstMergeAction = pSourceAction;
834 const ScChangeAction* pFirstSearchAction = pThisAction;
836 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
837 const ScChangeAction* pLastSearchAction = pThisTrack->GetLast();
839 // Create MergeChangeData from the following actions
840 sal_uLong nNewActionCount = 0;
841 const ScChangeAction* pCount = pSourceAction;
842 while ( pCount )
844 if ( bShared || !ScChangeTrack::MergeIgnore( *pCount, nFirstNewNumber ) )
845 ++nNewActionCount;
846 pCount = pCount->GetNext();
848 if (!nNewActionCount)
849 return; //! nothing to do - error notification?
850 // from here on no return
852 ScProgress aProgress( this, u"..."_ustr, nNewActionCount, true );
854 sal_uLong nLastMergeAction = pSourceTrack->GetLast()->GetActionNumber();
855 // UpdateReference-Undo, valid references for the last common state
856 pSourceTrack->MergePrepare( pFirstMergeAction, bShared );
858 // adjust MergeChangeData to all yet following actions in this document
859 // -> references valid for this document
860 while ( pThisAction )
862 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
863 if ( !bShared || !ScChangeTrack::MergeIgnore( *pThisAction, nFirstNewNumber ) )
865 ScChangeActionType eType = pThisAction->GetType();
866 switch ( eType )
868 case SC_CAT_INSERT_COLS :
869 case SC_CAT_INSERT_ROWS :
870 case SC_CAT_INSERT_TABS :
871 pSourceTrack->AppendInsert( pThisAction->GetBigRange().MakeRange( GetDocument() ) );
872 break;
873 case SC_CAT_DELETE_COLS :
874 case SC_CAT_DELETE_ROWS :
875 case SC_CAT_DELETE_TABS :
877 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pThisAction);
878 if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
879 { // deleted table contains deleted cols, which are not
880 sal_uLong nStart, nEnd;
881 pSourceTrack->AppendDeleteRange(
882 pDel->GetOverAllRange().MakeRange( GetDocument() ), nullptr, nStart, nEnd );
885 break;
886 case SC_CAT_MOVE :
888 const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pThisAction);
889 pSourceTrack->AppendMove( pMove->GetFromRange().MakeRange( GetDocument() ),
890 pMove->GetBigRange().MakeRange( GetDocument() ), nullptr );
892 break;
893 default:
895 // added to avoid warnings
899 pThisAction = pThisAction->GetNext();
902 LockPaint(); // #i73877# no repainting after each action
904 // take over MergeChangeData into the current document
905 bool bHasRejected = false;
906 OUString aOldUser = pThisTrack->GetUser();
907 pThisTrack->SetUseFixDateTime( true );
908 ScMarkData& rMarkData = pViewSh->GetViewData().GetMarkData();
909 ScMarkData aOldMarkData( rMarkData );
910 pSourceAction = pFirstMergeAction;
911 while ( pSourceAction && pSourceAction->GetActionNumber() <= nLastMergeAction )
913 bool bMergeAction = false;
914 if ( bShared )
916 if ( !bCheckDuplicates || !lcl_FindAction( rOtherDoc, pSourceAction, *m_pDocument, pFirstSearchAction, pLastSearchAction, bIgnore100Sec ) )
918 bMergeAction = true;
921 else
923 if ( !ScChangeTrack::MergeIgnore( *pSourceAction, nFirstNewNumber ) )
925 bMergeAction = true;
929 if ( bMergeAction )
931 ScChangeActionType eSourceType = pSourceAction->GetType();
932 if ( !bShared && pSourceAction->IsDeletedIn() )
934 //! does it need to be determined yet if really deleted in
935 //! _this_ document?
937 // lies in a range, which was deleted in this document
938 // -> is omitted
939 //! ??? revert deletion action ???
940 //! ??? save action somewhere else ???
941 #if OSL_DEBUG_LEVEL > 0
942 OUString aValue;
943 if ( eSourceType == SC_CAT_CONTENT )
944 aValue = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( m_pDocument.get() );
945 SAL_WARN( "sc", aValue << " omitted");
946 #endif
948 else
950 //! Take over date/author/comment of the source action!
952 pThisTrack->SetUser( pSourceAction->GetUser() );
953 pThisTrack->SetFixDateTimeUTC( pSourceAction->GetDateTimeUTC() );
954 sal_uLong nOldActionMax = pThisTrack->GetActionMax();
956 bool bExecute = true;
957 sal_uLong nReject = pSourceAction->GetRejectAction();
958 if ( nReject )
960 if ( bShared )
962 if ( nReject >= nFirstNewNumber )
964 nReject += nOffset;
966 ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
967 if ( pOldAction && pOldAction->IsVirgin() )
969 pThisTrack->Reject( pOldAction );
970 bHasRejected = true;
971 bExecute = false;
974 else
976 // decline old action (of the common ones)
977 ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
978 if (pOldAction && pOldAction->GetState() == SC_CAS_VIRGIN)
980 //! what happens at actions, which were accepted in this document???
981 //! error notification or what???
982 //! or execute reject change normally
984 pThisTrack->Reject(pOldAction);
985 bHasRejected = true; // for Paint
987 bExecute = false;
991 if ( bExecute )
993 // execute normally
994 ScRange aSourceRange = pSourceAction->GetBigRange().MakeRange( GetDocument() );
995 rMarkData.SelectOneTable( aSourceRange.aStart.Tab() );
996 switch ( eSourceType )
998 case SC_CAT_CONTENT:
1000 //! Test if it was at the very bottom in the document, then automatic
1001 //! row insert ???
1003 OSL_ENSURE( aSourceRange.aStart == aSourceRange.aEnd, "huch?" );
1004 ScAddress aPos = aSourceRange.aStart;
1005 OUString aValue = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( m_pDocument.get() );
1006 ScMatrixMode eMatrix = ScMatrixMode::NONE;
1007 const ScCellValue& rCell = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewCell();
1008 if (rCell.getType() == CELLTYPE_FORMULA)
1009 eMatrix = rCell.getFormula()->GetMatrixFlag();
1010 switch ( eMatrix )
1012 case ScMatrixMode::NONE :
1013 pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue );
1014 break;
1015 case ScMatrixMode::Formula :
1017 SCCOL nCols;
1018 SCROW nRows;
1019 rCell.getFormula()->GetMatColsRows(nCols, nRows);
1020 aSourceRange.aEnd.SetCol( aPos.Col() + nCols - 1 );
1021 aSourceRange.aEnd.SetRow( aPos.Row() + nRows - 1 );
1022 aValue = aValue.copy(1, aValue.getLength()-2); // remove the 1st and last characters.
1023 GetDocFunc().EnterMatrix( aSourceRange,
1024 nullptr, nullptr, aValue, false, false,
1025 OUString(), formula::FormulaGrammar::GRAM_DEFAULT );
1027 break;
1028 case ScMatrixMode::Reference : // do nothing
1029 break;
1032 break;
1033 case SC_CAT_INSERT_TABS :
1035 OUString aName;
1036 m_pDocument->CreateValidTabName( aName );
1037 (void)GetDocFunc().InsertTable( aSourceRange.aStart.Tab(), aName, true, false );
1039 break;
1040 case SC_CAT_INSERT_ROWS:
1041 (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSROWS_BEFORE, true, false );
1042 break;
1043 case SC_CAT_INSERT_COLS:
1044 (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSCOLS_BEFORE, true, false );
1045 break;
1046 case SC_CAT_DELETE_TABS :
1047 (void)GetDocFunc().DeleteTable( aSourceRange.aStart.Tab(), true );
1048 break;
1049 case SC_CAT_DELETE_ROWS:
1051 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
1052 if ( pDel->IsTopDelete() )
1054 aSourceRange = pDel->GetOverAllRange().MakeRange( GetDocument() );
1055 (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Rows, false );
1057 // #i101099# [Collaboration] Changes are not correctly shown
1058 if ( bShared )
1060 ScChangeAction* pAct = pThisTrack->GetLast();
1061 if ( pAct && pAct->GetType() == eSourceType && pAct->IsDeletedIn() && !pSourceAction->IsDeletedIn() )
1063 pAct->RemoveAllDeletedIn();
1068 break;
1069 case SC_CAT_DELETE_COLS:
1071 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
1072 if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
1073 { // deleted table contains deleted cols, which are not
1074 aSourceRange = pDel->GetOverAllRange().MakeRange( GetDocument() );
1075 (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Cols, false );
1078 break;
1079 case SC_CAT_MOVE :
1081 const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pSourceAction);
1082 ScRange aFromRange( pMove->GetFromRange().MakeRange( GetDocument() ) );
1083 (void)GetDocFunc().MoveBlock( aFromRange,
1084 aSourceRange.aStart, true, true, false, false );
1086 break;
1087 default:
1089 // added to avoid warnings
1093 const OUString& rComment = pSourceAction->GetComment();
1094 if ( !rComment.isEmpty() )
1096 ScChangeAction* pAct = pThisTrack->GetLast();
1097 if ( pAct && pAct->GetActionNumber() > nOldActionMax )
1098 pAct->SetComment( rComment );
1099 else
1100 OSL_FAIL( "MergeDocument: what to do with the comment?!?" );
1103 // adjust references
1104 pSourceTrack->MergeOwn( const_cast<ScChangeAction*>(pSourceAction), nFirstNewNumber, bShared );
1106 // merge action state
1107 if ( bShared && !pSourceAction->IsRejected() )
1109 ScChangeAction* pAct = pThisTrack->GetLast();
1110 if ( pAct && pAct->GetActionNumber() > nOldActionMax )
1112 ScChangeTrack::MergeActionState( pAct, pSourceAction );
1116 // fill merge map
1117 if ( bShared && pMergeMap )
1119 ScChangeAction* pAct = pThisTrack->GetLast();
1120 if ( pAct && pAct->GetActionNumber() > nOldActionMax )
1122 sal_uLong nActionMax = pAct->GetActionNumber();
1123 sal_uLong nActionCount = nActionMax - nOldActionMax;
1124 sal_uLong nAction = nActionMax - nActionCount + 1;
1125 sal_uLong nSourceAction = pSourceAction->GetActionNumber() - nActionCount + 1;
1126 while ( nAction <= nActionMax )
1128 if ( bInverseMap )
1130 (*pMergeMap)[ nAction++ ] = nSourceAction++;
1132 else
1134 (*pMergeMap)[ nSourceAction++ ] = nAction++;
1140 aProgress.SetStateCountDown( --nNewActionCount );
1142 pSourceAction = pSourceAction->GetNext();
1145 rMarkData = std::move(aOldMarkData);
1146 pThisTrack->SetUser(aOldUser);
1147 pThisTrack->SetUseFixDateTime( false );
1149 pSourceTrack->Clear(); //! this one is bungled now
1151 if (bHasRejected)
1152 PostPaintGridAll(); // Reject() doesn't paint itself
1154 UnlockPaint();
1157 bool ScDocShell::MergeSharedDocument( ScDocShell* pSharedDocShell )
1159 if ( !pSharedDocShell )
1161 return false;
1164 ScChangeTrack* pThisTrack = m_pDocument->GetChangeTrack();
1165 if ( !pThisTrack )
1167 return false;
1170 ScDocument& rSharedDoc = pSharedDocShell->GetDocument();
1171 ScChangeTrack* pSharedTrack = rSharedDoc.GetChangeTrack();
1172 if ( !pSharedTrack )
1174 return false;
1177 // reset show changes
1178 ScChangeViewSettings aChangeViewSet;
1179 aChangeViewSet.SetShowChanges( false );
1180 m_pDocument->SetChangeViewSettings( aChangeViewSet );
1182 // find first merge action in this document
1183 bool bIgnore100Sec = !pThisTrack->IsTimeNanoSeconds() || !pSharedTrack->IsTimeNanoSeconds();
1184 ScChangeAction* pThisAction = pThisTrack->GetFirst();
1185 ScChangeAction* pSharedAction = pSharedTrack->GetFirst();
1186 while ( lcl_Equal( pThisAction, pSharedAction, bIgnore100Sec ) )
1188 pThisAction = pThisAction->GetNext();
1189 pSharedAction = pSharedAction->GetNext();
1192 if ( pSharedAction )
1194 if ( pThisAction )
1196 // merge own changes into shared document
1197 sal_uLong nActStartShared = pSharedAction->GetActionNumber();
1198 sal_uLong nActEndShared = pSharedTrack->GetActionMax();
1199 std::optional<ScDocument> pTmpDoc(std::in_place);
1200 for ( sal_Int32 nIndex = 0; nIndex < m_pDocument->GetTableCount(); ++nIndex )
1202 OUString sTabName;
1203 pTmpDoc->CreateValidTabName( sTabName );
1204 pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
1206 m_pDocument->GetChangeTrack()->Clone( &*pTmpDoc );
1207 ScChangeActionMergeMap aOwnInverseMergeMap;
1208 pSharedDocShell->MergeDocument( *pTmpDoc, true, true, 0, &aOwnInverseMergeMap, true );
1209 pTmpDoc.reset();
1210 sal_uLong nActStartOwn = nActEndShared + 1;
1211 sal_uLong nActEndOwn = pSharedTrack->GetActionMax();
1213 // find conflicts
1214 ScConflictsList aConflictsList;
1215 ScConflictsFinder aFinder( pSharedTrack, nActStartShared, nActEndShared, nActStartOwn, nActEndOwn, aConflictsList );
1216 if ( aFinder.Find() )
1218 ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnInverseMergeMap );
1219 bool bLoop = true;
1220 while ( bLoop )
1222 bLoop = false;
1223 weld::Window* pWin = GetActiveDialogParent();
1224 ScConflictsDlg aDlg(pWin, GetViewData(), &rSharedDoc, aConflictsList);
1225 if (aDlg.run() == RET_CANCEL)
1227 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pWin,
1228 VclMessageType::Question, VclButtonsType::YesNo,
1229 ScResId(STR_DOC_WILLNOTBESAVED)));
1230 xQueryBox->set_default_response(RET_YES);
1231 if (xQueryBox->run() == RET_YES)
1233 return false;
1235 else
1237 bLoop = true;
1243 // undo own changes in shared document
1244 pSharedTrack->Undo( nActStartOwn, nActEndOwn );
1246 // clone change track for merging into own document
1247 pTmpDoc.emplace();
1248 for ( sal_Int32 nIndex = 0; nIndex < m_pDocument->GetTableCount(); ++nIndex )
1250 OUString sTabName;
1251 pTmpDoc->CreateValidTabName( sTabName );
1252 pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
1254 pThisTrack->Clone( &*pTmpDoc );
1256 // undo own changes since last save in own document
1257 sal_uLong nStartShared = pThisAction->GetActionNumber();
1258 ScChangeAction* pAction = pThisTrack->GetLast();
1259 while ( pAction && pAction->GetActionNumber() >= nStartShared )
1261 pThisTrack->Reject( pAction, true );
1262 pAction = pAction->GetPrev();
1265 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
1266 pThisTrack->Undo( nStartShared, pThisTrack->GetActionMax(), true );
1268 // merge shared changes into own document
1269 ScChangeActionMergeMap aSharedMergeMap;
1270 MergeDocument( rSharedDoc, true, true, 0, &aSharedMergeMap );
1271 sal_uLong nEndShared = pThisTrack->GetActionMax();
1273 // resolve conflicts for shared non-content actions
1274 if ( !aConflictsList.empty() )
1276 ScConflictsListHelper::TransformConflictsList( aConflictsList, &aSharedMergeMap, nullptr );
1277 ScConflictsResolver aResolver( pThisTrack, aConflictsList );
1278 pAction = pThisTrack->GetAction( nEndShared );
1279 while ( pAction && pAction->GetActionNumber() >= nStartShared )
1281 aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
1282 false /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
1283 pAction = pAction->GetPrev();
1286 nEndShared = pThisTrack->GetActionMax();
1288 // only show changes from shared document
1289 aChangeViewSet.SetShowChanges( true );
1290 aChangeViewSet.SetShowAccepted( true );
1291 aChangeViewSet.SetHasActionRange();
1292 aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
1293 m_pDocument->SetChangeViewSettings( aChangeViewSet );
1295 // merge own changes back into own document
1296 sal_uLong nStartOwn = nEndShared + 1;
1297 ScChangeActionMergeMap aOwnMergeMap;
1298 MergeDocument( *pTmpDoc, true, true, nEndShared - nStartShared + 1, &aOwnMergeMap );
1299 pTmpDoc.reset();
1300 sal_uLong nEndOwn = pThisTrack->GetActionMax();
1302 // resolve conflicts for shared content actions and own actions
1303 if ( !aConflictsList.empty() )
1305 ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnMergeMap );
1306 ScConflictsResolver aResolver( pThisTrack, aConflictsList );
1307 pAction = pThisTrack->GetAction( nEndShared );
1308 while ( pAction && pAction->GetActionNumber() >= nStartShared )
1310 aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
1311 true /*bHandleContentAction*/, false /*bHandleNonContentAction*/ );
1312 pAction = pAction->GetPrev();
1315 pAction = pThisTrack->GetAction( nEndOwn );
1316 while ( pAction && pAction->GetActionNumber() >= nStartOwn )
1318 aResolver.HandleAction( pAction, false /*bIsSharedAction*/,
1319 true /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
1320 pAction = pAction->GetPrev();
1324 else
1326 // merge shared changes into own document
1327 sal_uLong nStartShared = pThisTrack->GetActionMax() + 1;
1328 MergeDocument( rSharedDoc, true, true );
1329 sal_uLong nEndShared = pThisTrack->GetActionMax();
1331 // only show changes from shared document
1332 aChangeViewSet.SetShowChanges( true );
1333 aChangeViewSet.SetShowAccepted( true );
1334 aChangeViewSet.SetHasActionRange();
1335 aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
1336 m_pDocument->SetChangeViewSettings( aChangeViewSet );
1339 // update view
1340 PostPaintExtras();
1341 PostPaintGridAll();
1343 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
1344 VclMessageType::Info, VclButtonsType::Ok,
1345 ScResId(STR_DOC_UPDATED)));
1346 xInfoBox->run();
1349 return ( pThisAction != nullptr );
1352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */