xref: /AOO41X/main/sc/source/ui/undo/undobase.cxx (revision f7c60c9c54b9df31f919e125fa03a7515f4855a8)
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