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