xref: /trunk/main/sc/source/ui/docshell/docsh3.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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