1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
21 #include <com/sun/star/document/XDocumentProperties.hpp>
22
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 <sal/log.hxx>
29 #include <sfx2/viewfrm.hxx>
30 #include <sfx2/app.hxx>
31 #include <sfx2/docfile.hxx>
32 #include <sfx2/printer.hxx>
33 #include <svx/pageitem.hxx>
34 #include <svx/postattr.hxx>
35 #include <svx/svxids.hrc>
36 #include <unotools/misccfg.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/virdev.hxx>
39 #include <vcl/weld.hxx>
40
41 #include <docsh.hxx>
42 #include "docshimp.hxx"
43 #include <scmod.hxx>
44 #include <tabvwsh.hxx>
45 #include <viewdata.hxx>
46 #include <docpool.hxx>
47 #include <stlpool.hxx>
48 #include <patattr.hxx>
49 #include <uiitems.hxx>
50 #include <hints.hxx>
51 #include <docoptio.hxx>
52 #include <viewopti.hxx>
53 #include <pntlock.hxx>
54 #include <chgtrack.hxx>
55 #include <docfunc.hxx>
56 #include <formulacell.hxx>
57 #include <chgviset.hxx>
58 #include <progress.hxx>
59 #include <redcom.hxx>
60 #include <inputopt.hxx>
61 #include <drwlayer.hxx>
62 #include <inputhdl.hxx>
63 #include <conflictsdlg.hxx>
64 #include <globstr.hrc>
65 #include <scresid.hxx>
66 #include <markdata.hxx>
67 #include <memory>
68 #include <formulaopt.hxx>
69
70 #include <comphelper/lok.hxx>
71 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
72 #include <sfx2/lokhelper.hxx>
73
74 // Redraw - Notifications
75
PostEditView(ScEditEngineDefaulter * pEditEngine,const ScAddress & rCursorPos)76 void ScDocShell::PostEditView( ScEditEngineDefaulter* pEditEngine, const ScAddress& rCursorPos )
77 {
78 // Broadcast( ScEditViewHint( pEditEngine, rCursorPos ) );
79
80 // Test: only active ViewShell
81
82 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
83 if (pViewSh && pViewSh->GetViewData().GetDocShell() == this)
84 {
85 ScEditViewHint aHint( pEditEngine, rCursorPos );
86 pViewSh->Notify( *this, aHint );
87 }
88 }
89
PostDataChanged()90 void ScDocShell::PostDataChanged()
91 {
92 Broadcast( SfxHint( SfxHintId::ScDataChanged ) );
93 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScAnyDataChanged )); // Navigator
94 m_aDocument.PrepareFormulaCalc();
95 //! notify navigator directly!
96 }
97
PostPaint(SCCOL nStartCol,SCROW nStartRow,SCTAB nStartTab,SCCOL nEndCol,SCROW nEndRow,SCTAB nEndTab,PaintPartFlags nPart,sal_uInt16 nExtFlags)98 void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
99 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, PaintPartFlags nPart,
100 sal_uInt16 nExtFlags )
101 {
102 ScRange aRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
103 PostPaint(aRange, nPart, nExtFlags);
104 }
105
PostPaint(const ScRangeList & rRanges,PaintPartFlags nPart,sal_uInt16 nExtFlags)106 void ScDocShell::PostPaint( const ScRangeList& rRanges, PaintPartFlags nPart, sal_uInt16 nExtFlags )
107 {
108 ScRangeList aPaintRanges;
109 for (size_t i = 0, n = rRanges.size(); i < n; ++i)
110 {
111 const ScRange& rRange = rRanges[i];
112 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
113 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
114 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
115
116 if (!ValidCol(nCol1)) nCol1 = m_aDocument.MaxCol();
117 if (!ValidRow(nRow1)) nRow1 = m_aDocument.MaxRow();
118 if (!ValidCol(nCol2)) nCol2 = m_aDocument.MaxCol();
119 if (!ValidRow(nRow2)) nRow2 = m_aDocument.MaxRow();
120
121 if ( m_pPaintLockData )
122 {
123 // #i54081# PaintPartFlags::Extras still has to be broadcast because it changes the
124 // current sheet if it's invalid. All other flags added to pPaintLockData.
125 PaintPartFlags nLockPart = nPart & ~PaintPartFlags::Extras;
126 if ( nLockPart != PaintPartFlags::NONE )
127 {
128 //! nExtFlags ???
129 m_pPaintLockData->AddRange( ScRange( nCol1, nRow1, nTab1,
130 nCol2, nRow2, nTab2 ), nLockPart );
131 }
132
133 nPart &= PaintPartFlags::Extras; // for broadcasting
134 if (nPart == PaintPartFlags::NONE)
135 continue;
136 }
137
138 if (nExtFlags & SC_PF_LINES) // respect space for lines
139 {
140 //! check for hidden columns/rows!
141 if (nCol1>0) --nCol1;
142 if (nCol2<m_aDocument.MaxCol()) ++nCol2;
143 if (nRow1>0) --nRow1;
144 if (nRow2<m_aDocument.MaxRow()) ++nRow2;
145 }
146
147 // expand for the merged ones
148 if (nExtFlags & SC_PF_TESTMERGE)
149 m_aDocument.ExtendMerge( nCol1, nRow1, nCol2, nRow2, nTab1 );
150
151 if ( nCol1 != 0 || nCol2 != m_aDocument.MaxCol() )
152 {
153 // Extend to whole rows if SC_PF_WHOLEROWS is set, or rotated or non-left
154 // aligned cells are contained (see UpdatePaintExt).
155 // Special handling for RTL text (#i9731#) is unnecessary now with full
156 // support of right-aligned text.
157
158 if ( ( nExtFlags & SC_PF_WHOLEROWS ) ||
159 m_aDocument.HasAttrib( nCol1,nRow1,nTab1,
160 m_aDocument.MaxCol(),nRow2,nTab2, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
161 {
162 nCol1 = 0;
163 nCol2 = m_aDocument.MaxCol();
164 }
165 }
166 aPaintRanges.push_back(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
167 }
168
169 Broadcast(ScPaintHint(aPaintRanges.Combine(), nPart));
170
171 // LOK: we are supposed to update the row / columns headers (and actually
172 // the document size too - cell size affects that, obviously)
173 if ((nPart & (PaintPartFlags::Top | PaintPartFlags::Left)) && comphelper::LibreOfficeKit::isActive())
174 {
175 ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetModel());
176 SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
177 }
178 }
179
PostPaintGridAll()180 void ScDocShell::PostPaintGridAll()
181 {
182 PostPaint( 0,0,0, m_aDocument.MaxCol(),m_aDocument.MaxRow(),MAXTAB, PaintPartFlags::Grid );
183 }
184
PostPaintCell(SCCOL nCol,SCROW nRow,SCTAB nTab)185 void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab )
186 {
187 PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, SC_PF_TESTMERGE );
188 }
189
PostPaintCell(const ScAddress & rPos)190 void ScDocShell::PostPaintCell( const ScAddress& rPos )
191 {
192 PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab() );
193 }
194
PostPaintExtras()195 void ScDocShell::PostPaintExtras()
196 {
197 PostPaint( 0,0,0, m_aDocument.MaxCol(),m_aDocument.MaxRow(),MAXTAB, PaintPartFlags::Extras );
198 }
199
UpdatePaintExt(sal_uInt16 & rExtFlags,const ScRange & rRange)200 void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, const ScRange& rRange )
201 {
202 if ( ( rExtFlags & SC_PF_LINES ) == 0 &&
203 m_aDocument.HasAttrib( rRange, HasAttrFlags::Lines | HasAttrFlags::Shadow | HasAttrFlags::Conditional ) )
204 {
205 // If the range contains lines, shadow or conditional formats,
206 // set SC_PF_LINES to include one extra cell in all directions.
207
208 rExtFlags |= SC_PF_LINES;
209 }
210
211 if ( ( rExtFlags & SC_PF_WHOLEROWS ) == 0 &&
212 ( rRange.aStart.Col() != 0 || rRange.aEnd.Col() != m_aDocument.MaxCol() ) &&
213 m_aDocument.HasAttrib( rRange, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
214 {
215 // If the range contains (logically) right- or center-aligned cells,
216 // or rotated cells, set SC_PF_WHOLEROWS to paint the whole rows.
217 // This test isn't needed after the cell changes, because it's also
218 // tested in PostPaint. UpdatePaintExt may later be changed to do this
219 // only if called before the changes.
220
221 rExtFlags |= SC_PF_WHOLEROWS;
222 }
223 }
224
UpdatePaintExt(sal_uInt16 & rExtFlags,SCCOL nStartCol,SCROW nStartRow,SCTAB nStartTab,SCCOL nEndCol,SCROW nEndRow,SCTAB nEndTab)225 void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
226 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab )
227 {
228 UpdatePaintExt( rExtFlags, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) );
229 }
230
LockPaint_Impl(bool bDoc)231 void ScDocShell::LockPaint_Impl(bool bDoc)
232 {
233 if ( !m_pPaintLockData )
234 m_pPaintLockData.reset( new ScPaintLockData );
235 m_pPaintLockData->IncLevel(bDoc);
236 }
237
UnlockPaint_Impl(bool bDoc)238 void ScDocShell::UnlockPaint_Impl(bool bDoc)
239 {
240 if ( m_pPaintLockData )
241 {
242 if ( m_pPaintLockData->GetLevel(bDoc) )
243 m_pPaintLockData->DecLevel(bDoc);
244 if (!m_pPaintLockData->GetLevel(!bDoc) && !m_pPaintLockData->GetLevel(bDoc))
245 {
246 // Execute Paint now
247
248 // don't continue collecting
249 std::unique_ptr<ScPaintLockData> pPaint = std::move(m_pPaintLockData);
250
251 ScRangeListRef xRangeList = pPaint->GetRangeList();
252 if ( xRangeList.is() )
253 {
254 PaintPartFlags nParts = pPaint->GetParts();
255 for ( size_t i = 0, nCount = xRangeList->size(); i < nCount; i++ )
256 {
257 //! nExtFlags ???
258 ScRange const & rRange = (*xRangeList)[i];
259 PostPaint( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
260 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
261 nParts );
262 }
263 }
264
265 if ( pPaint->GetModified() )
266 SetDocumentModified();
267 }
268 }
269 else
270 {
271 OSL_FAIL("UnlockPaint without LockPaint");
272 }
273 }
274
LockDocument_Impl(sal_uInt16 nNew)275 void ScDocShell::LockDocument_Impl(sal_uInt16 nNew)
276 {
277 if (!m_nDocumentLock)
278 {
279 ScDrawLayer* pDrawLayer = m_aDocument.GetDrawLayer();
280 if (pDrawLayer)
281 pDrawLayer->setLock(true);
282 }
283 m_nDocumentLock = nNew;
284 }
285
UnlockDocument_Impl(sal_uInt16 nNew)286 void ScDocShell::UnlockDocument_Impl(sal_uInt16 nNew)
287 {
288 m_nDocumentLock = nNew;
289 if (!m_nDocumentLock)
290 {
291 ScDrawLayer* pDrawLayer = m_aDocument.GetDrawLayer();
292 if (pDrawLayer)
293 pDrawLayer->setLock(false);
294 }
295 }
296
SetLockCount(sal_uInt16 nNew)297 void ScDocShell::SetLockCount(sal_uInt16 nNew)
298 {
299 if (nNew) // set
300 {
301 if ( !m_pPaintLockData )
302 m_pPaintLockData.reset( new ScPaintLockData );
303 m_pPaintLockData->SetDocLevel(nNew-1);
304 LockDocument_Impl(nNew);
305 }
306 else if (m_pPaintLockData) // delete
307 {
308 m_pPaintLockData->SetDocLevel(0); // at unlock, execute immediately
309 UnlockPaint_Impl(true); // now
310 UnlockDocument_Impl(0);
311 }
312 }
313
LockPaint()314 void ScDocShell::LockPaint()
315 {
316 LockPaint_Impl(false);
317 }
318
UnlockPaint()319 void ScDocShell::UnlockPaint()
320 {
321 UnlockPaint_Impl(false);
322 }
323
LockDocument()324 void ScDocShell::LockDocument()
325 {
326 LockPaint_Impl(true);
327 LockDocument_Impl(m_nDocumentLock + 1);
328 }
329
UnlockDocument()330 void ScDocShell::UnlockDocument()
331 {
332 if (m_nDocumentLock)
333 {
334 UnlockPaint_Impl(true);
335 UnlockDocument_Impl(m_nDocumentLock - 1);
336 }
337 else
338 {
339 OSL_FAIL("UnlockDocument without LockDocument");
340 }
341 }
342
SetInplace(bool bInplace)343 void ScDocShell::SetInplace( bool bInplace )
344 {
345 if (m_bIsInplace != bInplace)
346 {
347 m_bIsInplace = bInplace;
348 CalcOutputFactor();
349 }
350 }
351
CalcOutputFactor()352 void ScDocShell::CalcOutputFactor()
353 {
354 if (m_bIsInplace)
355 {
356 m_nPrtToScreenFactor = 1.0; // otherwise it does not match the inactive display
357 return;
358 }
359
360 bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
361 if (bTextWysiwyg)
362 {
363 m_nPrtToScreenFactor = 1.0;
364 return;
365 }
366
367 OUString aTestString(
368 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789");
369 long nPrinterWidth = 0;
370 long nWindowWidth = 0;
371 const ScPatternAttr* pPattern = &m_aDocument.GetPool()->GetDefaultItem(ATTR_PATTERN);
372
373 vcl::Font aDefFont;
374 OutputDevice* pRefDev = GetRefDevice();
375 MapMode aOldMode = pRefDev->GetMapMode();
376 vcl::Font aOldFont = pRefDev->GetFont();
377
378 pRefDev->SetMapMode(MapMode(MapUnit::MapPixel));
379 pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, pRefDev); // font color doesn't matter here
380 pRefDev->SetFont(aDefFont);
381 nPrinterWidth = pRefDev->PixelToLogic(Size(pRefDev->GetTextWidth(aTestString), 0), MapMode(MapUnit::Map100thMM)).Width();
382 pRefDev->SetFont(aOldFont);
383 pRefDev->SetMapMode(aOldMode);
384
385 ScopedVclPtrInstance< VirtualDevice > pVirtWindow( *Application::GetDefaultDevice() );
386 pVirtWindow->SetMapMode(MapMode(MapUnit::MapPixel));
387 pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, pVirtWindow); // font color doesn't matter here
388 pVirtWindow->SetFont(aDefFont);
389 nWindowWidth = pVirtWindow->GetTextWidth(aTestString);
390 nWindowWidth = static_cast<long>( nWindowWidth / ScGlobal::nScreenPPTX * HMM_PER_TWIPS );
391
392 if (nPrinterWidth && nWindowWidth)
393 m_nPrtToScreenFactor = nPrinterWidth / static_cast<double>(nWindowWidth);
394 else
395 {
396 OSL_FAIL("GetTextSize returns 0 ??");
397 m_nPrtToScreenFactor = 1.0;
398 }
399 }
400
InitOptions(bool bForLoading)401 void ScDocShell::InitOptions(bool bForLoading) // called from InitNew and Load
402 {
403 // Settings from the SpellCheckCfg get into Doc- and ViewOptions
404
405 LanguageType nDefLang, nCjkLang, nCtlLang;
406 bool bAutoSpell;
407 ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang, bAutoSpell );
408 ScModule* pScMod = SC_MOD();
409
410 ScDocOptions aDocOpt = pScMod->GetDocOptions();
411 ScFormulaOptions aFormulaOpt = pScMod->GetFormulaOptions();
412 ScViewOptions aViewOpt = pScMod->GetViewOptions();
413 aDocOpt.SetAutoSpell( bAutoSpell );
414
415 // two-digit year entry from Tools->Options->General
416 aDocOpt.SetYear2000( sal::static_int_cast<sal_uInt16>( ::utl::MiscCfg().GetYear2000() ) );
417
418 if (bForLoading)
419 {
420 // #i112123# No style:decimal-places attribute means automatic decimals, not the configured default,
421 // so it must not be taken from the global options.
422 // Calculation settings are handled separately in ScXMLBodyContext::EndElement.
423 aDocOpt.SetStdPrecision( SvNumberFormatter::UNLIMITED_PRECISION );
424
425 // fdo#78294 The default null-date if
426 // <table:null-date table:date-value='...' />
427 // is absent is 1899-12-30 regardless what the configuration is set to.
428 // Import filters may override this value.
429 aDocOpt.SetDate( 30, 12, 1899);
430 }
431
432 m_aDocument.SetDocOptions( aDocOpt );
433 m_aDocument.SetViewOptions( aViewOpt );
434 SetFormulaOptions( aFormulaOpt, bForLoading );
435
436 // print options are now set directly before the printing
437
438 m_aDocument.SetLanguage( nDefLang, nCjkLang, nCtlLang );
439 }
440
GetDocumentPrinter()441 Printer* ScDocShell::GetDocumentPrinter() // for OLE
442 {
443 return m_aDocument.GetPrinter();
444 }
445
GetPrinter(bool bCreateIfNotExist)446 SfxPrinter* ScDocShell::GetPrinter(bool bCreateIfNotExist)
447 {
448 return m_aDocument.GetPrinter(bCreateIfNotExist);
449 }
450
UpdateFontList()451 void ScDocShell::UpdateFontList()
452 {
453 // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() );
454 m_pImpl->pFontList.reset(new FontList(GetRefDevice(), nullptr));
455 SvxFontListItem aFontListItem( m_pImpl->pFontList.get(), SID_ATTR_CHAR_FONTLIST );
456 PutItem( aFontListItem );
457
458 CalcOutputFactor();
459 }
460
GetRefDevice()461 OutputDevice* ScDocShell::GetRefDevice()
462 {
463 return m_aDocument.GetRefDevice();
464 }
465
SetPrinter(VclPtr<SfxPrinter> const & pNewPrinter,SfxPrinterChangeFlags nDiffFlags)466 sal_uInt16 ScDocShell::SetPrinter( VclPtr<SfxPrinter> const & pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
467 {
468 SfxPrinter *pOld = m_aDocument.GetPrinter( false );
469 if ( pOld && pOld->IsPrinting() )
470 return SFX_PRINTERROR_BUSY;
471
472 if (nDiffFlags & SfxPrinterChangeFlags::PRINTER)
473 {
474 if ( m_aDocument.GetPrinter() != pNewPrinter )
475 {
476 m_aDocument.SetPrinter( pNewPrinter );
477 m_aDocument.SetPrintOptions();
478
479 // MT: Use UpdateFontList: Will use Printer fonts only if needed!
480 /*
481 delete pImpl->pFontList;
482 pImpl->pFontList = new FontList( pNewPrinter, Application::GetDefaultDevice() );
483 SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST );
484 PutItem( aFontListItem );
485
486 CalcOutputFactor();
487 */
488 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
489 UpdateFontList();
490
491 ScModule* pScMod = SC_MOD();
492 SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this );
493 while (pFrame)
494 {
495 SfxViewShell* pSh = pFrame->GetViewShell();
496 if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pSh))
497 {
498 ScInputHandler* pInputHdl = pScMod->GetInputHdl(pViewSh);
499 if (pInputHdl)
500 pInputHdl->UpdateRefDevice();
501 }
502 pFrame = SfxViewFrame::GetNext( *pFrame, this );
503 }
504 }
505 }
506 else if (nDiffFlags & SfxPrinterChangeFlags::JOBSETUP)
507 {
508 SfxPrinter* pOldPrinter = m_aDocument.GetPrinter();
509 if (pOldPrinter)
510 {
511 pOldPrinter->SetJobSetup( pNewPrinter->GetJobSetup() );
512
513 // #i6706# Call SetPrinter with the old printer again, so the drawing layer
514 // RefDevice is set (calling ReformatAllTextObjects and rebuilding charts),
515 // because the JobSetup (printer device settings) may affect text layout.
516 m_aDocument.SetPrinter( pOldPrinter );
517 CalcOutputFactor(); // also with the new settings
518 }
519 }
520
521 if (nDiffFlags & SfxPrinterChangeFlags::OPTIONS)
522 {
523 m_aDocument.SetPrintOptions(); //! from new printer ???
524 }
525
526 if (nDiffFlags & (SfxPrinterChangeFlags::CHG_ORIENTATION | SfxPrinterChangeFlags::CHG_SIZE))
527 {
528 OUString aStyle = m_aDocument.GetPageStyle( GetCurTab() );
529 ScStyleSheetPool* pStPl = m_aDocument.GetStyleSheetPool();
530 SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(pStPl->Find(aStyle, SfxStyleFamily::Page));
531 if (pStyleSheet)
532 {
533 SfxItemSet& rSet = pStyleSheet->GetItemSet();
534
535 if (nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION)
536 {
537 const SvxPageItem& rOldItem = rSet.Get(ATTR_PAGE);
538 bool bWasLand = rOldItem.IsLandscape();
539 bool bNewLand = ( pNewPrinter->GetOrientation() == Orientation::Landscape );
540 if (bNewLand != bWasLand)
541 {
542 SvxPageItem aNewItem( rOldItem );
543 aNewItem.SetLandscape( bNewLand );
544 rSet.Put( aNewItem );
545
546 // flip size
547 Size aOldSize = rSet.Get(ATTR_PAGE_SIZE).GetSize();
548 Size aNewSize(aOldSize.Height(),aOldSize.Width());
549 SvxSizeItem aNewSItem(ATTR_PAGE_SIZE,aNewSize);
550 rSet.Put( aNewSItem );
551 }
552 }
553 if (nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE)
554 {
555 SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(pNewPrinter) );
556 rSet.Put( aPaperSizeItem );
557 }
558 }
559 }
560
561 PostPaint(0,0,0,m_aDocument.MaxCol(),m_aDocument.MaxRow(),MAXTAB,PaintPartFlags::All);
562
563 return 0;
564 }
565
GetChangeAction(const ScAddress & rPos)566 ScChangeAction* ScDocShell::GetChangeAction( const ScAddress& rPos )
567 {
568 ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
569 if (!pTrack)
570 return nullptr;
571
572 SCTAB nTab = rPos.Tab();
573
574 const ScChangeAction* pFound = nullptr;
575 const ScChangeAction* pAction = pTrack->GetFirst();
576 while (pAction)
577 {
578 ScChangeActionType eType = pAction->GetType();
579 //! ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc )...
580 if ( pAction->IsVisible() && eType != SC_CAT_DELETE_TABS )
581 {
582 const ScBigRange& rBig = pAction->GetBigRange();
583 if ( rBig.aStart.Tab() == nTab )
584 {
585 ScRange aRange = rBig.MakeRange();
586
587 if ( eType == SC_CAT_DELETE_ROWS )
588 aRange.aEnd.SetRow( aRange.aStart.Row() );
589 else if ( eType == SC_CAT_DELETE_COLS )
590 aRange.aEnd.SetCol( aRange.aStart.Col() );
591
592 if ( aRange.In( rPos ) )
593 {
594 pFound = pAction; // the last one wins
595 }
596 }
597 if ( pAction->GetType() == SC_CAT_MOVE )
598 {
599 ScRange aRange =
600 static_cast<const ScChangeActionMove*>(pAction)->
601 GetFromRange().MakeRange();
602 if ( aRange.In( rPos ) )
603 {
604 pFound = pAction;
605 }
606 }
607 }
608 pAction = pAction->GetNext();
609 }
610
611 return const_cast<ScChangeAction*>(pFound);
612 }
613
SetChangeComment(ScChangeAction * pAction,const OUString & rComment)614 void ScDocShell::SetChangeComment( ScChangeAction* pAction, const OUString& rComment )
615 {
616 if (pAction)
617 {
618 pAction->SetComment( rComment );
619 //! Undo ???
620 SetDocumentModified();
621
622 // Dialog-Notify
623 ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
624 if (pTrack)
625 {
626 sal_uLong nNumber = pAction->GetActionNumber();
627 pTrack->NotifyModified( ScChangeTrackMsgType::Change, nNumber, nNumber );
628 }
629 }
630 }
631
ExecuteChangeCommentDialog(ScChangeAction * pAction,weld::Window * pParent,bool bPrevNext)632 void ScDocShell::ExecuteChangeCommentDialog( ScChangeAction* pAction, weld::Window* pParent, bool bPrevNext)
633 {
634 if (!pAction) return; // without action is nothing...
635
636 OUString aComment = pAction->GetComment();
637 OUString aAuthor = pAction->GetUser();
638
639 DateTime aDT = pAction->GetDateTime();
640 OUString aDate = ScGlobal::pLocaleData->getDate( aDT ) + " " +
641 ScGlobal::pLocaleData->getTime( aDT, false );
642
643 SfxItemSet aSet(
644 GetPool(), svl::Items<SID_ATTR_POSTIT_AUTHOR, SID_ATTR_POSTIT_TEXT>{});
645
646 aSet.Put( SvxPostItTextItem ( aComment, SID_ATTR_POSTIT_TEXT ) );
647 aSet.Put( SvxPostItAuthorItem( aAuthor, SID_ATTR_POSTIT_AUTHOR ) );
648 aSet.Put( SvxPostItDateItem ( aDate, SID_ATTR_POSTIT_DATE ) );
649
650 std::unique_ptr<ScRedComDialog> pDlg(new ScRedComDialog( pParent, aSet,this,pAction,bPrevNext));
651
652 pDlg->Execute();
653 }
654
CompareDocument(ScDocument & rOtherDoc)655 void ScDocShell::CompareDocument( ScDocument& rOtherDoc )
656 {
657 ScChangeTrack* pTrack = m_aDocument.GetChangeTrack();
658 if ( pTrack && pTrack->GetFirst() )
659 {
660 //! there are changes -> inquiry if needs to be deleted
661 }
662
663 m_aDocument.EndChangeTracking();
664 m_aDocument.StartChangeTracking();
665
666 OUString aOldUser;
667 pTrack = m_aDocument.GetChangeTrack();
668 if ( pTrack )
669 {
670 aOldUser = pTrack->GetUser();
671
672 // check if comparing to same document
673
674 OUString aThisFile;
675 const SfxMedium* pThisMed = GetMedium();
676 if (pThisMed)
677 aThisFile = pThisMed->GetName();
678 OUString aOtherFile;
679 SfxObjectShell* pOtherSh = rOtherDoc.GetDocumentShell();
680 if (pOtherSh)
681 {
682 const SfxMedium* pOtherMed = pOtherSh->GetMedium();
683 if (pOtherMed)
684 aOtherFile = pOtherMed->GetName();
685 }
686 bool bSameDoc = ( aThisFile == aOtherFile && !aThisFile.isEmpty() );
687 if ( !bSameDoc )
688 {
689 // create change actions from comparing with the name of the user
690 // who last saved the document
691 // (only if comparing different documents)
692
693 using namespace ::com::sun::star;
694 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
695 GetModel(), uno::UNO_QUERY_THROW);
696 uno::Reference<document::XDocumentProperties> xDocProps(
697 xDPS->getDocumentProperties());
698 OSL_ENSURE(xDocProps.is(), "no DocumentProperties");
699 OUString aDocUser = xDocProps->getModifiedBy();
700
701 if ( !aDocUser.isEmpty() )
702 pTrack->SetUser( aDocUser );
703 }
704 }
705
706 m_aDocument.CompareDocument( rOtherDoc );
707
708 pTrack = m_aDocument.GetChangeTrack();
709 if ( pTrack )
710 pTrack->SetUser( aOldUser );
711
712 PostPaintGridAll();
713 SetDocumentModified();
714 }
715
716 // Merge (combine documents)
717
lcl_Equal(const ScChangeAction * pA,const ScChangeAction * pB,bool bIgnore100Sec)718 static bool lcl_Equal( const ScChangeAction* pA, const ScChangeAction* pB, bool bIgnore100Sec )
719 {
720 return pA && pB &&
721 pA->GetActionNumber() == pB->GetActionNumber() &&
722 pA->GetType() == pB->GetType() &&
723 pA->GetUser() == pB->GetUser() &&
724 (bIgnore100Sec ?
725 pA->GetDateTimeUTC().IsEqualIgnoreNanoSec( pB->GetDateTimeUTC() ) :
726 pA->GetDateTimeUTC() == pB->GetDateTimeUTC());
727 // don't compare state if an old change has been accepted
728 }
729
lcl_FindAction(ScDocument * pDoc,const ScChangeAction * pAction,ScDocument * pSearchDoc,const ScChangeAction * pFirstSearchAction,const ScChangeAction * pLastSearchAction,bool bIgnore100Sec)730 static bool lcl_FindAction( ScDocument* pDoc, const ScChangeAction* pAction, ScDocument* pSearchDoc, const ScChangeAction* pFirstSearchAction, const ScChangeAction* pLastSearchAction, bool bIgnore100Sec )
731 {
732 if ( !pDoc || !pAction || !pSearchDoc || !pFirstSearchAction || !pLastSearchAction )
733 {
734 return false;
735 }
736
737 sal_uLong nLastSearchAction = pLastSearchAction->GetActionNumber();
738 const ScChangeAction* pA = pFirstSearchAction;
739 while ( pA && pA->GetActionNumber() <= nLastSearchAction )
740 {
741 if ( pAction->GetType() == pA->GetType() &&
742 pAction->GetUser() == pA->GetUser() &&
743 (bIgnore100Sec ?
744 pAction->GetDateTimeUTC().IsEqualIgnoreNanoSec( pA->GetDateTimeUTC() ) :
745 pAction->GetDateTimeUTC() == pA->GetDateTimeUTC() ) &&
746 pAction->GetBigRange() == pA->GetBigRange() )
747 {
748 OUString aActionDesc;
749 pAction->GetDescription(aActionDesc, pDoc, true);
750 OUString aADesc;
751 pA->GetDescription(aADesc, pSearchDoc, true);
752 if (aActionDesc == aADesc)
753 {
754 OSL_FAIL( "lcl_FindAction(): found equal action!" );
755 return true;
756 }
757 }
758 pA = pA->GetNext();
759 }
760
761 return false;
762 }
763
MergeDocument(ScDocument & rOtherDoc,bool bShared,bool bCheckDuplicates,sal_uLong nOffset,ScChangeActionMergeMap * pMergeMap,bool bInverseMap)764 void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheckDuplicates, sal_uLong nOffset, ScChangeActionMergeMap* pMergeMap, bool bInverseMap )
765 {
766 ScTabViewShell* pViewSh = GetBestViewShell( false ); //! functions to the DocShell
767 if (!pViewSh)
768 return;
769
770 ScChangeTrack* pSourceTrack = rOtherDoc.GetChangeTrack();
771 if (!pSourceTrack)
772 return; //! nothing to do - error notification?
773
774 ScChangeTrack* pThisTrack = m_aDocument.GetChangeTrack();
775 if ( !pThisTrack )
776 { // turn on
777 m_aDocument.StartChangeTracking();
778 pThisTrack = m_aDocument.GetChangeTrack();
779 OSL_ENSURE(pThisTrack,"ChangeTracking not enabled?");
780 if ( !bShared )
781 {
782 // turn on visual RedLining
783 ScChangeViewSettings aChangeViewSet;
784 aChangeViewSet.SetShowChanges(true);
785 m_aDocument.SetChangeViewSettings(aChangeViewSet);
786 }
787 }
788
789 // include Nano seconds in compare?
790 bool bIgnore100Sec = !pSourceTrack->IsTimeNanoSeconds() ||
791 !pThisTrack->IsTimeNanoSeconds();
792
793 // find common initial position
794 sal_uLong nFirstNewNumber = 0;
795 const ScChangeAction* pSourceAction = pSourceTrack->GetFirst();
796 const ScChangeAction* pThisAction = pThisTrack->GetFirst();
797 // skip identical actions
798 while ( lcl_Equal( pSourceAction, pThisAction, bIgnore100Sec ) )
799 {
800 nFirstNewNumber = pSourceAction->GetActionNumber() + 1;
801 pSourceAction = pSourceAction->GetNext();
802 pThisAction = pThisAction->GetNext();
803 }
804 // pSourceAction and pThisAction now point to the first "own" actions
805 // The common actions before don't interest at all
806
807 //! Inquiry if the documents where equal before the change tracking !!!
808
809 const ScChangeAction* pFirstMergeAction = pSourceAction;
810 const ScChangeAction* pFirstSearchAction = pThisAction;
811
812 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
813 const ScChangeAction* pLastSearchAction = pThisTrack->GetLast();
814
815 // Create MergeChangeData from the following actions
816 sal_uLong nNewActionCount = 0;
817 const ScChangeAction* pCount = pSourceAction;
818 while ( pCount )
819 {
820 if ( bShared || !ScChangeTrack::MergeIgnore( *pCount, nFirstNewNumber ) )
821 ++nNewActionCount;
822 pCount = pCount->GetNext();
823 }
824 if (!nNewActionCount)
825 return; //! nothing to do - error notification?
826 // from here on no return
827
828 ScProgress aProgress( this, "...", nNewActionCount, true );
829
830 sal_uLong nLastMergeAction = pSourceTrack->GetLast()->GetActionNumber();
831 // UpdateReference-Undo, valid references for the last common state
832 pSourceTrack->MergePrepare( pFirstMergeAction, bShared );
833
834 // adjust MergeChangeData to all yet following actions in this document
835 // -> references valid for this document
836 while ( pThisAction )
837 {
838 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
839 if ( !bShared || !ScChangeTrack::MergeIgnore( *pThisAction, nFirstNewNumber ) )
840 {
841 ScChangeActionType eType = pThisAction->GetType();
842 switch ( eType )
843 {
844 case SC_CAT_INSERT_COLS :
845 case SC_CAT_INSERT_ROWS :
846 case SC_CAT_INSERT_TABS :
847 pSourceTrack->AppendInsert( pThisAction->GetBigRange().MakeRange() );
848 break;
849 case SC_CAT_DELETE_COLS :
850 case SC_CAT_DELETE_ROWS :
851 case SC_CAT_DELETE_TABS :
852 {
853 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pThisAction);
854 if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
855 { // deleted table contains deleted cols, which are not
856 sal_uLong nStart, nEnd;
857 pSourceTrack->AppendDeleteRange(
858 pDel->GetOverAllRange().MakeRange(), nullptr, nStart, nEnd );
859 }
860 }
861 break;
862 case SC_CAT_MOVE :
863 {
864 const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pThisAction);
865 pSourceTrack->AppendMove( pMove->GetFromRange().MakeRange(),
866 pMove->GetBigRange().MakeRange(), nullptr );
867 }
868 break;
869 default:
870 {
871 // added to avoid warnings
872 }
873 }
874 }
875 pThisAction = pThisAction->GetNext();
876 }
877
878 LockPaint(); // #i73877# no repainting after each action
879
880 // take over MergeChangeData into the current document
881 bool bHasRejected = false;
882 OUString aOldUser = pThisTrack->GetUser();
883 pThisTrack->SetUseFixDateTime( true );
884 ScMarkData& rMarkData = pViewSh->GetViewData().GetMarkData();
885 ScMarkData aOldMarkData( rMarkData );
886 pSourceAction = pFirstMergeAction;
887 while ( pSourceAction && pSourceAction->GetActionNumber() <= nLastMergeAction )
888 {
889 bool bMergeAction = false;
890 if ( bShared )
891 {
892 if ( !bCheckDuplicates || !lcl_FindAction( &rOtherDoc, pSourceAction, &m_aDocument, pFirstSearchAction, pLastSearchAction, bIgnore100Sec ) )
893 {
894 bMergeAction = true;
895 }
896 }
897 else
898 {
899 if ( !ScChangeTrack::MergeIgnore( *pSourceAction, nFirstNewNumber ) )
900 {
901 bMergeAction = true;
902 }
903 }
904
905 if ( bMergeAction )
906 {
907 ScChangeActionType eSourceType = pSourceAction->GetType();
908 if ( !bShared && pSourceAction->IsDeletedIn() )
909 {
910 //! does it need to be determined yet if really deleted in
911 //! _this_ document?
912
913 // lies in a range, which was deleted in this document
914 // -> is omitted
915 //! ??? revert deletion action ???
916 //! ??? save action somewhere else ???
917 #if OSL_DEBUG_LEVEL > 0
918 OUString aValue;
919 if ( eSourceType == SC_CAT_CONTENT )
920 static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( aValue, &m_aDocument );
921 SAL_WARN( "sc", aValue << " omitted");
922 #endif
923 }
924 else
925 {
926 //! Take over date/author/comment of the source action!
927
928 pThisTrack->SetUser( pSourceAction->GetUser() );
929 pThisTrack->SetFixDateTimeUTC( pSourceAction->GetDateTimeUTC() );
930 sal_uLong nOldActionMax = pThisTrack->GetActionMax();
931
932 bool bExecute = true;
933 sal_uLong nReject = pSourceAction->GetRejectAction();
934 if ( nReject )
935 {
936 if ( bShared )
937 {
938 if ( nReject >= nFirstNewNumber )
939 {
940 nReject += nOffset;
941 }
942 ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
943 if ( pOldAction && pOldAction->IsVirgin() )
944 {
945 pThisTrack->Reject( pOldAction );
946 bHasRejected = true;
947 bExecute = false;
948 }
949 }
950 else
951 {
952 // decline old action (of the common ones)
953 ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
954 if (pOldAction && pOldAction->GetState() == SC_CAS_VIRGIN)
955 {
956 //! what happens at actions, which were accepted in this document???
957 //! error notification or what???
958 //! or execute reject change normally
959
960 pThisTrack->Reject(pOldAction);
961 bHasRejected = true; // for Paint
962 }
963 bExecute = false;
964 }
965 }
966
967 if ( bExecute )
968 {
969 // execute normally
970 ScRange aSourceRange = pSourceAction->GetBigRange().MakeRange();
971 rMarkData.SelectOneTable( aSourceRange.aStart.Tab() );
972 switch ( eSourceType )
973 {
974 case SC_CAT_CONTENT:
975 {
976 //! Test if it was at the very bottom in the document, then automatic
977 //! row insert ???
978
979 OSL_ENSURE( aSourceRange.aStart == aSourceRange.aEnd, "huch?" );
980 ScAddress aPos = aSourceRange.aStart;
981 OUString aValue;
982 static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( aValue, &m_aDocument );
983 ScMatrixMode eMatrix = ScMatrixMode::NONE;
984 const ScCellValue& rCell = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewCell();
985 if (rCell.meType == CELLTYPE_FORMULA)
986 eMatrix = rCell.mpFormula->GetMatrixFlag();
987 switch ( eMatrix )
988 {
989 case ScMatrixMode::NONE :
990 pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue );
991 break;
992 case ScMatrixMode::Formula :
993 {
994 SCCOL nCols;
995 SCROW nRows;
996 rCell.mpFormula->GetMatColsRows(nCols, nRows);
997 aSourceRange.aEnd.SetCol( aPos.Col() + nCols - 1 );
998 aSourceRange.aEnd.SetRow( aPos.Row() + nRows - 1 );
999 aValue = aValue.copy(1, aValue.getLength()-2); // remove the 1st and last characters.
1000 GetDocFunc().EnterMatrix( aSourceRange,
1001 nullptr, nullptr, aValue, false, false,
1002 EMPTY_OUSTRING, formula::FormulaGrammar::GRAM_DEFAULT );
1003 }
1004 break;
1005 case ScMatrixMode::Reference : // do nothing
1006 break;
1007 }
1008 }
1009 break;
1010 case SC_CAT_INSERT_TABS :
1011 {
1012 OUString aName;
1013 m_aDocument.CreateValidTabName( aName );
1014 (void)GetDocFunc().InsertTable( aSourceRange.aStart.Tab(), aName, true, false );
1015 }
1016 break;
1017 case SC_CAT_INSERT_ROWS:
1018 (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSROWS_BEFORE, true, false );
1019 break;
1020 case SC_CAT_INSERT_COLS:
1021 (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSCOLS_BEFORE, true, false );
1022 break;
1023 case SC_CAT_DELETE_TABS :
1024 (void)GetDocFunc().DeleteTable( aSourceRange.aStart.Tab(), true );
1025 break;
1026 case SC_CAT_DELETE_ROWS:
1027 {
1028 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
1029 if ( pDel->IsTopDelete() )
1030 {
1031 aSourceRange = pDel->GetOverAllRange().MakeRange();
1032 (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Rows, false );
1033
1034 // #i101099# [Collaboration] Changes are not correctly shown
1035 if ( bShared )
1036 {
1037 ScChangeAction* pAct = pThisTrack->GetLast();
1038 if ( pAct && pAct->GetType() == eSourceType && pAct->IsDeletedIn() && !pSourceAction->IsDeletedIn() )
1039 {
1040 pAct->RemoveAllDeletedIn();
1041 }
1042 }
1043 }
1044 }
1045 break;
1046 case SC_CAT_DELETE_COLS:
1047 {
1048 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
1049 if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
1050 { // deleted table contains deleted cols, which are not
1051 aSourceRange = pDel->GetOverAllRange().MakeRange();
1052 (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Cols, false );
1053 }
1054 }
1055 break;
1056 case SC_CAT_MOVE :
1057 {
1058 const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pSourceAction);
1059 ScRange aFromRange( pMove->GetFromRange().MakeRange() );
1060 (void)GetDocFunc().MoveBlock( aFromRange,
1061 aSourceRange.aStart, true, true, false, false );
1062 }
1063 break;
1064 default:
1065 {
1066 // added to avoid warnings
1067 }
1068 }
1069 }
1070 const OUString& rComment = pSourceAction->GetComment();
1071 if ( !rComment.isEmpty() )
1072 {
1073 ScChangeAction* pAct = pThisTrack->GetLast();
1074 if ( pAct && pAct->GetActionNumber() > nOldActionMax )
1075 pAct->SetComment( rComment );
1076 else
1077 OSL_FAIL( "MergeDocument: what to do with the comment?!?" );
1078 }
1079
1080 // adjust references
1081 pSourceTrack->MergeOwn( const_cast<ScChangeAction*>(pSourceAction), nFirstNewNumber, bShared );
1082
1083 // merge action state
1084 if ( bShared && !pSourceAction->IsRejected() )
1085 {
1086 ScChangeAction* pAct = pThisTrack->GetLast();
1087 if ( pAct && pAct->GetActionNumber() > nOldActionMax )
1088 {
1089 ScChangeTrack::MergeActionState( pAct, pSourceAction );
1090 }
1091 }
1092
1093 // fill merge map
1094 if ( bShared && pMergeMap )
1095 {
1096 ScChangeAction* pAct = pThisTrack->GetLast();
1097 if ( pAct && pAct->GetActionNumber() > nOldActionMax )
1098 {
1099 sal_uLong nActionMax = pAct->GetActionNumber();
1100 sal_uLong nActionCount = nActionMax - nOldActionMax;
1101 sal_uLong nAction = nActionMax - nActionCount + 1;
1102 sal_uLong nSourceAction = pSourceAction->GetActionNumber() - nActionCount + 1;
1103 while ( nAction <= nActionMax )
1104 {
1105 if ( bInverseMap )
1106 {
1107 (*pMergeMap)[ nAction++ ] = nSourceAction++;
1108 }
1109 else
1110 {
1111 (*pMergeMap)[ nSourceAction++ ] = nAction++;
1112 }
1113 }
1114 }
1115 }
1116 }
1117 aProgress.SetStateCountDown( --nNewActionCount );
1118 }
1119 pSourceAction = pSourceAction->GetNext();
1120 }
1121
1122 rMarkData = aOldMarkData;
1123 pThisTrack->SetUser(aOldUser);
1124 pThisTrack->SetUseFixDateTime( false );
1125
1126 pSourceTrack->Clear(); //! this one is bungled now
1127
1128 if (bHasRejected)
1129 PostPaintGridAll(); // Reject() doesn't paint itself
1130
1131 UnlockPaint();
1132 }
1133
MergeSharedDocument(ScDocShell * pSharedDocShell)1134 bool ScDocShell::MergeSharedDocument( ScDocShell* pSharedDocShell )
1135 {
1136 if ( !pSharedDocShell )
1137 {
1138 return false;
1139 }
1140
1141 ScChangeTrack* pThisTrack = m_aDocument.GetChangeTrack();
1142 if ( !pThisTrack )
1143 {
1144 return false;
1145 }
1146
1147 ScDocument& rSharedDoc = pSharedDocShell->GetDocument();
1148 ScChangeTrack* pSharedTrack = rSharedDoc.GetChangeTrack();
1149 if ( !pSharedTrack )
1150 {
1151 return false;
1152 }
1153
1154 // reset show changes
1155 ScChangeViewSettings aChangeViewSet;
1156 aChangeViewSet.SetShowChanges( false );
1157 m_aDocument.SetChangeViewSettings( aChangeViewSet );
1158
1159 // find first merge action in this document
1160 bool bIgnore100Sec = !pThisTrack->IsTimeNanoSeconds() || !pSharedTrack->IsTimeNanoSeconds();
1161 ScChangeAction* pThisAction = pThisTrack->GetFirst();
1162 ScChangeAction* pSharedAction = pSharedTrack->GetFirst();
1163 while ( lcl_Equal( pThisAction, pSharedAction, bIgnore100Sec ) )
1164 {
1165 pThisAction = pThisAction->GetNext();
1166 pSharedAction = pSharedAction->GetNext();
1167 }
1168
1169 if ( pSharedAction )
1170 {
1171 if ( pThisAction )
1172 {
1173 // merge own changes into shared document
1174 sal_uLong nActStartShared = pSharedAction->GetActionNumber();
1175 sal_uLong nActEndShared = pSharedTrack->GetActionMax();
1176 std::unique_ptr<ScDocument> pTmpDoc(new ScDocument);
1177 for ( sal_Int32 nIndex = 0; nIndex < m_aDocument.GetTableCount(); ++nIndex )
1178 {
1179 OUString sTabName;
1180 pTmpDoc->CreateValidTabName( sTabName );
1181 pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
1182 }
1183 m_aDocument.GetChangeTrack()->Clone( pTmpDoc.get() );
1184 ScChangeActionMergeMap aOwnInverseMergeMap;
1185 pSharedDocShell->MergeDocument( *pTmpDoc, true, true, 0, &aOwnInverseMergeMap, true );
1186 pTmpDoc.reset();
1187 sal_uLong nActStartOwn = nActEndShared + 1;
1188 sal_uLong nActEndOwn = pSharedTrack->GetActionMax();
1189
1190 // find conflicts
1191 ScConflictsList aConflictsList;
1192 ScConflictsFinder aFinder( pSharedTrack, nActStartShared, nActEndShared, nActStartOwn, nActEndOwn, aConflictsList );
1193 if ( aFinder.Find() )
1194 {
1195 ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnInverseMergeMap );
1196 bool bLoop = true;
1197 while ( bLoop )
1198 {
1199 bLoop = false;
1200 weld::Window* pWin = GetActiveDialogParent();
1201 ScConflictsDlg aDlg(pWin, GetViewData(), &rSharedDoc, aConflictsList);
1202 if (aDlg.run() == RET_CANCEL)
1203 {
1204 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pWin,
1205 VclMessageType::Question, VclButtonsType::YesNo,
1206 ScResId(STR_DOC_WILLNOTBESAVED)));
1207 xQueryBox->set_default_response(RET_YES);
1208 if (xQueryBox->run() == RET_YES)
1209 {
1210 return false;
1211 }
1212 else
1213 {
1214 bLoop = true;
1215 }
1216 }
1217 }
1218 }
1219
1220 // undo own changes in shared document
1221 pSharedTrack->Undo( nActStartOwn, nActEndOwn );
1222
1223 // clone change track for merging into own document
1224 pTmpDoc.reset(new ScDocument);
1225 for ( sal_Int32 nIndex = 0; nIndex < m_aDocument.GetTableCount(); ++nIndex )
1226 {
1227 OUString sTabName;
1228 pTmpDoc->CreateValidTabName( sTabName );
1229 pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
1230 }
1231 pThisTrack->Clone( pTmpDoc.get() );
1232
1233 // undo own changes since last save in own document
1234 sal_uLong nStartShared = pThisAction->GetActionNumber();
1235 ScChangeAction* pAction = pThisTrack->GetLast();
1236 while ( pAction && pAction->GetActionNumber() >= nStartShared )
1237 {
1238 pThisTrack->Reject( pAction, true );
1239 pAction = pAction->GetPrev();
1240 }
1241
1242 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
1243 pThisTrack->Undo( nStartShared, pThisTrack->GetActionMax(), true );
1244
1245 // merge shared changes into own document
1246 ScChangeActionMergeMap aSharedMergeMap;
1247 MergeDocument( rSharedDoc, true, true, 0, &aSharedMergeMap );
1248 sal_uLong nEndShared = pThisTrack->GetActionMax();
1249
1250 // resolve conflicts for shared non-content actions
1251 if ( !aConflictsList.empty() )
1252 {
1253 ScConflictsListHelper::TransformConflictsList( aConflictsList, &aSharedMergeMap, nullptr );
1254 ScConflictsResolver aResolver( pThisTrack, aConflictsList );
1255 pAction = pThisTrack->GetAction( nEndShared );
1256 while ( pAction && pAction->GetActionNumber() >= nStartShared )
1257 {
1258 aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
1259 false /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
1260 pAction = pAction->GetPrev();
1261 }
1262 }
1263 nEndShared = pThisTrack->GetActionMax();
1264
1265 // only show changes from shared document
1266 aChangeViewSet.SetShowChanges( true );
1267 aChangeViewSet.SetShowAccepted( true );
1268 aChangeViewSet.SetHasActionRange();
1269 aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
1270 m_aDocument.SetChangeViewSettings( aChangeViewSet );
1271
1272 // merge own changes back into own document
1273 sal_uLong nStartOwn = nEndShared + 1;
1274 ScChangeActionMergeMap aOwnMergeMap;
1275 MergeDocument( *pTmpDoc, true, true, nEndShared - nStartShared + 1, &aOwnMergeMap );
1276 pTmpDoc.reset();
1277 sal_uLong nEndOwn = pThisTrack->GetActionMax();
1278
1279 // resolve conflicts for shared content actions and own actions
1280 if ( !aConflictsList.empty() )
1281 {
1282 ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnMergeMap );
1283 ScConflictsResolver aResolver( pThisTrack, aConflictsList );
1284 pAction = pThisTrack->GetAction( nEndShared );
1285 while ( pAction && pAction->GetActionNumber() >= nStartShared )
1286 {
1287 aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
1288 true /*bHandleContentAction*/, false /*bHandleNonContentAction*/ );
1289 pAction = pAction->GetPrev();
1290 }
1291
1292 pAction = pThisTrack->GetAction( nEndOwn );
1293 while ( pAction && pAction->GetActionNumber() >= nStartOwn )
1294 {
1295 aResolver.HandleAction( pAction, false /*bIsSharedAction*/,
1296 true /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
1297 pAction = pAction->GetPrev();
1298 }
1299 }
1300 }
1301 else
1302 {
1303 // merge shared changes into own document
1304 sal_uLong nStartShared = pThisTrack->GetActionMax() + 1;
1305 MergeDocument( rSharedDoc, true, true );
1306 sal_uLong nEndShared = pThisTrack->GetActionMax();
1307
1308 // only show changes from shared document
1309 aChangeViewSet.SetShowChanges( true );
1310 aChangeViewSet.SetShowAccepted( true );
1311 aChangeViewSet.SetHasActionRange();
1312 aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
1313 m_aDocument.SetChangeViewSettings( aChangeViewSet );
1314 }
1315
1316 // update view
1317 PostPaintExtras();
1318 PostPaintGridAll();
1319
1320 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
1321 VclMessageType::Info, VclButtonsType::Ok,
1322 ScResId(STR_DOC_UPDATED)));
1323 xInfoBox->run();
1324 }
1325
1326 return ( pThisAction != nullptr );
1327 }
1328
1329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1330