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