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
PostEditView(ScEditEngineDefaulter * pEditEngine,const ScAddress & rCursorPos)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
PostDataChanged()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
PostPaint(SCCOL nStartCol,SCROW nStartRow,SCTAB nStartTab,SCCOL nEndCol,SCROW nEndRow,SCTAB nEndTab,sal_uInt16 nPart,sal_uInt16 nExtFlags)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
PostPaint(const ScRange & rRange,sal_uInt16 nPart,sal_uInt16 nExtFlags)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
PostPaintGridAll()177 void ScDocShell::PostPaintGridAll()
178 {
179 PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID );
180 }
181
PostPaintCell(SCCOL nCol,SCROW nRow,SCTAB nTab)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
PostPaintCell(const ScAddress & rPos)187 void ScDocShell::PostPaintCell( const ScAddress& rPos )
188 {
189 PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab() );
190 }
191
PostPaintExtras()192 void ScDocShell::PostPaintExtras()
193 {
194 PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS );
195 }
196
UpdatePaintExt(sal_uInt16 & rExtFlags,const ScRange & rRange)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
UpdatePaintExt(sal_uInt16 & rExtFlags,SCCOL nStartCol,SCROW nStartRow,SCTAB nStartTab,SCCOL nEndCol,SCROW nEndRow,SCTAB nEndTab)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
LockPaint_Impl(sal_Bool bDoc)229 void ScDocShell::LockPaint_Impl(sal_Bool bDoc)
230 {
231 if ( !pPaintLockData )
232 pPaintLockData = new ScPaintLockData(0); //! Modus...
233 pPaintLockData->IncLevel(bDoc);
234 }
235
UnlockPaint_Impl(sal_Bool bDoc)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
LockDocument_Impl(sal_uInt16 nNew)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
UnlockDocument_Impl(sal_uInt16 nNew)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
GetLockCount() const298 sal_uInt16 ScDocShell::GetLockCount() const
299 {
300 return nDocumentLock;
301 }
302
SetLockCount(sal_uInt16 nNew)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
LockPaint()320 void ScDocShell::LockPaint()
321 {
322 LockPaint_Impl(sal_False);
323 }
324
UnlockPaint()325 void ScDocShell::UnlockPaint()
326 {
327 UnlockPaint_Impl(sal_False);
328 }
329
LockDocument()330 void ScDocShell::LockDocument()
331 {
332 LockPaint_Impl(sal_True);
333 LockDocument_Impl(nDocumentLock + 1);
334 }
335
UnlockDocument()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
SetInplace(sal_Bool bInplace)351 void ScDocShell::SetInplace( sal_Bool bInplace )
352 {
353 if (bIsInplace != bInplace)
354 {
355 bIsInplace = bInplace;
356 CalcOutputFactor();
357 }
358 }
359
CalcOutputFactor()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
GetOutputFactor() const410 double ScDocShell::GetOutputFactor() const
411 {
412 return nPrtToScreenFactor;
413 }
414
415 //---------------------------------------------------------------------
416
InitOptions(bool bForLoading)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
GetDocumentPrinter()451 Printer* ScDocShell::GetDocumentPrinter() // fuer OLE
452 {
453 return aDocument.GetPrinter();
454 }
455
GetPrinter(sal_Bool bCreateIfNotExist)456 SfxPrinter* ScDocShell::GetPrinter(sal_Bool bCreateIfNotExist)
457 {
458 return aDocument.GetPrinter(bCreateIfNotExist);
459 }
460
UpdateFontList()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
GetRefDevice()472 OutputDevice* ScDocShell::GetRefDevice()
473 {
474 return aDocument.GetRefDevice();
475 }
476
SetPrinter(SfxPrinter * pNewPrinter,sal_uInt16 nDiffFlags)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
GetChangeAction(const ScAddress & rPos)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
SetChangeComment(ScChangeAction * pAction,const String & rComment)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
ExecuteChangeCommentDialog(ScChangeAction * pAction,Window * pParent,sal_Bool bPrevNext)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
CompareDocument(ScDocument & rOtherDoc)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
lcl_Equal(const ScChangeAction * pA,const ScChangeAction * pB,sal_Bool bIgnore100Sec)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
lcl_FindAction(ScDocument * pDoc,const ScChangeAction * pAction,ScDocument * pSearchDoc,const ScChangeAction * pFirstSearchAction,const ScChangeAction * pLastSearchAction,sal_Bool bIgnore100Sec)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
MergeDocument(ScDocument & rOtherDoc,bool bShared,bool bCheckDuplicates,sal_uLong nOffset,ScChangeActionMergeMap * pMergeMap,bool bInverseMap)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
MergeSharedDocument(ScDocShell * pSharedDocShell)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