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