xref: /trunk/main/sc/source/ui/undo/undobase.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include <vcl/virdev.hxx>
36 
37 #include "undobase.hxx"
38 #include "refundo.hxx"
39 #include "docsh.hxx"
40 #include "tabvwsh.hxx"
41 #include "undoolk.hxx"
42 #include "undodraw.hxx"
43 #include "dbcolect.hxx"
44 #include "attrib.hxx"
45 #include "queryparam.hxx"
46 #include "globstr.hrc"
47 
48 // STATIC DATA -----------------------------------------------------------
49 
50 TYPEINIT1(ScSimpleUndo,     SfxUndoAction);
51 TYPEINIT1(ScBlockUndo,      ScSimpleUndo);
52 TYPEINIT1(ScMoveUndo,       ScSimpleUndo);
53 TYPEINIT1(ScDBFuncUndo,     ScSimpleUndo);
54 TYPEINIT1(ScUndoWrapper,    SfxUndoAction);
55 
56 // -----------------------------------------------------------------------
57 
58 ScSimpleUndo::ScSimpleUndo( ScDocShell* pDocSh ) :
59     pDocShell( pDocSh ),
60     pDetectiveUndo( NULL )
61 {
62 }
63 
64 __EXPORT ScSimpleUndo::~ScSimpleUndo()
65 {
66     delete pDetectiveUndo;
67 }
68 
69 bool ScSimpleUndo::SetViewMarkData( const ScMarkData& rMarkData )
70 {
71     if ( IsPaintLocked() )
72         return false;
73 
74     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
75     if ( !pViewShell )
76         return false;
77 
78     pViewShell->SetMarkData( rMarkData );
79     return true;
80 }
81 
82 sal_Bool __EXPORT ScSimpleUndo::Merge( SfxUndoAction *pNextAction )
83 {
84     //  Zu jeder Undo-Action kann eine SdrUndoGroup fuer das Aktualisieren
85     //  der Detektiv-Pfeile gehoeren.
86     //  DetectiveRefresh kommt immer hinterher, die SdrUndoGroup ist in
87     //  eine ScUndoDraw Action verpackt.
88     //  Nur beim automatischen Aktualisieren wird AddUndoAction mit
89     //  bTryMerg=sal_True gerufen.
90 
91     if ( !pDetectiveUndo && pNextAction->ISA(ScUndoDraw) )
92     {
93         //  SdrUndoAction aus der ScUndoDraw Action uebernehmen,
94         //  ScUndoDraw wird dann vom UndoManager geloescht
95 
96         ScUndoDraw* pCalcUndo = (ScUndoDraw*)pNextAction;
97         pDetectiveUndo = pCalcUndo->GetDrawUndo();
98         pCalcUndo->ForgetDrawUndo();
99         return sal_True;
100     }
101 
102     return sal_False;
103 }
104 
105 void ScSimpleUndo::BeginUndo()
106 {
107     pDocShell->SetInUndo( sal_True );
108 
109     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
110     if (pViewShell)
111         pViewShell->HideAllCursors();       // z.B. wegen zusammengefassten Zellen
112 
113     //  detective updates happened last, must be undone first
114     if (pDetectiveUndo)
115         pDetectiveUndo->Undo();
116 }
117 
118 void ScSimpleUndo::EndUndo()
119 {
120     pDocShell->SetDocumentModified();
121 
122     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
123     if (pViewShell)
124     {
125         pViewShell->UpdateAutoFillMark();
126         pViewShell->UpdateInputHandler();
127         pViewShell->ShowAllCursors();
128     }
129 
130     pDocShell->SetInUndo( sal_False );
131 }
132 
133 void ScSimpleUndo::BeginRedo()
134 {
135     pDocShell->SetInUndo( sal_True );   //! eigenes Flag fuer Redo?
136 
137     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
138     if (pViewShell)
139         pViewShell->HideAllCursors();       // z.B. wegen zusammengefassten Zellen
140 }
141 
142 void ScSimpleUndo::EndRedo()
143 {
144     if (pDetectiveUndo)
145         pDetectiveUndo->Redo();
146 
147     pDocShell->SetDocumentModified();
148 
149     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
150     if (pViewShell)
151     {
152         pViewShell->UpdateAutoFillMark();
153         pViewShell->UpdateInputHandler();
154         pViewShell->ShowAllCursors();
155     }
156 
157     pDocShell->SetInUndo( sal_False );
158 }
159 
160 void ScSimpleUndo::ShowTable( SCTAB nTab )          // static
161 {
162     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
163     if (pViewShell)
164         pViewShell->SetTabNo( nTab );
165 }
166 
167 void ScSimpleUndo::ShowTable( const ScRange& rRange )           // static
168 {
169     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
170     if (pViewShell)
171     {
172         SCTAB nStart = rRange.aStart.Tab();
173         SCTAB nEnd   = rRange.aEnd.Tab();
174         SCTAB nTab = pViewShell->GetViewData()->GetTabNo();
175         if ( nTab < nStart || nTab > nEnd )                     // wenn nicht im Bereich:
176             pViewShell->SetTabNo( nStart );                     // auf erste des Bereiches
177     }
178 }
179 
180 
181 // -----------------------------------------------------------------------
182 
183 ScBlockUndo::ScBlockUndo( ScDocShell* pDocSh, const ScRange& rRange,
184                                             ScBlockUndoMode eBlockMode ) :
185     ScSimpleUndo( pDocSh ),
186     aBlockRange( rRange ),
187     eMode( eBlockMode )
188 {
189     pDrawUndo = GetSdrUndoAction( pDocShell->GetDocument() );
190 }
191 
192 __EXPORT ScBlockUndo::~ScBlockUndo()
193 {
194     DeleteSdrUndoAction( pDrawUndo );
195 }
196 
197 void ScBlockUndo::BeginUndo()
198 {
199     ScSimpleUndo::BeginUndo();
200     EnableDrawAdjust( pDocShell->GetDocument(), sal_False );
201 }
202 
203 void ScBlockUndo::EndUndo()
204 {
205     if (eMode == SC_UNDO_AUTOHEIGHT)
206         AdjustHeight();
207 
208     EnableDrawAdjust( pDocShell->GetDocument(), sal_True );
209     DoSdrUndoAction( pDrawUndo, pDocShell->GetDocument() );
210 
211     ShowBlock();
212     ScSimpleUndo::EndUndo();
213 }
214 
215 /*
216 void ScBlockUndo::BeginRedo()
217 {
218     ScSimpleUndo::BeginRedo();
219 }
220 */
221 
222 void ScBlockUndo::EndRedo()
223 {
224     if (eMode == SC_UNDO_AUTOHEIGHT)
225         AdjustHeight();
226 
227     ShowBlock();
228     ScSimpleUndo::EndRedo();
229 }
230 
231 sal_Bool ScBlockUndo::AdjustHeight()
232 {
233     ScDocument* pDoc = pDocShell->GetDocument();
234 
235     VirtualDevice aVirtDev;
236     Fraction aZoomX( 1, 1 );
237     Fraction aZoomY = aZoomX;
238     double nPPTX, nPPTY;
239     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
240     if (pViewShell)
241     {
242         ScViewData* pData = pViewShell->GetViewData();
243         nPPTX = pData->GetPPTX();
244         nPPTY = pData->GetPPTY();
245         aZoomX = pData->GetZoomX();
246         aZoomY = pData->GetZoomY();
247     }
248     else
249     {
250         //  Zoom auf 100 lassen
251         nPPTX = ScGlobal::nScreenPPTX;
252         nPPTY = ScGlobal::nScreenPPTY;
253     }
254 
255     sal_Bool bRet = pDoc->SetOptimalHeight( aBlockRange.aStart.Row(), aBlockRange.aEnd.Row(),
256 /*!*/                                   aBlockRange.aStart.Tab(), 0, &aVirtDev,
257                                         nPPTX, nPPTY, aZoomX, aZoomY, sal_False );
258 
259     if (bRet)
260         pDocShell->PostPaint( 0,      aBlockRange.aStart.Row(), aBlockRange.aStart.Tab(),
261                               MAXCOL, MAXROW,                   aBlockRange.aEnd.Tab(),
262                               PAINT_GRID | PAINT_LEFT );
263 
264     return bRet;
265 }
266 
267 void ScBlockUndo::ShowBlock()
268 {
269     if ( IsPaintLocked() )
270         return;
271 
272     ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
273     if (pViewShell)
274     {
275         ShowTable( aBlockRange );       // bei mehreren Tabs im Range ist jede davon gut
276         pViewShell->MoveCursorAbs( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
277                                    SC_FOLLOW_JUMP, sal_False, sal_False );
278         SCTAB nTab = pViewShell->GetViewData()->GetTabNo();
279         ScRange aRange = aBlockRange;
280         aRange.aStart.SetTab( nTab );
281         aRange.aEnd.SetTab( nTab );
282         pViewShell->MarkRange( aRange );
283 
284         //  nicht per SetMarkArea an MarkData, wegen evtl. fehlendem Paint
285     }
286 }
287 
288 
289 // -----------------------------------------------------------------------
290 
291 ScMoveUndo::ScMoveUndo( ScDocShell* pDocSh, ScDocument* pRefDoc, ScRefUndoData* pRefData,
292                                                 ScMoveUndoMode eRefMode ) :
293     ScSimpleUndo( pDocSh ),
294     pRefUndoDoc( pRefDoc ),
295     pRefUndoData( pRefData ),
296     eMode( eRefMode )
297 {
298     ScDocument* pDoc = pDocShell->GetDocument();
299     if (pRefUndoData)
300         pRefUndoData->DeleteUnchanged(pDoc);
301     pDrawUndo = GetSdrUndoAction( pDoc );
302 }
303 
304 __EXPORT ScMoveUndo::~ScMoveUndo()
305 {
306     delete pRefUndoData;
307     delete pRefUndoDoc;
308     DeleteSdrUndoAction( pDrawUndo );
309 }
310 
311 void ScMoveUndo::UndoRef()
312 {
313     ScDocument* pDoc = pDocShell->GetDocument();
314     ScRange aRange(0,0,0, MAXCOL,MAXROW,pRefUndoDoc->GetTableCount()-1);
315     pRefUndoDoc->CopyToDocument( aRange, IDF_FORMULA, sal_False, pDoc, NULL, sal_False );
316     if (pRefUndoData)
317         pRefUndoData->DoUndo( pDoc, (eMode == SC_UNDO_REFFIRST) );
318         // #65055# HACK: ScDragDropUndo ist der einzige mit REFFIRST.
319         // Falls nicht, resultiert daraus evtl. ein zu haeufiges Anpassen
320         // der ChartRefs, nicht schoen, aber auch nicht schlecht..
321 }
322 
323 void ScMoveUndo::BeginUndo()
324 {
325     ScSimpleUndo::BeginUndo();
326 
327     EnableDrawAdjust( pDocShell->GetDocument(), sal_False );
328 
329     if (pRefUndoDoc && eMode == SC_UNDO_REFFIRST)
330         UndoRef();
331 }
332 
333 void ScMoveUndo::EndUndo()
334 {
335     //@17.12.97 Reihenfolge der Fkt.s geaendert
336     DoSdrUndoAction( pDrawUndo, pDocShell->GetDocument() );     // #125875# must also be called when pointer is null
337 
338     if (pRefUndoDoc && eMode == SC_UNDO_REFLAST)
339         UndoRef();
340 
341     EnableDrawAdjust( pDocShell->GetDocument(), sal_True );
342 
343     ScSimpleUndo::EndUndo();
344 }
345 
346 /*
347 void ScMoveUndo::BeginRedo()
348 {
349     ScSimpleUndo::BeginRedo();
350 }
351 */
352 
353 /*
354 void ScMoveUndo::EndRedo()
355 {
356     ScSimpleUndo::EndRedo();
357 }
358 */
359 
360 // -----------------------------------------------------------------------
361 
362 ScDBFuncUndo::ScDBFuncUndo( ScDocShell* pDocSh, const ScRange& rOriginal, SdrUndoAction* pDrawUndo ) :
363     ScSimpleUndo( pDocSh ),
364     aOriginalRange( rOriginal ),
365     mpDrawUndo( pDrawUndo )
366 {
367     pAutoDBRange = pDocSh->GetOldAutoDBRange();
368 }
369 
370 ScDBFuncUndo::~ScDBFuncUndo()
371 {
372     DeleteSdrUndoAction( mpDrawUndo );
373     delete pAutoDBRange;
374 }
375 
376 void ScDBFuncUndo::SetDrawUndoAction( SdrUndoAction* pDrawUndo )
377 {
378     DeleteSdrUndoAction( mpDrawUndo );
379     mpDrawUndo = pDrawUndo;
380 }
381 
382 void ScDBFuncUndo::BeginUndo()
383 {
384     ScSimpleUndo::BeginUndo();
385     DoSdrUndoAction( mpDrawUndo, pDocShell->GetDocument() );
386 }
387 
388 void ScDBFuncUndo::EndUndo()
389 {
390     ScSimpleUndo::EndUndo();
391 
392     if ( pAutoDBRange )
393     {
394         sal_uInt16 nNoNameIndex;
395         ScDocument* pDoc = pDocShell->GetDocument();
396         ScDBCollection* pColl = pDoc->GetDBCollection();
397         if ( pColl->SearchName( ScGlobal::GetRscString( STR_DB_NONAME ), nNoNameIndex ) )
398         {
399             ScDBData* pNoNameData = (*pColl)[nNoNameIndex];
400 
401             SCCOL nRangeX1;
402             SCROW nRangeY1;
403             SCCOL nRangeX2;
404             SCROW nRangeY2;
405             SCTAB nRangeTab;
406             pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
407             pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
408 
409             *pNoNameData = *pAutoDBRange;
410 
411             if ( pAutoDBRange->HasAutoFilter() )
412             {
413                 // restore AutoFilter buttons
414                 pAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
415                 pDoc->ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, SC_MF_AUTO );
416                 pDocShell->PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PAINT_GRID );
417             }
418         }
419     }
420 }
421 
422 void ScDBFuncUndo::BeginRedo()
423 {
424     RedoSdrUndoAction( mpDrawUndo );
425     if ( pAutoDBRange )
426     {
427         // move the database range to this function's position again (see ScDocShell::GetDBData)
428 
429         sal_uInt16 nNoNameIndex;
430         ScDocument* pDoc = pDocShell->GetDocument();
431         ScDBCollection* pColl = pDoc->GetDBCollection();
432         if ( pColl->SearchName( ScGlobal::GetRscString( STR_DB_NONAME ), nNoNameIndex ) )
433         {
434             ScDBData* pNoNameData = (*pColl)[nNoNameIndex];
435 
436             SCCOL nRangeX1;
437             SCROW nRangeY1;
438             SCCOL nRangeX2;
439             SCROW nRangeY2;
440             SCTAB nRangeTab;
441             pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
442             pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
443 
444             pNoNameData->SetSortParam( ScSortParam() );
445             pNoNameData->SetQueryParam( ScQueryParam() );
446             pNoNameData->SetSubTotalParam( ScSubTotalParam() );
447 
448             pNoNameData->SetArea( aOriginalRange.aStart.Tab(),
449                                   aOriginalRange.aStart.Col(), aOriginalRange.aStart.Row(),
450                                   aOriginalRange.aEnd.Col(), aOriginalRange.aEnd.Row() );
451 
452             pNoNameData->SetByRow( sal_True );
453             pNoNameData->SetAutoFilter( sal_False );
454             // header is always set with the operation in redo
455         }
456     }
457 
458     ScSimpleUndo::BeginRedo();
459 }
460 
461 void ScDBFuncUndo::EndRedo()
462 {
463     ScSimpleUndo::EndRedo();
464 }
465 
466 // -----------------------------------------------------------------------
467 
468 ScUndoWrapper::ScUndoWrapper( SfxUndoAction* pUndo ) :
469     pWrappedUndo( pUndo )
470 {
471 }
472 
473 ScUndoWrapper::~ScUndoWrapper()
474 {
475     delete pWrappedUndo;
476 }
477 
478 void ScUndoWrapper::ForgetWrappedUndo()
479 {
480     pWrappedUndo = NULL;    // don't delete in dtor - pointer must be stored outside
481 }
482 
483 String ScUndoWrapper::GetComment() const
484 {
485     if (pWrappedUndo)
486         return pWrappedUndo->GetComment();
487     else
488         return String();
489 }
490 
491 String ScUndoWrapper::GetRepeatComment(SfxRepeatTarget& rTarget) const
492 {
493     if (pWrappedUndo)
494         return pWrappedUndo->GetRepeatComment(rTarget);
495     else
496         return String();
497 }
498 
499 sal_uInt16 ScUndoWrapper::GetId() const
500 {
501     if (pWrappedUndo)
502         return pWrappedUndo->GetId();
503     else
504         return 0;
505 }
506 
507 sal_Bool ScUndoWrapper::IsLinked()
508 {
509     if (pWrappedUndo)
510         return pWrappedUndo->IsLinked();
511     else
512         return sal_False;
513 }
514 
515 void ScUndoWrapper::SetLinked( sal_Bool bIsLinked )
516 {
517     if (pWrappedUndo)
518         pWrappedUndo->SetLinked(bIsLinked);
519 }
520 
521 sal_Bool ScUndoWrapper::Merge( SfxUndoAction* pNextAction )
522 {
523     if (pWrappedUndo)
524         return pWrappedUndo->Merge(pNextAction);
525     else
526         return sal_False;
527 }
528 
529 void ScUndoWrapper::Undo()
530 {
531     if (pWrappedUndo)
532         pWrappedUndo->Undo();
533 }
534 
535 void ScUndoWrapper::Redo()
536 {
537     if (pWrappedUndo)
538         pWrappedUndo->Redo();
539 }
540 
541 void ScUndoWrapper::Repeat(SfxRepeatTarget& rTarget)
542 {
543     if (pWrappedUndo)
544         pWrappedUndo->Repeat(rTarget);
545 }
546 
547 sal_Bool ScUndoWrapper::CanRepeat(SfxRepeatTarget& rTarget) const
548 {
549     if (pWrappedUndo)
550         return pWrappedUndo->CanRepeat(rTarget);
551     else
552         return sal_False;
553 }
554 
555 
556