Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / ui / docshell / docfunc.cxx
blob8aacaad8f163696c81962d0a9552482690aca473
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
22 #include <sfx2/app.hxx>
23 #include <editeng/editobj.hxx>
24 #include <sfx2/linkmgr.hxx>
25 #include <sfx2/bindings.hxx>
26 #include <vcl/msgbox.hxx>
27 #include <vcl/virdev.hxx>
28 #include <vcl/waitobj.hxx>
29 #include <svl/PasswordHelper.hxx>
31 #include <com/sun/star/container/XNameContainer.hpp>
32 #include <com/sun/star/script/ModuleType.hpp>
33 #include <com/sun/star/script/XLibraryContainer.hpp>
34 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
36 #include "docfunc.hxx"
38 #include "sc.hrc"
40 #include "arealink.hxx"
41 #include "attrib.hxx"
42 #include "dociter.hxx"
43 #include "autoform.hxx"
44 #include "formulacell.hxx"
45 #include "cellmergeoption.hxx"
46 #include "detdata.hxx"
47 #include "detfunc.hxx"
48 #include "docpool.hxx"
49 #include "docsh.hxx"
50 #include "drwlayer.hxx"
51 #include "editutil.hxx"
52 #include "globstr.hrc"
53 #include "globalnames.hxx"
54 #include "olinetab.hxx"
55 #include "patattr.hxx"
56 #include "rangenam.hxx"
57 #include "rangeutl.hxx"
58 #include "refundo.hxx"
59 #include "scresid.hxx"
60 #include "stlpool.hxx"
61 #include "stlsheet.hxx"
62 #include "tablink.hxx"
63 #include "tabvwsh.hxx"
64 #include "uiitems.hxx"
65 #include "undoblk.hxx"
66 #include "undocell.hxx"
67 #include "undodraw.hxx"
68 #include "undotab.hxx"
69 #include "waitoff.hxx"
70 #include "sizedev.hxx"
71 #include "scmod.hxx"
72 #include "inputhdl.hxx"
73 #include "inputwin.hxx"
74 #include "editable.hxx"
75 #include "compiler.hxx"
76 #include "scui_def.hxx"
77 #include "tabprotection.hxx"
78 #include "clipparam.hxx"
79 #include "externalrefmgr.hxx"
80 #include "undorangename.hxx"
81 #include "progress.hxx"
82 #include "dpobject.hxx"
83 #include "stringutil.hxx"
84 #include "cellvalue.hxx"
85 #include "tokenarray.hxx"
86 #include <rowheightcontext.hxx>
87 #include <cellvalues.hxx>
88 #include <undoconvert.hxx>
89 #include <docfuncutil.hxx>
91 #include <memory>
92 #include <utility>
93 #include <basic/basmgr.hxx>
94 #include <memory>
95 #include <set>
96 #include <vector>
98 using namespace com::sun::star;
99 using ::std::vector;
101 IMPL_LINK_TYPED( ScDocFunc, NotifyDrawUndo, SdrUndoAction*, pUndoAction, void )
103 // #i101118# if drawing layer collects the undo actions, add it there
104 ScDrawLayer* pDrawLayer = rDocShell.GetDocument().GetDrawLayer();
105 if( pDrawLayer && pDrawLayer->IsRecording() )
106 pDrawLayer->AddCalcUndo( pUndoAction );
107 else
108 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDraw( pUndoAction, &rDocShell ) );
109 rDocShell.SetDrawModified();
111 // the affected sheet isn't known, so all stream positions are invalidated
112 ScDocument& rDoc = rDocShell.GetDocument();
113 SCTAB nTabCount = rDoc.GetTableCount();
114 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
115 if (rDoc.IsStreamValid(nTab))
116 rDoc.SetStreamValid(nTab, false);
119 // Zeile ueber dem Range painten (fuer Linien nach AdjustRowHeight)
121 static void lcl_PaintAbove( ScDocShell& rDocShell, const ScRange& rRange )
123 SCROW nRow = rRange.aStart.Row();
124 if ( nRow > 0 )
126 SCTAB nTab = rRange.aStart.Tab(); //! alle?
127 --nRow;
128 rDocShell.PostPaint( ScRange(0,nRow,nTab, MAXCOL,nRow,nTab), PAINT_GRID );
132 bool ScDocFunc::AdjustRowHeight( const ScRange& rRange, bool bPaint )
134 ScDocument& rDoc = rDocShell.GetDocument();
135 if ( rDoc.IsImportingXML() )
137 // for XML import, all row heights are updated together after importing
138 return false;
140 if ( !rDoc.IsAdjustHeightEnabled() )
142 return false;
145 SCTAB nTab = rRange.aStart.Tab();
146 SCROW nStartRow = rRange.aStart.Row();
147 SCROW nEndRow = rRange.aEnd.Row();
149 ScSizeDeviceProvider aProv( &rDocShell );
150 Fraction aOne(1,1);
152 sc::RowHeightContext aCxt(aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice());
153 bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab);
155 if ( bPaint && bChanged )
156 rDocShell.PostPaint(ScRange(0, nStartRow, nTab, MAXCOL, MAXROW, nTab),
157 PAINT_GRID | PAINT_LEFT);
159 return bChanged;
162 bool ScDocFunc::DetectiveAddPred(const ScAddress& rPos)
164 ScDocShellModificator aModificator( rDocShell );
166 rDocShell.MakeDrawLayer();
167 ScDocument& rDoc = rDocShell.GetDocument();
168 bool bUndo (rDoc.IsUndoEnabled());
169 ScDrawLayer* pModel = rDoc.GetDrawLayer();
170 SCCOL nCol = rPos.Col();
171 SCROW nRow = rPos.Row();
172 SCTAB nTab = rPos.Tab();
174 if (bUndo)
175 pModel->BeginCalcUndo(false);
176 bool bDone = ScDetectiveFunc( &rDoc,nTab ).ShowPred( nCol, nRow );
177 SdrUndoGroup* pUndo = nullptr;
178 if (bUndo)
179 pUndo = pModel->GetCalcUndo();
180 if (bDone)
182 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDPRED );
183 rDoc.AddDetectiveOperation( aOperation );
184 if (bUndo)
186 rDocShell.GetUndoManager()->AddUndoAction(
187 new ScUndoDetective( &rDocShell, pUndo, &aOperation ) );
189 aModificator.SetDocumentModified();
190 SfxBindings* pBindings = rDocShell.GetViewBindings();
191 if (pBindings)
192 pBindings->Invalidate( SID_DETECTIVE_REFRESH );
194 else
195 delete pUndo;
197 return bDone;
200 bool ScDocFunc::DetectiveDelPred(const ScAddress& rPos)
202 ScDocument& rDoc = rDocShell.GetDocument();
204 bool bUndo(rDoc.IsUndoEnabled());
205 ScDrawLayer* pModel = rDoc.GetDrawLayer();
206 if (!pModel)
207 return false;
209 ScDocShellModificator aModificator( rDocShell );
211 SCCOL nCol = rPos.Col();
212 SCROW nRow = rPos.Row();
213 SCTAB nTab = rPos.Tab();
215 if (bUndo)
216 pModel->BeginCalcUndo(false);
217 bool bDone = ScDetectiveFunc( &rDoc,nTab ).DeletePred( nCol, nRow );
218 SdrUndoGroup* pUndo = nullptr;
219 if (bUndo)
220 pUndo = pModel->GetCalcUndo();
221 if (bDone)
223 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELPRED );
224 rDoc.AddDetectiveOperation( aOperation );
225 if (bUndo)
227 rDocShell.GetUndoManager()->AddUndoAction(
228 new ScUndoDetective( &rDocShell, pUndo, &aOperation ) );
230 aModificator.SetDocumentModified();
231 SfxBindings* pBindings = rDocShell.GetViewBindings();
232 if (pBindings)
233 pBindings->Invalidate( SID_DETECTIVE_REFRESH );
235 else
236 delete pUndo;
238 return bDone;
241 bool ScDocFunc::DetectiveAddSucc(const ScAddress& rPos)
243 ScDocShellModificator aModificator( rDocShell );
245 rDocShell.MakeDrawLayer();
246 ScDocument& rDoc = rDocShell.GetDocument();
248 bool bUndo(rDoc.IsUndoEnabled());
249 ScDrawLayer* pModel = rDoc.GetDrawLayer();
250 SCCOL nCol = rPos.Col();
251 SCROW nRow = rPos.Row();
252 SCTAB nTab = rPos.Tab();
254 if (bUndo)
255 pModel->BeginCalcUndo(false);
256 bool bDone = ScDetectiveFunc( &rDoc,nTab ).ShowSucc( nCol, nRow );
257 SdrUndoGroup* pUndo = nullptr;
258 if (bUndo)
259 pUndo = pModel->GetCalcUndo();
260 if (bDone)
262 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDSUCC );
263 rDoc.AddDetectiveOperation( aOperation );
264 if (bUndo)
266 rDocShell.GetUndoManager()->AddUndoAction(
267 new ScUndoDetective( &rDocShell, pUndo, &aOperation ) );
269 aModificator.SetDocumentModified();
270 SfxBindings* pBindings = rDocShell.GetViewBindings();
271 if (pBindings)
272 pBindings->Invalidate( SID_DETECTIVE_REFRESH );
274 else
275 delete pUndo;
277 return bDone;
280 bool ScDocFunc::DetectiveDelSucc(const ScAddress& rPos)
282 ScDocument& rDoc = rDocShell.GetDocument();
284 bool bUndo (rDoc.IsUndoEnabled());
285 ScDrawLayer* pModel = rDoc.GetDrawLayer();
286 if (!pModel)
287 return false;
289 ScDocShellModificator aModificator( rDocShell );
291 SCCOL nCol = rPos.Col();
292 SCROW nRow = rPos.Row();
293 SCTAB nTab = rPos.Tab();
295 if (bUndo)
296 pModel->BeginCalcUndo(false);
297 bool bDone = ScDetectiveFunc( &rDoc,nTab ).DeleteSucc( nCol, nRow );
298 SdrUndoGroup* pUndo = nullptr;
299 if (bUndo)
300 pUndo = pModel->GetCalcUndo();
301 if (bDone)
303 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELSUCC );
304 rDoc.AddDetectiveOperation( aOperation );
305 if (bUndo)
307 rDocShell.GetUndoManager()->AddUndoAction(
308 new ScUndoDetective( &rDocShell, pUndo, &aOperation ) );
310 aModificator.SetDocumentModified();
311 SfxBindings* pBindings = rDocShell.GetViewBindings();
312 if (pBindings)
313 pBindings->Invalidate( SID_DETECTIVE_REFRESH );
315 else
316 delete pUndo;
318 return bDone;
321 bool ScDocFunc::DetectiveAddError(const ScAddress& rPos)
323 ScDocShellModificator aModificator( rDocShell );
325 rDocShell.MakeDrawLayer();
326 ScDocument& rDoc = rDocShell.GetDocument();
328 bool bUndo (rDoc.IsUndoEnabled());
329 ScDrawLayer* pModel = rDoc.GetDrawLayer();
330 SCCOL nCol = rPos.Col();
331 SCROW nRow = rPos.Row();
332 SCTAB nTab = rPos.Tab();
334 if (bUndo)
335 pModel->BeginCalcUndo(false);
336 bool bDone = ScDetectiveFunc( &rDoc,nTab ).ShowError( nCol, nRow );
337 SdrUndoGroup* pUndo = nullptr;
338 if (bUndo)
339 pUndo = pModel->GetCalcUndo();
340 if (bDone)
342 ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDERROR );
343 rDoc.AddDetectiveOperation( aOperation );
344 if (bUndo)
346 rDocShell.GetUndoManager()->AddUndoAction(
347 new ScUndoDetective( &rDocShell, pUndo, &aOperation ) );
349 aModificator.SetDocumentModified();
350 SfxBindings* pBindings = rDocShell.GetViewBindings();
351 if (pBindings)
352 pBindings->Invalidate( SID_DETECTIVE_REFRESH );
354 else
355 delete pUndo;
357 return bDone;
360 bool ScDocFunc::DetectiveMarkInvalid(SCTAB nTab)
362 ScDocShellModificator aModificator( rDocShell );
364 rDocShell.MakeDrawLayer();
365 ScDocument& rDoc = rDocShell.GetDocument();
367 bool bUndo (rDoc.IsUndoEnabled());
368 ScDrawLayer* pModel = rDoc.GetDrawLayer();
370 vcl::Window* pWaitWin = ScDocShell::GetActiveDialogParent();
371 if (pWaitWin)
372 pWaitWin->EnterWait();
373 if (bUndo)
374 pModel->BeginCalcUndo(false);
375 bool bOverflow;
376 bool bDone = ScDetectiveFunc( &rDoc,nTab ).MarkInvalid( bOverflow );
377 SdrUndoGroup* pUndo = nullptr;
378 if (bUndo)
379 pUndo = pModel->GetCalcUndo();
380 if (pWaitWin)
381 pWaitWin->LeaveWait();
382 if (bDone)
384 if (pUndo && bUndo)
386 pUndo->SetComment( ScGlobal::GetRscString( STR_UNDO_DETINVALID ) );
387 rDocShell.GetUndoManager()->AddUndoAction( pUndo );
389 aModificator.SetDocumentModified();
390 if ( bOverflow )
392 ScopedVclPtrInstance<InfoBox>( nullptr,
393 ScGlobal::GetRscString( STR_DETINVALID_OVERFLOW ) )->Execute();
396 else
397 delete pUndo;
399 return bDone;
402 bool ScDocFunc::DetectiveDelAll(SCTAB nTab)
404 ScDocument& rDoc = rDocShell.GetDocument();
406 bool bUndo (rDoc.IsUndoEnabled());
407 ScDrawLayer* pModel = rDoc.GetDrawLayer();
408 if (!pModel)
409 return false;
411 ScDocShellModificator aModificator( rDocShell );
413 if (bUndo)
414 pModel->BeginCalcUndo(false);
415 bool bDone = ScDetectiveFunc( &rDoc,nTab ).DeleteAll( SC_DET_DETECTIVE );
416 SdrUndoGroup* pUndo = nullptr;
417 if (bUndo)
418 pUndo = pModel->GetCalcUndo();
419 if (bDone)
421 ScDetOpList* pOldList = rDoc.GetDetOpList();
422 ScDetOpList* pUndoList = nullptr;
423 if (bUndo)
424 pUndoList = pOldList ? new ScDetOpList(*pOldList) : nullptr;
426 rDoc.ClearDetectiveOperations();
428 if (bUndo)
430 rDocShell.GetUndoManager()->AddUndoAction(
431 new ScUndoDetective( &rDocShell, pUndo, nullptr, pUndoList ) );
433 aModificator.SetDocumentModified();
434 SfxBindings* pBindings = rDocShell.GetViewBindings();
435 if (pBindings)
436 pBindings->Invalidate( SID_DETECTIVE_REFRESH );
438 else
439 delete pUndo;
441 return bDone;
444 bool ScDocFunc::DetectiveRefresh( bool bAutomatic )
446 bool bDone = false;
447 ScDocument& rDoc = rDocShell.GetDocument();
449 ScDetOpList* pList = rDoc.GetDetOpList();
450 if ( pList && pList->Count() )
452 rDocShell.MakeDrawLayer();
453 ScDrawLayer* pModel = rDoc.GetDrawLayer();
454 const bool bUndo (rDoc.IsUndoEnabled());
455 if (bUndo)
456 pModel->BeginCalcUndo(false);
458 // Loeschen auf allen Tabellen
460 SCTAB nTabCount = rDoc.GetTableCount();
461 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
462 ScDetectiveFunc( &rDoc,nTab ).DeleteAll( SC_DET_ARROWS ); // don't remove circles
464 // Wiederholen
466 size_t nCount = pList->Count();
467 for (size_t i=0; i < nCount; ++i)
469 const ScDetOpData& rData = pList->GetObject(i);
470 const ScAddress& aPos = rData.GetPos();
471 ScDetectiveFunc aFunc( &rDoc, aPos.Tab() );
472 SCCOL nCol = aPos.Col();
473 SCROW nRow = aPos.Row();
474 switch (rData.GetOperation())
476 case SCDETOP_ADDSUCC:
477 aFunc.ShowSucc( nCol, nRow );
478 break;
479 case SCDETOP_DELSUCC:
480 aFunc.DeleteSucc( nCol, nRow );
481 break;
482 case SCDETOP_ADDPRED:
483 aFunc.ShowPred( nCol, nRow );
484 break;
485 case SCDETOP_DELPRED:
486 aFunc.DeletePred( nCol, nRow );
487 break;
488 case SCDETOP_ADDERROR:
489 aFunc.ShowError( nCol, nRow );
490 break;
491 default:
492 OSL_FAIL("falsche Op bei DetectiveRefresh");
496 if (bUndo)
498 SdrUndoGroup* pUndo = pModel->GetCalcUndo();
499 if (pUndo)
501 pUndo->SetComment( ScGlobal::GetRscString( STR_UNDO_DETREFRESH ) );
502 // wenn automatisch, an letzte Aktion anhaengen
503 rDocShell.GetUndoManager()->AddUndoAction(
504 new ScUndoDraw( pUndo, &rDocShell ),
505 bAutomatic );
508 rDocShell.SetDrawModified();
509 bDone = true;
511 return bDone;
514 static void lcl_collectAllPredOrSuccRanges(
515 const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens, ScDocShell& rDocShell,
516 bool bPred)
518 ScDocument& rDoc = rDocShell.GetDocument();
519 vector<ScTokenRef> aRefTokens;
520 ScRangeList aSrcRanges(rSrcRanges);
521 if (aSrcRanges.empty())
522 return;
523 ScRange* p = aSrcRanges.front();
524 ScDetectiveFunc aDetFunc(&rDoc, p->aStart.Tab());
525 ScRangeList aDestRanges;
526 for (size_t i = 0, n = aSrcRanges.size(); i < n; ++i)
528 p = aSrcRanges[i];
529 if (bPred)
531 aDetFunc.GetAllPreds(
532 p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), aRefTokens);
534 else
536 aDetFunc.GetAllSuccs(
537 p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), aRefTokens);
540 rRefTokens.swap(aRefTokens);
543 void ScDocFunc::DetectiveCollectAllPreds(const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens)
545 lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, true);
548 void ScDocFunc::DetectiveCollectAllSuccs(const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens)
550 lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, false);
553 bool ScDocFunc::DeleteContents(
554 const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi )
556 ScDocShellModificator aModificator( rDocShell );
558 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
560 OSL_FAIL("ScDocFunc::DeleteContents ohne Markierung");
561 return false;
564 ScDocument& rDoc = rDocShell.GetDocument();
566 if (bRecord && !rDoc.IsUndoEnabled())
567 bRecord = false;
569 ScEditableTester aTester( &rDoc, rMark );
570 if (!aTester.IsEditable())
572 if (!bApi)
573 rDocShell.ErrorMessage(aTester.GetMessageId());
574 return false;
577 ScRange aMarkRange;
579 ScMarkData aMultiMark = rMark;
580 aMultiMark.SetMarking(false); // fuer MarkToMulti
582 std::unique_ptr<ScDocument> pUndoDoc;
583 bool bMulti = aMultiMark.IsMultiMarked();
584 aMultiMark.MarkToMulti();
585 aMultiMark.GetMultiMarkArea( aMarkRange );
586 ScRange aExtendedRange(aMarkRange);
587 if ( rDoc.ExtendMerge( aExtendedRange, true ) )
588 bMulti = false;
590 // no objects on protected tabs
591 bool bObjects = (nFlags & InsertDeleteFlags::OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark);
593 sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted
594 if ( nFlags & InsertDeleteFlags::ATTRIB )
595 rDocShell.UpdatePaintExt( nExtFlags, aMarkRange );
597 // Reihenfolge:
598 // 1) BeginDrawUndo
599 // 2) Objekte loeschen (DrawUndo wird gefuellt)
600 // 3) Inhalte fuer Undo kopieren und Undo-Aktion anlegen
601 // 4) Inhalte loeschen
603 bool bDrawUndo = bObjects || (nFlags & InsertDeleteFlags::NOTE);
604 if (bRecord && bDrawUndo)
605 rDoc.BeginDrawUndo();
607 if (bObjects)
609 if (bMulti)
610 rDoc.DeleteObjectsInSelection( aMultiMark );
611 else
612 rDoc.DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
613 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
614 aMultiMark );
617 // To keep track of all non-empty cells within the deleted area.
618 std::shared_ptr<ScSimpleUndo::DataSpansType> pDataSpans;
620 if ( bRecord )
622 pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, aMultiMark, aMarkRange, nFlags, bMulti);
623 pDataSpans = sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, aMultiMark, aMarkRange);
626 rDoc.DeleteSelection( nFlags, aMultiMark );
628 // add undo action after drawing undo is complete (objects and note captions)
629 if( bRecord )
631 sc::DocFuncUtil::addDeleteContentsUndo(
632 rDocShell.GetUndoManager(), &rDocShell, aMultiMark, aExtendedRange,
633 std::move(pUndoDoc), nFlags, pDataSpans, bMulti, bDrawUndo);
636 if (!AdjustRowHeight( aExtendedRange ))
637 rDocShell.PostPaint( aExtendedRange, PAINT_GRID, nExtFlags );
638 else if (nExtFlags & SC_PF_LINES)
639 lcl_PaintAbove( rDocShell, aExtendedRange ); // fuer Linien ueber dem Bereich
641 aModificator.SetDocumentModified();
643 return true;
646 bool ScDocFunc::DeleteCell(
647 const ScAddress& rPos, const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord )
649 ScDocShellModificator aModificator(rDocShell);
651 ScDocument& rDoc = rDocShell.GetDocument();
653 if (bRecord && !rDoc.IsUndoEnabled())
654 bRecord = false;
656 ScEditableTester aTester(&rDoc, rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark);
657 if (!aTester.IsEditable())
659 rDocShell.ErrorMessage(aTester.GetMessageId());
660 return false;
663 // no objects on protected tabs
664 bool bObjects = (nFlags & InsertDeleteFlags::OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark);
666 sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted
667 if (nFlags & InsertDeleteFlags::ATTRIB)
668 rDocShell.UpdatePaintExt(nExtFlags, rPos);
670 // order op opeeration:
671 // 1) BeginDrawUndo
672 // 2) delete objects (DrawUndo is filled)
673 // 3) copy contents for undo
674 // 4) delete contents
675 // 5) add undo-action
677 bool bDrawUndo = bObjects || (nFlags & InsertDeleteFlags::NOTE); // needed for shown notes
678 if (bDrawUndo && bRecord)
679 rDoc.BeginDrawUndo();
681 if (bObjects)
682 rDoc.DeleteObjectsInArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark);
684 // To keep track of all non-empty cells within the deleted area.
685 std::shared_ptr<ScSimpleUndo::DataSpansType> pDataSpans;
687 std::unique_ptr<ScDocument> pUndoDoc;
688 if (bRecord)
690 pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, rMark, rPos, nFlags, false);
691 pDataSpans = sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, rMark, rPos);
694 rDoc.DeleteArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark, nFlags);
696 if (bRecord)
698 sc::DocFuncUtil::addDeleteContentsUndo(
699 rDocShell.GetUndoManager(), &rDocShell, rMark, rPos, std::move(pUndoDoc),
700 nFlags, pDataSpans, false, bDrawUndo);
703 if (!AdjustRowHeight(rPos))
704 rDocShell.PostPaint(
705 rPos.Col(), rPos.Row(), rPos.Tab(), rPos.Col(), rPos.Row(), rPos.Tab(),
706 PAINT_GRID, nExtFlags);
708 aModificator.SetDocumentModified();
710 return true;
713 bool ScDocFunc::TransliterateText( const ScMarkData& rMark, sal_Int32 nType,
714 bool bApi )
716 ScDocShellModificator aModificator( rDocShell );
718 ScDocument& rDoc = rDocShell.GetDocument();
719 bool bRecord = true;
720 if (bRecord && !rDoc.IsUndoEnabled())
721 bRecord = false;
723 ScEditableTester aTester( &rDoc, rMark );
724 if (!aTester.IsEditable())
726 if (!bApi)
727 rDocShell.ErrorMessage(aTester.GetMessageId());
728 return false;
731 ScRange aMarkRange;
732 ScMarkData aMultiMark = rMark;
733 aMultiMark.SetMarking(false); // for MarkToMulti
734 aMultiMark.MarkToMulti();
735 aMultiMark.GetMultiMarkArea( aMarkRange );
737 if (bRecord)
739 SCTAB nStartTab = aMarkRange.aStart.Tab();
740 SCTAB nTabCount = rDoc.GetTableCount();
742 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
743 pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab );
744 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
745 for (; itr != itrEnd && *itr < nTabCount; ++itr)
746 if (*itr != nStartTab)
747 pUndoDoc->AddUndoTab( *itr, *itr );
749 ScRange aCopyRange = aMarkRange;
750 aCopyRange.aStart.SetTab(0);
751 aCopyRange.aEnd.SetTab(nTabCount-1);
752 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::CONTENTS, true, pUndoDoc, &aMultiMark );
754 rDocShell.GetUndoManager()->AddUndoAction(
755 new ScUndoTransliterate( &rDocShell, aMultiMark, pUndoDoc, nType ) );
758 rDoc.TransliterateText( aMultiMark, nType );
760 if (!AdjustRowHeight( aMarkRange ))
761 rDocShell.PostPaint( aMarkRange, PAINT_GRID );
763 aModificator.SetDocumentModified();
765 return true;
768 bool ScDocFunc::SetNormalString( bool& o_rbNumFmtSet, const ScAddress& rPos, const OUString& rText, bool bApi )
770 ScDocShellModificator aModificator( rDocShell );
771 ScDocument& rDoc = rDocShell.GetDocument();
773 bool bUndo(rDoc.IsUndoEnabled());
774 ScEditableTester aTester( &rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
775 if (!aTester.IsEditable())
777 if (!bApi)
778 rDocShell.ErrorMessage(aTester.GetMessageId());
779 return false;
782 bool bEditDeleted = (rDoc.GetCellType(rPos) == CELLTYPE_EDIT);
783 ScUndoEnterData::ValuesType aOldValues;
785 if (bUndo)
787 ScUndoEnterData::Value aOldValue;
789 aOldValue.mnTab = rPos.Tab();
790 aOldValue.maCell.assign(rDoc, rPos);
792 const SfxPoolItem* pItem;
793 const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(),rPos.Row(),rPos.Tab() );
794 if ( SfxItemState::SET == pPattern->GetItemSet().GetItemState(
795 ATTR_VALUE_FORMAT,false,&pItem) )
797 aOldValue.mbHasFormat = true;
798 aOldValue.mnFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
800 else
801 aOldValue.mbHasFormat = false;
803 aOldValues.push_back(aOldValue);
806 o_rbNumFmtSet = rDoc.SetString( rPos.Col(), rPos.Row(), rPos.Tab(), rText );
808 if (bUndo)
810 // wegen ChangeTracking darf UndoAction erst nach SetString angelegt werden
811 rDocShell.GetUndoManager()->AddUndoAction(
812 new ScUndoEnterData(&rDocShell, rPos, aOldValues, rText, nullptr));
815 if ( bEditDeleted || rDoc.HasAttrib( ScRange(rPos), HASATTR_NEEDHEIGHT ) )
816 AdjustRowHeight( ScRange(rPos) );
818 rDocShell.PostPaintCell( rPos );
819 aModificator.SetDocumentModified();
821 // notify input handler here the same way as in PutCell
822 if (bApi)
823 NotifyInputHandler( rPos );
825 return true;
828 bool ScDocFunc::SetValueCell( const ScAddress& rPos, double fVal, bool bInteraction )
830 ScDocShellModificator aModificator( rDocShell );
831 ScDocument& rDoc = rDocShell.GetDocument();
832 bool bUndo = rDoc.IsUndoEnabled();
834 bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT);
836 ScCellValue aOldVal;
837 if (bUndo)
838 aOldVal.assign(rDoc, rPos);
840 rDoc.SetValue(rPos, fVal);
842 if (bUndo)
844 svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager();
845 ScCellValue aNewVal;
846 aNewVal.assign(rDoc, rPos);
847 pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal));
850 if (bHeight)
851 AdjustRowHeight(rPos);
853 rDocShell.PostPaintCell( rPos );
854 aModificator.SetDocumentModified();
856 // #103934#; notify editline and cell in edit mode
857 if (!bInteraction)
858 NotifyInputHandler( rPos );
860 return true;
863 void ScDocFunc::SetValueCells( const ScAddress& rPos, const std::vector<double>& aVals, bool bInteraction )
865 // Check for invalid range.
866 SCROW nLastRow = rPos.Row() + aVals.size() - 1;
867 if (nLastRow > MAXROW)
868 // out of bound.
869 return;
871 ScRange aRange(rPos);
872 aRange.aEnd.SetRow(nLastRow);
874 ScDocShellModificator aModificator(rDocShell);
875 ScDocument& rDoc = rDocShell.GetDocument();
877 if (rDoc.IsUndoEnabled())
879 sc::UndoSetCells* pUndoObj = new sc::UndoSetCells(&rDocShell, rPos);
880 rDoc.TransferCellValuesTo(rPos, aVals.size(), pUndoObj->GetOldValues());
881 pUndoObj->SetNewValues(aVals);
882 svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager();
883 pUndoMgr->AddUndoAction(pUndoObj);
886 rDoc.SetValues(rPos, aVals);
888 rDocShell.PostPaint(aRange, PAINT_GRID);
889 aModificator.SetDocumentModified();
891 // #103934#; notify editline and cell in edit mode
892 if (!bInteraction)
893 NotifyInputHandler(rPos);
896 bool ScDocFunc::SetStringCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction )
898 ScDocShellModificator aModificator( rDocShell );
899 ScDocument& rDoc = rDocShell.GetDocument();
900 bool bUndo = rDoc.IsUndoEnabled();
902 bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT);
904 ScCellValue aOldVal;
905 if (bUndo)
906 aOldVal.assign(rDoc, rPos);
908 ScSetStringParam aParam;
909 aParam.setTextInput();
910 rDoc.SetString(rPos, rStr, &aParam);
912 if (bUndo)
914 svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager();
915 ScCellValue aNewVal;
916 aNewVal.assign(rDoc, rPos);
917 pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal));
920 if (bHeight)
921 AdjustRowHeight(rPos);
923 rDocShell.PostPaintCell( rPos );
924 aModificator.SetDocumentModified();
926 // #103934#; notify editline and cell in edit mode
927 if (!bInteraction)
928 NotifyInputHandler( rPos );
930 return true;
933 bool ScDocFunc::SetEditCell( const ScAddress& rPos, const EditTextObject& rStr, bool bInteraction )
935 ScDocShellModificator aModificator( rDocShell );
936 ScDocument& rDoc = rDocShell.GetDocument();
937 bool bUndo = rDoc.IsUndoEnabled();
939 bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT);
941 ScCellValue aOldVal;
942 if (bUndo)
943 aOldVal.assign(rDoc, rPos);
945 rDoc.SetEditText(rPos, rStr.Clone());
947 if (bUndo)
949 svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager();
950 ScCellValue aNewVal;
951 aNewVal.assign(rDoc, rPos);
952 pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal));
955 if (bHeight)
956 AdjustRowHeight(rPos);
958 rDocShell.PostPaintCell( rPos );
959 aModificator.SetDocumentModified();
961 // #103934#; notify editline and cell in edit mode
962 if (!bInteraction)
963 NotifyInputHandler( rPos );
965 return true;
968 bool ScDocFunc::SetStringOrEditCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction )
970 ScDocument& rDoc = rDocShell.GetDocument();
972 if (ScStringUtil::isMultiline(rStr))
974 ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
975 rEngine.SetText(rStr);
976 std::unique_ptr<EditTextObject> pEditText(rEngine.CreateTextObject());
977 return SetEditCell(rPos, *pEditText, bInteraction);
979 else
980 return SetStringCell(rPos, rStr, bInteraction);
983 bool ScDocFunc::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell, bool bInteraction )
985 std::unique_ptr<ScFormulaCell> xCell(pCell);
987 ScDocShellModificator aModificator( rDocShell );
988 ScDocument& rDoc = rDocShell.GetDocument();
989 bool bUndo = rDoc.IsUndoEnabled();
991 bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT);
993 ScCellValue aOldVal;
994 if (bUndo)
995 aOldVal.assign(rDoc, rPos);
997 pCell = rDoc.SetFormulaCell(rPos, xCell.release());
999 // For performance reasons API calls may disable calculation while
1000 // operating and recalculate once when done. If through user interaction
1001 // and AutoCalc is disabled, calculate the formula (without its
1002 // dependencies) once so the result matches the current document's content.
1003 if (bInteraction && !rDoc.GetAutoCalc() && pCell)
1005 // calculate just the cell once and set Dirty again
1006 pCell->Interpret();
1007 pCell->SetDirtyVar();
1008 rDoc.PutInFormulaTree( pCell);
1011 if (bUndo)
1013 svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager();
1014 ScCellValue aNewVal;
1015 aNewVal.assign(rDoc, rPos);
1016 pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal));
1019 if (bHeight)
1020 AdjustRowHeight(rPos);
1022 rDocShell.PostPaintCell( rPos );
1023 aModificator.SetDocumentModified();
1025 // #103934#; notify editline and cell in edit mode
1026 if (!bInteraction)
1027 NotifyInputHandler( rPos );
1029 return true;
1032 void ScDocFunc::NotifyInputHandler( const ScAddress& rPos )
1034 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1035 if ( pViewSh && pViewSh->GetViewData().GetDocShell() == &rDocShell )
1037 ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
1038 if ( pInputHdl && pInputHdl->GetCursorPos() == rPos )
1040 bool bIsEditMode(pInputHdl->IsEditMode());
1042 // set modified if in editmode, because so the string is not set in the InputWindow like in the cell
1043 // (the cell shows the same like the InputWindow)
1044 if (bIsEditMode)
1045 pInputHdl->SetModified();
1046 pViewSh->UpdateInputHandler(false, !bIsEditMode);
1051 struct ScMyRememberItem
1053 sal_Int32 nIndex;
1054 SfxItemSet aItemSet;
1056 ScMyRememberItem(const SfxItemSet& rItemSet, sal_Int32 nTempIndex) :
1057 nIndex(nTempIndex), aItemSet(rItemSet) {}
1060 typedef ::std::list<ScMyRememberItem*> ScMyRememberItemList;
1062 void ScDocFunc::PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, bool bApi )
1064 // PutData ruft PutCell oder SetNormalString
1066 bool bRet = false;
1067 ScDocument& rDoc = rDocShell.GetDocument();
1068 ScEditAttrTester aTester( &rEngine );
1069 bool bEditCell = aTester.NeedsObject();
1070 if ( bEditCell )
1072 // #i61702# With bLoseContent set, the content of rEngine isn't restored
1073 // (used in loading XML, where after the removeActionLock call the API object's
1074 // EditEngine isn't accessed again.
1075 bool bLoseContent = rDoc.IsImportingXML();
1077 bool bUpdateMode(rEngine.GetUpdateMode());
1078 if (bUpdateMode)
1079 rEngine.SetUpdateMode(false);
1081 ScMyRememberItemList aRememberItems;
1082 ScMyRememberItem* pRememberItem = nullptr;
1084 // All paragraph attributes must be removed before calling CreateTextObject,
1085 // not only alignment, so the object doesn't contain the cell attributes as
1086 // paragraph attributes. Before remove the attributes store they in a list to
1087 // set they back to the EditEngine.
1088 sal_Int32 nCount = rEngine.GetParagraphCount();
1089 for (sal_Int32 i=0; i<nCount; i++)
1091 const SfxItemSet& rOld = rEngine.GetParaAttribs( i );
1092 if ( rOld.Count() )
1094 if ( !bLoseContent )
1096 pRememberItem = new ScMyRememberItem(rEngine.GetParaAttribs(i), i);
1097 aRememberItems.push_back(pRememberItem);
1099 rEngine.SetParaAttribs( i, SfxItemSet( *rOld.GetPool(), rOld.GetRanges() ) );
1103 // A copy of pNewData will be stored in the cell.
1104 std::unique_ptr<EditTextObject> pNewData(rEngine.CreateTextObject());
1105 bRet = SetEditCell(rPos, *pNewData, !bApi);
1107 // Set the paragraph attributes back to the EditEngine.
1108 if (!aRememberItems.empty())
1110 ScMyRememberItemList::iterator aItr = aRememberItems.begin();
1111 while (aItr != aRememberItems.end())
1113 pRememberItem = *aItr;
1114 rEngine.SetParaAttribs(pRememberItem->nIndex, pRememberItem->aItemSet);
1115 delete pRememberItem;
1116 aItr = aRememberItems.erase(aItr);
1120 // #i61702# if the content isn't accessed, there's no need to set the UpdateMode again
1121 if ( bUpdateMode && !bLoseContent )
1122 rEngine.SetUpdateMode(true);
1124 else
1126 OUString aText = rEngine.GetText();
1127 if (aText.isEmpty())
1129 bool bNumFmtSet = false;
1130 bRet = SetNormalString( bNumFmtSet, rPos, aText, bApi );
1132 else
1133 bRet = SetStringCell(rPos, aText, !bApi);
1136 if ( bRet && aTester.NeedsCellAttr() )
1138 const SfxItemSet& rEditAttr = aTester.GetAttribs();
1139 ScPatternAttr aPattern( rDoc.GetPool() );
1140 aPattern.GetFromEditItemSet( &rEditAttr );
1141 aPattern.DeleteUnchanged( rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() ) );
1142 aPattern.GetItemSet().ClearItem( ATTR_HOR_JUSTIFY ); // wasn't removed above if no edit object
1143 if ( aPattern.GetItemSet().Count() > 0 )
1145 ScMarkData aMark;
1146 aMark.SelectTable( rPos.Tab(), true );
1147 aMark.SetMarkArea( ScRange( rPos ) );
1148 ApplyAttributes( aMark, aPattern, bApi );
1153 static ScTokenArray* lcl_ScDocFunc_CreateTokenArrayXML( const OUString& rText, const OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar )
1155 ScTokenArray* pCode = new ScTokenArray;
1156 pCode->AddStringXML( rText );
1157 if( (eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) && (!rFormulaNmsp.isEmpty()) )
1158 pCode->AddStringXML( rFormulaNmsp );
1159 return pCode;
1162 bool ScDocFunc::SetCellText(
1163 const ScAddress& rPos, const OUString& rText, bool bInterpret, bool bEnglish, bool bApi,
1164 const formula::FormulaGrammar::Grammar eGrammar )
1166 bool bSet = false;
1167 if ( bInterpret )
1169 if ( bEnglish )
1171 ScDocument& rDoc = rDocShell.GetDocument();
1173 ::std::unique_ptr<ScExternalRefManager::ApiGuard> pExtRefGuard;
1174 if (bApi)
1175 pExtRefGuard.reset(new ScExternalRefManager::ApiGuard(&rDoc));
1177 ScInputStringType aRes =
1178 ScStringUtil::parseInputString(*rDoc.GetFormatTable(), rText, LANGUAGE_ENGLISH_US);
1180 switch (aRes.meType)
1182 case ScInputStringType::Formula:
1183 bSet = SetFormulaCell(rPos, new ScFormulaCell(&rDoc, rPos, aRes.maText, eGrammar), !bApi);
1184 break;
1185 case ScInputStringType::Number:
1186 bSet = SetValueCell(rPos, aRes.mfValue, !bApi);
1187 break;
1188 case ScInputStringType::Text:
1189 bSet = SetStringOrEditCell(rPos, aRes.maText, !bApi);
1190 break;
1191 default:
1195 // sonst Null behalten -> SetString mit lokalen Formeln/Zahlformat
1197 else if (!rText.isEmpty())
1199 bSet = SetStringOrEditCell(rPos, rText, !bApi);
1202 if (!bSet)
1204 bool bNumFmtSet = false;
1205 bSet = SetNormalString( bNumFmtSet, rPos, rText, bApi );
1207 return bSet;
1210 bool ScDocFunc::ShowNote( const ScAddress& rPos, bool bShow )
1212 ScDocument& rDoc = rDocShell.GetDocument();
1213 ScPostIt* pNote = rDoc.GetNote( rPos );
1214 if( !pNote || (bShow == pNote->IsCaptionShown()) ) return false;
1216 // move the caption to internal or hidden layer and create undo action
1217 pNote->ShowCaption( rPos, bShow );
1218 if( rDoc.IsUndoEnabled() )
1219 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoShowHideNote( rDocShell, rPos, bShow ) );
1221 if (rDoc.IsStreamValid(rPos.Tab()))
1222 rDoc.SetStreamValid(rPos.Tab(), false);
1224 rDocShell.SetDocumentModified();
1226 return true;
1229 void ScDocFunc::SetNoteText( const ScAddress& rPos, const OUString& rText, bool bApi )
1231 ScDocShellModificator aModificator( rDocShell );
1233 ScDocument& rDoc = rDocShell.GetDocument();
1234 ScEditableTester aTester( &rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
1235 if (!aTester.IsEditable())
1237 if (!bApi)
1238 rDocShell.ErrorMessage(aTester.GetMessageId());
1239 return;
1242 OUString aNewText = convertLineEnd(rText, GetSystemLineEnd()); //! ist das noetig ???
1244 if( ScPostIt* pNote = (!aNewText.isEmpty()) ? rDoc.GetOrCreateNote( rPos ) : rDoc.GetNote(rPos) )
1245 pNote->SetText( rPos, aNewText );
1247 //! Undo !!!
1249 if (rDoc.IsStreamValid(rPos.Tab()))
1250 rDoc.SetStreamValid(rPos.Tab(), false);
1252 rDocShell.PostPaintCell( rPos );
1253 aModificator.SetDocumentModified();
1256 void ScDocFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate, bool bApi )
1258 ScDocShellModificator aModificator( rDocShell );
1259 ScDocument& rDoc = rDocShell.GetDocument();
1260 ScEditableTester aTester( &rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
1261 if (aTester.IsEditable())
1263 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
1264 ::svl::IUndoManager* pUndoMgr = (pDrawLayer && rDoc.IsUndoEnabled()) ? rDocShell.GetUndoManager() : nullptr;
1266 ScNoteData aOldData;
1267 ScPostIt* pOldNote = rDoc.ReleaseNote( rPos );
1268 if( pOldNote )
1270 // ensure existing caption object before draw undo tracking starts
1271 pOldNote->GetOrCreateCaption( rPos );
1272 // rescue note data for undo
1273 aOldData = pOldNote->GetNoteData();
1276 // collect drawing undo actions for deleting/inserting caption objects
1277 if( pUndoMgr )
1278 pDrawLayer->BeginCalcUndo(false);
1280 // delete the note (creates drawing undo action for the caption object)
1281 delete pOldNote;
1283 // create new note (creates drawing undo action for the new caption object)
1284 ScNoteData aNewData;
1285 if( ScPostIt* pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true ) )
1287 if( pAuthor ) pNewNote->SetAuthor( *pAuthor );
1288 if( pDate ) pNewNote->SetDate( *pDate );
1289 // rescue note data for undo
1290 aNewData = pNewNote->GetNoteData();
1293 // create the undo action
1294 if( pUndoMgr && (aOldData.mpCaption || aNewData.mpCaption) )
1295 pUndoMgr->AddUndoAction( new ScUndoReplaceNote( rDocShell, rPos, aOldData, aNewData, pDrawLayer->GetCalcUndo() ) );
1297 // repaint cell (to make note marker visible)
1298 rDocShell.PostPaintCell( rPos );
1300 if (rDoc.IsStreamValid(rPos.Tab()))
1301 rDoc.SetStreamValid(rPos.Tab(), false);
1303 aModificator.SetDocumentModified();
1305 else if (!bApi)
1307 rDocShell.ErrorMessage(aTester.GetMessageId());
1311 bool ScDocFunc::ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern,
1312 bool bApi )
1314 ScDocument& rDoc = rDocShell.GetDocument();
1315 bool bRecord = true;
1316 if ( bRecord && !rDoc.IsUndoEnabled() )
1317 bRecord = false;
1319 bool bImportingXML = rDoc.IsImportingXML();
1320 // Cell formats can still be set if the range isn't editable only because of matrix formulas.
1321 // #i62483# When loading XML, the check can be skipped altogether.
1322 bool bOnlyNotBecauseOfMatrix;
1323 if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix )
1324 && !bOnlyNotBecauseOfMatrix )
1326 if (!bApi)
1327 rDocShell.ErrorMessage(STR_PROTECTIONERR);
1328 return false;
1331 ScDocShellModificator aModificator( rDocShell );
1333 //! Umrandung
1335 ScRange aMultiRange;
1336 bool bMulti = rMark.IsMultiMarked();
1337 if ( bMulti )
1338 rMark.GetMultiMarkArea( aMultiRange );
1339 else
1340 rMark.GetMarkArea( aMultiRange );
1342 if ( bRecord )
1344 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1345 pUndoDoc->InitUndo( &rDoc, aMultiRange.aStart.Tab(), aMultiRange.aEnd.Tab() );
1346 rDoc.CopyToDocument( aMultiRange, InsertDeleteFlags::ATTRIB, bMulti, pUndoDoc, &rMark );
1348 rDocShell.GetUndoManager()->AddUndoAction(
1349 new ScUndoSelectionAttr(
1350 &rDocShell, rMark,
1351 aMultiRange.aStart.Col(), aMultiRange.aStart.Row(), aMultiRange.aStart.Tab(),
1352 aMultiRange.aEnd.Col(), aMultiRange.aEnd.Row(), aMultiRange.aEnd.Tab(),
1353 pUndoDoc, bMulti, &rPattern ) );
1356 // While loading XML it is not necessary to ask HasAttrib. It needs too much time.
1357 sal_uInt16 nExtFlags = 0;
1358 if ( !bImportingXML )
1359 rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content before the change
1360 rDoc.ApplySelectionPattern( rPattern, rMark );
1361 if ( !bImportingXML )
1362 rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content after the change
1364 if (!AdjustRowHeight( aMultiRange ))
1365 rDocShell.PostPaint( aMultiRange, PAINT_GRID, nExtFlags );
1366 else if (nExtFlags & SC_PF_LINES)
1367 lcl_PaintAbove( rDocShell, aMultiRange ); // fuer Linien ueber dem Bereich
1369 aModificator.SetDocumentModified();
1371 return true;
1374 bool ScDocFunc::ApplyStyle( const ScMarkData& rMark, const OUString& rStyleName,
1375 bool bApi )
1377 ScDocument& rDoc = rDocShell.GetDocument();
1378 bool bRecord = true;
1379 if ( bRecord && !rDoc.IsUndoEnabled() )
1380 bRecord = false;
1382 bool bImportingXML = rDoc.IsImportingXML();
1383 // Cell formats can still be set if the range isn't editable only because of matrix formulas.
1384 // #i62483# When loading XML, the check can be skipped altogether.
1385 bool bOnlyNotBecauseOfMatrix;
1386 if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix )
1387 && !bOnlyNotBecauseOfMatrix )
1389 if (!bApi)
1390 rDocShell.ErrorMessage(STR_PROTECTIONERR);
1391 return false;
1394 ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( rDoc.GetStyleSheetPool()->Find(
1395 rStyleName, SfxStyleFamily::Para ));
1396 if (!pStyleSheet)
1397 return false;
1399 ScDocShellModificator aModificator( rDocShell );
1401 ScRange aMultiRange;
1402 bool bMulti = rMark.IsMultiMarked();
1403 if ( bMulti )
1404 rMark.GetMultiMarkArea( aMultiRange );
1405 else
1406 rMark.GetMarkArea( aMultiRange );
1408 if ( bRecord )
1410 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1411 SCTAB nStartTab = aMultiRange.aStart.Tab();
1412 SCTAB nTabCount = rDoc.GetTableCount();
1413 pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab );
1414 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
1415 for (; itr != itrEnd && *itr < nTabCount; ++itr)
1416 if (*itr != nStartTab)
1417 pUndoDoc->AddUndoTab( *itr, *itr );
1419 ScRange aCopyRange = aMultiRange;
1420 aCopyRange.aStart.SetTab(0);
1421 aCopyRange.aEnd.SetTab(nTabCount-1);
1422 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, pUndoDoc, &rMark );
1424 rDocShell.GetUndoManager()->AddUndoAction(
1425 new ScUndoSelectionStyle(
1426 &rDocShell, rMark, aMultiRange, rStyleName, pUndoDoc ) );
1430 rDoc.ApplySelectionStyle( (ScStyleSheet&)*pStyleSheet, rMark );
1432 if (!AdjustRowHeight( aMultiRange ))
1433 rDocShell.PostPaint( aMultiRange, PAINT_GRID );
1435 aModificator.SetDocumentModified();
1437 return true;
1440 namespace {
1443 * Check if this insertion attempt would end up cutting one or more pivot
1444 * tables in half, which is not desirable.
1446 * @return true if this insertion can be done safely without shearing any
1447 * existing pivot tables, false otherwise.
1449 bool canInsertCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, InsCellCmd eCmd, const ScDocument* pDoc)
1451 if (!pDoc->HasPivotTable())
1452 // This document has no pivot tables.
1453 return true;
1455 const ScDPCollection* pDPs = pDoc->GetDPCollection();
1456 ScMarkData::const_iterator itBeg = rMarkData.begin(), itEnd = rMarkData.end();
1458 ScRange aRange(rRange); // local copy
1459 switch (eCmd)
1461 case INS_INSROWS_BEFORE:
1463 aRange.aStart.SetCol(0);
1464 aRange.aEnd.SetCol(MAXCOL);
1465 SAL_FALLTHROUGH;
1467 case INS_CELLSDOWN:
1469 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1471 if (pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), *it))
1472 // This column range cuts through at least one pivot table. Not good.
1473 return false;
1476 // Start row must be either at the top or above any pivot tables.
1477 if (aRange.aStart.Row() < 0)
1478 // I don't know how to handle this case.
1479 return false;
1481 if (aRange.aStart.Row() == 0)
1482 // First row is always allowed.
1483 return true;
1485 ScRange aTest(aRange);
1486 aTest.aStart.IncRow(-1); // Test one row up.
1487 aTest.aEnd.SetRow(aTest.aStart.Row());
1488 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1490 aTest.aStart.SetTab(*it);
1491 aTest.aEnd.SetTab(*it);
1492 if (pDPs->HasTable(aTest))
1493 return false;
1496 break;
1497 case INS_INSCOLS_BEFORE:
1499 aRange.aStart.SetRow(0);
1500 aRange.aEnd.SetRow(MAXROW);
1501 SAL_FALLTHROUGH;
1503 case INS_CELLSRIGHT:
1505 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1507 if (pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), *it))
1508 // This column range cuts through at least one pivot table. Not good.
1509 return false;
1512 // Start row must be either at the top or above any pivot tables.
1513 if (aRange.aStart.Col() < 0)
1514 // I don't know how to handle this case.
1515 return false;
1517 if (aRange.aStart.Col() == 0)
1518 // First row is always allowed.
1519 return true;
1521 ScRange aTest(aRange);
1522 aTest.aStart.IncCol(-1); // Test one column to the left.
1523 aTest.aEnd.SetCol(aTest.aStart.Col());
1524 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1526 aTest.aStart.SetTab(*it);
1527 aTest.aEnd.SetTab(*it);
1528 if (pDPs->HasTable(aTest))
1529 return false;
1532 break;
1533 default:
1536 return true;
1540 * Check if this deletion attempt would end up cutting one or more pivot
1541 * tables in half, which is not desirable.
1543 * @return true if this deletion can be done safely without shearing any
1544 * existing pivot tables, false otherwise.
1546 bool canDeleteCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, DelCellCmd eCmd, const ScDocument* pDoc)
1548 if (!pDoc->HasPivotTable())
1549 // This document has no pivot tables.
1550 return true;
1552 const ScDPCollection* pDPs = pDoc->GetDPCollection();
1553 ScMarkData::const_iterator itBeg = rMarkData.begin(), itEnd = rMarkData.end();
1555 ScRange aRange(rRange); // local copy
1557 switch (eCmd)
1559 case DEL_DELROWS:
1561 aRange.aStart.SetCol(0);
1562 aRange.aEnd.SetCol(MAXCOL);
1563 SAL_FALLTHROUGH;
1565 case DEL_CELLSUP:
1567 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1569 if (pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), *it))
1570 // This column range cuts through at least one pivot table. Not good.
1571 return false;
1574 ScRange aTest(aRange);
1575 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1577 aTest.aStart.SetTab(*it);
1578 aTest.aEnd.SetTab(*it);
1579 if (pDPs->HasTable(aTest))
1580 return false;
1583 break;
1584 case DEL_DELCOLS:
1586 aRange.aStart.SetRow(0);
1587 aRange.aEnd.SetRow(MAXROW);
1588 SAL_FALLTHROUGH;
1590 case DEL_CELLSLEFT:
1592 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1594 if (pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), *it))
1595 // This column range cuts through at least one pivot table. Not good.
1596 return false;
1599 ScRange aTest(aRange);
1600 for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it)
1602 aTest.aStart.SetTab(*it);
1603 aTest.aEnd.SetTab(*it);
1604 if (pDPs->HasTable(aTest))
1605 return false;
1608 break;
1609 default:
1612 return true;
1617 bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, InsCellCmd eCmd,
1618 bool bRecord, bool bApi, bool bPartOfPaste )
1620 ScDocShellModificator aModificator( rDocShell );
1622 if (rDocShell.GetDocument().GetChangeTrack() &&
1623 ((eCmd == INS_CELLSDOWN && (rRange.aStart.Col() != 0 || rRange.aEnd.Col() != MAXCOL)) ||
1624 (eCmd == INS_CELLSRIGHT && (rRange.aStart.Row() != 0 || rRange.aEnd.Row() != MAXROW))))
1626 // We should not reach this via UI disabled slots.
1627 assert(bApi);
1628 SAL_WARN("sc.ui","ScDocFunc::InsertCells - no change-tracking of partial cell shift");
1629 return false;
1632 ScRange aTargetRange( rRange );
1634 // If insertion is for full cols/rows and after the current
1635 // selection, then shift the range accordingly
1636 if ( eCmd == INS_INSROWS_AFTER )
1638 ScRange aErrorRange( ScAddress::UNINITIALIZED );
1639 if (!aTargetRange.Move(0, rRange.aEnd.Row() - rRange.aStart.Row() + 1, 0, aErrorRange))
1641 assert(!"can't move");
1644 if ( eCmd == INS_INSCOLS_AFTER )
1646 ScRange aErrorRange( ScAddress::UNINITIALIZED );
1647 if (!aTargetRange.Move(rRange.aEnd.Col() - rRange.aStart.Col() + 1, 0, 0, aErrorRange))
1649 assert(!"can't move");
1653 SCCOL nStartCol = aTargetRange.aStart.Col();
1654 SCROW nStartRow = aTargetRange.aStart.Row();
1655 SCTAB nStartTab = aTargetRange.aStart.Tab();
1656 SCCOL nEndCol = aTargetRange.aEnd.Col();
1657 SCROW nEndRow = aTargetRange.aEnd.Row();
1658 SCTAB nEndTab = aTargetRange.aEnd.Tab();
1660 if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) )
1662 OSL_FAIL("invalid row in InsertCells");
1663 return false;
1666 ScDocument& rDoc = rDocShell.GetDocument();
1667 SCTAB nTabCount = rDoc.GetTableCount();
1668 SCCOL nPaintStartCol = nStartCol;
1669 SCROW nPaintStartRow = nStartRow;
1670 SCCOL nPaintEndCol = nEndCol;
1671 SCROW nPaintEndRow = nEndRow;
1672 sal_uInt16 nPaintFlags = PAINT_GRID;
1673 bool bSuccess;
1674 SCTAB i;
1676 ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); //preserve current cursor position
1677 SCCOL nCursorCol = 0;
1678 SCROW nCursorRow = 0;
1679 if( pViewSh )
1681 nCursorCol = pViewSh->GetViewData().GetCurX();
1682 nCursorRow = pViewSh->GetViewData().GetCurY();
1685 if (bRecord && !rDoc.IsUndoEnabled())
1686 bRecord = false;
1688 ScMarkData aMark;
1689 if (pTabMark)
1690 aMark = *pTabMark;
1691 else
1693 SCTAB nCount = 0;
1694 for( i=0; i<nTabCount; i++ )
1696 if( !rDoc.IsScenario(i) )
1698 nCount++;
1699 if( nCount == nEndTab+1 )
1701 aMark.SelectTable( i, true );
1702 break;
1708 ScMarkData aFullMark( aMark ); // including scenario sheets
1709 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
1710 for (; itr != itrEnd && *itr < nTabCount; ++itr)
1711 for( SCTAB j = *itr+1; j<nTabCount && rDoc.IsScenario(j); j++ )
1712 aFullMark.SelectTable( j, true );
1714 SCTAB nSelCount = aMark.GetSelectCount();
1716 // Adjust also related scenarios
1718 SCCOL nMergeTestStartCol = nStartCol;
1719 SCROW nMergeTestStartRow = nStartRow;
1720 SCCOL nMergeTestEndCol = nEndCol;
1721 SCROW nMergeTestEndRow = nEndRow;
1723 ScRange aExtendMergeRange( aTargetRange );
1725 if( aTargetRange.aStart == aTargetRange.aEnd && rDoc.HasAttrib(aTargetRange, HASATTR_MERGED) )
1727 rDoc.ExtendMerge( aExtendMergeRange );
1728 rDoc.ExtendOverlapped( aExtendMergeRange );
1729 nMergeTestEndCol = aExtendMergeRange.aEnd.Col();
1730 nMergeTestEndRow = aExtendMergeRange.aEnd.Row();
1731 nPaintEndCol = nMergeTestEndCol;
1732 nPaintEndRow = nMergeTestEndRow;
1735 if ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER )
1737 nMergeTestStartCol = 0;
1738 nMergeTestEndCol = MAXCOL;
1740 if ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER )
1742 nMergeTestStartRow = 0;
1743 nMergeTestEndRow = MAXROW;
1745 if ( eCmd == INS_CELLSDOWN )
1746 nMergeTestEndRow = MAXROW;
1747 if ( eCmd == INS_CELLSRIGHT )
1748 nMergeTestEndCol = MAXCOL;
1750 bool bNeedRefresh = false;
1752 SCCOL nEditTestEndCol = (eCmd==INS_INSCOLS_BEFORE || eCmd==INS_INSCOLS_AFTER) ? MAXCOL : nMergeTestEndCol;
1753 SCROW nEditTestEndRow = (eCmd==INS_INSROWS_BEFORE || eCmd==INS_INSROWS_AFTER) ? MAXROW : nMergeTestEndRow;
1754 ScEditableTester aTester( &rDoc, nMergeTestStartCol, nMergeTestStartRow, nEditTestEndCol, nEditTestEndRow, aMark );
1755 if (!aTester.IsEditable())
1757 if (!bApi)
1758 rDocShell.ErrorMessage(aTester.GetMessageId());
1759 return false;
1762 // Check if this insertion is allowed with respect to pivot table.
1763 if (!canInsertCellsByPivot(aTargetRange, aMark, eCmd, &rDoc))
1765 if (!bApi)
1766 rDocShell.ErrorMessage(STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE);
1767 return false;
1770 WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // wichtig wegen TrackFormulas bei UpdateReference
1772 ScDocument* pRefUndoDoc = nullptr;
1773 ScRefUndoData* pUndoData = nullptr;
1774 if ( bRecord )
1776 pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1777 pRefUndoDoc->InitUndo( &rDoc, 0, nTabCount-1 );
1779 // pRefUndoDoc is filled in InsertCol / InsertRow
1781 pUndoData = new ScRefUndoData( &rDoc );
1783 rDoc.BeginDrawUndo();
1786 // #i8302 : we unmerge overwhelming ranges, before insertion all the actions are put in the same ListAction
1787 // the patch comes from mloiseleur and maoyg
1788 bool bInsertMerge = false;
1789 std::vector<ScRange> qIncreaseRange;
1790 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTCELLS );
1791 if (bRecord)
1792 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
1793 std::unique_ptr<ScUndoRemoveMerge> pUndoRemoveMerge;
1795 itr = aMark.begin();
1796 for (; itr != itrEnd && nTabCount; ++itr)
1798 i = *itr;
1799 if( rDoc.HasAttrib( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1801 if (eCmd==INS_CELLSRIGHT)
1802 bNeedRefresh = true;
1804 SCCOL nMergeStartCol = nMergeTestStartCol;
1805 SCROW nMergeStartRow = nMergeTestStartRow;
1806 SCCOL nMergeEndCol = nMergeTestEndCol;
1807 SCROW nMergeEndRow = nMergeTestEndRow;
1809 rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
1810 rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
1812 if(( eCmd == INS_CELLSDOWN && ( nMergeStartCol != nMergeTestStartCol || nMergeEndCol != nMergeTestEndCol )) ||
1813 (eCmd == INS_CELLSRIGHT && ( nMergeStartRow != nMergeTestStartRow || nMergeEndRow != nMergeTestEndRow )) )
1815 if (!bApi)
1816 rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0);
1817 rDocShell.GetUndoManager()->LeaveListAction();
1818 delete pUndoData;
1819 return false;
1822 SCCOL nTestCol = -1;
1823 SCROW nTestRow1 = -1;
1824 SCROW nTestRow2 = -1;
1826 ScDocAttrIterator aTestIter( &rDoc, i, nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow );
1827 ScRange aExtendRange( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i );
1828 const ScPatternAttr* pPattern = nullptr;
1829 const ScMergeFlagAttr* pMergeFlagAttr = nullptr;
1830 while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != nullptr )
1832 const ScMergeAttr* pMergeFlag = static_cast<const ScMergeAttr*>( &pPattern->GetItem(ATTR_MERGE) );
1833 pMergeFlagAttr = static_cast<const ScMergeFlagAttr*>( &pPattern->GetItem(ATTR_MERGE_FLAG) );
1834 ScMF nNewFlags = pMergeFlagAttr->GetValue() & ( ScMF::Hor | ScMF::Ver );
1835 if( ( pMergeFlag && pMergeFlag->IsMerged() ) || nNewFlags == ScMF::Hor || nNewFlags == ScMF::Ver )
1837 ScRange aRange( nTestCol, nTestRow1, i );
1838 rDoc.ExtendOverlapped(aRange);
1839 rDoc.ExtendMerge(aRange, true);
1841 if( nTestRow1 < nTestRow2 && nNewFlags == ScMF::Hor )
1843 for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ )
1845 ScRange aTestRange( nTestCol, nTestRow, i );
1846 rDoc.ExtendOverlapped( aTestRange );
1847 rDoc.ExtendMerge( aTestRange, true);
1848 ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i );
1849 if( !aExtendRange.In( aMergeRange ) )
1851 qIncreaseRange.push_back( aTestRange );
1852 bInsertMerge = true;
1856 else
1858 ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i );
1859 if( !aExtendRange.In( aMergeRange ) )
1861 qIncreaseRange.push_back( aRange );
1863 bInsertMerge = true;
1868 if( bInsertMerge )
1870 if( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN )
1872 nStartRow = aExtendMergeRange.aStart.Row();
1873 nEndRow = aExtendMergeRange.aEnd.Row();
1875 if( eCmd == INS_CELLSDOWN )
1876 nEndCol = nMergeTestEndCol;
1877 else
1879 nStartCol = 0;
1880 nEndCol = MAXCOL;
1883 else if( eCmd == INS_CELLSRIGHT || eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER )
1886 nStartCol = aExtendMergeRange.aStart.Col();
1887 nEndCol = aExtendMergeRange.aEnd.Col();
1888 if( eCmd == INS_CELLSRIGHT )
1890 nEndRow = nMergeTestEndRow;
1892 else
1894 nStartRow = 0;
1895 nEndRow = MAXROW;
1899 if( !qIncreaseRange.empty() )
1901 if (bRecord && !pUndoRemoveMerge)
1903 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1904 pUndoDoc->InitUndo( &rDoc, *aMark.begin(), *aMark.rbegin());
1905 pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, rRange, pUndoDoc ));
1908 for( ::std::vector<ScRange>::const_iterator iIter( qIncreaseRange.begin()); iIter != qIncreaseRange.end(); ++iIter )
1910 ScRange aRange( *iIter );
1911 if( rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
1913 UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() );
1918 else
1920 if (!bApi)
1921 rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0);
1922 rDocShell.GetUndoManager()->LeaveListAction();
1923 delete pUndoData;
1924 return false;
1929 if (bRecord && pUndoRemoveMerge)
1931 rDocShell.GetUndoManager()->AddUndoAction( pUndoRemoveMerge.release());
1934 switch (eCmd)
1936 case INS_CELLSDOWN:
1937 bSuccess = rDoc.InsertRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark );
1938 nPaintEndRow = MAXROW;
1939 break;
1940 case INS_INSROWS_BEFORE:
1941 case INS_INSROWS_AFTER:
1942 bSuccess = rDoc.InsertRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark );
1943 nPaintStartCol = 0;
1944 nPaintEndCol = MAXCOL;
1945 nPaintEndRow = MAXROW;
1946 nPaintFlags |= PAINT_LEFT;
1947 break;
1948 case INS_CELLSRIGHT:
1949 bSuccess = rDoc.InsertCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark );
1950 nPaintEndCol = MAXCOL;
1951 break;
1952 case INS_INSCOLS_BEFORE:
1953 case INS_INSCOLS_AFTER:
1954 bSuccess = rDoc.InsertCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark );
1955 nPaintStartRow = 0;
1956 nPaintEndRow = MAXROW;
1957 nPaintEndCol = MAXCOL;
1958 nPaintFlags |= PAINT_TOP;
1959 break;
1960 default:
1961 OSL_FAIL("Falscher Code beim Einfuegen");
1962 bSuccess = false;
1963 break;
1966 if ( bSuccess )
1968 SCTAB nUndoPos = 0;
1970 if ( bRecord )
1972 SCTAB* pTabs = new SCTAB[nSelCount];
1973 SCTAB* pScenarios = new SCTAB[nSelCount];
1974 nUndoPos = 0;
1975 itr = aMark.begin();
1976 for (; itr != itrEnd && *itr < nTabCount; ++itr)
1978 SCTAB nCount = 0;
1979 for( SCTAB j=*itr+1; j<nTabCount && rDoc.IsScenario(j); j++ )
1980 nCount ++;
1982 pScenarios[nUndoPos] = nCount;
1983 pTabs[nUndoPos] = *itr;
1984 nUndoPos ++;
1987 if( !bInsertMerge )
1989 rDocShell.GetUndoManager()->LeaveListAction();
1992 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoInsertCells(
1993 &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ),
1994 nUndoPos, pTabs, pScenarios, eCmd, pRefUndoDoc, pUndoData, bPartOfPaste ) );
1997 // #i8302 : we remerge growing ranges, with the new part inserted
1999 while( !qIncreaseRange.empty() )
2001 ScRange aRange = qIncreaseRange.back();
2002 if( !rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
2004 switch (eCmd)
2006 case INS_CELLSDOWN:
2007 case INS_INSROWS_BEFORE:
2008 case INS_INSROWS_AFTER:
2009 aRange.aEnd.IncRow(static_cast<SCsCOL>(nEndRow-nStartRow+1));
2010 break;
2011 case INS_CELLSRIGHT:
2012 case INS_INSCOLS_BEFORE:
2013 case INS_INSCOLS_AFTER:
2014 aRange.aEnd.IncCol(static_cast<SCsCOL>(nEndCol-nStartCol+1));
2015 break;
2016 default:
2017 break;
2019 ScCellMergeOption aMergeOption(
2020 aRange.aStart.Col(), aRange.aStart.Row(),
2021 aRange.aEnd.Col(), aRange.aEnd.Row() );
2022 aMergeOption.maTabs.insert(aRange.aStart.Tab());
2023 MergeCells(aMergeOption, false, true, true);
2025 qIncreaseRange.pop_back();
2028 if( bInsertMerge )
2029 rDocShell.GetUndoManager()->LeaveListAction();
2031 itr = aMark.begin();
2032 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2034 i = *itr;
2035 rDoc.SetDrawPageSize(i);
2037 if (bNeedRefresh)
2038 rDoc.ExtendMerge( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i, true );
2039 else
2040 rDoc.RefreshAutoFilter( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i );
2042 if ( eCmd == INS_INSROWS_BEFORE ||eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSROWS_AFTER ||eCmd == INS_INSCOLS_AFTER )
2043 rDoc.UpdatePageBreaks( i );
2045 sal_uInt16 nExtFlags = 0;
2046 rDocShell.UpdatePaintExt( nExtFlags, nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i );
2048 SCTAB nScenarioCount = 0;
2050 for( SCTAB j = i+1; j<nTabCount && rDoc.IsScenario(j); j++ )
2051 nScenarioCount ++;
2053 bool bAdjusted = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER ) ?
2054 AdjustRowHeight(ScRange(0, nStartRow, i, MAXCOL, nEndRow, i+nScenarioCount )) :
2055 AdjustRowHeight(ScRange(0, nPaintStartRow, i, MAXCOL, nPaintEndRow, i+nScenarioCount ));
2056 if (bAdjusted)
2058 // paint only what is not done by AdjustRowHeight
2059 if (nPaintFlags & PAINT_TOP)
2060 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i+nScenarioCount, PAINT_TOP );
2062 else
2063 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i+nScenarioCount, nPaintFlags, nExtFlags );
2066 else
2068 if( bInsertMerge )
2070 while( !qIncreaseRange.empty() )
2072 ScRange aRange = qIncreaseRange.back();
2073 ScCellMergeOption aMergeOption(
2074 aRange.aStart.Col(), aRange.aStart.Row(),
2075 aRange.aEnd.Col(), aRange.aEnd.Row() );
2076 MergeCells(aMergeOption, false, true, true);
2077 qIncreaseRange.pop_back();
2080 if( pViewSh )
2082 pViewSh->MarkRange( aTargetRange, false );
2083 pViewSh->SetCursor( nCursorCol, nCursorRow );
2087 rDocShell.GetUndoManager()->LeaveListAction();
2088 rDocShell.GetUndoManager()->RemoveLastUndoAction();
2090 delete pRefUndoDoc;
2091 delete pUndoData;
2092 if (!bApi)
2093 rDocShell.ErrorMessage(STR_INSERT_FULL); // Spalte/Zeile voll
2096 aModificator.SetDocumentModified();
2098 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
2099 return bSuccess;
2102 bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, DelCellCmd eCmd,
2103 bool bApi )
2105 ScDocShellModificator aModificator( rDocShell );
2107 if (rDocShell.GetDocument().GetChangeTrack() &&
2108 ((eCmd == DEL_CELLSUP && (rRange.aStart.Col() != 0 || rRange.aEnd.Col() != MAXCOL)) ||
2109 (eCmd == DEL_CELLSLEFT && (rRange.aStart.Row() != 0 || rRange.aEnd.Row() != MAXROW))))
2111 // We should not reach this via UI disabled slots.
2112 assert(bApi);
2113 SAL_WARN("sc.ui","ScDocFunc::DeleteCells - no change-tracking of partial cell shift");
2114 return false;
2117 SCCOL nStartCol = rRange.aStart.Col();
2118 SCROW nStartRow = rRange.aStart.Row();
2119 SCTAB nStartTab = rRange.aStart.Tab();
2120 SCCOL nEndCol = rRange.aEnd.Col();
2121 SCROW nEndRow = rRange.aEnd.Row();
2122 SCTAB nEndTab = rRange.aEnd.Tab();
2124 if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) )
2126 OSL_FAIL("invalid row in DeleteCells");
2127 return false;
2130 ScDocument& rDoc = rDocShell.GetDocument();
2131 SCTAB nTabCount = rDoc.GetTableCount();
2132 SCCOL nPaintStartCol = nStartCol;
2133 SCROW nPaintStartRow = nStartRow;
2134 SCCOL nPaintEndCol = nEndCol;
2135 SCROW nPaintEndRow = nEndRow;
2136 sal_uInt16 nPaintFlags = PAINT_GRID;
2138 bool bRecord = true;
2139 if (bRecord && !rDoc.IsUndoEnabled())
2140 bRecord = false;
2142 ScMarkData aMark;
2143 if (pTabMark)
2144 aMark = *pTabMark;
2145 else
2147 SCTAB nCount = 0;
2148 for(SCTAB i=0; i<nTabCount; i++ )
2150 if( !rDoc.IsScenario(i) )
2152 nCount++;
2153 if( nCount == nEndTab+1 )
2155 aMark.SelectTable(i, true);
2156 break;
2162 ScMarkData aFullMark( aMark ); // including scenario sheets
2163 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
2164 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2165 for( SCTAB j = *itr+1; j<nTabCount && rDoc.IsScenario(j); j++ )
2166 aFullMark.SelectTable( j, true );
2168 SCTAB nSelCount = aMark.GetSelectCount();
2170 SCCOL nUndoStartCol = nStartCol;
2171 SCROW nUndoStartRow = nStartRow;
2172 SCCOL nUndoEndCol = nEndCol;
2173 SCROW nUndoEndRow = nEndRow;
2175 ScRange aExtendMergeRange( rRange );
2177 if( rRange.aStart == rRange.aEnd && rDoc.HasAttrib(rRange, HASATTR_MERGED) )
2179 rDoc.ExtendMerge( aExtendMergeRange );
2180 rDoc.ExtendOverlapped( aExtendMergeRange );
2181 nUndoEndCol = aExtendMergeRange.aEnd.Col();
2182 nUndoEndRow = aExtendMergeRange.aEnd.Row();
2183 nPaintEndCol = nUndoEndCol;
2184 nPaintEndRow = nUndoEndRow;
2187 if (eCmd==DEL_DELROWS)
2189 nUndoStartCol = 0;
2190 nUndoEndCol = MAXCOL;
2192 if (eCmd==DEL_DELCOLS)
2194 nUndoStartRow = 0;
2195 nUndoEndRow = MAXROW;
2197 // Test Zellschutz
2199 SCCOL nEditTestEndX = nUndoEndCol;
2200 if ( eCmd==DEL_DELCOLS || eCmd==DEL_CELLSLEFT )
2201 nEditTestEndX = MAXCOL;
2202 SCROW nEditTestEndY = nUndoEndRow;
2203 if ( eCmd==DEL_DELROWS || eCmd==DEL_CELLSUP )
2204 nEditTestEndY = MAXROW;
2205 ScEditableTester aTester( &rDoc, nUndoStartCol, nUndoStartRow, nEditTestEndX, nEditTestEndY, aMark );
2206 if (!aTester.IsEditable())
2208 if (!bApi)
2209 rDocShell.ErrorMessage(aTester.GetMessageId());
2210 return false;
2213 if (!canDeleteCellsByPivot(rRange, aMark, eCmd, &rDoc))
2215 if (!bApi)
2216 rDocShell.ErrorMessage(STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE);
2217 return false;
2219 // Test zusammengefasste
2221 SCCOL nMergeTestEndCol = (eCmd==DEL_CELLSLEFT) ? MAXCOL : nUndoEndCol;
2222 SCROW nMergeTestEndRow = (eCmd==DEL_CELLSUP) ? MAXROW : nUndoEndRow;
2223 SCCOL nExtendStartCol = nUndoStartCol;
2224 SCROW nExtendStartRow = nUndoStartRow;
2225 bool bNeedRefresh = false;
2227 //Issue 8302 want to be able to insert into the middle of merged cells
2228 //the patch comes from maoyg
2229 ::std::vector<ScRange> qDecreaseRange;
2230 bool bDeletingMerge = false;
2231 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_DELETECELLS );
2232 if (bRecord)
2233 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
2234 std::unique_ptr<ScUndoRemoveMerge> pUndoRemoveMerge;
2236 itr = aMark.begin();
2237 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2239 SCTAB i = *itr;
2240 if ( rDoc.HasAttrib( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HASATTR_MERGED | HASATTR_OVERLAPPED ))
2242 SCCOL nMergeStartCol = nUndoStartCol;
2243 SCROW nMergeStartRow = nUndoStartRow;
2244 SCCOL nMergeEndCol = nMergeTestEndCol;
2245 SCROW nMergeEndRow = nMergeTestEndRow;
2247 rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
2248 rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
2249 if( ( eCmd == DEL_CELLSUP && ( nMergeStartCol != nUndoStartCol || nMergeEndCol != nMergeTestEndCol))||
2250 ( eCmd == DEL_CELLSLEFT && ( nMergeStartRow != nUndoStartRow || nMergeEndRow != nMergeTestEndRow)))
2252 if (!bApi)
2253 rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0);
2254 rDocShell.GetUndoManager()->LeaveListAction();
2255 return false;
2258 nExtendStartCol = nMergeStartCol;
2259 nExtendStartRow = nMergeStartRow;
2260 SCCOL nTestCol = -1;
2261 SCROW nTestRow1 = -1;
2262 SCROW nTestRow2 = -1;
2264 ScDocAttrIterator aTestIter( &rDoc, i, nUndoStartCol, nUndoStartRow, nMergeTestEndCol, nMergeTestEndRow );
2265 ScRange aExtendRange( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i );
2266 const ScPatternAttr* pPattern = nullptr;
2267 const ScMergeFlagAttr* pMergeFlagAttr = nullptr;
2268 while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != nullptr )
2270 const ScMergeAttr* pMergeFlag = static_cast<const ScMergeAttr*>( &pPattern->GetItem( ATTR_MERGE ) );
2271 pMergeFlagAttr = static_cast<const ScMergeFlagAttr*>( &pPattern->GetItem( ATTR_MERGE_FLAG ) );
2272 ScMF nNewFlags = pMergeFlagAttr->GetValue() & ( ScMF::Hor | ScMF::Ver );
2273 if( ( pMergeFlag && pMergeFlag->IsMerged() ) || nNewFlags == ScMF::Hor || nNewFlags == ScMF::Ver )
2275 ScRange aRange( nTestCol, nTestRow1, i );
2276 rDoc.ExtendOverlapped( aRange );
2277 rDoc.ExtendMerge( aRange, true );
2279 if( nTestRow1 < nTestRow2 && nNewFlags == ScMF::Hor )
2281 for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ )
2283 ScRange aTestRange( nTestCol, nTestRow, i );
2284 rDoc.ExtendOverlapped( aTestRange );
2285 rDoc.ExtendMerge( aTestRange, true );
2286 ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i );
2287 if( !aExtendRange.In( aMergeRange ) )
2289 qDecreaseRange.push_back( aTestRange );
2290 bDeletingMerge = true;
2294 else
2296 ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i );
2297 if( !aExtendRange.In( aMergeRange ) )
2299 qDecreaseRange.push_back( aRange );
2301 bDeletingMerge = true;
2306 if( bDeletingMerge )
2309 if( eCmd == DEL_DELROWS || eCmd == DEL_CELLSUP )
2311 nStartRow = aExtendMergeRange.aStart.Row();
2312 nEndRow = aExtendMergeRange.aEnd.Row();
2313 bNeedRefresh = true;
2315 if( eCmd == DEL_CELLSUP )
2317 nEndCol = aExtendMergeRange.aEnd.Col();
2319 else
2321 nStartCol = 0;
2322 nEndCol = MAXCOL;
2325 else if( eCmd == DEL_CELLSLEFT || eCmd == DEL_DELCOLS )
2328 nStartCol = aExtendMergeRange.aStart.Col();
2329 nEndCol = aExtendMergeRange.aEnd.Col();
2330 if( eCmd == DEL_CELLSLEFT )
2332 nEndRow = aExtendMergeRange.aEnd.Row();
2333 bNeedRefresh = true;
2335 else
2337 nStartRow = 0;
2338 nEndRow = MAXROW;
2342 if( !qDecreaseRange.empty() )
2344 if (bRecord && !pUndoRemoveMerge)
2346 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2347 pUndoDoc->InitUndo( &rDoc, *aMark.begin(), *aMark.rbegin());
2348 pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, rRange, pUndoDoc ));
2351 for( ::std::vector<ScRange>::const_iterator iIter( qDecreaseRange.begin()); iIter != qDecreaseRange.end(); ++iIter )
2353 ScRange aRange( *iIter );
2354 if( rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
2356 UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() );
2361 else
2363 if (!bApi)
2364 rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0);
2365 rDocShell.GetUndoManager()->LeaveListAction();
2366 return false;
2371 if (bRecord && pUndoRemoveMerge)
2373 rDocShell.GetUndoManager()->AddUndoAction( pUndoRemoveMerge.release());
2376 // ausfuehren
2378 WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // wichtig wegen TrackFormulas bei UpdateReference
2380 ScDocument* pUndoDoc = nullptr;
2381 ScDocument* pRefUndoDoc = nullptr;
2382 ScRefUndoData* pUndoData = nullptr;
2383 if ( bRecord )
2385 // With the fix for #101329#, UpdateRef always puts cells into pRefUndoDoc at their old position,
2386 // so it's no longer necessary to copy more than the deleted range into pUndoDoc.
2388 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2389 pUndoDoc->InitUndo( &rDoc, 0, nTabCount-1, (eCmd==DEL_DELCOLS), (eCmd==DEL_DELROWS) );
2390 itr = aMark.begin();
2391 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2393 SCTAB nScenarioCount = 0;
2395 for( SCTAB j = *itr+1; j<nTabCount && rDoc.IsScenario(j); j++ )
2396 nScenarioCount ++;
2398 rDoc.CopyToDocument( nUndoStartCol, nUndoStartRow, *itr, nUndoEndCol, nUndoEndRow, *itr+nScenarioCount,
2399 InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, pUndoDoc );
2402 pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2403 pRefUndoDoc->InitUndo( &rDoc, 0, nTabCount-1 );
2405 pUndoData = new ScRefUndoData( &rDoc );
2407 rDoc.BeginDrawUndo();
2410 sal_uInt16 nExtFlags = 0;
2411 itr = aMark.begin();
2412 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2414 rDocShell.UpdatePaintExt( nExtFlags, nStartCol, nStartRow, *itr, nEndCol, nEndRow, *itr );
2417 bool bUndoOutline = false;
2418 switch (eCmd)
2420 case DEL_CELLSUP:
2421 rDoc.DeleteRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, nullptr, &aFullMark );
2422 nPaintEndRow = MAXROW;
2423 break;
2424 case DEL_DELROWS:
2425 rDoc.DeleteRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &bUndoOutline, &aFullMark );
2426 nPaintStartCol = 0;
2427 nPaintEndCol = MAXCOL;
2428 nPaintEndRow = MAXROW;
2429 nPaintFlags |= PAINT_LEFT;
2430 break;
2431 case DEL_CELLSLEFT:
2432 rDoc.DeleteCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, nullptr, &aFullMark );
2433 nPaintEndCol = MAXCOL;
2434 break;
2435 case DEL_DELCOLS:
2436 rDoc.DeleteCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &bUndoOutline, &aFullMark );
2437 nPaintStartRow = 0;
2438 nPaintEndRow = MAXROW;
2439 nPaintEndCol = MAXCOL;
2440 nPaintFlags |= PAINT_TOP;
2441 break;
2442 default:
2443 OSL_FAIL("Falscher Code beim Loeschen");
2444 break;
2447 //! Test, ob Outline in Groesse geaendert
2449 if ( bRecord )
2451 itr = aFullMark.begin();
2452 itrEnd = aFullMark.end();
2453 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2454 pRefUndoDoc->DeleteAreaTab(nUndoStartCol,nUndoStartRow,nUndoEndCol,nUndoEndRow, *itr, InsertDeleteFlags::ALL);
2456 // alle Tabellen anlegen, damit Formeln kopiert werden koennen:
2457 pUndoDoc->AddUndoTab( 0, nTabCount-1 );
2459 // kopieren mit bColRowFlags=false (#54194#)
2460 pRefUndoDoc->CopyToDocument(0,0,0,MAXCOL,MAXROW,MAXTAB,InsertDeleteFlags::FORMULA,false,pUndoDoc,nullptr,false);
2461 delete pRefUndoDoc;
2463 SCTAB* pTabs = new SCTAB[nSelCount];
2464 SCTAB* pScenarios = new SCTAB[nSelCount];
2465 SCTAB nUndoPos = 0;
2467 itr = aMark.begin();
2468 itrEnd = aMark.end();
2469 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2471 SCTAB nCount = 0;
2472 for( SCTAB j=*itr+1; j<nTabCount && rDoc.IsScenario(j); j++ )
2473 nCount ++;
2475 pScenarios[nUndoPos] = nCount;
2476 pTabs[nUndoPos] = *itr;
2477 nUndoPos ++;
2480 if( !bDeletingMerge )
2482 rDocShell.GetUndoManager()->LeaveListAction();
2485 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDeleteCells(
2486 &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ),nUndoPos, pTabs, pScenarios,
2487 eCmd, pUndoDoc, pUndoData ) );
2490 // #i8302 want to be able to insert into the middle of merged cells
2491 // the patch comes from maoyg
2493 while( !qDecreaseRange.empty() )
2495 ScRange aRange = qDecreaseRange.back();
2497 long nDecreaseRowCount = 0;
2498 long nDecreaseColCount = 0;
2499 if( eCmd == DEL_CELLSUP || eCmd == DEL_DELROWS )
2501 if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() )
2502 nDecreaseRowCount = nEndRow-nStartRow+1;
2503 else if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow >= aRange.aStart.Row() && nEndRow >= aRange.aEnd.Row() )
2504 nDecreaseRowCount = aRange.aEnd.Row()-nStartRow+1;
2505 else if( nStartRow >= aRange.aStart.Row() && nStartRow >= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() )
2506 nDecreaseRowCount = aRange.aEnd.Row()-nEndRow+1;
2508 else if( eCmd == DEL_CELLSLEFT || eCmd == DEL_DELCOLS )
2510 if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() )
2511 nDecreaseColCount = nEndCol-nStartCol+1;
2512 else if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol >= aRange.aStart.Col() && nEndCol >= aRange.aEnd.Col() )
2513 nDecreaseColCount = aRange.aEnd.Col()-nStartCol+1;
2514 else if( nStartCol >= aRange.aStart.Col() && nStartCol >= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() )
2515 nDecreaseColCount = aRange.aEnd.Col()-nEndCol+1;
2518 switch (eCmd)
2520 case DEL_CELLSUP:
2521 case DEL_DELROWS:
2522 aRange.aEnd.SetRow(static_cast<SCsCOL>( aRange.aEnd.Row()-nDecreaseRowCount));
2523 break;
2524 case DEL_CELLSLEFT:
2525 case DEL_DELCOLS:
2526 aRange.aEnd.SetCol(static_cast<SCsCOL>( aRange.aEnd.Col()-nDecreaseColCount));
2527 break;
2528 default:
2529 break;
2532 if( !rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
2534 ScCellMergeOption aMergeOption(aRange);
2535 MergeCells( aMergeOption, false, true, true );
2537 qDecreaseRange.pop_back();
2540 if( bDeletingMerge )
2541 rDocShell.GetUndoManager()->LeaveListAction();
2543 if ( bNeedRefresh )
2545 // #i51445# old merge flag attributes must be deleted also for single cells,
2546 // not only for whole columns/rows
2548 if ( eCmd==DEL_DELCOLS || eCmd==DEL_CELLSLEFT )
2549 nMergeTestEndCol = MAXCOL;
2550 if ( eCmd==DEL_DELROWS || eCmd==DEL_CELLSUP )
2551 nMergeTestEndRow = MAXROW;
2552 ScPatternAttr aPattern( rDoc.GetPool() );
2553 aPattern.GetItemSet().Put( ScMergeFlagAttr() );
2555 rDoc.ApplyPatternArea( nExtendStartCol, nExtendStartRow, nMergeTestEndCol, nMergeTestEndRow, aMark, aPattern );
2557 itr = aMark.begin();
2558 itrEnd = aMark.end();
2559 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2561 SCTAB nScenarioCount = 0;
2563 for( SCTAB j = *itr+1; j<nTabCount && rDoc.IsScenario(j); j++ )
2564 nScenarioCount ++;
2566 ScRange aMergedRange( nExtendStartCol, nExtendStartRow, *itr, nMergeTestEndCol, nMergeTestEndRow, *itr+nScenarioCount );
2567 rDoc.ExtendMerge( aMergedRange, true );
2571 itr = aMark.begin();
2572 itrEnd = aMark.end();
2573 for (; itr != itrEnd && *itr < nTabCount; ++itr)
2575 rDoc.SetDrawPageSize(*itr);
2577 if ( eCmd == DEL_DELCOLS || eCmd == DEL_DELROWS )
2578 rDoc.UpdatePageBreaks( *itr );
2580 rDocShell.UpdatePaintExt( nExtFlags, nPaintStartCol, nPaintStartRow, *itr, nPaintEndCol, nPaintEndRow, *itr );
2582 SCTAB nScenarioCount = 0;
2584 for( SCTAB j = *itr+1; j<nTabCount && rDoc.IsScenario(j); j++ )
2585 nScenarioCount ++;
2587 // ganze Zeilen loeschen: nichts anpassen
2588 if ( eCmd == DEL_DELROWS || !AdjustRowHeight(ScRange( 0, nPaintStartRow, *itr, MAXCOL, nPaintEndRow, *itr+nScenarioCount )) )
2589 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, *itr, nPaintEndCol, nPaintEndRow, *itr+nScenarioCount, nPaintFlags, nExtFlags );
2590 else
2592 // paint only what is not done by AdjustRowHeight
2593 if (nExtFlags & SC_PF_LINES)
2594 lcl_PaintAbove( rDocShell, ScRange( nPaintStartCol, nPaintStartRow, *itr, nPaintEndCol, nPaintEndRow, *itr+nScenarioCount) );
2595 if (nPaintFlags & PAINT_TOP)
2596 rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, *itr, nPaintEndCol, nPaintEndRow, *itr+nScenarioCount, PAINT_TOP );
2600 aModificator.SetDocumentModified();
2602 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
2604 return true;
2607 bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos,
2608 bool bCut, bool bRecord, bool bPaint, bool bApi )
2610 ScDocShellModificator aModificator( rDocShell );
2612 SCCOL nStartCol = rSource.aStart.Col();
2613 SCROW nStartRow = rSource.aStart.Row();
2614 SCTAB nStartTab = rSource.aStart.Tab();
2615 SCCOL nEndCol = rSource.aEnd.Col();
2616 SCROW nEndRow = rSource.aEnd.Row();
2617 SCTAB nEndTab = rSource.aEnd.Tab();
2618 SCCOL nDestCol = rDestPos.Col();
2619 SCROW nDestRow = rDestPos.Row();
2620 SCTAB nDestTab = rDestPos.Tab();
2622 if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) || !ValidRow(nDestRow) )
2624 OSL_FAIL("invalid row in MoveBlock");
2625 return false;
2628 // zugehoerige Szenarien auch anpassen - nur wenn innerhalb einer Tabelle verschoben wird!
2629 bool bScenariosAdded = false;
2630 ScDocument& rDoc = rDocShell.GetDocument();
2631 if (bRecord && !rDoc.IsUndoEnabled())
2632 bRecord = false;
2634 SCTAB nTabCount = rDoc.GetTableCount();
2635 if ( nDestTab == nStartTab && !rDoc.IsScenario(nEndTab) )
2636 while ( nEndTab+1 < nTabCount && rDoc.IsScenario(nEndTab+1) )
2638 ++nEndTab;
2639 bScenariosAdded = true;
2642 SCTAB nSrcTabCount = nEndTab-nStartTab+1;
2643 SCTAB nDestEndTab = nDestTab+nSrcTabCount-1;
2644 SCTAB nTab;
2646 ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
2648 ScMarkData aSourceMark;
2649 for (nTab=nStartTab; nTab<=nEndTab; nTab++)
2650 aSourceMark.SelectTable( nTab, true ); // Source selektieren
2651 aSourceMark.SetMarkArea( rSource );
2653 ScDocShellRef aDragShellRef;
2654 if ( rDoc.HasOLEObjectsInArea( rSource ) )
2656 aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
2657 aDragShellRef->DoInitNew();
2659 ScDrawLayer::SetGlobalDrawPersist(aDragShellRef);
2661 ScClipParam aClipParam(ScRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nStartTab), bCut);
2662 rDoc.CopyToClip(aClipParam, pClipDoc, &aSourceMark, bScenariosAdded, true);
2664 ScDrawLayer::SetGlobalDrawPersist(nullptr);
2666 SCCOL nOldEndCol = nEndCol;
2667 SCROW nOldEndRow = nEndRow;
2668 bool bClipOver = false;
2669 for (nTab=nStartTab; nTab<=nEndTab; nTab++)
2671 SCCOL nTmpEndCol = nOldEndCol;
2672 SCROW nTmpEndRow = nOldEndRow;
2673 if (rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab ))
2674 bClipOver = true;
2675 if ( nTmpEndCol > nEndCol ) nEndCol = nTmpEndCol;
2676 if ( nTmpEndRow > nEndRow ) nEndRow = nTmpEndRow;
2679 SCCOL nDestEndCol = nDestCol + ( nOldEndCol-nStartCol );
2680 SCROW nDestEndRow = nDestRow + ( nOldEndRow-nStartRow );
2682 SCCOL nUndoEndCol = nDestCol + ( nEndCol-nStartCol ); // erweitert im Zielblock
2683 SCROW nUndoEndRow = nDestRow + ( nEndRow-nStartRow );
2685 bool bIncludeFiltered = bCut;
2686 if ( !bIncludeFiltered )
2688 // adjust sizes to include only non-filtered rows
2690 SCCOL nClipX;
2691 SCROW nClipY;
2692 pClipDoc->GetClipArea( nClipX, nClipY, false );
2693 SCROW nUndoAdd = nUndoEndRow - nDestEndRow;
2694 nDestEndRow = nDestRow + nClipY;
2695 nUndoEndRow = nDestEndRow + nUndoAdd;
2698 if (!ValidCol(nUndoEndCol) || !ValidRow(nUndoEndRow))
2700 if (!bApi)
2701 rDocShell.ErrorMessage(STR_PASTE_FULL);
2702 delete pClipDoc;
2703 return false;
2706 // Test auf Zellschutz
2708 ScEditableTester aTester;
2709 for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
2710 aTester.TestBlock( &rDoc, nTab, nDestCol,nDestRow, nUndoEndCol,nUndoEndRow );
2711 if (bCut)
2712 for (nTab=nStartTab; nTab<=nEndTab; nTab++)
2713 aTester.TestBlock( &rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow );
2715 if (!aTester.IsEditable())
2717 if (!bApi)
2718 rDocShell.ErrorMessage(aTester.GetMessageId());
2719 delete pClipDoc;
2720 return false;
2723 // Test auf zusammengefasste - beim Verschieben erst nach dem Loeschen
2725 if (bClipOver && !bCut)
2726 if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab, nUndoEndCol,nUndoEndRow,nDestEndTab,
2727 HASATTR_MERGED | HASATTR_OVERLAPPED ))
2728 { // "Zusammenfassen nicht verschachteln !"
2729 if (!bApi)
2730 rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0);
2731 delete pClipDoc;
2732 return false;
2735 // Are there borders in the cells? (for painting)
2737 sal_uInt16 nSourceExt = 0;
2738 rDocShell.UpdatePaintExt( nSourceExt, nStartCol,nStartRow,nStartTab, nEndCol,nEndRow,nEndTab );
2739 sal_uInt16 nDestExt = 0;
2740 rDocShell.UpdatePaintExt( nDestExt, nDestCol,nDestRow,nDestTab, nDestEndCol,nDestEndRow,nDestEndTab );
2742 // ausfuehren
2744 ScDocument* pUndoDoc = nullptr;
2746 if (bRecord)
2748 bool bWholeCols = ( nStartRow == 0 && nEndRow == MAXROW );
2749 bool bWholeRows = ( nStartCol == 0 && nEndCol == MAXCOL );
2750 InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
2752 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2753 pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab, bWholeCols, bWholeRows );
2755 if (bCut)
2757 rDoc.CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
2758 nUndoFlags, false, pUndoDoc );
2761 if ( nDestTab != nStartTab )
2762 pUndoDoc->AddUndoTab( nDestTab, nDestEndTab, bWholeCols, bWholeRows );
2763 rDoc.CopyToDocument( nDestCol, nDestRow, nDestTab,
2764 nDestEndCol, nDestEndRow, nDestEndTab,
2765 nUndoFlags, false, pUndoDoc );
2766 rDoc.BeginDrawUndo();
2769 bool bSourceHeight = false; // Hoehen angepasst?
2770 if (bCut)
2772 ScMarkData aDelMark; // only for tables
2773 for (nTab=nStartTab; nTab<=nEndTab; nTab++)
2775 rDoc.DeleteAreaTab( nStartCol,nStartRow, nOldEndCol,nOldEndRow, nTab, InsertDeleteFlags::ALL );
2776 aDelMark.SelectTable( nTab, true );
2778 rDoc.DeleteObjectsInArea( nStartCol,nStartRow, nOldEndCol,nOldEndRow, aDelMark );
2780 // Test auf zusammengefasste
2782 if (bClipOver)
2783 if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab,
2784 nUndoEndCol,nUndoEndRow,nDestEndTab,
2785 HASATTR_MERGED | HASATTR_OVERLAPPED ))
2787 rDoc.CopyFromClip( rSource, aSourceMark, InsertDeleteFlags::ALL, nullptr, pClipDoc );
2788 for (nTab=nStartTab; nTab<=nEndTab; nTab++)
2790 SCCOL nTmpEndCol = nEndCol;
2791 SCROW nTmpEndRow = nEndRow;
2792 rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab, true );
2795 // Fehlermeldung erst nach dem Wiederherstellen des Inhalts
2796 if (!bApi) // "Zusammenfassen nicht verschachteln !"
2797 rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0);
2799 delete pUndoDoc;
2800 delete pClipDoc;
2801 return false;
2804 bSourceHeight = AdjustRowHeight( rSource, false );
2807 ScRange aPasteDest( nDestCol, nDestRow, nDestTab, nDestEndCol, nDestEndRow, nDestEndTab );
2809 ScMarkData aDestMark;
2810 for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
2811 aDestMark.SelectTable( nTab, true ); // Destination selektieren
2812 aDestMark.SetMarkArea( aPasteDest );
2814 /* Do not drawing objects here. While pasting, the
2815 function ScDocument::UpdateReference() is called which calls
2816 ScDrawLayer::MoveCells() which may move away inserted objects to wrong
2817 positions (e.g. if source and destination range overlaps).*/
2818 rDoc.CopyFromClip( aPasteDest, aDestMark, InsertDeleteFlags::ALL & ~(InsertDeleteFlags::OBJECTS),
2819 nullptr, pClipDoc, true, false, bIncludeFiltered );
2821 // skipped rows and merged cells don't mix
2822 if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
2823 UnmergeCells( aPasteDest, false, nullptr );
2825 bool bDestHeight = AdjustRowHeight(
2826 ScRange( 0,nDestRow,nDestTab, MAXCOL,nDestEndRow,nDestEndTab ),
2827 false );
2829 /* Paste drawing objects after adjusting formula references
2830 and row heights. There are no cell notes or drawing objects, if the
2831 clipdoc does not contain a drawing layer.*/
2832 if ( pClipDoc->GetDrawLayer() )
2833 rDoc.CopyFromClip( aPasteDest, aDestMark, InsertDeleteFlags::OBJECTS,
2834 nullptr, pClipDoc, true, false, bIncludeFiltered );
2836 if (bRecord)
2838 rDocShell.GetUndoManager()->AddUndoAction(
2839 new ScUndoDragDrop( &rDocShell, ScRange(
2840 nStartCol, nStartRow, nStartTab,
2841 nOldEndCol, nOldEndRow, nEndTab ),
2842 ScAddress( nDestCol, nDestRow, nDestTab ),
2843 bCut, pUndoDoc, nullptr, bScenariosAdded ) );
2846 SCCOL nDestPaintEndCol = nDestEndCol;
2847 SCROW nDestPaintEndRow = nDestEndRow;
2848 for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
2850 SCCOL nTmpEndCol = nDestEndCol;
2851 SCROW nTmpEndRow = nDestEndRow;
2852 rDoc.ExtendMerge( nDestCol, nDestRow, nTmpEndCol, nTmpEndRow, nTab, true );
2853 if (nTmpEndCol > nDestPaintEndCol) nDestPaintEndCol = nTmpEndCol;
2854 if (nTmpEndRow > nDestPaintEndRow) nDestPaintEndRow = nTmpEndRow;
2857 if (bCut)
2858 for (nTab=nStartTab; nTab<=nEndTab; nTab++)
2859 rDoc.RefreshAutoFilter( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
2861 if (bPaint)
2863 // Zielbereich:
2865 SCCOL nPaintStartX = nDestCol;
2866 SCROW nPaintStartY = nDestRow;
2867 SCCOL nPaintEndX = nDestPaintEndCol;
2868 SCROW nPaintEndY = nDestPaintEndRow;
2869 sal_uInt16 nFlags = PAINT_GRID;
2871 if ( nStartRow==0 && nEndRow==MAXROW ) // Breiten mitkopiert?
2873 nPaintEndX = MAXCOL;
2874 nPaintStartY = 0;
2875 nPaintEndY = MAXROW;
2876 nFlags |= PAINT_TOP;
2878 if ( bDestHeight || ( nStartCol == 0 && nEndCol == MAXCOL ) )
2880 nPaintEndY = MAXROW;
2881 nPaintStartX = 0;
2882 nPaintEndX = MAXCOL;
2883 nFlags |= PAINT_LEFT;
2885 if ( bScenariosAdded )
2887 nPaintStartX = 0;
2888 nPaintStartY = 0;
2889 nPaintEndX = MAXCOL;
2890 nPaintEndY = MAXROW;
2893 rDocShell.PostPaint( nPaintStartX,nPaintStartY,nDestTab,
2894 nPaintEndX,nPaintEndY,nDestEndTab, nFlags, nSourceExt | nDestExt );
2896 if ( bCut )
2898 // Quellbereich:
2900 nPaintStartX = nStartCol;
2901 nPaintStartY = nStartRow;
2902 nPaintEndX = nEndCol;
2903 nPaintEndY = nEndRow;
2904 nFlags = PAINT_GRID;
2906 if ( bSourceHeight )
2908 nPaintEndY = MAXROW;
2909 nPaintStartX = 0;
2910 nPaintEndX = MAXCOL;
2911 nFlags |= PAINT_LEFT;
2913 if ( bScenariosAdded )
2915 nPaintStartX = 0;
2916 nPaintStartY = 0;
2917 nPaintEndX = MAXCOL;
2918 nPaintEndY = MAXROW;
2921 rDocShell.PostPaint( nPaintStartX,nPaintStartY,nStartTab,
2922 nPaintEndX,nPaintEndY,nEndTab, nFlags, nSourceExt );
2926 aModificator.SetDocumentModified();
2928 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
2930 delete pClipDoc;
2931 return true;
2934 uno::Reference< uno::XInterface > GetDocModuleObject( SfxObjectShell& rDocSh, OUString& sCodeName )
2936 uno::Reference< lang::XMultiServiceFactory> xSF(rDocSh.GetModel(), uno::UNO_QUERY);
2937 uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess;
2938 uno::Reference< uno::XInterface > xDocModuleApiObject;
2939 if ( xSF.is() )
2941 xVBACodeNamedObjectAccess.set( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY );
2942 xDocModuleApiObject.set( xVBACodeNamedObjectAccess->getByName( sCodeName ), uno::UNO_QUERY );
2944 return xDocModuleApiObject;
2948 static script::ModuleInfo lcl_InitModuleInfo( SfxObjectShell& rDocSh, OUString& sModule )
2950 script::ModuleInfo sModuleInfo;
2951 sModuleInfo.ModuleType = script::ModuleType::DOCUMENT;
2952 sModuleInfo.ModuleObject = GetDocModuleObject( rDocSh, sModule );
2953 return sModuleInfo;
2956 void VBA_InsertModule( ScDocument& rDoc, SCTAB nTab, const OUString& sModuleName, const OUString& sSource )
2958 SfxObjectShell& rDocSh = *rDoc.GetDocumentShell();
2959 uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer();
2960 OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" );
2962 uno::Reference< container::XNameContainer > xLib;
2963 if( xLibContainer.is() )
2965 OUString aLibName( "Standard" );
2966 if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() )
2968 aLibName = rDocSh.GetBasicManager()->GetName();
2970 uno::Any aLibAny = xLibContainer->getByName( aLibName );
2971 aLibAny >>= xLib;
2973 if( xLib.is() )
2975 // if the Module with codename exists then find a new name
2976 sal_Int32 nNum = 0;
2977 OUString genModuleName;
2978 if ( !sModuleName.isEmpty() )
2979 genModuleName = sModuleName;
2980 else
2982 genModuleName = "Sheet1";
2983 nNum = 1;
2985 while( xLib->hasByName( genModuleName ) )
2986 genModuleName = "Sheet" + OUString::number( ++nNum );
2988 uno::Any aSourceAny;
2989 OUString sTmpSource = sSource;
2990 if ( sTmpSource.isEmpty() )
2991 sTmpSource = "Rem Attribute VBA_ModuleType=VBADocumentModule\nOption VBASupport 1\n";
2992 aSourceAny <<= sTmpSource;
2993 uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY );
2994 if ( xVBAModuleInfo.is() )
2996 rDoc.SetCodeName( nTab, genModuleName );
2997 script::ModuleInfo sModuleInfo = lcl_InitModuleInfo( rDocSh, genModuleName );
2998 xVBAModuleInfo->insertModuleInfo( genModuleName, sModuleInfo );
2999 xLib->insertByName( genModuleName, aSourceAny );
3005 void VBA_DeleteModule( ScDocShell& rDocSh, const OUString& sModuleName )
3007 uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer();
3008 OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" );
3010 uno::Reference< container::XNameContainer > xLib;
3011 if( xLibContainer.is() )
3013 OUString aLibName( "Standard" );
3014 if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() )
3016 aLibName = rDocSh.GetBasicManager()->GetName();
3018 uno::Any aLibAny = xLibContainer->getByName( aLibName );
3019 aLibAny >>= xLib;
3021 if( xLib.is() )
3023 uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY );
3024 if( xLib->hasByName( sModuleName ) )
3025 xLib->removeByName( sModuleName );
3026 if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo(sModuleName) )
3027 xVBAModuleInfo->removeModuleInfo( sModuleName );
3032 bool ScDocFunc::InsertTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi )
3034 bool bSuccess = false;
3035 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
3037 ScDocShellModificator aModificator( rDocShell );
3039 ScDocument& rDoc = rDocShell.GetDocument();
3041 // Strange loop, also basic is loaded too early ( InsertTable )
3042 // is called via the xml import for sheets in described in ODF
3043 bool bInsertDocModule = false;
3045 if( !rDocShell.GetDocument().IsImportingXML() )
3047 bInsertDocModule = rDoc.IsInVBAMode();
3049 if ( bInsertDocModule || ( bRecord && !rDoc.IsUndoEnabled() ) )
3050 bRecord = false;
3052 if (bRecord)
3053 rDoc.BeginDrawUndo(); // InsertTab erzeugt ein SdrUndoNewPage
3055 SCTAB nTabCount = rDoc.GetTableCount();
3056 bool bAppend = ( nTab >= nTabCount );
3057 if ( bAppend )
3058 nTab = nTabCount; // wichtig fuer Undo
3060 if (rDoc.InsertTab( nTab, rName ))
3062 if (bRecord)
3063 rDocShell.GetUndoManager()->AddUndoAction(
3064 new ScUndoInsertTab( &rDocShell, nTab, bAppend, rName));
3065 // Views updaten:
3066 // Only insert vba modules if vba mode ( and not currently importing XML )
3067 if( bInsertDocModule )
3069 OUString sSource, sCodeName;
3070 VBA_InsertModule( rDoc, nTab, sCodeName, sSource );
3072 rDocShell.Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab ) );
3074 rDocShell.PostPaintExtras();
3075 aModificator.SetDocumentModified();
3076 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
3077 bSuccess = true;
3079 else if (!bApi)
3080 rDocShell.ErrorMessage(STR_TABINSERT_ERROR);
3082 return bSuccess;
3085 bool ScDocFunc::DeleteTable( SCTAB nTab, bool bRecord, bool /* bApi */ )
3087 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
3089 ScDocShellModificator aModificator( rDocShell );
3091 bool bSuccess = false;
3092 ScDocument& rDoc = rDocShell.GetDocument();
3093 bool bVbaEnabled = rDoc.IsInVBAMode();
3094 if (bRecord && !rDoc.IsUndoEnabled())
3095 bRecord = false;
3096 if ( bVbaEnabled )
3097 bRecord = false;
3098 bool bWasLinked = rDoc.IsLinked(nTab);
3099 ScDocument* pUndoDoc = nullptr;
3100 ScRefUndoData* pUndoData = nullptr;
3101 if (bRecord)
3103 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
3104 SCTAB nCount = rDoc.GetTableCount();
3106 pUndoDoc->InitUndo( &rDoc, nTab, nTab, true, true ); // nur nTab mit Flags
3107 pUndoDoc->AddUndoTab( 0, nCount-1 ); // alle Tabs fuer Referenzen
3109 rDoc.CopyToDocument(0,0,nTab, MAXCOL,MAXROW,nTab, InsertDeleteFlags::ALL,false, pUndoDoc );
3110 OUString aOldName;
3111 rDoc.GetName( nTab, aOldName );
3112 pUndoDoc->RenameTab( nTab, aOldName, false );
3113 if (bWasLinked)
3114 pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab),
3115 rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
3116 rDoc.GetLinkTab(nTab),
3117 rDoc.GetLinkRefreshDelay(nTab) );
3119 if ( rDoc.IsScenario(nTab) )
3121 pUndoDoc->SetScenario( nTab, true );
3122 OUString aComment;
3123 Color aColor;
3124 sal_uInt16 nScenFlags;
3125 rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags );
3126 pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags );
3127 bool bActive = rDoc.IsActiveScenario( nTab );
3128 pUndoDoc->SetActiveScenario( nTab, bActive );
3130 pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) );
3131 pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
3132 pUndoDoc->SetSheetEvents( nTab, rDoc.GetSheetEvents( nTab ) );
3134 // Drawing-Layer muss sein Undo selbst in der Hand behalten !!!
3135 rDoc.BeginDrawUndo(); // DeleteTab erzeugt ein SdrUndoDelPage
3137 pUndoData = new ScRefUndoData( &rDoc );
3140 if (rDoc.DeleteTab(nTab))
3142 if (bRecord)
3144 vector<SCTAB> theTabs;
3145 theTabs.push_back(nTab);
3146 rDocShell.GetUndoManager()->AddUndoAction(
3147 new ScUndoDeleteTab( &rDocShell, theTabs, pUndoDoc, pUndoData ));
3149 // Views updaten:
3150 if( bVbaEnabled )
3152 OUString sCodeName;
3153 if( rDoc.GetCodeName( nTab, sCodeName ) )
3155 VBA_DeleteModule( rDocShell, sCodeName );
3158 rDocShell.Broadcast( ScTablesHint( SC_TAB_DELETED, nTab ) );
3160 if (bWasLinked)
3162 rDocShell.UpdateLinks(); // Link-Manager updaten
3163 SfxBindings* pBindings = rDocShell.GetViewBindings();
3164 if (pBindings)
3165 pBindings->Invalidate(SID_LINKS);
3168 rDocShell.PostPaintExtras();
3169 aModificator.SetDocumentModified();
3171 SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
3172 pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
3173 pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
3174 pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
3176 bSuccess = true;
3178 else
3180 delete pUndoDoc;
3181 delete pUndoData;
3183 return bSuccess;
3186 void ScDocFunc::SetTableVisible( SCTAB nTab, bool bVisible, bool bApi )
3188 ScDocument& rDoc = rDocShell.GetDocument();
3189 bool bUndo(rDoc.IsUndoEnabled());
3190 if ( rDoc.IsVisible( nTab ) == bVisible )
3191 return; // nichts zu tun - ok
3193 if ( !rDoc.IsDocEditable() )
3195 if (!bApi)
3196 rDocShell.ErrorMessage(STR_PROTECTIONERR);
3197 return;
3200 ScDocShellModificator aModificator( rDocShell );
3202 if ( !bVisible && !rDoc.IsImportingXML() ) // #i57869# allow hiding in any order for loading
3204 // nicht alle Tabellen ausblenden
3206 sal_uInt16 nVisCount = 0;
3207 SCTAB nCount = rDoc.GetTableCount();
3208 for (SCTAB i=0; i<nCount && nVisCount<2; i++)
3209 if (rDoc.IsVisible(i))
3210 ++nVisCount;
3212 if (nVisCount <= 1)
3214 if (!bApi)
3215 rDocShell.ErrorMessage(STR_PROTECTIONERR); //! eigene Meldung?
3216 return;
3220 rDoc.SetVisible( nTab, bVisible );
3221 if (bUndo)
3223 std::vector<SCTAB> undoTabs;
3224 undoTabs.push_back(nTab);
3225 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoShowHideTab( &rDocShell, undoTabs, bVisible ) );
3228 // Views updaten:
3229 if (!bVisible)
3230 rDocShell.Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) );
3232 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
3233 rDocShell.PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS);
3234 aModificator.SetDocumentModified();
3237 bool ScDocFunc::SetLayoutRTL( SCTAB nTab, bool bRTL, bool /* bApi */ )
3239 ScDocument& rDoc = rDocShell.GetDocument();
3240 bool bUndo(rDoc.IsUndoEnabled());
3241 if ( rDoc.IsLayoutRTL( nTab ) == bRTL )
3242 return true; // nothing to do - ok
3244 //! protection (sheet or document?)
3246 ScDocShellModificator aModificator( rDocShell );
3248 rDoc.SetLayoutRTL( nTab, bRTL );
3250 if (bUndo)
3252 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoLayoutRTL( &rDocShell, nTab, bRTL ) );
3255 rDocShell.PostPaint( 0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_ALL );
3256 aModificator.SetDocumentModified();
3258 SfxBindings* pBindings = rDocShell.GetViewBindings();
3259 if (pBindings)
3261 pBindings->Invalidate( FID_TAB_RTL );
3262 pBindings->Invalidate( SID_ATTR_SIZE );
3265 return true;
3268 bool ScDocFunc::RenameTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi )
3270 ScDocument& rDoc = rDocShell.GetDocument();
3271 if (bRecord && !rDoc.IsUndoEnabled())
3272 bRecord = false;
3273 if ( !rDoc.IsDocEditable() )
3275 if (!bApi)
3276 rDocShell.ErrorMessage(STR_PROTECTIONERR);
3277 return false;
3280 ScDocShellModificator aModificator( rDocShell );
3282 bool bSuccess = false;
3283 OUString sOldName;
3284 rDoc.GetName(nTab, sOldName);
3285 if (rDoc.RenameTab( nTab, rName ))
3287 if (bRecord)
3289 rDocShell.GetUndoManager()->AddUndoAction(
3290 new ScUndoRenameTab( &rDocShell, nTab, sOldName, rName));
3292 rDocShell.PostPaintExtras();
3293 aModificator.SetDocumentModified();
3294 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
3296 bSuccess = true;
3298 return bSuccess;
3301 bool ScDocFunc::SetTabBgColor( SCTAB nTab, const Color& rColor, bool bRecord, bool bApi )
3304 ScDocument& rDoc = rDocShell.GetDocument();
3305 if (bRecord && !rDoc.IsUndoEnabled())
3306 bRecord = false;
3307 if ( !rDoc.IsDocEditable() || rDoc.IsTabProtected(nTab) )
3309 if (!bApi)
3310 rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Check to see what this string is...
3311 return false;
3314 Color aOldTabBgColor;
3315 aOldTabBgColor = rDoc.GetTabBgColor(nTab);
3317 bool bSuccess = false;
3318 rDoc.SetTabBgColor(nTab, rColor);
3319 if ( rDoc.GetTabBgColor(nTab) == rColor)
3320 bSuccess = true;
3321 if (bSuccess)
3323 if (bRecord)
3325 rDocShell.GetUndoManager()->AddUndoAction(
3326 new ScUndoTabColor( &rDocShell, nTab, aOldTabBgColor, rColor));
3328 rDocShell.PostPaintExtras();
3329 ScDocShellModificator aModificator( rDocShell );
3330 aModificator.SetDocumentModified();
3331 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
3333 bSuccess = true;
3335 return bSuccess;
3338 bool ScDocFunc::SetTabBgColor(
3339 ScUndoTabColorInfo::List& rUndoTabColorList, bool bApi )
3341 ScDocument& rDoc = rDocShell.GetDocument();
3342 bool bRecord = true;
3343 if (!rDoc.IsUndoEnabled())
3344 bRecord = false;
3346 if ( !rDoc.IsDocEditable() )
3348 if (!bApi)
3349 rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error...
3350 return false;
3353 sal_uInt16 nTab;
3354 Color aNewTabBgColor;
3355 bool bSuccess = true;
3356 size_t nTabProtectCount = 0;
3357 size_t nTabListCount = rUndoTabColorList.size();
3358 for ( size_t i = 0; i < nTabListCount; ++i )
3360 ScUndoTabColorInfo& rInfo = rUndoTabColorList[i];
3361 nTab = rInfo.mnTabId;
3362 if ( !rDoc.IsTabProtected(nTab) )
3364 aNewTabBgColor = rInfo.maNewTabBgColor;
3365 rInfo.maOldTabBgColor = rDoc.GetTabBgColor(nTab);
3366 rDoc.SetTabBgColor(nTab, aNewTabBgColor);
3367 if ( rDoc.GetTabBgColor(nTab) != aNewTabBgColor)
3369 bSuccess = false;
3370 break;
3373 else
3375 nTabProtectCount++;
3379 if ( nTabProtectCount == nTabListCount )
3381 if (!bApi)
3382 rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error...
3383 return false;
3386 if (bSuccess)
3388 if (bRecord)
3390 rDocShell.GetUndoManager()->AddUndoAction(
3391 new ScUndoTabColor( &rDocShell, rUndoTabColorList));
3393 rDocShell.PostPaintExtras();
3394 ScDocShellModificator aModificator( rDocShell );
3395 aModificator.SetDocumentModified();
3397 return bSuccess;
3400 //! SetWidthOrHeight - noch doppelt zu ViewFunc !!!!!!
3401 //! Probleme:
3402 //! - Optimale Hoehe fuer Edit-Zellen ist unterschiedlich zwischen Drucker und Bildschirm
3403 //! - Optimale Breite braucht Selektion, um evtl. nur selektierte Zellen zu beruecksichtigen
3405 static sal_uInt16 lcl_GetOptimalColWidth( ScDocShell& rDocShell, SCCOL nCol, SCTAB nTab, bool bFormula )
3407 ScSizeDeviceProvider aProv(&rDocShell);
3408 OutputDevice* pDev = aProv.GetDevice(); // has pixel MapMode
3409 double nPPTX = aProv.GetPPTX();
3410 double nPPTY = aProv.GetPPTY();
3412 ScDocument& rDoc = rDocShell.GetDocument();
3413 Fraction aOne(1,1);
3414 sal_uInt16 nTwips = rDoc.GetOptimalColWidth( nCol, nTab, pDev, nPPTX, nPPTY, aOne, aOne,
3415 bFormula );
3417 return nTwips;
3420 bool ScDocFunc::SetWidthOrHeight(
3421 bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, SCTAB nTab,
3422 ScSizeMode eMode, sal_uInt16 nSizeTwips, bool bRecord, bool bApi )
3424 ScDocShellModificator aModificator( rDocShell );
3426 if (rRanges.empty())
3427 return true;
3429 ScDocument& rDoc = rDocShell.GetDocument();
3430 if ( bRecord && !rDoc.IsUndoEnabled() )
3431 bRecord = false;
3433 // import into read-only document is possible
3434 if ( !rDoc.IsChangeReadOnlyEnabled() && !rDocShell.IsEditable() )
3436 if (!bApi)
3437 rDocShell.ErrorMessage(STR_PROTECTIONERR); //! eigene Meldung?
3438 return false;
3441 bool bSuccess = false;
3442 SCCOLROW nStart = rRanges[0].mnStart;
3443 SCCOLROW nEnd = rRanges[0].mnEnd;
3445 bool bFormula = false;
3446 if ( eMode == SC_SIZE_OPTIMAL )
3448 //! Option "Formeln anzeigen" - woher nehmen?
3451 ScDocument* pUndoDoc = nullptr;
3452 ScOutlineTable* pUndoTab = nullptr;
3453 std::vector<sc::ColRowSpan> aUndoRanges;
3455 if ( bRecord )
3457 rDoc.BeginDrawUndo(); // Drawing Updates
3459 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
3460 if (bWidth)
3462 pUndoDoc->InitUndo( &rDoc, nTab, nTab, true );
3463 rDoc.CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, static_cast<SCCOL>(nEnd), MAXROW, nTab, InsertDeleteFlags::NONE, false, pUndoDoc );
3465 else
3467 pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, true );
3468 rDoc.CopyToDocument( 0, static_cast<SCROW>(nStart), nTab, MAXCOL, static_cast<SCROW>(nEnd), nTab, InsertDeleteFlags::NONE, false, pUndoDoc );
3471 aUndoRanges = rRanges;
3473 ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
3474 if (pTable)
3475 pUndoTab = new ScOutlineTable( *pTable );
3478 bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
3479 bool bOutline = false;
3481 for (const sc::ColRowSpan& rRange : rRanges)
3483 SCCOLROW nStartNo = rRange.mnStart;
3484 SCCOLROW nEndNo = rRange.mnEnd;
3486 if ( !bWidth ) // Hoehen immer blockweise
3488 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
3490 bool bAll = ( eMode==SC_SIZE_OPTIMAL );
3491 if (!bAll)
3493 // fuer alle eingeblendeten CR_MANUALSIZE loeschen,
3494 // dann SetOptimalHeight mit bShrink = FALSE
3495 for (SCROW nRow=nStartNo; nRow<=nEndNo; nRow++)
3497 sal_uInt8 nOld = rDoc.GetRowFlags(nRow,nTab);
3498 SCROW nLastRow = -1;
3499 bool bHidden = rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow);
3500 if ( !bHidden && ( nOld & CR_MANUALSIZE ) )
3501 rDoc.SetRowFlags( nRow, nTab, nOld & ~CR_MANUALSIZE );
3505 ScSizeDeviceProvider aProv( &rDocShell );
3506 Fraction aOne(1,1);
3507 sc::RowHeightContext aCxt(aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice());
3508 aCxt.setForceAutoSize(bAll);
3509 rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab);
3511 if (bAll)
3512 rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
3514 // Manual-Flag wird bei bAll=sal_True schon in SetOptimalHeight gesetzt
3515 // (an bei Extra-Height, sonst aus).
3517 else if ( eMode==SC_SIZE_DIRECT || eMode==SC_SIZE_ORIGINAL )
3519 if (nSizeTwips)
3521 rDoc.SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
3522 rDoc.SetManualHeight( nStartNo, nEndNo, nTab, true ); // height was set manually
3524 if ( eMode != SC_SIZE_ORIGINAL )
3525 rDoc.ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
3527 else if ( eMode==SC_SIZE_SHOW )
3529 rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
3532 else // Spaltenbreiten
3534 for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
3536 if ( eMode != SC_SIZE_VISOPT || !rDoc.ColHidden(nCol, nTab) )
3538 sal_uInt16 nThisSize = nSizeTwips;
3540 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
3541 nThisSize = nSizeTwips +
3542 lcl_GetOptimalColWidth( rDocShell, nCol, nTab, bFormula );
3543 if ( nThisSize )
3544 rDoc.SetColWidth( nCol, nTab, nThisSize );
3546 if ( eMode != SC_SIZE_ORIGINAL )
3547 rDoc.ShowCol( nCol, nTab, bShow );
3552 // adjust outlines
3554 if ( eMode != SC_SIZE_ORIGINAL )
3556 if (bWidth)
3557 bOutline = bOutline || rDoc.UpdateOutlineCol(
3558 static_cast<SCCOL>(nStartNo),
3559 static_cast<SCCOL>(nEndNo), nTab, bShow );
3560 else
3561 bOutline = bOutline || rDoc.UpdateOutlineRow(
3562 static_cast<SCROW>(nStartNo),
3563 static_cast<SCROW>(nEndNo), nTab, bShow );
3566 rDoc.SetDrawPageSize(nTab);
3568 if (!bOutline)
3569 DELETEZ(pUndoTab);
3571 if (bRecord)
3573 ScMarkData aMark;
3574 aMark.SelectOneTable( nTab );
3575 rDocShell.GetUndoManager()->AddUndoAction(
3576 new ScUndoWidthOrHeight(
3577 &rDocShell, aMark, nStart, nTab, nEnd, nTab, pUndoDoc,
3578 aUndoRanges, pUndoTab, eMode, nSizeTwips, bWidth));
3581 rDoc.UpdatePageBreaks( nTab );
3583 rDocShell.PostPaint(0,0,nTab,MAXCOL,MAXROW,nTab,PAINT_ALL);
3584 aModificator.SetDocumentModified();
3586 return bSuccess;
3589 bool ScDocFunc::InsertPageBreak( bool bColumn, const ScAddress& rPos,
3590 bool bRecord, bool bSetModified, bool /* bApi */ )
3592 ScDocShellModificator aModificator( rDocShell );
3594 ScDocument& rDoc = rDocShell.GetDocument();
3595 if (bRecord && !rDoc.IsUndoEnabled())
3596 bRecord = false;
3597 SCTAB nTab = rPos.Tab();
3598 SfxBindings* pBindings = rDocShell.GetViewBindings();
3600 SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) :
3601 static_cast<SCCOLROW>(rPos.Row());
3602 if (nPos == 0)
3603 return false; // erste Spalte / Zeile
3605 ScBreakType nBreak = bColumn ?
3606 rDoc.HasColBreak(static_cast<SCCOL>(nPos), nTab) :
3607 rDoc.HasRowBreak(static_cast<SCROW>(nPos), nTab);
3608 if (nBreak & BREAK_MANUAL)
3609 return true;
3611 if (bRecord)
3612 rDocShell.GetUndoManager()->AddUndoAction(
3613 new ScUndoPageBreak( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, true ) );
3615 if (bColumn)
3616 rDoc.SetColBreak(static_cast<SCCOL>(nPos), nTab, false, true);
3617 else
3618 rDoc.SetRowBreak(static_cast<SCROW>(nPos), nTab, false, true);
3620 rDoc.InvalidatePageBreaks(nTab);
3621 rDoc.UpdatePageBreaks( nTab );
3623 if (rDoc.IsStreamValid(nTab))
3624 rDoc.SetStreamValid(nTab, false);
3626 if (bColumn)
3628 rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID );
3629 if (pBindings)
3631 pBindings->Invalidate( FID_INS_COLBRK );
3632 pBindings->Invalidate( FID_DEL_COLBRK );
3635 else
3637 rDocShell.PostPaint( 0, static_cast<SCROW>(nPos)-1, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID );
3638 if (pBindings)
3640 pBindings->Invalidate( FID_INS_ROWBRK );
3641 pBindings->Invalidate( FID_DEL_ROWBRK );
3644 if (pBindings)
3645 pBindings->Invalidate( FID_DEL_MANUALBREAKS );
3647 if (bSetModified)
3648 aModificator.SetDocumentModified();
3650 return true;
3653 bool ScDocFunc::RemovePageBreak( bool bColumn, const ScAddress& rPos,
3654 bool bRecord, bool bSetModified, bool /* bApi */ )
3656 ScDocShellModificator aModificator( rDocShell );
3658 ScDocument& rDoc = rDocShell.GetDocument();
3659 if (bRecord && !rDoc.IsUndoEnabled())
3660 bRecord = false;
3661 SCTAB nTab = rPos.Tab();
3662 SfxBindings* pBindings = rDocShell.GetViewBindings();
3664 SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) :
3665 static_cast<SCCOLROW>(rPos.Row());
3667 ScBreakType nBreak;
3668 if (bColumn)
3669 nBreak = rDoc.HasColBreak(static_cast<SCCOL>(nPos), nTab);
3670 else
3671 nBreak = rDoc.HasRowBreak(static_cast<SCROW>(nPos), nTab);
3672 if ((nBreak & BREAK_MANUAL) == 0)
3673 // There is no manual break.
3674 return false;
3676 if (bRecord)
3677 rDocShell.GetUndoManager()->AddUndoAction(
3678 new ScUndoPageBreak( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, false ) );
3680 if (bColumn)
3681 rDoc.RemoveColBreak(static_cast<SCCOL>(nPos), nTab, false, true);
3682 else
3683 rDoc.RemoveRowBreak(static_cast<SCROW>(nPos), nTab, false, true);
3685 rDoc.UpdatePageBreaks( nTab );
3687 if (rDoc.IsStreamValid(nTab))
3688 rDoc.SetStreamValid(nTab, false);
3690 if (bColumn)
3692 rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID );
3693 if (pBindings)
3695 pBindings->Invalidate( FID_INS_COLBRK );
3696 pBindings->Invalidate( FID_DEL_COLBRK );
3699 else
3701 rDocShell.PostPaint( 0, nPos-1, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID );
3702 if (pBindings)
3704 pBindings->Invalidate( FID_INS_ROWBRK );
3705 pBindings->Invalidate( FID_DEL_ROWBRK );
3708 if (pBindings)
3709 pBindings->Invalidate( FID_DEL_MANUALBREAKS );
3711 if (bSetModified)
3712 aModificator.SetDocumentModified();
3714 return true;
3717 void ScDocFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
3719 ScDocument& rDoc = rDocShell.GetDocument();
3721 rDoc.SetTabProtection(nTab, &rProtect);
3722 if (rDoc.IsUndoEnabled())
3724 ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
3725 OSL_ENSURE(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!");
3726 if (pProtect)
3728 ::std::unique_ptr<ScTableProtection> p(new ScTableProtection(*pProtect));
3729 p->setProtected(true); // just in case ...
3730 rDocShell.GetUndoManager()->AddUndoAction(
3731 new ScUndoTabProtect(&rDocShell, nTab, std::move(p)) );
3733 // ownership of unique_ptr now transferred to ScUndoTabProtect.
3737 rDocShell.PostPaintGridAll();
3738 ScDocShellModificator aModificator(rDocShell);
3739 aModificator.SetDocumentModified();
3742 bool ScDocFunc::Protect( SCTAB nTab, const OUString& rPassword, bool /*bApi*/ )
3744 ScDocument& rDoc = rDocShell.GetDocument();
3745 if (nTab == TABLEID_DOC)
3747 // document protection
3748 ScDocProtection aProtection;
3749 aProtection.setProtected(true);
3750 aProtection.setPassword(rPassword);
3751 rDoc.SetDocProtection(&aProtection);
3752 if (rDoc.IsUndoEnabled())
3754 ScDocProtection* pProtect = rDoc.GetDocProtection();
3755 OSL_ENSURE(pProtect, "ScDocFunc::Unprotect: ScDocProtection pointer is NULL!");
3756 if (pProtect)
3758 ::std::unique_ptr<ScDocProtection> p(new ScDocProtection(*pProtect));
3759 p->setProtected(true); // just in case ...
3760 rDocShell.GetUndoManager()->AddUndoAction(
3761 new ScUndoDocProtect(&rDocShell, std::move(p)) );
3762 // ownership of unique_ptr is transferred to ScUndoDocProtect.
3766 else
3768 // sheet protection
3770 ScTableProtection aProtection;
3771 aProtection.setProtected(true);
3772 aProtection.setPassword(rPassword);
3773 rDoc.SetTabProtection(nTab, &aProtection);
3774 if (rDoc.IsUndoEnabled())
3776 ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
3777 OSL_ENSURE(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!");
3778 if (pProtect)
3780 ::std::unique_ptr<ScTableProtection> p(new ScTableProtection(*pProtect));
3781 p->setProtected(true); // just in case ...
3782 rDocShell.GetUndoManager()->AddUndoAction(
3783 new ScUndoTabProtect(&rDocShell, nTab, std::move(p)) );
3784 // ownership of unique_ptr now transferred to ScUndoTabProtect.
3789 rDocShell.PostPaintGridAll();
3790 ScDocShellModificator aModificator( rDocShell );
3791 aModificator.SetDocumentModified();
3793 return true;
3796 bool ScDocFunc::Unprotect( SCTAB nTab, const OUString& rPassword, bool bApi )
3798 ScDocument& rDoc = rDocShell.GetDocument();
3800 if (nTab == TABLEID_DOC)
3802 // document protection
3804 ScDocProtection* pDocProtect = rDoc.GetDocProtection();
3805 if (!pDocProtect || !pDocProtect->isProtected())
3806 // already unprotected (should not happen)!
3807 return true;
3809 // save the protection state before unprotect (for undo).
3810 ::std::unique_ptr<ScDocProtection> pProtectCopy(new ScDocProtection(*pDocProtect));
3812 if (!pDocProtect->verifyPassword(rPassword))
3814 if (!bApi)
3816 ScopedVclPtrInstance< InfoBox > aBox( ScDocShell::GetActiveDialogParent(), OUString( ScResId( SCSTR_WRONGPASSWORD ) ) );
3817 aBox->Execute();
3819 return false;
3822 rDoc.SetDocProtection(nullptr);
3823 if (rDoc.IsUndoEnabled())
3825 pProtectCopy->setProtected(false);
3826 rDocShell.GetUndoManager()->AddUndoAction(
3827 new ScUndoDocProtect(&rDocShell, std::move(pProtectCopy)) );
3828 // ownership of unique_ptr now transferred to ScUndoDocProtect.
3831 else
3833 // sheet protection
3835 ScTableProtection* pTabProtect = rDoc.GetTabProtection(nTab);
3836 if (!pTabProtect || !pTabProtect->isProtected())
3837 // already unprotected (should not happen)!
3838 return true;
3840 // save the protection state before unprotect (for undo).
3841 ::std::unique_ptr<ScTableProtection> pProtectCopy(new ScTableProtection(*pTabProtect));
3842 if (!pTabProtect->verifyPassword(rPassword))
3844 if (!bApi)
3846 ScopedVclPtrInstance< InfoBox > aBox( ScDocShell::GetActiveDialogParent(), OUString( ScResId( SCSTR_WRONGPASSWORD ) ) );
3847 aBox->Execute();
3849 return false;
3852 rDoc.SetTabProtection(nTab, nullptr);
3853 if (rDoc.IsUndoEnabled())
3855 pProtectCopy->setProtected(false);
3856 rDocShell.GetUndoManager()->AddUndoAction(
3857 new ScUndoTabProtect(&rDocShell, nTab, std::move(pProtectCopy)) );
3858 // ownership of unique_ptr now transferred to ScUndoTabProtect.
3862 rDocShell.PostPaintGridAll();
3863 ScDocShellModificator aModificator( rDocShell );
3864 aModificator.SetDocumentModified();
3866 return true;
3869 void ScDocFunc::ClearItems( const ScMarkData& rMark, const sal_uInt16* pWhich, bool bApi )
3871 ScDocShellModificator aModificator( rDocShell );
3873 ScDocument& rDoc = rDocShell.GetDocument();
3874 bool bUndo (rDoc.IsUndoEnabled());
3875 ScEditableTester aTester( &rDoc, rMark );
3876 if (!aTester.IsEditable())
3878 if (!bApi)
3879 rDocShell.ErrorMessage(aTester.GetMessageId());
3880 return;
3883 // #i12940# ClearItems is called (from setPropertyToDefault) directly with uno object's cached
3884 // MarkData (GetMarkData), so rMark must be changed to multi selection for ClearSelectionItems
3885 // here.
3887 ScRange aMarkRange;
3888 ScMarkData aMultiMark = rMark;
3889 aMultiMark.SetMarking(false); // for MarkToMulti
3890 aMultiMark.MarkToMulti();
3891 aMultiMark.GetMultiMarkArea( aMarkRange );
3893 if (bUndo)
3895 SCTAB nStartTab = aMarkRange.aStart.Tab();
3896 SCTAB nEndTab = aMarkRange.aEnd.Tab();
3898 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
3899 pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab );
3900 rDoc.CopyToDocument( aMarkRange, InsertDeleteFlags::ATTRIB, true, pUndoDoc, &aMultiMark );
3902 rDocShell.GetUndoManager()->AddUndoAction(
3903 new ScUndoClearItems( &rDocShell, aMultiMark, pUndoDoc, pWhich ) );
3906 rDoc.ClearSelectionItems( pWhich, aMultiMark );
3908 rDocShell.PostPaint( aMarkRange, PAINT_GRID, SC_PF_LINES | SC_PF_TESTMERGE );
3909 aModificator.SetDocumentModified();
3911 //! Bindings-Invalidate etc.?
3914 bool ScDocFunc::ChangeIndent( const ScMarkData& rMark, bool bIncrement, bool bApi )
3916 ScDocShellModificator aModificator( rDocShell );
3918 ScDocument& rDoc = rDocShell.GetDocument();
3919 bool bUndo(rDoc.IsUndoEnabled());
3920 ScEditableTester aTester( &rDoc, rMark );
3921 if (!aTester.IsEditable())
3923 if (!bApi)
3924 rDocShell.ErrorMessage(aTester.GetMessageId());
3925 return false;
3928 ScRange aMarkRange;
3929 rMark.GetMultiMarkArea( aMarkRange );
3931 if (bUndo)
3933 SCTAB nStartTab = aMarkRange.aStart.Tab();
3934 SCTAB nTabCount = rDoc.GetTableCount();
3936 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
3937 pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab );
3938 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
3939 for (; itr != itrEnd && *itr < nTabCount; ++itr)
3940 if (*itr != nStartTab)
3941 pUndoDoc->AddUndoTab( *itr, *itr );
3943 ScRange aCopyRange = aMarkRange;
3944 aCopyRange.aStart.SetTab(0);
3945 aCopyRange.aEnd.SetTab(nTabCount-1);
3946 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, true, pUndoDoc, &rMark );
3948 rDocShell.GetUndoManager()->AddUndoAction(
3949 new ScUndoIndent( &rDocShell, rMark, pUndoDoc, bIncrement ) );
3952 rDoc.ChangeSelectionIndent( bIncrement, rMark );
3954 rDocShell.PostPaint( aMarkRange, PAINT_GRID, SC_PF_LINES | SC_PF_TESTMERGE );
3955 aModificator.SetDocumentModified();
3957 SfxBindings* pBindings = rDocShell.GetViewBindings();
3958 if (pBindings)
3960 pBindings->Invalidate( SID_ALIGNLEFT ); // ChangeIndent setzt auf links
3961 pBindings->Invalidate( SID_ALIGNRIGHT );
3962 pBindings->Invalidate( SID_ALIGNBLOCK );
3963 pBindings->Invalidate( SID_ALIGNCENTERHOR );
3964 pBindings->Invalidate( SID_ATTR_LRSPACE );
3965 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_LEFT );
3966 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_RIGHT );
3967 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_BLOCK );
3968 pBindings->Invalidate( SID_ATTR_PARA_ADJUST_CENTER);
3969 // pseudo slots for Format menu
3970 pBindings->Invalidate( SID_ALIGN_ANY_HDEFAULT );
3971 pBindings->Invalidate( SID_ALIGN_ANY_LEFT );
3972 pBindings->Invalidate( SID_ALIGN_ANY_HCENTER );
3973 pBindings->Invalidate( SID_ALIGN_ANY_RIGHT );
3974 pBindings->Invalidate( SID_ALIGN_ANY_JUSTIFIED );
3977 return true;
3980 bool ScDocFunc::AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark,
3981 sal_uInt16 nFormatNo, bool bApi )
3983 ScDocShellModificator aModificator( rDocShell );
3985 bool bSuccess = false;
3986 ScDocument& rDoc = rDocShell.GetDocument();
3987 SCCOL nStartCol = rRange.aStart.Col();
3988 SCROW nStartRow = rRange.aStart.Row();
3989 SCTAB nStartTab = rRange.aStart.Tab();
3990 SCCOL nEndCol = rRange.aEnd.Col();
3991 SCROW nEndRow = rRange.aEnd.Row();
3992 SCTAB nEndTab = rRange.aEnd.Tab();
3994 bool bRecord = true;
3995 if (!rDoc.IsUndoEnabled())
3996 bRecord = false;
3997 ScMarkData aMark;
3998 if (pTabMark)
3999 aMark = *pTabMark;
4000 else
4002 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4003 aMark.SelectTable( nTab, true );
4006 ScAutoFormat* pAutoFormat = ScGlobal::GetOrCreateAutoFormat();
4007 ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
4008 if ( nFormatNo < pAutoFormat->size() && aTester.IsEditable() )
4010 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
4012 bool bSize = pAutoFormat->findByIndex(nFormatNo)->GetIncludeWidthHeight();
4014 SCTAB nTabCount = rDoc.GetTableCount();
4015 ScDocument* pUndoDoc = nullptr;
4016 if ( bRecord )
4018 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4019 pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab, bSize, bSize );
4020 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
4021 for (; itr != itrEnd && *itr < nTabCount; ++itr)
4022 if (*itr != nStartTab)
4023 pUndoDoc->AddUndoTab( *itr, *itr, bSize, bSize );
4025 ScRange aCopyRange = rRange;
4026 aCopyRange.aStart.SetTab(0);
4027 aCopyRange.aStart.SetTab(nTabCount-1);
4028 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, false, pUndoDoc, &aMark );
4029 if (bSize)
4031 rDoc.CopyToDocument( nStartCol,0,0, nEndCol,MAXROW,nTabCount-1,
4032 InsertDeleteFlags::NONE, false, pUndoDoc, &aMark );
4033 rDoc.CopyToDocument( 0,nStartRow,0, MAXCOL,nEndRow,nTabCount-1,
4034 InsertDeleteFlags::NONE, false, pUndoDoc, &aMark );
4036 rDoc.BeginDrawUndo();
4039 rDoc.AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo, aMark );
4041 if (bSize)
4043 std::vector<sc::ColRowSpan> aCols(1, sc::ColRowSpan(nStartCol,nEndCol));
4044 std::vector<sc::ColRowSpan> aRows(1, sc::ColRowSpan(nStartRow,nEndRow));
4046 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
4047 for (; itr != itrEnd && *itr < nTabCount; ++itr)
4049 SetWidthOrHeight(true, aCols, *itr, SC_SIZE_VISOPT, STD_EXTRA_WIDTH, false, true);
4050 SetWidthOrHeight(false, aRows, *itr, SC_SIZE_VISOPT, 0, false, false);
4051 rDocShell.PostPaint( 0,0,*itr, MAXCOL,MAXROW,*itr,
4052 PAINT_GRID | PAINT_LEFT | PAINT_TOP );
4055 else
4057 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
4058 for (; itr != itrEnd && *itr < nTabCount; ++itr)
4060 bool bAdj = AdjustRowHeight( ScRange(nStartCol, nStartRow, *itr,
4061 nEndCol, nEndRow, *itr), false );
4062 if (bAdj)
4063 rDocShell.PostPaint( 0,nStartRow,*itr, MAXCOL,MAXROW,*itr,
4064 PAINT_GRID | PAINT_LEFT );
4065 else
4066 rDocShell.PostPaint( nStartCol, nStartRow, *itr,
4067 nEndCol, nEndRow, *itr, PAINT_GRID );
4071 if ( bRecord ) // Draw-Undo erst jetzt verfuegbar
4073 rDocShell.GetUndoManager()->AddUndoAction(
4074 new ScUndoAutoFormat( &rDocShell, rRange, pUndoDoc, aMark, bSize, nFormatNo ) );
4077 aModificator.SetDocumentModified();
4079 else if (!bApi)
4080 rDocShell.ErrorMessage(aTester.GetMessageId());
4082 return bSuccess;
4085 bool ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark,
4086 const ScTokenArray* pTokenArray, const OUString& rString, bool bApi, bool bEnglish,
4087 const OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar )
4089 if (ScViewData::SelectionFillDOOM( rRange ))
4090 return false;
4092 ScDocShellModificator aModificator( rDocShell );
4094 bool bSuccess = false;
4095 ScDocument& rDoc = rDocShell.GetDocument();
4096 SCCOL nStartCol = rRange.aStart.Col();
4097 SCROW nStartRow = rRange.aStart.Row();
4098 SCTAB nStartTab = rRange.aStart.Tab();
4099 SCCOL nEndCol = rRange.aEnd.Col();
4100 SCROW nEndRow = rRange.aEnd.Row();
4101 SCTAB nEndTab = rRange.aEnd.Tab();
4103 ScMarkData aMark;
4104 if (pTabMark)
4105 aMark = *pTabMark;
4106 else
4108 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4109 aMark.SelectTable( nTab, true );
4112 ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
4113 if ( aTester.IsEditable() )
4115 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
4117 ScDocument* pUndoDoc = nullptr;
4119 const bool bUndo(rDoc.IsUndoEnabled());
4120 if (bUndo)
4122 //! auch bei Undo selektierte Tabellen beruecksichtigen
4123 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4124 pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab );
4125 rDoc.CopyToDocument( rRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, pUndoDoc );
4128 // use TokenArray if given, string (and flags) otherwise
4129 if ( pTokenArray )
4131 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
4132 aMark, EMPTY_OUSTRING, pTokenArray, eGrammar);
4134 else if ( rDoc.IsImportingXML() )
4136 ScTokenArray* pCode = lcl_ScDocFunc_CreateTokenArrayXML( rString, rFormulaNmsp, eGrammar );
4137 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
4138 aMark, EMPTY_OUSTRING, pCode, eGrammar);
4139 delete pCode;
4140 rDoc.IncXMLImportedFormulaCount( rString.getLength() );
4142 else if (bEnglish)
4144 ScCompiler aComp( &rDoc, rRange.aStart);
4145 aComp.SetGrammar(eGrammar);
4146 ScTokenArray* pCode = aComp.CompileString( rString );
4147 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
4148 aMark, EMPTY_OUSTRING, pCode, eGrammar);
4149 delete pCode;
4151 else
4152 rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
4153 aMark, rString, nullptr, eGrammar);
4155 if (bUndo)
4157 //! auch bei Undo selektierte Tabellen beruecksichtigen
4158 rDocShell.GetUndoManager()->AddUndoAction(
4159 new ScUndoEnterMatrix( &rDocShell, rRange, pUndoDoc, rString ) );
4162 // Err522 beim Paint von DDE-Formeln werden jetzt beim Interpretieren abgefangen
4163 rDocShell.PostPaint( nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab, PAINT_GRID );
4164 aModificator.SetDocumentModified();
4166 bSuccess = true;
4168 else if (!bApi)
4169 rDocShell.ErrorMessage(aTester.GetMessageId());
4171 return bSuccess;
4174 bool ScDocFunc::TabOp( const ScRange& rRange, const ScMarkData* pTabMark,
4175 const ScTabOpParam& rParam, bool bRecord, bool bApi )
4177 ScDocShellModificator aModificator( rDocShell );
4179 bool bSuccess = false;
4180 ScDocument& rDoc = rDocShell.GetDocument();
4181 SCCOL nStartCol = rRange.aStart.Col();
4182 SCROW nStartRow = rRange.aStart.Row();
4183 SCTAB nStartTab = rRange.aStart.Tab();
4184 SCCOL nEndCol = rRange.aEnd.Col();
4185 SCROW nEndRow = rRange.aEnd.Row();
4186 SCTAB nEndTab = rRange.aEnd.Tab();
4188 if (bRecord && !rDoc.IsUndoEnabled())
4189 bRecord = false;
4191 ScMarkData aMark;
4192 if (pTabMark)
4193 aMark = *pTabMark;
4194 else
4196 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4197 aMark.SelectTable( nTab, true );
4200 ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
4201 if ( aTester.IsEditable() )
4203 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
4204 rDoc.SetDirty( rRange, false );
4205 if ( bRecord )
4207 //! auch bei Undo selektierte Tabellen beruecksichtigen
4208 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4209 pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab );
4210 rDoc.CopyToDocument( rRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, pUndoDoc );
4212 rDocShell.GetUndoManager()->AddUndoAction(
4213 new ScUndoTabOp( &rDocShell,
4214 nStartCol, nStartRow, nStartTab,
4215 nEndCol, nEndRow, nEndTab, pUndoDoc,
4216 rParam.aRefFormulaCell,
4217 rParam.aRefFormulaEnd,
4218 rParam.aRefRowCell,
4219 rParam.aRefColCell,
4220 rParam.meMode) );
4222 rDoc.InsertTableOp(rParam, nStartCol, nStartRow, nEndCol, nEndRow, aMark);
4223 rDocShell.PostPaintGridAll();
4224 aModificator.SetDocumentModified();
4225 bSuccess = true;
4227 else if (!bApi)
4228 rDocShell.ErrorMessage(aTester.GetMessageId());
4230 return bSuccess;
4233 inline ScDirection DirFromFillDir( FillDir eDir )
4235 if (eDir==FILL_TO_BOTTOM)
4236 return DIR_BOTTOM;
4237 else if (eDir==FILL_TO_RIGHT)
4238 return DIR_RIGHT;
4239 else if (eDir==FILL_TO_TOP)
4240 return DIR_TOP;
4241 else // if (eDir==FILL_TO_LEFT)
4242 return DIR_LEFT;
4245 namespace {
4248 * Expand the fill range as necessary, to allow copying of adjacent cell(s)
4249 * even when those cells are not in the original range.
4251 void adjustFillRangeForAdjacentCopy(ScRange& rRange, FillDir eDir)
4253 switch (eDir)
4255 case FILL_TO_BOTTOM:
4257 if (rRange.aStart.Row() == 0)
4258 return;
4260 if (rRange.aStart.Row() != rRange.aEnd.Row())
4261 return;
4263 // Include the above row.
4264 ScAddress& s = rRange.aStart;
4265 s.SetRow(s.Row()-1);
4267 break;
4268 case FILL_TO_TOP:
4270 if (rRange.aStart.Row() == MAXROW)
4271 return;
4273 if (rRange.aStart.Row() != rRange.aEnd.Row())
4274 return;
4276 // Include the row below.
4277 ScAddress& e = rRange.aEnd;
4278 e.SetRow(e.Row()+1);
4280 break;
4281 case FILL_TO_LEFT:
4283 if (rRange.aStart.Col() == MAXCOL)
4284 return;
4286 if (rRange.aStart.Col() != rRange.aEnd.Col())
4287 return;
4289 // Include the column to the right.
4290 ScAddress& e = rRange.aEnd;
4291 e.SetCol(e.Col()+1);
4293 break;
4294 case FILL_TO_RIGHT:
4296 if (rRange.aStart.Col() == 0)
4297 return;
4299 if (rRange.aStart.Col() != rRange.aEnd.Col())
4300 return;
4302 // Include the column to the left.
4303 ScAddress& s = rRange.aStart;
4304 s.SetCol(s.Col()-1);
4306 break;
4307 default:
4314 bool ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMark,
4315 FillDir eDir, bool bApi )
4317 ScDocShellModificator aModificator( rDocShell );
4318 ScDocument& rDoc = rDocShell.GetDocument();
4320 bool bSuccess = false;
4321 ScRange aRange = rRange;
4322 adjustFillRangeForAdjacentCopy(aRange, eDir);
4324 SCCOL nStartCol = aRange.aStart.Col();
4325 SCROW nStartRow = aRange.aStart.Row();
4326 SCTAB nStartTab = aRange.aStart.Tab();
4327 SCCOL nEndCol = aRange.aEnd.Col();
4328 SCROW nEndRow = aRange.aEnd.Row();
4329 SCTAB nEndTab = aRange.aEnd.Tab();
4331 bool bRecord = true;
4332 if (!rDoc.IsUndoEnabled())
4333 bRecord = false;
4335 ScMarkData aMark;
4336 if (pTabMark)
4337 aMark = *pTabMark;
4338 else
4340 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4341 aMark.SelectTable( nTab, true );
4344 ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
4345 if ( aTester.IsEditable() )
4347 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
4349 ScRange aSourceArea = aRange;
4350 ScRange aDestArea = aRange;
4352 SCCOLROW nCount = 0;
4353 switch (eDir)
4355 case FILL_TO_BOTTOM:
4356 nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row();
4357 aSourceArea.aEnd.SetRow( aSourceArea.aStart.Row() );
4358 break;
4359 case FILL_TO_RIGHT:
4360 nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col();
4361 aSourceArea.aEnd.SetCol( aSourceArea.aStart.Col() );
4362 break;
4363 case FILL_TO_TOP:
4364 nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row();
4365 aSourceArea.aStart.SetRow( aSourceArea.aEnd.Row() );
4366 break;
4367 case FILL_TO_LEFT:
4368 nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col();
4369 aSourceArea.aStart.SetCol( aSourceArea.aEnd.Col() );
4370 break;
4373 ScDocument* pUndoDoc = nullptr;
4374 if ( bRecord )
4376 SCTAB nTabCount = rDoc.GetTableCount();
4377 SCTAB nDestStartTab = aDestArea.aStart.Tab();
4379 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4380 pUndoDoc->InitUndo( &rDoc, nDestStartTab, nDestStartTab );
4381 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
4382 for (; itr != itrEnd && *itr < nTabCount; ++itr)
4383 if (*itr != nDestStartTab)
4384 pUndoDoc->AddUndoTab( *itr, *itr );
4386 ScRange aCopyRange = aDestArea;
4387 aCopyRange.aStart.SetTab(0);
4388 aCopyRange.aEnd.SetTab(nTabCount-1);
4389 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::AUTOFILL, false, pUndoDoc, &aMark );
4392 sal_uLong nProgCount;
4393 if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP)
4394 nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
4395 else
4396 nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
4397 nProgCount *= nCount;
4398 ScProgress aProgress( rDoc.GetDocumentShell(),
4399 ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount, true );
4401 rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
4402 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress,
4403 aMark, nCount, eDir, FILL_SIMPLE );
4404 AdjustRowHeight(aRange);
4406 if ( bRecord ) // Draw-Undo erst jetzt verfuegbar
4408 rDocShell.GetUndoManager()->AddUndoAction(
4409 new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark,
4410 eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307) );
4413 rDocShell.PostPaintGridAll();
4414 aModificator.SetDocumentModified();
4416 bSuccess = true;
4418 else if (!bApi)
4419 rDocShell.ErrorMessage(aTester.GetMessageId());
4421 return bSuccess;
4424 bool ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark,
4425 FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
4426 double fStart, double fStep, double fMax,
4427 bool bApi )
4429 ScDocShellModificator aModificator( rDocShell );
4431 bool bSuccess = false;
4432 ScDocument& rDoc = rDocShell.GetDocument();
4433 SCCOL nStartCol = rRange.aStart.Col();
4434 SCROW nStartRow = rRange.aStart.Row();
4435 SCTAB nStartTab = rRange.aStart.Tab();
4436 SCCOL nEndCol = rRange.aEnd.Col();
4437 SCROW nEndRow = rRange.aEnd.Row();
4438 SCTAB nEndTab = rRange.aEnd.Tab();
4440 bool bRecord = true;
4441 if (!rDoc.IsUndoEnabled())
4442 bRecord = false;
4444 ScMarkData aMark;
4445 if (pTabMark)
4446 aMark = *pTabMark;
4447 else
4449 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4450 aMark.SelectTable( nTab, true );
4453 ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
4454 if ( aTester.IsEditable() )
4456 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
4458 ScRange aSourceArea = rRange;
4459 ScRange aDestArea = rRange;
4461 SCSIZE nCount = rDoc.GetEmptyLinesInBlock(
4462 aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aStart.Tab(),
4463 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aSourceArea.aEnd.Tab(),
4464 DirFromFillDir(eDir) );
4466 // mindestens eine Zeile/Spalte als Quellbereich behalten:
4467 SCSIZE nTotLines = ( eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP ) ?
4468 static_cast<SCSIZE>( aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1 ) :
4469 static_cast<SCSIZE>( aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1 );
4470 if ( nCount >= nTotLines )
4471 nCount = nTotLines - 1;
4473 switch (eDir)
4475 case FILL_TO_BOTTOM:
4476 aSourceArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() - nCount ) );
4477 break;
4478 case FILL_TO_RIGHT:
4479 aSourceArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() - nCount ) );
4480 break;
4481 case FILL_TO_TOP:
4482 aSourceArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() + nCount ) );
4483 break;
4484 case FILL_TO_LEFT:
4485 aSourceArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() + nCount ) );
4486 break;
4489 ScDocument* pUndoDoc = nullptr;
4490 if ( bRecord )
4492 SCTAB nTabCount = rDoc.GetTableCount();
4493 SCTAB nDestStartTab = aDestArea.aStart.Tab();
4495 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4496 pUndoDoc->InitUndo( &rDoc, nDestStartTab, nDestStartTab );
4497 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
4498 for (; itr != itrEnd && *itr < nTabCount; ++itr)
4499 if (*itr != nDestStartTab)
4500 pUndoDoc->AddUndoTab( *itr, *itr );
4502 rDoc.CopyToDocument(
4503 aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0,
4504 aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1,
4505 InsertDeleteFlags::AUTOFILL, false, pUndoDoc, &aMark );
4508 if (aDestArea.aStart.Col() <= aDestArea.aEnd.Col() &&
4509 aDestArea.aStart.Row() <= aDestArea.aEnd.Row())
4511 if ( fStart != MAXDOUBLE )
4513 SCCOL nValX = (eDir == FILL_TO_LEFT) ? aDestArea.aEnd.Col() : aDestArea.aStart.Col();
4514 SCROW nValY = (eDir == FILL_TO_TOP ) ? aDestArea.aEnd.Row() : aDestArea.aStart.Row();
4515 SCTAB nTab = aDestArea.aStart.Tab();
4516 rDoc.SetValue( nValX, nValY, nTab, fStart );
4519 sal_uLong nProgCount;
4520 if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP)
4521 nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
4522 else
4523 nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
4524 nProgCount *= nCount;
4525 ScProgress aProgress( rDoc.GetDocumentShell(),
4526 ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount, true );
4528 rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
4529 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress,
4530 aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax );
4531 AdjustRowHeight(rRange);
4533 rDocShell.PostPaintGridAll();
4534 aModificator.SetDocumentModified();
4537 if ( bRecord ) // Draw-Undo erst jetzt verfuegbar
4539 rDocShell.GetUndoManager()->AddUndoAction(
4540 new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark,
4541 eDir, eCmd, eDateCmd, fStart, fStep, fMax) );
4544 bSuccess = true;
4546 else if (!bApi)
4547 rDocShell.ErrorMessage(aTester.GetMessageId());
4549 return bSuccess;
4552 bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark,
4553 FillDir eDir, sal_uLong nCount, bool bApi )
4555 double fStep = 1.0;
4556 double fMax = MAXDOUBLE;
4557 return FillAuto( rRange, pTabMark, eDir, FILL_AUTO, FILL_DAY, nCount, fStep, fMax, true/*bRecord*/, bApi );
4560 bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, sal_uLong nCount, double fStep, double fMax, bool bRecord, bool bApi )
4562 ScDocShellModificator aModificator( rDocShell );
4564 ScDocument& rDoc = rDocShell.GetDocument();
4565 SCCOL nStartCol = rRange.aStart.Col();
4566 SCROW nStartRow = rRange.aStart.Row();
4567 SCTAB nStartTab = rRange.aStart.Tab();
4568 SCCOL nEndCol = rRange.aEnd.Col();
4569 SCROW nEndRow = rRange.aEnd.Row();
4570 SCTAB nEndTab = rRange.aEnd.Tab();
4572 if (bRecord && !rDoc.IsUndoEnabled())
4573 bRecord = false;
4575 ScMarkData aMark;
4576 if (pTabMark)
4577 aMark = *pTabMark;
4578 else
4580 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4581 aMark.SelectTable( nTab, true );
4584 ScRange aSourceArea = rRange;
4585 ScRange aDestArea = rRange;
4587 switch (eDir)
4589 case FILL_TO_BOTTOM:
4590 aDestArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() + nCount ) );
4591 break;
4592 case FILL_TO_TOP:
4593 if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Row() ))
4595 OSL_FAIL("FillAuto: Row < 0");
4596 nCount = aSourceArea.aStart.Row();
4598 aDestArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() - nCount ) );
4599 break;
4600 case FILL_TO_RIGHT:
4601 aDestArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() + nCount ) );
4602 break;
4603 case FILL_TO_LEFT:
4604 if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Col() ))
4606 OSL_FAIL("FillAuto: Col < 0");
4607 nCount = aSourceArea.aStart.Col();
4609 aDestArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() - nCount ) );
4610 break;
4611 default:
4612 OSL_FAIL("Falsche Richtung bei FillAuto");
4613 break;
4616 // Zellschutz testen
4617 //! Quellbereich darf geschuetzt sein !!!
4618 //! aber kein Matrixfragment enthalten !!!
4620 ScEditableTester aTester( &rDoc, aDestArea );
4621 if ( !aTester.IsEditable() )
4623 if (!bApi)
4624 rDocShell.ErrorMessage(aTester.GetMessageId());
4625 return false;
4628 if ( rDoc.HasSelectedBlockMatrixFragment( nStartCol, nStartRow,
4629 nEndCol, nEndRow, aMark ) )
4631 if (!bApi)
4632 rDocShell.ErrorMessage(STR_MATRIXFRAGMENTERR);
4633 return false;
4636 // FID_FILL_... slots should already had been disabled, check here for API
4637 // calls, no message.
4638 if (ScViewData::SelectionFillDOOM( aDestArea))
4639 return false;
4641 WaitObject aWait( ScDocShell::GetActiveDialogParent() );
4643 ScDocument* pUndoDoc = nullptr;
4644 if ( bRecord )
4646 SCTAB nTabCount = rDoc.GetTableCount();
4647 SCTAB nDestStartTab = aDestArea.aStart.Tab();
4649 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4650 pUndoDoc->InitUndo( &rDoc, nDestStartTab, nDestStartTab );
4651 ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end();
4652 for (; itr != itrEnd && nTabCount; ++itr)
4653 if (*itr != nDestStartTab)
4654 pUndoDoc->AddUndoTab( *itr, *itr );
4656 // do not clone note captions in undo document
4657 rDoc.CopyToDocument(
4658 aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0,
4659 aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1,
4660 InsertDeleteFlags::AUTOFILL, false, pUndoDoc, &aMark );
4663 sal_uLong nProgCount;
4664 if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP)
4665 nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
4666 else
4667 nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
4668 nProgCount *= nCount;
4669 ScProgress aProgress( rDoc.GetDocumentShell(),
4670 ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount, true );
4672 rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
4673 aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress,
4674 aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax );
4676 AdjustRowHeight(aDestArea);
4678 if ( bRecord ) // Draw-Undo erst jetzt verfuegbar
4680 rDocShell.GetUndoManager()->AddUndoAction(
4681 new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark,
4682 eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax) );
4685 rDocShell.PostPaintGridAll();
4686 aModificator.SetDocumentModified();
4688 rRange = aDestArea; // Zielbereich zurueckgeben (zum Markieren)
4689 return true;
4692 bool ScDocFunc::MergeCells( const ScCellMergeOption& rOption, bool bContents, bool bRecord, bool bApi )
4694 using ::std::set;
4696 ScDocShellModificator aModificator( rDocShell );
4698 SCCOL nStartCol = rOption.mnStartCol;
4699 SCROW nStartRow = rOption.mnStartRow;
4700 SCCOL nEndCol = rOption.mnEndCol;
4701 SCROW nEndRow = rOption.mnEndRow;
4702 if ((nStartCol == nEndCol && nStartRow == nEndRow) || rOption.maTabs.empty())
4704 // Nothing to do. Bail out quick.
4705 return true;
4708 ScDocument& rDoc = rDocShell.GetDocument();
4709 set<SCTAB>::const_iterator itrBeg = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end();
4710 SCTAB nTab1 = *itrBeg, nTab2 = *rOption.maTabs.rbegin();
4712 if (bRecord && !rDoc.IsUndoEnabled())
4713 bRecord = false;
4715 for (set<SCTAB>::const_iterator itr = itrBeg; itr != itrEnd; ++itr)
4717 ScEditableTester aTester( &rDoc, *itr, nStartCol, nStartRow, nEndCol, nEndRow );
4718 if (!aTester.IsEditable())
4720 if (!bApi)
4721 rDocShell.ErrorMessage(aTester.GetMessageId());
4722 return false;
4725 if ( rDoc.HasAttrib( nStartCol, nStartRow, *itr, nEndCol, nEndRow, *itr,
4726 HASATTR_MERGED | HASATTR_OVERLAPPED ) )
4728 // "Zusammenfassen nicht verschachteln !"
4729 if (!bApi)
4730 rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0);
4731 return false;
4735 ScDocument* pUndoDoc = nullptr;
4736 bool bNeedContentsUndo = false;
4737 for (set<SCTAB>::const_iterator itr = itrBeg; itr != itrEnd; ++itr)
4739 SCTAB nTab = *itr;
4740 bool bNeedContents = bContents &&
4741 ( !rDoc.IsBlockEmpty( nTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) ||
4742 !rDoc.IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) );
4744 if (bRecord)
4746 // test if the range contains other notes which also implies that we need an undo document
4747 bool bHasNotes = false;
4748 for( ScAddress aPos( nStartCol, nStartRow, nTab ); !bHasNotes && (aPos.Col() <= nEndCol); aPos.IncCol() )
4749 for( aPos.SetRow( nStartRow ); !bHasNotes && (aPos.Row() <= nEndRow); aPos.IncRow() )
4750 bHasNotes = ((aPos.Col() != nStartCol) || (aPos.Row() != nStartRow)) && (rDoc.HasNote(aPos));
4752 if (!pUndoDoc)
4754 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4755 pUndoDoc->InitUndo(&rDoc, nTab1, nTab2);
4757 // note captions are collected by drawing undo
4758 rDoc.CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
4759 InsertDeleteFlags::ALL|InsertDeleteFlags::NOCAPTIONS, false, pUndoDoc );
4760 if( bHasNotes )
4761 rDoc.BeginDrawUndo();
4764 if (bNeedContents)
4765 rDoc.DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
4766 rDoc.DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
4768 if (rOption.mbCenter)
4770 rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) );
4771 rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxVerJustifyItem( SVX_VER_JUSTIFY_CENTER, ATTR_VER_JUSTIFY ) );
4774 if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab ) ) )
4775 rDocShell.PostPaint( nStartCol, nStartRow, nTab,
4776 nEndCol, nEndRow, nTab, PAINT_GRID );
4777 if (bNeedContents || rOption.mbCenter)
4779 ScRange aRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab);
4780 rDoc.SetDirty(aRange, true);
4783 bNeedContentsUndo |= bNeedContents;
4786 if (pUndoDoc)
4788 SdrUndoGroup* pDrawUndo = rDoc.GetDrawLayer() ? rDoc.GetDrawLayer()->GetCalcUndo() : nullptr;
4789 rDocShell.GetUndoManager()->AddUndoAction(
4790 new ScUndoMerge(&rDocShell, rOption, bNeedContentsUndo, pUndoDoc, pDrawUndo) );
4793 aModificator.SetDocumentModified();
4795 SfxBindings* pBindings = rDocShell.GetViewBindings();
4796 if (pBindings)
4798 pBindings->Invalidate( FID_MERGE_ON );
4799 pBindings->Invalidate( FID_MERGE_OFF );
4800 pBindings->Invalidate( FID_MERGE_TOGGLE );
4803 return true;
4806 bool ScDocFunc::UnmergeCells( const ScRange& rRange, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge )
4808 ScCellMergeOption aOption(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
4809 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
4810 for (SCTAB i = nTab1; i <= nTab2; ++i)
4811 aOption.maTabs.insert(i);
4813 return UnmergeCells(aOption, bRecord, pUndoRemoveMerge);
4816 bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge )
4818 using ::std::set;
4820 if (rOption.maTabs.empty())
4821 // Nothing to unmerge.
4822 return true;
4824 ScDocShellModificator aModificator( rDocShell );
4825 ScDocument& rDoc = rDocShell.GetDocument();
4827 if (bRecord && !rDoc.IsUndoEnabled())
4828 bRecord = false;
4830 ScDocument* pUndoDoc = (pUndoRemoveMerge ? pUndoRemoveMerge->GetUndoDoc() : nullptr);
4831 assert( pUndoDoc || !pUndoRemoveMerge );
4832 for (set<SCTAB>::const_iterator itr = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end();
4833 itr != itrEnd; ++itr)
4835 SCTAB nTab = *itr;
4836 ScRange aRange = rOption.getSingleRange(nTab);
4837 if ( !rDoc.HasAttrib(aRange, HASATTR_MERGED) )
4838 continue;
4840 ScRange aExtended = aRange;
4841 rDoc.ExtendMerge(aExtended);
4842 ScRange aRefresh = aExtended;
4843 rDoc.ExtendOverlapped(aRefresh);
4845 if (bRecord)
4847 if (!pUndoDoc)
4849 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
4850 pUndoDoc->InitUndo(&rDoc, *rOption.maTabs.begin(), *rOption.maTabs.rbegin());
4852 rDoc.CopyToDocument(aExtended, InsertDeleteFlags::ATTRIB, false, pUndoDoc);
4855 const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE );
4856 ScPatternAttr aPattern( rDoc.GetPool() );
4857 aPattern.GetItemSet().Put( rDefAttr );
4858 rDoc.ApplyPatternAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
4859 aRange.aEnd.Col(), aRange.aEnd.Row(), nTab,
4860 aPattern );
4862 rDoc.RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(),
4863 aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab,
4864 ScMF::Hor | ScMF::Ver );
4866 rDoc.ExtendMerge( aRefresh, true );
4868 if ( !AdjustRowHeight( aExtended ) )
4869 rDocShell.PostPaint( aExtended, PAINT_GRID );
4872 if (bRecord)
4874 if (pUndoRemoveMerge)
4876 // If pUndoRemoveMerge was passed, the caller is responsible for
4877 // adding it to Undo. Just add the current option.
4878 pUndoRemoveMerge->AddCellMergeOption( rOption);
4880 else
4882 rDocShell.GetUndoManager()->AddUndoAction(
4883 new ScUndoRemoveMerge( &rDocShell, rOption, pUndoDoc ) );
4886 aModificator.SetDocumentModified();
4888 return true;
4891 void ScDocFunc::ModifyRangeNames( const ScRangeName& rNewRanges, SCTAB nTab )
4893 SetNewRangeNames( new ScRangeName(rNewRanges), true, nTab );
4896 void ScDocFunc::SetNewRangeNames( ScRangeName* pNewRanges, bool bModifyDoc, SCTAB nTab ) // takes ownership of pNewRanges
4898 ScDocShellModificator aModificator( rDocShell );
4900 OSL_ENSURE( pNewRanges, "pNewRanges is 0" );
4901 ScDocument& rDoc = rDocShell.GetDocument();
4902 bool bUndo(rDoc.IsUndoEnabled());
4904 if (bUndo)
4906 ScRangeName* pOld;
4907 if (nTab >=0)
4909 pOld = rDoc.GetRangeName(nTab);
4911 else
4913 pOld = rDoc.GetRangeName();
4915 ScRangeName* pUndoRanges = new ScRangeName(*pOld);
4916 ScRangeName* pRedoRanges = new ScRangeName(*pNewRanges);
4917 rDocShell.GetUndoManager()->AddUndoAction(
4918 new ScUndoRangeNames( &rDocShell, pUndoRanges, pRedoRanges, nTab ) );
4921 // #i55926# While loading XML, formula cells only have a single string token,
4922 // so CompileNameFormula would never find any name (index) tokens, and would
4923 // unnecessarily loop through all cells.
4924 bool bCompile = ( !rDoc.IsImportingXML() && rDoc.GetNamedRangesLockCount() == 0 );
4926 if ( bCompile )
4927 rDoc.PreprocessRangeNameUpdate();
4928 if (nTab >= 0)
4929 rDoc.SetRangeName( nTab, pNewRanges ); // takes ownership
4930 else
4931 rDoc.SetRangeName( pNewRanges ); // takes ownership
4932 if ( bCompile )
4933 rDoc.CompileHybridFormula();
4935 if (bModifyDoc)
4937 aModificator.SetDocumentModified();
4938 SfxGetpApp()->Broadcast( SfxSimpleHint(SC_HINT_AREAS_CHANGED) );
4942 void ScDocFunc::ModifyAllRangeNames(const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap)
4944 ScDocShellModificator aModificator(rDocShell);
4945 ScDocument& rDoc = rDocShell.GetDocument();
4947 if (rDoc.IsUndoEnabled())
4949 std::map<OUString, ScRangeName*> aOldRangeMap;
4950 rDoc.GetRangeNameMap(aOldRangeMap);
4951 rDocShell.GetUndoManager()->AddUndoAction(
4952 new ScUndoAllRangeNames(&rDocShell, aOldRangeMap, rRangeMap));
4955 rDoc.PreprocessRangeNameUpdate();
4956 rDoc.SetAllRangeNames(rRangeMap);
4957 rDoc.CompileHybridFormula();
4959 aModificator.SetDocumentModified();
4960 SfxGetpApp()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED));
4963 void ScDocFunc::CreateOneName( ScRangeName& rList,
4964 SCCOL nPosX, SCROW nPosY, SCTAB nTab,
4965 SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
4966 bool& rCancel, bool bApi )
4968 if (rCancel)
4969 return;
4971 ScDocument& rDoc = rDocShell.GetDocument();
4972 if (!rDoc.HasValueData( nPosX, nPosY, nTab ))
4974 OUString aName = rDoc.GetString(nPosX, nPosY, nTab);
4975 ScRangeData::MakeValidName(aName);
4976 if (!aName.isEmpty())
4978 OUString aContent(ScRange( nX1, nY1, nTab, nX2, nY2, nTab ).Format(ScRefFlags::RANGE_ABS_3D, &rDoc));
4980 bool bInsert = false;
4981 ScRangeData* pOld = rList.findByUpperName(ScGlobal::pCharClass->uppercase(aName));
4982 if (pOld)
4984 OUString aOldStr;
4985 pOld->GetSymbol( aOldStr );
4986 if (aOldStr != aContent)
4988 if (bApi)
4989 bInsert = true; // per API nicht nachfragen
4990 else
4992 OUString aTemplate = ScGlobal::GetRscString( STR_CREATENAME_REPLACE );
4994 OUString aMessage = aTemplate.getToken( 0, '#' );
4995 aMessage += aName;
4996 aMessage += aTemplate.getToken( 1, '#' );
4998 short nResult = ScopedVclPtrInstance<QueryBox>( ScDocShell::GetActiveDialogParent(),
4999 WinBits(WB_YES_NO_CANCEL | WB_DEF_YES),
5000 aMessage )->Execute();
5001 if ( nResult == RET_YES )
5003 rList.erase(*pOld);
5004 bInsert = true;
5006 else if ( nResult == RET_CANCEL )
5007 rCancel = true;
5011 else
5012 bInsert = true;
5014 if (bInsert)
5016 ScRangeData* pData = new ScRangeData( &rDoc, aName, aContent,
5017 ScAddress( nPosX, nPosY, nTab));
5018 if (!rList.insert(pData))
5020 OSL_FAIL("nanu?");
5027 bool ScDocFunc::CreateNames( const ScRange& rRange, sal_uInt16 nFlags, bool bApi, SCTAB aTab )
5029 if (!nFlags)
5030 return false; // war nix
5032 ScDocShellModificator aModificator( rDocShell );
5034 bool bDone = false;
5035 SCCOL nStartCol = rRange.aStart.Col();
5036 SCROW nStartRow = rRange.aStart.Row();
5037 SCCOL nEndCol = rRange.aEnd.Col();
5038 SCROW nEndRow = rRange.aEnd.Row();
5039 SCTAB nTab = rRange.aStart.Tab();
5040 OSL_ENSURE(rRange.aEnd.Tab() == nTab, "CreateNames: mehrere Tabellen geht nicht");
5042 bool bValid = true;
5043 if ( nFlags & ( NAME_TOP | NAME_BOTTOM ) )
5044 if ( nStartRow == nEndRow )
5045 bValid = false;
5046 if ( nFlags & ( NAME_LEFT | NAME_RIGHT ) )
5047 if ( nStartCol == nEndCol )
5048 bValid = false;
5050 if (bValid)
5052 ScDocument& rDoc = rDocShell.GetDocument();
5053 ScRangeName* pNames;
5054 if (aTab >=0)
5055 pNames = rDoc.GetRangeName(nTab);
5056 else
5057 pNames = rDoc.GetRangeName();
5059 if (!pNames)
5060 return false; // soll nicht sein
5061 ScRangeName aNewRanges( *pNames );
5063 bool bTop = ( ( nFlags & NAME_TOP ) != 0 );
5064 bool bLeft = ( ( nFlags & NAME_LEFT ) != 0 );
5065 bool bBottom = ( ( nFlags & NAME_BOTTOM ) != 0 );
5066 bool bRight = ( ( nFlags & NAME_RIGHT ) != 0 );
5068 SCCOL nContX1 = nStartCol;
5069 SCROW nContY1 = nStartRow;
5070 SCCOL nContX2 = nEndCol;
5071 SCROW nContY2 = nEndRow;
5073 if ( bTop )
5074 ++nContY1;
5075 if ( bLeft )
5076 ++nContX1;
5077 if ( bBottom )
5078 --nContY2;
5079 if ( bRight )
5080 --nContX2;
5082 bool bCancel = false;
5083 SCCOL i;
5084 SCROW j;
5086 if ( bTop )
5087 for (i=nContX1; i<=nContX2; i++)
5088 CreateOneName( aNewRanges, i,nStartRow,nTab, i,nContY1,i,nContY2, bCancel, bApi );
5089 if ( bLeft )
5090 for (j=nContY1; j<=nContY2; j++)
5091 CreateOneName( aNewRanges, nStartCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi );
5092 if ( bBottom )
5093 for (i=nContX1; i<=nContX2; i++)
5094 CreateOneName( aNewRanges, i,nEndRow,nTab, i,nContY1,i,nContY2, bCancel, bApi );
5095 if ( bRight )
5096 for (j=nContY1; j<=nContY2; j++)
5097 CreateOneName( aNewRanges, nEndCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi );
5099 if ( bTop && bLeft )
5100 CreateOneName( aNewRanges, nStartCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
5101 if ( bTop && bRight )
5102 CreateOneName( aNewRanges, nEndCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
5103 if ( bBottom && bLeft )
5104 CreateOneName( aNewRanges, nStartCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
5105 if ( bBottom && bRight )
5106 CreateOneName( aNewRanges, nEndCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
5108 ModifyRangeNames( aNewRanges, aTab );
5109 bDone = true;
5113 return bDone;
5116 bool ScDocFunc::InsertNameList( const ScAddress& rStartPos, bool bApi )
5118 ScDocShellModificator aModificator( rDocShell );
5120 bool bDone = false;
5121 ScDocument& rDoc = rDocShell.GetDocument();
5122 const bool bRecord = rDoc.IsUndoEnabled();
5123 SCTAB nTab = rStartPos.Tab();
5125 //local names have higher priority than global names
5126 ScRangeName* pLocalList = rDoc.GetRangeName(nTab);
5127 sal_uInt16 nValidCount = 0;
5128 ScRangeName::iterator itrLocalBeg = pLocalList->begin(), itrLocalEnd = pLocalList->end();
5129 for (ScRangeName::iterator itr = itrLocalBeg; itr != itrLocalEnd; ++itr)
5131 const ScRangeData& r = *itr->second;
5132 if (!r.HasType(ScRangeData::Type::Database))
5133 ++nValidCount;
5135 ScRangeName* pList = rDoc.GetRangeName();
5136 ScRangeName::iterator itrBeg = pList->begin(), itrEnd = pList->end();
5137 for (ScRangeName::iterator itr = itrBeg; itr != itrEnd; ++itr)
5139 const ScRangeData& r = *itr->second;
5140 if (!r.HasType(ScRangeData::Type::Database) && !pLocalList->findByUpperName(r.GetUpperName()))
5141 ++nValidCount;
5144 if (nValidCount)
5146 SCCOL nStartCol = rStartPos.Col();
5147 SCROW nStartRow = rStartPos.Row();
5148 SCCOL nEndCol = nStartCol + 1;
5149 SCROW nEndRow = nStartRow + static_cast<SCROW>(nValidCount) - 1;
5151 ScEditableTester aTester( &rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow );
5152 if (aTester.IsEditable())
5154 ScDocument* pUndoDoc = nullptr;
5156 if (bRecord)
5158 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
5159 pUndoDoc->InitUndo( &rDoc, nTab, nTab );
5160 rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
5161 InsertDeleteFlags::ALL, false, pUndoDoc );
5163 rDoc.BeginDrawUndo(); // wegen Hoehenanpassung
5166 std::unique_ptr<ScRangeData*[]> ppSortArray(new ScRangeData* [ nValidCount ]);
5167 sal_uInt16 j = 0;
5168 for (ScRangeName::iterator itr = itrLocalBeg; itr != itrLocalEnd; ++itr)
5170 ScRangeData& r = *itr->second;
5171 if (!r.HasType(ScRangeData::Type::Database))
5172 ppSortArray[j++] = &r;
5174 for (ScRangeName::iterator itr = itrBeg; itr != itrEnd; ++itr)
5176 ScRangeData& r = *itr->second;
5177 if (!r.HasType(ScRangeData::Type::Database) && !pLocalList->findByUpperName(itr->first))
5178 ppSortArray[j++] = &r;
5180 qsort( static_cast<void*>(ppSortArray.get()), nValidCount, sizeof(ScRangeData*),
5181 &ScRangeData_QsortNameCompare );
5182 OUString aName;
5183 OUStringBuffer aContent;
5184 OUString aFormula;
5185 SCROW nOutRow = nStartRow;
5186 for (j=0; j<nValidCount; j++)
5188 ScRangeData* pData = ppSortArray[j];
5189 pData->GetName(aName);
5190 // relative Referenzen Excel-konform auf die linke Spalte anpassen:
5191 pData->UpdateSymbol(aContent, ScAddress( nStartCol, nOutRow, nTab ));
5192 aFormula = "=" + aContent.toString();
5193 ScSetStringParam aParam;
5194 aParam.setTextInput();
5195 rDoc.SetString(ScAddress(nStartCol,nOutRow,nTab), aName, &aParam);
5196 rDoc.SetString(ScAddress(nEndCol,nOutRow,nTab), aFormula, &aParam);
5197 ++nOutRow;
5200 ppSortArray.reset();
5202 if (bRecord)
5204 ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
5205 pRedoDoc->InitUndo( &rDoc, nTab, nTab );
5206 rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
5207 InsertDeleteFlags::ALL, false, pRedoDoc );
5209 rDocShell.GetUndoManager()->AddUndoAction(
5210 new ScUndoListNames( &rDocShell,
5211 ScRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab ),
5212 pUndoDoc, pRedoDoc ) );
5215 if (!AdjustRowHeight(ScRange(0,nStartRow,nTab,MAXCOL,nEndRow,nTab)))
5216 rDocShell.PostPaint( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, PAINT_GRID );
5218 aModificator.SetDocumentModified();
5219 bDone = true;
5221 else if (!bApi)
5222 rDocShell.ErrorMessage(aTester.GetMessageId());
5224 return bDone;
5227 void ScDocFunc::ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd )
5229 ScDocument& rDoc = rDocShell.GetDocument();
5230 SCCOL nStartCol = rOldRange.aStart.Col();
5231 SCROW nStartRow = rOldRange.aStart.Row();
5232 SCTAB nTab = rOldRange.aStart.Tab();
5234 OUString aFormula;
5235 rDoc.GetFormula( nStartCol, nStartRow, nTab, aFormula );
5236 if ( aFormula.startsWith("{") && aFormula.endsWith("}") )
5238 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_RESIZEMATRIX );
5239 bool bUndo(rDoc.IsUndoEnabled());
5240 if (bUndo)
5241 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
5243 aFormula = aFormula.copy(1, aFormula.getLength()-2);
5245 ScMarkData aMark;
5246 aMark.SetMarkArea( rOldRange );
5247 aMark.SelectTable( nTab, true );
5248 ScRange aNewRange( rOldRange.aStart, rNewEnd );
5250 if ( DeleteContents( aMark, InsertDeleteFlags::CONTENTS, true, false/*bApi*/ ) )
5252 // GRAM_PODF_A1 for API compatibility.
5253 if (!EnterMatrix( aNewRange, &aMark, nullptr, aFormula, false/*bApi*/, false, EMPTY_OUSTRING, formula::FormulaGrammar::GRAM_PODF_A1 ))
5255 // versuchen, alten Zustand wiederherzustellen
5256 EnterMatrix( rOldRange, &aMark, nullptr, aFormula, false/*bApi*/, false, EMPTY_OUSTRING, formula::FormulaGrammar::GRAM_PODF_A1 );
5260 if (bUndo)
5261 rDocShell.GetUndoManager()->LeaveListAction();
5265 void ScDocFunc::InsertAreaLink( const OUString& rFile, const OUString& rFilter,
5266 const OUString& rOptions, const OUString& rSource,
5267 const ScRange& rDestRange, sal_uLong nRefresh,
5268 bool bFitBlock, bool bApi )
5270 ScDocument& rDoc = rDocShell.GetDocument();
5271 bool bUndo (rDoc.IsUndoEnabled());
5273 sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
5275 // #i52120# if other area links exist at the same start position,
5276 // remove them first (file format specifies only one link definition
5277 // for a cell)
5279 sal_uInt16 nLinkCount = pLinkManager->GetLinks().size();
5280 sal_uInt16 nRemoved = 0;
5281 sal_uInt16 nLinkPos = 0;
5282 while (nLinkPos<nLinkCount)
5284 ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[nLinkPos].get();
5285 ScAreaLink* pLink = dynamic_cast<ScAreaLink*>(pBase);
5286 if (pLink && pLink->GetDestArea().aStart == rDestRange.aStart)
5288 if ( bUndo )
5290 if ( !nRemoved )
5292 // group all remove and the insert action
5293 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTAREALINK );
5294 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
5297 ScAreaLink* pOldArea = static_cast<ScAreaLink*>(pBase);
5298 rDocShell.GetUndoManager()->AddUndoAction(
5299 new ScUndoRemoveAreaLink( &rDocShell,
5300 pOldArea->GetFile(), pOldArea->GetFilter(), pOldArea->GetOptions(),
5301 pOldArea->GetSource(), pOldArea->GetDestArea(), pOldArea->GetRefreshDelay() ) );
5303 pLinkManager->Remove( pBase );
5304 nLinkCount = pLinkManager->GetLinks().size();
5305 ++nRemoved;
5307 else
5308 ++nLinkPos;
5311 OUString aFilterName = rFilter;
5312 OUString aNewOptions = rOptions;
5313 if (aFilterName.isEmpty())
5314 ScDocumentLoader::GetFilterName( rFile, aFilterName, aNewOptions, true, !bApi );
5316 // remove application prefix from filter name here, so the filter options
5317 // aren't reset when the filter name is changed in ScAreaLink::DataChanged
5318 ScDocumentLoader::RemoveAppPrefix( aFilterName );
5320 ScAreaLink* pLink = new ScAreaLink( &rDocShell, rFile, aFilterName,
5321 aNewOptions, rSource, rDestRange, nRefresh );
5322 OUString aTmp = aFilterName;
5323 pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, rFile, &aTmp, &rSource );
5325 // Undo fuer den leeren Link
5327 if (bUndo)
5329 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoInsertAreaLink( &rDocShell,
5330 rFile, aFilterName, aNewOptions,
5331 rSource, rDestRange, nRefresh ) );
5332 if ( nRemoved )
5333 rDocShell.GetUndoManager()->LeaveListAction(); // undo for link update is still separate
5336 // Update hat sein eigenes Undo
5337 if (rDoc.IsExecuteLinkEnabled())
5339 pLink->SetDoInsert(bFitBlock); // beim ersten Update ggf. nichts einfuegen
5340 pLink->Update(); // kein SetInCreate -> Update ausfuehren
5342 pLink->SetDoInsert(true); // Default = true
5344 SfxBindings* pBindings = rDocShell.GetViewBindings();
5345 if (pBindings)
5346 pBindings->Invalidate( SID_LINKS );
5348 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); // Navigator
5351 void ScDocFunc::ReplaceConditionalFormat( sal_uLong nOldFormat, ScConditionalFormat* pFormat, SCTAB nTab, const ScRangeList& rRanges )
5353 ScDocShellModificator aModificator(rDocShell);
5354 ScDocument& rDoc = rDocShell.GetDocument();
5355 if(rDoc.IsTabProtected(nTab))
5356 return;
5358 bool bUndo = rDoc.IsUndoEnabled();
5359 ScDocument* pUndoDoc = nullptr;
5360 ScRange aCombinedRange = rRanges.Combine();
5361 ScRange aCompleteRange;
5362 if(bUndo)
5364 pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
5365 pUndoDoc->InitUndo( &rDoc, nTab, nTab );
5367 if(pFormat)
5369 aCompleteRange = aCombinedRange;
5371 if(nOldFormat)
5373 ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat);
5374 if(pOldFormat)
5375 aCompleteRange.ExtendTo(pOldFormat->GetRange().Combine());
5378 rDoc.CopyToDocument( aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab,
5379 aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab,
5380 InsertDeleteFlags::ALL, false, pUndoDoc );
5383 std::unique_ptr<ScRange> pRepaintRange;
5384 if(nOldFormat)
5386 ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat);
5387 if(pOldFormat)
5389 pRepaintRange.reset(new ScRange( pOldFormat->GetRange().Combine() ));
5390 rDoc.RemoveCondFormatData(pOldFormat->GetRange(), nTab, pOldFormat->GetKey());
5393 rDoc.DeleteConditionalFormat(nOldFormat, nTab);
5394 rDoc.SetStreamValid(nTab, false);
5396 if(pFormat)
5398 if(pRepaintRange)
5399 pRepaintRange->ExtendTo(aCombinedRange);
5400 else
5401 pRepaintRange.reset(new ScRange(aCombinedRange));
5403 sal_uLong nIndex = rDoc.AddCondFormat(pFormat, nTab);
5405 rDoc.AddCondFormatData(rRanges, nTab, nIndex);
5406 rDoc.SetStreamValid(nTab, false);
5409 if(bUndo)
5411 ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
5412 pRedoDoc->InitUndo( &rDoc, nTab, nTab );
5413 rDoc.CopyToDocument( aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab,
5414 aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab,
5415 InsertDeleteFlags::ALL, false, pRedoDoc );
5416 rDocShell.GetUndoManager()->AddUndoAction(
5417 new ScUndoConditionalFormat(&rDocShell, pUndoDoc, pRedoDoc, aCompleteRange));
5420 if(pRepaintRange)
5421 rDocShell.PostPaint(*pRepaintRange, PAINT_GRID);
5423 aModificator.SetDocumentModified();
5424 SfxGetpApp()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED));
5427 void ScDocFunc::SetConditionalFormatList( ScConditionalFormatList* pList, SCTAB nTab )
5429 ScDocShellModificator aModificator(rDocShell);
5430 ScDocument& rDoc = rDocShell.GetDocument();
5431 if(rDoc.IsTabProtected(nTab))
5432 return;
5434 // first remove all old entries
5435 ScConditionalFormatList* pOldList = rDoc.GetCondFormList(nTab);
5436 for(ScConditionalFormatList::const_iterator itr = pOldList->begin(), itrEnd = pOldList->end(); itr != itrEnd; ++itr)
5438 rDoc.RemoveCondFormatData((*itr)->GetRange(), nTab, (*itr)->GetKey());
5441 // then set new entries
5442 for(ScConditionalFormatList::iterator itr = pList->begin(); itr != pList->end(); ++itr)
5444 rDoc.AddCondFormatData((*itr)->GetRange(), nTab, (*itr)->GetKey());
5447 rDoc.SetCondFormList(pList, nTab);
5448 rDocShell.PostPaintGridAll();
5450 rDoc.SetStreamValid(nTab, false);
5451 aModificator.SetDocumentModified();
5452 SfxGetpApp()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED));
5455 void ScDocFunc::ConvertFormulaToValue( const ScRange& rRange, bool bInteraction )
5457 ScDocShellModificator aModificator(rDocShell);
5458 ScDocument& rDoc = rDocShell.GetDocument();
5459 bool bRecord = true;
5460 if (!rDoc.IsUndoEnabled())
5461 bRecord = false;
5463 ScEditableTester aTester(&rDoc, rRange);
5464 if (!aTester.IsEditable())
5466 if (bInteraction)
5467 rDocShell.ErrorMessage(aTester.GetMessageId());
5468 return;
5471 sc::TableValues aUndoVals(rRange);
5472 sc::TableValues* pUndoVals = bRecord ? &aUndoVals : nullptr;
5474 rDoc.ConvertFormulaToValue(rRange, pUndoVals);
5476 if (bRecord && pUndoVals)
5478 rDocShell.GetUndoManager()->AddUndoAction(
5479 new sc::UndoFormulaToValue(&rDocShell, *pUndoVals));
5482 rDocShell.PostPaint(rRange, PAINT_GRID);
5483 rDocShell.PostDataChanged();
5484 rDoc.BroadcastCells(rRange, SC_HINT_DATACHANGED);
5485 aModificator.SetDocumentModified();
5488 void ScDocFunc::EnterListAction( sal_uInt16 nNameResId )
5490 OUString aUndo( ScGlobal::GetRscString( nNameResId ) );
5491 rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
5494 void ScDocFunc::EndListAction()
5496 rDocShell.GetUndoManager()->LeaveListAction();
5499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */