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