/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "scitems.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include "docfunc.hxx" #include "sc.hrc" #include "arealink.hxx" #include "attrib.hxx" #include "dociter.hxx" #include "autoform.hxx" #include "formulacell.hxx" #include "cellmergeoption.hxx" #include "detdata.hxx" #include "detfunc.hxx" #include "docpool.hxx" #include "docsh.hxx" #include "drwlayer.hxx" #include "editutil.hxx" #include "globstr.hrc" #include "globalnames.hxx" #include "olinetab.hxx" #include "patattr.hxx" #include "rangenam.hxx" #include "rangeutl.hxx" #include "refundo.hxx" #include "scresid.hxx" #include "stlpool.hxx" #include "stlsheet.hxx" #include "tablink.hxx" #include "tabvwsh.hxx" #include "uiitems.hxx" #include "undoblk.hxx" #include "undocell.hxx" #include "undodraw.hxx" #include "undotab.hxx" #include "waitoff.hxx" #include "sizedev.hxx" #include "scmod.hxx" #include "inputhdl.hxx" #include "inputwin.hxx" #include "editable.hxx" #include "compiler.hxx" #include "scui_def.hxx" #include "tabprotection.hxx" #include "clipparam.hxx" #include "externalrefmgr.hxx" #include "undorangename.hxx" #include "progress.hxx" #include "dpobject.hxx" #include "stringutil.hxx" #include "cellvalue.hxx" #include "tokenarray.hxx" #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; using ::com::sun::star::uno::Sequence; using ::std::vector; // STATIC DATA ----------------------------------------------------------- IMPL_LINK( ScDocFunc, NotifyDrawUndo, SdrUndoAction*, pUndoAction ) { // #i101118# if drawing layer collects the undo actions, add it there ScDrawLayer* pDrawLayer = rDocShell.GetDocument().GetDrawLayer(); if( pDrawLayer && pDrawLayer->IsRecording() ) pDrawLayer->AddCalcUndo( pUndoAction ); else rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDraw( pUndoAction, &rDocShell ) ); rDocShell.SetDrawModified(); // the affected sheet isn't known, so all stream positions are invalidated ScDocument& rDoc = rDocShell.GetDocument(); SCTAB nTabCount = rDoc.GetTableCount(); for (SCTAB nTab=0; nTab 0 ) { SCTAB nTab = rRange.aStart.Tab(); //! alle? --nRow; rDocShell.PostPaint( ScRange(0,nRow,nTab, MAXCOL,nRow,nTab), PAINT_GRID ); } } bool ScDocFunc::AdjustRowHeight( const ScRange& rRange, bool bPaint ) { ScDocument& rDoc = rDocShell.GetDocument(); if ( rDoc.IsImportingXML() ) { // for XML import, all row heights are updated together after importing return false; } if ( !rDoc.IsAdjustHeightEnabled() ) { return false; } SCTAB nTab = rRange.aStart.Tab(); SCROW nStartRow = rRange.aStart.Row(); SCROW nEndRow = rRange.aEnd.Row(); ScSizeDeviceProvider aProv( &rDocShell ); Fraction aOne(1,1); sc::RowHeightContext aCxt(aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice()); bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab); if ( bPaint && bChanged ) rDocShell.PostPaint(ScRange(0, nStartRow, nTab, MAXCOL, MAXROW, nTab), PAINT_GRID | PAINT_LEFT); return bChanged; } bool ScDocFunc::DetectiveAddPred(const ScAddress& rPos) { ScDocShellModificator aModificator( rDocShell ); rDocShell.MakeDrawLayer(); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); ScDrawLayer* pModel = rDoc.GetDrawLayer(); SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if (bUndo) pModel->BeginCalcUndo(false); bool bDone = ScDetectiveFunc( &rDoc,nTab ).ShowPred( nCol, nRow ); SdrUndoGroup* pUndo = NULL; if (bUndo) pUndo = pModel->GetCalcUndo(); if (bDone) { ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDPRED ); rDoc.AddDetectiveOperation( aOperation ); if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); } aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate( SID_DETECTIVE_REFRESH ); } else delete pUndo; return bDone; } bool ScDocFunc::DetectiveDelPred(const ScAddress& rPos) { ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo(rDoc.IsUndoEnabled()); ScDrawLayer* pModel = rDoc.GetDrawLayer(); if (!pModel) return false; ScDocShellModificator aModificator( rDocShell ); SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if (bUndo) pModel->BeginCalcUndo(false); bool bDone = ScDetectiveFunc( &rDoc,nTab ).DeletePred( nCol, nRow ); SdrUndoGroup* pUndo = NULL; if (bUndo) pUndo = pModel->GetCalcUndo(); if (bDone) { ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELPRED ); rDoc.AddDetectiveOperation( aOperation ); if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); } aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate( SID_DETECTIVE_REFRESH ); } else delete pUndo; return bDone; } bool ScDocFunc::DetectiveAddSucc(const ScAddress& rPos) { ScDocShellModificator aModificator( rDocShell ); rDocShell.MakeDrawLayer(); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo(rDoc.IsUndoEnabled()); ScDrawLayer* pModel = rDoc.GetDrawLayer(); SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if (bUndo) pModel->BeginCalcUndo(false); bool bDone = ScDetectiveFunc( &rDoc,nTab ).ShowSucc( nCol, nRow ); SdrUndoGroup* pUndo = NULL; if (bUndo) pUndo = pModel->GetCalcUndo(); if (bDone) { ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDSUCC ); rDoc.AddDetectiveOperation( aOperation ); if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); } aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate( SID_DETECTIVE_REFRESH ); } else delete pUndo; return bDone; } bool ScDocFunc::DetectiveDelSucc(const ScAddress& rPos) { ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); ScDrawLayer* pModel = rDoc.GetDrawLayer(); if (!pModel) return false; ScDocShellModificator aModificator( rDocShell ); SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if (bUndo) pModel->BeginCalcUndo(false); bool bDone = ScDetectiveFunc( &rDoc,nTab ).DeleteSucc( nCol, nRow ); SdrUndoGroup* pUndo = NULL; if (bUndo) pUndo = pModel->GetCalcUndo(); if (bDone) { ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELSUCC ); rDoc.AddDetectiveOperation( aOperation ); if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); } aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate( SID_DETECTIVE_REFRESH ); } else delete pUndo; return bDone; } bool ScDocFunc::DetectiveAddError(const ScAddress& rPos) { ScDocShellModificator aModificator( rDocShell ); rDocShell.MakeDrawLayer(); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); ScDrawLayer* pModel = rDoc.GetDrawLayer(); SCCOL nCol = rPos.Col(); SCROW nRow = rPos.Row(); SCTAB nTab = rPos.Tab(); if (bUndo) pModel->BeginCalcUndo(false); bool bDone = ScDetectiveFunc( &rDoc,nTab ).ShowError( nCol, nRow ); SdrUndoGroup* pUndo = NULL; if (bUndo) pUndo = pModel->GetCalcUndo(); if (bDone) { ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDERROR ); rDoc.AddDetectiveOperation( aOperation ); if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); } aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate( SID_DETECTIVE_REFRESH ); } else delete pUndo; return bDone; } bool ScDocFunc::DetectiveMarkInvalid(SCTAB nTab) { ScDocShellModificator aModificator( rDocShell ); rDocShell.MakeDrawLayer(); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); ScDrawLayer* pModel = rDoc.GetDrawLayer(); vcl::Window* pWaitWin = rDocShell.GetActiveDialogParent(); if (pWaitWin) pWaitWin->EnterWait(); if (bUndo) pModel->BeginCalcUndo(false); bool bOverflow; bool bDone = ScDetectiveFunc( &rDoc,nTab ).MarkInvalid( bOverflow ); SdrUndoGroup* pUndo = NULL; if (bUndo) pUndo = pModel->GetCalcUndo(); if (pWaitWin) pWaitWin->LeaveWait(); if (bDone) { if (pUndo && bUndo) { pUndo->SetComment( ScGlobal::GetRscString( STR_UNDO_DETINVALID ) ); rDocShell.GetUndoManager()->AddUndoAction( pUndo ); } aModificator.SetDocumentModified(); if ( bOverflow ) { InfoBox( NULL, ScGlobal::GetRscString( STR_DETINVALID_OVERFLOW ) ).Execute(); } } else delete pUndo; return bDone; } bool ScDocFunc::DetectiveDelAll(SCTAB nTab) { ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); ScDrawLayer* pModel = rDoc.GetDrawLayer(); if (!pModel) return false; ScDocShellModificator aModificator( rDocShell ); if (bUndo) pModel->BeginCalcUndo(false); bool bDone = ScDetectiveFunc( &rDoc,nTab ).DeleteAll( SC_DET_DETECTIVE ); SdrUndoGroup* pUndo = NULL; if (bUndo) pUndo = pModel->GetCalcUndo(); if (bDone) { ScDetOpList* pOldList = rDoc.GetDetOpList(); ScDetOpList* pUndoList = NULL; if (bUndo) pUndoList = pOldList ? new ScDetOpList(*pOldList) : NULL; rDoc.ClearDetectiveOperations(); if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDetective( &rDocShell, pUndo, NULL, pUndoList ) ); } aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate( SID_DETECTIVE_REFRESH ); } else delete pUndo; return bDone; } bool ScDocFunc::DetectiveRefresh( bool bAutomatic ) { bool bDone = false; ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); ScDetOpList* pList = rDoc.GetDetOpList(); if ( pList && pList->Count() ) { rDocShell.MakeDrawLayer(); ScDrawLayer* pModel = rDoc.GetDrawLayer(); if (bUndo) pModel->BeginCalcUndo(false); // Loeschen auf allen Tabellen SCTAB nTabCount = rDoc.GetTableCount(); for (SCTAB nTab=0; nTabCount(); for (size_t i=0; i < nCount; ++i) { const ScDetOpData* pData = pList->GetObject(i); if (pData) { ScAddress aPos = pData->GetPos(); ScDetectiveFunc aFunc( &rDoc, aPos.Tab() ); SCCOL nCol = aPos.Col(); SCROW nRow = aPos.Row(); switch (pData->GetOperation()) { case SCDETOP_ADDSUCC: aFunc.ShowSucc( nCol, nRow ); break; case SCDETOP_DELSUCC: aFunc.DeleteSucc( nCol, nRow ); break; case SCDETOP_ADDPRED: aFunc.ShowPred( nCol, nRow ); break; case SCDETOP_DELPRED: aFunc.DeletePred( nCol, nRow ); break; case SCDETOP_ADDERROR: aFunc.ShowError( nCol, nRow ); break; default: OSL_FAIL("falsche Op bei DetectiveRefresh"); } } } if (bUndo) { SdrUndoGroup* pUndo = pModel->GetCalcUndo(); if (pUndo) { pUndo->SetComment( ScGlobal::GetRscString( STR_UNDO_DETREFRESH ) ); // wenn automatisch, an letzte Aktion anhaengen rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDraw( pUndo, &rDocShell ), bAutomatic ); } } rDocShell.SetDrawModified(); bDone = true; } return bDone; } static void lcl_collectAllPredOrSuccRanges( const ScRangeList& rSrcRanges, vector& rRefTokens, ScDocShell& rDocShell, bool bPred) { ScDocument& rDoc = rDocShell.GetDocument(); vector aRefTokens; ScRangeList aSrcRanges(rSrcRanges); if (aSrcRanges.empty()) return; ScRange* p = aSrcRanges.front(); ScDetectiveFunc aDetFunc(&rDoc, p->aStart.Tab()); ScRangeList aDestRanges; for (size_t i = 0, n = aSrcRanges.size(); i < n; ++i) { p = aSrcRanges[i]; if (bPred) { aDetFunc.GetAllPreds( p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), aRefTokens); } else { aDetFunc.GetAllSuccs( p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), aRefTokens); } } rRefTokens.swap(aRefTokens); } void ScDocFunc::DetectiveCollectAllPreds(const ScRangeList& rSrcRanges, vector& rRefTokens) { lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, true); } void ScDocFunc::DetectiveCollectAllSuccs(const ScRangeList& rSrcRanges, vector& rRefTokens) { lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, false); } bool ScDocFunc::DeleteContents( const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) { OSL_FAIL("ScDocFunc::DeleteContents ohne Markierung"); return false; } ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScEditableTester aTester( &rDoc, rMark ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } ScRange aMarkRange; ScMarkData aMultiMark = rMark; aMultiMark.SetMarking(false); // fuer MarkToMulti ScDocument* pUndoDoc = NULL; bool bMulti = aMultiMark.IsMultiMarked(); aMultiMark.MarkToMulti(); aMultiMark.GetMultiMarkArea( aMarkRange ); ScRange aExtendedRange(aMarkRange); if ( rDoc.ExtendMerge( aExtendedRange, true ) ) bMulti = false; // no objects on protected tabs bool bObjects = (nFlags & IDF_OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark); sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted if ( nFlags & IDF_ATTRIB ) rDocShell.UpdatePaintExt( nExtFlags, aMarkRange ); // Reihenfolge: // 1) BeginDrawUndo // 2) Objekte loeschen (DrawUndo wird gefuellt) // 3) Inhalte fuer Undo kopieren und Undo-Aktion anlegen // 4) Inhalte loeschen bool bDrawUndo = bObjects || (nFlags & IDF_NOTE); if (bRecord && bDrawUndo) rDoc.BeginDrawUndo(); if (bObjects) { if (bMulti) rDoc.DeleteObjectsInSelection( aMultiMark ); else rDoc.DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), aMultiMark ); } // To keep track of all non-empty cells within the deleted area. boost::shared_ptr pDataSpans; if ( bRecord ) { pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, aMultiMark, aMarkRange, nFlags, bMulti); pDataSpans.reset(sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, aMultiMark, aMarkRange)); } rDoc.DeleteSelection( nFlags, aMultiMark ); // add undo action after drawing undo is complete (objects and note captions) if( bRecord ) { sc::DocFuncUtil::addDeleteContentsUndo( rDocShell.GetUndoManager(), &rDocShell, aMultiMark, aExtendedRange, pUndoDoc, nFlags, pDataSpans, bMulti, bDrawUndo); } if (!AdjustRowHeight( aExtendedRange )) rDocShell.PostPaint( aExtendedRange, PAINT_GRID, nExtFlags ); else if (nExtFlags & SC_PF_LINES) lcl_PaintAbove( rDocShell, aExtendedRange ); // fuer Linien ueber dem Bereich aModificator.SetDocumentModified(); return true; } bool ScDocFunc::DeleteCell( const ScAddress& rPos, const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi ) { ScDocShellModificator aModificator(rDocShell); ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScEditableTester aTester(&rDoc, rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } // no objects on protected tabs bool bObjects = (nFlags & IDF_OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark); sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted if (nFlags & IDF_ATTRIB) rDocShell.UpdatePaintExt(nExtFlags, rPos); // order op opeeration: // 1) BeginDrawUndo // 2) delete objects (DrawUndo is filled) // 3) copy contents for undo // 4) delete contents // 5) add undo-action bool bDrawUndo = bObjects || (nFlags & IDF_NOTE); // needed for shown notes if (bDrawUndo && bRecord) rDoc.BeginDrawUndo(); if (bObjects) rDoc.DeleteObjectsInArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark); // To keep track of all non-empty cells within the deleted area. boost::shared_ptr pDataSpans; ScDocument* pUndoDoc = NULL; if (bRecord) { pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, rMark, rPos, nFlags, false); pDataSpans.reset(sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, rMark, rPos)); } rDoc.DeleteArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark, nFlags); if (bRecord) { sc::DocFuncUtil::addDeleteContentsUndo( rDocShell.GetUndoManager(), &rDocShell, rMark, rPos, pUndoDoc, nFlags, pDataSpans, false, bDrawUndo); } if (!AdjustRowHeight(rPos)) rDocShell.PostPaint( rPos.Col(), rPos.Row(), rPos.Tab(), rPos.Col(), rPos.Row(), rPos.Tab(), PAINT_GRID, nExtFlags); aModificator.SetDocumentModified(); return true; } bool ScDocFunc::TransliterateText( const ScMarkData& rMark, sal_Int32 nType, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScEditableTester aTester( &rDoc, rMark ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } ScRange aMarkRange; ScMarkData aMultiMark = rMark; aMultiMark.SetMarking(false); // for MarkToMulti aMultiMark.MarkToMulti(); aMultiMark.GetMultiMarkArea( aMarkRange ); if (bRecord) { SCTAB nStartTab = aMarkRange.aStart.Tab(); SCTAB nTabCount = rDoc.GetTableCount(); ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab ); ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) if (*itr != nStartTab) pUndoDoc->AddUndoTab( *itr, *itr ); ScRange aCopyRange = aMarkRange; aCopyRange.aStart.SetTab(0); aCopyRange.aEnd.SetTab(nTabCount-1); rDoc.CopyToDocument( aCopyRange, IDF_CONTENTS, true, pUndoDoc, &aMultiMark ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoTransliterate( &rDocShell, aMultiMark, pUndoDoc, nType ) ); } rDoc.TransliterateText( aMultiMark, nType ); if (!AdjustRowHeight( aMarkRange )) rDocShell.PostPaint( aMarkRange, PAINT_GRID ); aModificator.SetDocumentModified(); return true; } bool ScDocFunc::SetNormalString( bool& o_rbNumFmtSet, const ScAddress& rPos, const OUString& rText, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo(rDoc.IsUndoEnabled()); ScEditableTester aTester( &rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } bool bEditDeleted = (rDoc.GetCellType(rPos) == CELLTYPE_EDIT); ScUndoEnterData::ValuesType aOldValues; if (bUndo) { ScUndoEnterData::Value aOldValue; aOldValue.mnTab = rPos.Tab(); aOldValue.maCell.assign(rDoc, rPos); const SfxPoolItem* pItem; const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(),rPos.Row(),rPos.Tab() ); if ( SfxItemState::SET == pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT,false,&pItem) ) { aOldValue.mbHasFormat = true; aOldValue.mnFormat = static_cast(pItem)->GetValue(); } else aOldValue.mbHasFormat = false; aOldValues.push_back(aOldValue); } o_rbNumFmtSet = rDoc.SetString( rPos.Col(), rPos.Row(), rPos.Tab(), rText ); if (bUndo) { // wegen ChangeTracking darf UndoAction erst nach SetString angelegt werden rDocShell.GetUndoManager()->AddUndoAction( new ScUndoEnterData(&rDocShell, rPos, aOldValues, rText, NULL)); } if ( bEditDeleted || rDoc.HasAttrib( ScRange(rPos), HASATTR_NEEDHEIGHT ) ) AdjustRowHeight( ScRange(rPos) ); rDocShell.PostPaintCell( rPos ); aModificator.SetDocumentModified(); // notify input handler here the same way as in PutCell if (bApi) NotifyInputHandler( rPos ); return true; } bool ScDocFunc::SetValueCell( const ScAddress& rPos, double fVal, bool bInteraction ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo = rDoc.IsUndoEnabled(); bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT); ScCellValue aOldVal; if (bUndo) aOldVal.assign(rDoc, rPos); rDoc.SetValue(rPos, fVal); if (bUndo) { svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager(); ScCellValue aNewVal; aNewVal.assign(rDoc, rPos); pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal)); } if (bHeight) AdjustRowHeight(rPos); rDocShell.PostPaintCell( rPos ); aModificator.SetDocumentModified(); // #103934#; notify editline and cell in edit mode if (!bInteraction) NotifyInputHandler( rPos ); return true; } bool ScDocFunc::SetValueCells( const ScAddress& rPos, const std::vector& aVals, bool bInteraction ) { // Check for invalid range. SCROW nLastRow = rPos.Row() + aVals.size() - 1; if (nLastRow > MAXROW) // out of bound. return false; ScRange aRange(rPos); aRange.aEnd.SetRow(nLastRow); ScDocShellModificator aModificator(rDocShell); ScDocument& rDoc = rDocShell.GetDocument(); if (rDoc.IsUndoEnabled()) { sc::UndoSetCells* pUndoObj = new sc::UndoSetCells(&rDocShell, rPos); rDoc.TransferCellValuesTo(rPos, aVals.size(), pUndoObj->GetOldValues()); pUndoObj->SetNewValues(aVals); svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager(); pUndoMgr->AddUndoAction(pUndoObj); } rDoc.SetValues(rPos, aVals); rDocShell.PostPaint(aRange, PAINT_GRID); aModificator.SetDocumentModified(); // #103934#; notify editline and cell in edit mode if (!bInteraction) NotifyInputHandler(rPos); return true; } bool ScDocFunc::SetStringCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo = rDoc.IsUndoEnabled(); bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT); ScCellValue aOldVal; if (bUndo) aOldVal.assign(rDoc, rPos); ScSetStringParam aParam; aParam.setTextInput(); rDoc.SetString(rPos, rStr, &aParam); if (bUndo) { svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager(); ScCellValue aNewVal; aNewVal.assign(rDoc, rPos); pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal)); } if (bHeight) AdjustRowHeight(rPos); rDocShell.PostPaintCell( rPos ); aModificator.SetDocumentModified(); // #103934#; notify editline and cell in edit mode if (!bInteraction) NotifyInputHandler( rPos ); return true; } bool ScDocFunc::SetEditCell( const ScAddress& rPos, const EditTextObject& rStr, bool bInteraction ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo = rDoc.IsUndoEnabled(); bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT); ScCellValue aOldVal; if (bUndo) aOldVal.assign(rDoc, rPos); rDoc.SetEditText(rPos, rStr.Clone()); if (bUndo) { svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager(); ScCellValue aNewVal; aNewVal.assign(rDoc, rPos); pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal)); } if (bHeight) AdjustRowHeight(rPos); rDocShell.PostPaintCell( rPos ); aModificator.SetDocumentModified(); // #103934#; notify editline and cell in edit mode if (!bInteraction) NotifyInputHandler( rPos ); return true; } bool ScDocFunc::SetStringOrEditCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction ) { ScDocument& rDoc = rDocShell.GetDocument(); if (ScStringUtil::isMultiline(rStr)) { ScFieldEditEngine& rEngine = rDoc.GetEditEngine(); rEngine.SetText(rStr); boost::scoped_ptr pEditText(rEngine.CreateTextObject()); return SetEditCell(rPos, *pEditText, bInteraction); } else return SetStringCell(rPos, rStr, bInteraction); } bool ScDocFunc::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell, bool bInteraction ) { std::unique_ptr xCell(pCell); ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo = rDoc.IsUndoEnabled(); bool bHeight = rDoc.HasAttrib(rPos, HASATTR_NEEDHEIGHT); ScCellValue aOldVal; if (bUndo) aOldVal.assign(rDoc, rPos); pCell = rDoc.SetFormulaCell(rPos, xCell.release()); // For performance reasons API calls may disable calculation while // operating and recalculate once when done. If through user interaction // and AutoCalc is disabled, calculate the formula (without its // dependencies) once so the result matches the current document's content. if (bInteraction && !rDoc.GetAutoCalc() && pCell) { // calculate just the cell once and set Dirty again pCell->Interpret(); pCell->SetDirtyVar(); rDoc.PutInFormulaTree( pCell); } if (bUndo) { svl::IUndoManager* pUndoMgr = rDocShell.GetUndoManager(); ScCellValue aNewVal; aNewVal.assign(rDoc, rPos); pUndoMgr->AddUndoAction(new ScUndoSetCell(&rDocShell, rPos, aOldVal, aNewVal)); } if (bHeight) AdjustRowHeight(rPos); rDocShell.PostPaintCell( rPos ); aModificator.SetDocumentModified(); // #103934#; notify editline and cell in edit mode if (!bInteraction) NotifyInputHandler( rPos ); return true; } void ScDocFunc::NotifyInputHandler( const ScAddress& rPos ) { ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); if ( pViewSh && pViewSh->GetViewData().GetDocShell() == &rDocShell ) { ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(); if ( pInputHdl && pInputHdl->GetCursorPos() == rPos ) { bool bIsEditMode(pInputHdl->IsEditMode()); // set modified if in editmode, because so the string is not set in the InputWindow like in the cell // (the cell shows the same like the InputWindow) if (bIsEditMode) pInputHdl->SetModified(); pViewSh->UpdateInputHandler(false, !bIsEditMode); } } } struct ScMyRememberItem { sal_Int32 nIndex; SfxItemSet aItemSet; ScMyRememberItem(const SfxItemSet& rItemSet, sal_Int32 nTempIndex) : nIndex(nTempIndex), aItemSet(rItemSet) {} }; typedef ::std::list ScMyRememberItemList; bool ScDocFunc::PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, bool bApi ) { // PutData ruft PutCell oder SetNormalString bool bRet = false; ScDocument& rDoc = rDocShell.GetDocument(); ScEditAttrTester aTester( &rEngine ); bool bEditCell = aTester.NeedsObject(); if ( bEditCell ) { // #i61702# With bLoseContent set, the content of rEngine isn't restored // (used in loading XML, where after the removeActionLock call the API object's // EditEngine isn't accessed again. bool bLoseContent = rDoc.IsImportingXML(); bool bUpdateMode(rEngine.GetUpdateMode()); if (bUpdateMode) rEngine.SetUpdateMode(false); ScMyRememberItemList aRememberItems; ScMyRememberItem* pRememberItem = NULL; // All paragraph attributes must be removed before calling CreateTextObject, // not only alignment, so the object doesn't contain the cell attributes as // paragraph attributes. Before remove the attributes store they in a list to // set they back to the EditEngine. sal_Int32 nCount = rEngine.GetParagraphCount(); for (sal_Int32 i=0; i pNewData(rEngine.CreateTextObject()); bRet = SetEditCell(rPos, *pNewData, !bApi); // Set the paragraph attributes back to the EditEngine. if (!aRememberItems.empty()) { ScMyRememberItemList::iterator aItr = aRememberItems.begin(); while (aItr != aRememberItems.end()) { pRememberItem = *aItr; rEngine.SetParaAttribs(pRememberItem->nIndex, pRememberItem->aItemSet); delete pRememberItem; aItr = aRememberItems.erase(aItr); } } // #i61702# if the content isn't accessed, there's no need to set the UpdateMode again if ( bUpdateMode && !bLoseContent ) rEngine.SetUpdateMode(true); } else { OUString aText = rEngine.GetText(); if (aText.isEmpty()) { bool bNumFmtSet = false; bRet = SetNormalString( bNumFmtSet, rPos, aText, bApi ); } else bRet = SetStringCell(rPos, aText, !bApi); } if ( bRet && aTester.NeedsCellAttr() ) { const SfxItemSet& rEditAttr = aTester.GetAttribs(); ScPatternAttr aPattern( rDoc.GetPool() ); aPattern.GetFromEditItemSet( &rEditAttr ); aPattern.DeleteUnchanged( rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() ) ); aPattern.GetItemSet().ClearItem( ATTR_HOR_JUSTIFY ); // wasn't removed above if no edit object if ( aPattern.GetItemSet().Count() > 0 ) { ScMarkData aMark; aMark.SelectTable( rPos.Tab(), true ); aMark.SetMarkArea( ScRange( rPos ) ); ApplyAttributes( aMark, aPattern, true, bApi ); } } return bRet; } static ScTokenArray* lcl_ScDocFunc_CreateTokenArrayXML( const OUString& rText, const OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { ScTokenArray* pCode = new ScTokenArray; pCode->AddStringXML( rText ); if( (eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) && (!rFormulaNmsp.isEmpty()) ) pCode->AddStringXML( rFormulaNmsp ); return pCode; } bool ScDocFunc::SetCellText( const ScAddress& rPos, const OUString& rText, bool bInterpret, bool bEnglish, bool bApi, const formula::FormulaGrammar::Grammar eGrammar ) { bool bSet = false; if ( bInterpret ) { if ( bEnglish ) { ScDocument& rDoc = rDocShell.GetDocument(); ::boost::scoped_ptr pExtRefGuard; if (bApi) pExtRefGuard.reset(new ScExternalRefManager::ApiGuard(&rDoc)); ScInputStringType aRes = ScStringUtil::parseInputString(*rDoc.GetFormatTable(), rText, LANGUAGE_ENGLISH_US); switch (aRes.meType) { case ScInputStringType::Formula: bSet = SetFormulaCell(rPos, new ScFormulaCell(&rDoc, rPos, aRes.maText, eGrammar), !bApi); break; case ScInputStringType::Number: bSet = SetValueCell(rPos, aRes.mfValue, !bApi); break; case ScInputStringType::Text: bSet = SetStringOrEditCell(rPos, aRes.maText, !bApi); break; default: ; } } // sonst Null behalten -> SetString mit lokalen Formeln/Zahlformat } else if (!rText.isEmpty()) { bSet = SetStringOrEditCell(rPos, rText, !bApi); } if (!bSet) { bool bNumFmtSet = false; bSet = SetNormalString( bNumFmtSet, rPos, rText, bApi ); } return bSet; } bool ScDocFunc::ShowNote( const ScAddress& rPos, bool bShow ) { ScDocument& rDoc = rDocShell.GetDocument(); ScPostIt* pNote = rDoc.GetNote( rPos ); if( !pNote || (bShow == pNote->IsCaptionShown()) ) return false; // move the caption to internal or hidden layer and create undo action pNote->ShowCaption( rPos, bShow ); if( rDoc.IsUndoEnabled() ) rDocShell.GetUndoManager()->AddUndoAction( new ScUndoShowHideNote( rDocShell, rPos, bShow ) ); if (rDoc.IsStreamValid(rPos.Tab())) rDoc.SetStreamValid(rPos.Tab(), false); rDocShell.SetDocumentModified(); return true; } bool ScDocFunc::SetNoteText( const ScAddress& rPos, const OUString& rText, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); ScEditableTester aTester( &rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } OUString aNewText = convertLineEnd(rText, GetSystemLineEnd()); //! ist das noetig ??? if( ScPostIt* pNote = (!aNewText.isEmpty()) ? rDoc.GetOrCreateNote( rPos ) : rDoc.GetNote(rPos) ) pNote->SetText( rPos, aNewText ); //! Undo !!! if (rDoc.IsStreamValid(rPos.Tab())) rDoc.SetStreamValid(rPos.Tab(), false); rDocShell.PostPaintCell( rPos ); aModificator.SetDocumentModified(); return true; } bool ScDocFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate, bool bApi ) { bool bDone = false; ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); ScEditableTester aTester( &rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); if (aTester.IsEditable()) { ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); ::svl::IUndoManager* pUndoMgr = (pDrawLayer && rDoc.IsUndoEnabled()) ? rDocShell.GetUndoManager() : 0; ScNoteData aOldData; ScPostIt* pOldNote = rDoc.ReleaseNote( rPos ); if( pOldNote ) { // ensure existing caption object before draw undo tracking starts pOldNote->GetOrCreateCaption( rPos ); // rescue note data for undo aOldData = pOldNote->GetNoteData(); } // collect drawing undo actions for deleting/inserting caption objects if( pUndoMgr ) pDrawLayer->BeginCalcUndo(false); // delete the note (creates drawing undo action for the caption object) delete pOldNote; // create new note (creates drawing undo action for the new caption object) ScNoteData aNewData; if( ScPostIt* pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true ) ) { if( pAuthor ) pNewNote->SetAuthor( *pAuthor ); if( pDate ) pNewNote->SetDate( *pDate ); // rescue note data for undo aNewData = pNewNote->GetNoteData(); } // create the undo action if( pUndoMgr && (aOldData.mpCaption || aNewData.mpCaption) ) pUndoMgr->AddUndoAction( new ScUndoReplaceNote( rDocShell, rPos, aOldData, aNewData, pDrawLayer->GetCalcUndo() ) ); // repaint cell (to make note marker visible) rDocShell.PostPaintCell( rPos ); if (rDoc.IsStreamValid(rPos.Tab())) rDoc.SetStreamValid(rPos.Tab(), false); aModificator.SetDocumentModified(); bDone = true; } else if (!bApi) { rDocShell.ErrorMessage(aTester.GetMessageId()); } return bDone; } bool ScDocFunc::ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern, bool bRecord, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); if ( bRecord && !rDoc.IsUndoEnabled() ) bRecord = false; bool bImportingXML = rDoc.IsImportingXML(); // Cell formats can still be set if the range isn't editable only because of matrix formulas. // #i62483# When loading XML, the check can be skipped altogether. bool bOnlyNotBecauseOfMatrix; if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); return false; } ScDocShellModificator aModificator( rDocShell ); //! Umrandung ScRange aMultiRange; bool bMulti = rMark.IsMultiMarked(); if ( bMulti ) rMark.GetMultiMarkArea( aMultiRange ); else rMark.GetMarkArea( aMultiRange ); if ( bRecord ) { ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, aMultiRange.aStart.Tab(), aMultiRange.aEnd.Tab() ); rDoc.CopyToDocument( aMultiRange, IDF_ATTRIB, bMulti, pUndoDoc, &rMark ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoSelectionAttr( &rDocShell, rMark, aMultiRange.aStart.Col(), aMultiRange.aStart.Row(), aMultiRange.aStart.Tab(), aMultiRange.aEnd.Col(), aMultiRange.aEnd.Row(), aMultiRange.aEnd.Tab(), pUndoDoc, bMulti, &rPattern ) ); } // While loading XML it is not necessary to ask HasAttrib. It needs too much time. sal_uInt16 nExtFlags = 0; if ( !bImportingXML ) rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content before the change rDoc.ApplySelectionPattern( rPattern, rMark ); if ( !bImportingXML ) rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content after the change if (!AdjustRowHeight( aMultiRange )) rDocShell.PostPaint( aMultiRange, PAINT_GRID, nExtFlags ); else if (nExtFlags & SC_PF_LINES) lcl_PaintAbove( rDocShell, aMultiRange ); // fuer Linien ueber dem Bereich aModificator.SetDocumentModified(); return true; } bool ScDocFunc::ApplyStyle( const ScMarkData& rMark, const OUString& rStyleName, bool bRecord, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); if ( bRecord && !rDoc.IsUndoEnabled() ) bRecord = false; bool bImportingXML = rDoc.IsImportingXML(); // Cell formats can still be set if the range isn't editable only because of matrix formulas. // #i62483# When loading XML, the check can be skipped altogether. bool bOnlyNotBecauseOfMatrix; if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); return false; } ScStyleSheet* pStyleSheet = static_cast( rDoc.GetStyleSheetPool()->Find( rStyleName, SFX_STYLE_FAMILY_PARA )); if (!pStyleSheet) return false; ScDocShellModificator aModificator( rDocShell ); ScRange aMultiRange; bool bMulti = rMark.IsMultiMarked(); if ( bMulti ) rMark.GetMultiMarkArea( aMultiRange ); else rMark.GetMarkArea( aMultiRange ); if ( bRecord ) { ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); SCTAB nStartTab = aMultiRange.aStart.Tab(); SCTAB nTabCount = rDoc.GetTableCount(); pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab ); ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) if (*itr != nStartTab) pUndoDoc->AddUndoTab( *itr, *itr ); ScRange aCopyRange = aMultiRange; aCopyRange.aStart.SetTab(0); aCopyRange.aEnd.SetTab(nTabCount-1); rDoc.CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &rMark ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoSelectionStyle( &rDocShell, rMark, aMultiRange, rStyleName, pUndoDoc ) ); } rDoc.ApplySelectionStyle( (ScStyleSheet&)*pStyleSheet, rMark ); if (!AdjustRowHeight( aMultiRange )) rDocShell.PostPaint( aMultiRange, PAINT_GRID, 0 ); aModificator.SetDocumentModified(); return true; } namespace { /** * Check if this insertion attempt would end up cutting one or more pivot * tables in half, which is not desirable. * * @return true if this insertion can be done safely without shearing any * existing pivot tables, false otherwise. */ bool canInsertCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, InsCellCmd eCmd, const ScDocument* pDoc) { if (!pDoc->HasPivotTable()) // This document has no pivot tables. return true; const ScDPCollection* pDPs = pDoc->GetDPCollection(); ScMarkData::const_iterator itBeg = rMarkData.begin(), itEnd = rMarkData.end(); ScRange aRange(rRange); // local copy switch (eCmd) { case INS_INSROWS: { aRange.aStart.SetCol(0); aRange.aEnd.SetCol(MAXCOL); // Continue below. } case INS_CELLSDOWN: { for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { if (pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), *it)) // This column range cuts through at least one pivot table. Not good. return false; } // Start row must be either at the top or above any pivot tables. if (aRange.aStart.Row() < 0) // I don't know how to handle this case. return false; if (aRange.aStart.Row() == 0) // First row is always allowed. return true; ScRange aTest(aRange); aTest.aStart.IncRow(-1); // Test one row up. aTest.aEnd.SetRow(aTest.aStart.Row()); for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { aTest.aStart.SetTab(*it); aTest.aEnd.SetTab(*it); if (pDPs->HasTable(aTest)) return false; } } break; case INS_INSCOLS: { aRange.aStart.SetRow(0); aRange.aEnd.SetRow(MAXROW); // Continue below. } case INS_CELLSRIGHT: { for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { if (pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), *it)) // This column range cuts through at least one pivot table. Not good. return false; } // Start row must be either at the top or above any pivot tables. if (aRange.aStart.Col() < 0) // I don't know how to handle this case. return false; if (aRange.aStart.Col() == 0) // First row is always allowed. return true; ScRange aTest(aRange); aTest.aStart.IncCol(-1); // Test one column to the left. aTest.aEnd.SetCol(aTest.aStart.Col()); for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { aTest.aStart.SetTab(*it); aTest.aEnd.SetTab(*it); if (pDPs->HasTable(aTest)) return false; } } break; default: ; } return true; } /** * Check if this deletion attempt would end up cutting one or more pivot * tables in half, which is not desirable. * * @return true if this deletion can be done safely without shearing any * existing pivot tables, false otherwise. */ bool canDeleteCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, DelCellCmd eCmd, const ScDocument* pDoc) { if (!pDoc->HasPivotTable()) // This document has no pivot tables. return true; const ScDPCollection* pDPs = pDoc->GetDPCollection(); ScMarkData::const_iterator itBeg = rMarkData.begin(), itEnd = rMarkData.end(); ScRange aRange(rRange); // local copy switch (eCmd) { case DEL_DELROWS: { aRange.aStart.SetCol(0); aRange.aEnd.SetCol(MAXCOL); // Continue below. } case DEL_CELLSUP: { for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { if (pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), *it)) // This column range cuts through at least one pivot table. Not good. return false; } ScRange aTest(aRange); for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { aTest.aStart.SetTab(*it); aTest.aEnd.SetTab(*it); if (pDPs->HasTable(aTest)) return false; } } break; case DEL_DELCOLS: { aRange.aStart.SetRow(0); aRange.aEnd.SetRow(MAXROW); // Continue below. } case DEL_CELLSLEFT: { for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { if (pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), *it)) // This column range cuts through at least one pivot table. Not good. return false; } ScRange aTest(aRange); for (ScMarkData::const_iterator it = itBeg; it != itEnd; ++it) { aTest.aStart.SetTab(*it); aTest.aEnd.SetTab(*it); if (pDPs->HasTable(aTest)) return false; } } break; default: ; } return true; } } bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, InsCellCmd eCmd, bool bRecord, bool bApi, bool bPartOfPaste ) { ScDocShellModificator aModificator( rDocShell ); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCTAB nStartTab = rRange.aStart.Tab(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nEndTab = rRange.aEnd.Tab(); if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) ) { OSL_FAIL("invalid row in InsertCells"); return false; } ScDocument& rDoc = rDocShell.GetDocument(); SCTAB nTabCount = rDoc.GetTableCount(); SCCOL nPaintStartCol = nStartCol; SCROW nPaintStartRow = nStartRow; SCCOL nPaintEndCol = nEndCol; SCROW nPaintEndRow = nEndRow; sal_uInt16 nPaintFlags = PAINT_GRID; bool bSuccess; SCTAB i; ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); //preserve current cursor position SCCOL nCursorCol = 0; SCROW nCursorRow = 0; if( pViewSh ) { nCursorCol = pViewSh->GetViewData().GetCurX(); nCursorRow = pViewSh->GetViewData().GetCurY(); } if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { SCTAB nCount = 0; for( i=0; iInitUndo( &rDoc, 0, nTabCount-1, false, false ); // pRefUndoDoc is filled in InsertCol / InsertRow pUndoData = new ScRefUndoData( &rDoc ); rDoc.BeginDrawUndo(); } // #i8302 : we unmerge overwhelming ranges, before insertion all the actions are put in the same ListAction // the patch comes from mloiseleur and maoyg bool bInsertMerge = false; std::vector qIncreaseRange; OUString aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTCELLS ); if (bRecord) rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); itr = aMark.begin(); for (; itr != itrEnd && nTabCount; ++itr) { i = *itr; if( rDoc.HasAttrib( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) { if (eCmd==INS_CELLSRIGHT) bNeedRefresh = true; SCCOL nMergeStartCol = nMergeTestStartCol; SCROW nMergeStartRow = nMergeTestStartRow; SCCOL nMergeEndCol = nMergeTestEndCol; SCROW nMergeEndRow = nMergeTestEndRow; rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); if(( eCmd == INS_CELLSDOWN && ( nMergeStartCol != nMergeTestStartCol || nMergeEndCol != nMergeTestEndCol )) || (eCmd == INS_CELLSRIGHT && ( nMergeStartRow != nMergeTestStartRow || nMergeEndRow != nMergeTestEndRow )) ) { if (!bApi) rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); rDocShell.GetUndoManager()->LeaveListAction(); delete pUndoData; return false; } SCCOL nTestCol = -1; SCROW nTestRow1 = -1; SCROW nTestRow2 = -1; ScDocAttrIterator aTestIter( &rDoc, i, nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow ); ScRange aExtendRange( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i ); const ScPatternAttr* pPattern = NULL; const ScMergeAttr* pMergeFlag = NULL; const ScMergeFlagAttr* pMergeFlagAttr = NULL; while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != NULL ) { pMergeFlag = static_cast( &pPattern->GetItem(ATTR_MERGE) ); pMergeFlagAttr = static_cast( &pPattern->GetItem(ATTR_MERGE_FLAG) ); sal_Int16 nNewFlags = pMergeFlagAttr->GetValue() & ( SC_MF_HOR | SC_MF_VER ); if( ( pMergeFlag && pMergeFlag->IsMerged() ) || nNewFlags == SC_MF_HOR || nNewFlags == SC_MF_VER ) { ScRange aRange( nTestCol, nTestRow1, i ); rDoc.ExtendOverlapped(aRange); rDoc.ExtendMerge(aRange, true); if( nTestRow1 < nTestRow2 && nNewFlags == SC_MF_HOR ) { for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ ) { ScRange aTestRange( nTestCol, nTestRow, i ); rDoc.ExtendOverlapped( aTestRange ); rDoc.ExtendMerge( aTestRange, true); ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i ); if( !aExtendRange.In( aMergeRange ) ) { qIncreaseRange.push_back( aTestRange ); bInsertMerge = true; } } } else { ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i ); if( !aExtendRange.In( aMergeRange ) ) { qIncreaseRange.push_back( aRange ); } bInsertMerge = true; } } } if( bInsertMerge ) { if( eCmd == INS_INSROWS || eCmd == INS_CELLSDOWN ) { nStartRow = aExtendMergeRange.aStart.Row(); nEndRow = aExtendMergeRange.aEnd.Row(); if( eCmd == INS_CELLSDOWN ) nEndCol = nMergeTestEndCol; else { nStartCol = 0; nEndCol = MAXCOL; } } else if( eCmd == INS_CELLSRIGHT || eCmd == INS_INSCOLS ) { nStartCol = aExtendMergeRange.aStart.Col(); nEndCol = aExtendMergeRange.aEnd.Col(); if( eCmd == INS_CELLSRIGHT ) { nEndRow = nMergeTestEndRow; } else { nStartRow = 0; nEndRow = MAXROW; } } if( !qIncreaseRange.empty() ) { for( ::std::vector::const_iterator iIter( qIncreaseRange.begin()); iIter != qIncreaseRange.end(); ++iIter ) { ScRange aRange( *iIter ); if( rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) { UnmergeCells( aRange, true ); } } } } else { if (!bApi) rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); rDocShell.GetUndoManager()->LeaveListAction(); delete pUndoData; return false; } } } switch (eCmd) { case INS_CELLSDOWN: bSuccess = rDoc.InsertRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark ); nPaintEndRow = MAXROW; break; case INS_INSROWS: bSuccess = rDoc.InsertRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark ); nPaintStartCol = 0; nPaintEndCol = MAXCOL; nPaintEndRow = MAXROW; nPaintFlags |= PAINT_LEFT; break; case INS_CELLSRIGHT: bSuccess = rDoc.InsertCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark ); nPaintEndCol = MAXCOL; break; case INS_INSCOLS: bSuccess = rDoc.InsertCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark ); nPaintStartRow = 0; nPaintEndRow = MAXROW; nPaintEndCol = MAXCOL; nPaintFlags |= PAINT_TOP; break; default: OSL_FAIL("Falscher Code beim Einfuegen"); bSuccess = false; break; } if ( bSuccess ) { SCTAB* pTabs = NULL; SCTAB* pScenarios = NULL; SCTAB nUndoPos = 0; if ( bRecord ) { pTabs = new SCTAB[nSelCount]; pScenarios = new SCTAB[nSelCount]; nUndoPos = 0; itr = aMark.begin(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { SCTAB nCount = 0; for( SCTAB j=*itr+1; jLeaveListAction(); } rDocShell.GetUndoManager()->AddUndoAction( new ScUndoInsertCells( &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ), nUndoPos, pTabs, pScenarios, eCmd, pRefUndoDoc, pUndoData, bPartOfPaste ) ); } // #i8302 : we remerge growing ranges, with the new part inserted while( !qIncreaseRange.empty() ) { ScRange aRange = qIncreaseRange.back(); if( !rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) { switch (eCmd) { case INS_CELLSDOWN: case INS_INSROWS: aRange.aEnd.IncRow(static_cast(nEndRow-nStartRow+1)); break; case INS_CELLSRIGHT: case INS_INSCOLS: aRange.aEnd.IncCol(static_cast(nEndCol-nStartCol+1)); break; default: break; } ScCellMergeOption aMergeOption( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ); aMergeOption.maTabs.insert(aRange.aStart.Tab()); MergeCells(aMergeOption, false, true, true); } qIncreaseRange.pop_back(); } if( bInsertMerge ) rDocShell.GetUndoManager()->LeaveListAction(); itr = aMark.begin(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { i = *itr; rDoc.SetDrawPageSize(i); if (bNeedRefresh) rDoc.ExtendMerge( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i, true ); else rDoc.RefreshAutoFilter( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i ); if ( eCmd == INS_INSROWS || eCmd == INS_INSCOLS ) rDoc.UpdatePageBreaks( i ); sal_uInt16 nExtFlags = 0; rDocShell.UpdatePaintExt( nExtFlags, nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i ); SCTAB nScenarioCount = 0; for( SCTAB j = i+1; jMarkRange( rRange, false ); pViewSh->SetCursor( nCursorCol, nCursorRow ); } } rDocShell.GetUndoManager()->LeaveListAction(); rDocShell.GetUndoManager()->RemoveLastUndoAction(); delete pRefUndoDoc; delete pUndoData; if (!bApi) rDocShell.ErrorMessage(STR_INSERT_FULL); // Spalte/Zeile voll } aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); return bSuccess; } bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, DelCellCmd eCmd, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCTAB nStartTab = rRange.aStart.Tab(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nEndTab = rRange.aEnd.Tab(); if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) ) { OSL_FAIL("invalid row in DeleteCells"); return false; } ScDocument& rDoc = rDocShell.GetDocument(); SCTAB nTabCount = rDoc.GetTableCount(); SCCOL nPaintStartCol = nStartCol; SCROW nPaintStartRow = nStartRow; SCCOL nPaintEndCol = nEndCol; SCROW nPaintEndRow = nEndRow; sal_uInt16 nPaintFlags = PAINT_GRID; if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { SCTAB nCount = 0; for(SCTAB i=0; i qDecreaseRange; bool bDeletingMerge = false; OUString aUndo = ScGlobal::GetRscString( STR_UNDO_DELETECELLS ); if (bRecord) rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); itr = aMark.begin(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { SCTAB i = *itr; if ( rDoc.HasAttrib( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HASATTR_MERGED | HASATTR_OVERLAPPED )) { SCCOL nMergeStartCol = nUndoStartCol; SCROW nMergeStartRow = nUndoStartRow; SCCOL nMergeEndCol = nMergeTestEndCol; SCROW nMergeEndRow = nMergeTestEndRow; rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i ); if( ( eCmd == DEL_CELLSUP && ( nMergeStartCol != nUndoStartCol || nMergeEndCol != nMergeTestEndCol))|| ( eCmd == DEL_CELLSLEFT && ( nMergeStartRow != nUndoStartRow || nMergeEndRow != nMergeTestEndRow))) { if (!bApi) rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0); rDocShell.GetUndoManager()->LeaveListAction(); return false; } nExtendStartCol = nMergeStartCol; nExtendStartRow = nMergeStartRow; SCCOL nTestCol = -1; SCROW nTestRow1 = -1; SCROW nTestRow2 = -1; ScDocAttrIterator aTestIter( &rDoc, i, nUndoStartCol, nUndoStartRow, nMergeTestEndCol, nMergeTestEndRow ); ScRange aExtendRange( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i ); const ScPatternAttr* pPattern = NULL; const ScMergeAttr* pMergeFlag = NULL; const ScMergeFlagAttr* pMergeFlagAttr = NULL; while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != NULL ) { pMergeFlag = static_cast( &pPattern->GetItem( ATTR_MERGE ) ); pMergeFlagAttr = static_cast( &pPattern->GetItem( ATTR_MERGE_FLAG ) ); sal_Int16 nNewFlags = pMergeFlagAttr->GetValue() & ( SC_MF_HOR | SC_MF_VER ); if( ( pMergeFlag && pMergeFlag->IsMerged() ) || nNewFlags == SC_MF_HOR || nNewFlags == SC_MF_VER ) { ScRange aRange( nTestCol, nTestRow1, i ); rDoc.ExtendOverlapped( aRange ); rDoc.ExtendMerge( aRange, true ); if( nTestRow1 < nTestRow2 && nNewFlags == SC_MF_HOR ) { for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ ) { ScRange aTestRange( nTestCol, nTestRow, i ); rDoc.ExtendOverlapped( aTestRange ); rDoc.ExtendMerge( aTestRange, true ); ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i ); if( !aExtendRange.In( aMergeRange ) ) { qDecreaseRange.push_back( aTestRange ); bDeletingMerge = true; } } } else { ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i ); if( !aExtendRange.In( aMergeRange ) ) { qDecreaseRange.push_back( aRange ); } bDeletingMerge = true; } } } if( bDeletingMerge ) { if( eCmd == DEL_DELROWS || eCmd == DEL_CELLSUP ) { nStartRow = aExtendMergeRange.aStart.Row(); nEndRow = aExtendMergeRange.aEnd.Row(); bNeedRefresh = true; if( eCmd == DEL_CELLSUP ) { nEndCol = aExtendMergeRange.aEnd.Col(); } else { nStartCol = 0; nEndCol = MAXCOL; } } else if( eCmd == DEL_CELLSLEFT || eCmd == DEL_DELCOLS ) { nStartCol = aExtendMergeRange.aStart.Col(); nEndCol = aExtendMergeRange.aEnd.Col(); if( eCmd == DEL_CELLSLEFT ) { nEndRow = aExtendMergeRange.aEnd.Row(); bNeedRefresh = true; } else { nStartRow = 0; nEndRow = MAXROW; } } if( !qDecreaseRange.empty() ) { for( ::std::vector::const_iterator iIter( qDecreaseRange.begin()); iIter != qDecreaseRange.end(); ++iIter ) { ScRange aRange( *iIter ); if( rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) { UnmergeCells( aRange, true ); } } } } else { if (!bApi) rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0); rDocShell.GetUndoManager()->LeaveListAction(); return false; } } } // ausfuehren WaitObject aWait( rDocShell.GetActiveDialogParent() ); // wichtig wegen TrackFormulas bei UpdateReference ScDocument* pUndoDoc = NULL; ScDocument* pRefUndoDoc = NULL; ScRefUndoData* pUndoData = NULL; if ( bRecord ) { // With the fix for #101329#, UpdateRef always puts cells into pRefUndoDoc at their old position, // so it's no longer necessary to copy more than the deleted range into pUndoDoc. pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, 0, nTabCount-1, (eCmd==DEL_DELCOLS), (eCmd==DEL_DELROWS) ); itr = aMark.begin(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { SCTAB nScenarioCount = 0; for( SCTAB j = *itr+1; jInitUndo( &rDoc, 0, nTabCount-1, false, false ); pUndoData = new ScRefUndoData( &rDoc ); rDoc.BeginDrawUndo(); } sal_uInt16 nExtFlags = 0; itr = aMark.begin(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { rDocShell.UpdatePaintExt( nExtFlags, nStartCol, nStartRow, *itr, nEndCol, nEndRow, *itr ); } bool bUndoOutline = false; switch (eCmd) { case DEL_CELLSUP: rDoc.DeleteRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast(nEndRow-nStartRow+1), pRefUndoDoc, NULL, &aFullMark ); nPaintEndRow = MAXROW; break; case DEL_DELROWS: rDoc.DeleteRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast(nEndRow-nStartRow+1), pRefUndoDoc, &bUndoOutline, &aFullMark ); nPaintStartCol = 0; nPaintEndCol = MAXCOL; nPaintEndRow = MAXROW; nPaintFlags |= PAINT_LEFT; break; case DEL_CELLSLEFT: rDoc.DeleteCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast(nEndCol-nStartCol+1), pRefUndoDoc, NULL, &aFullMark ); nPaintEndCol = MAXCOL; break; case DEL_DELCOLS: rDoc.DeleteCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast(nEndCol-nStartCol+1), pRefUndoDoc, &bUndoOutline, &aFullMark ); nPaintStartRow = 0; nPaintEndRow = MAXROW; nPaintEndCol = MAXCOL; nPaintFlags |= PAINT_TOP; break; default: OSL_FAIL("Falscher Code beim Loeschen"); break; } //! Test, ob Outline in Groesse geaendert if ( bRecord ) { itr = aFullMark.begin(), itrEnd = aFullMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) pRefUndoDoc->DeleteAreaTab(nUndoStartCol,nUndoStartRow,nUndoEndCol,nUndoEndRow, *itr, IDF_ALL); // alle Tabellen anlegen, damit Formeln kopiert werden koennen: pUndoDoc->AddUndoTab( 0, nTabCount-1, false, false ); // kopieren mit bColRowFlags=false (#54194#) pRefUndoDoc->CopyToDocument(0,0,0,MAXCOL,MAXROW,MAXTAB,IDF_FORMULA,false,pUndoDoc,NULL,false); delete pRefUndoDoc; SCTAB* pTabs = new SCTAB[nSelCount]; SCTAB* pScenarios = new SCTAB[nSelCount]; SCTAB nUndoPos = 0; itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { SCTAB nCount = 0; for( SCTAB j=*itr+1; jLeaveListAction(); } rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDeleteCells( &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ),nUndoPos, pTabs, pScenarios, eCmd, pUndoDoc, pUndoData ) ); } // #i8302 want to be able to insert into the middle of merged cells // the patch comes from maoyg while( !qDecreaseRange.empty() ) { ScRange aRange = qDecreaseRange.back(); long nDecreaseRowCount = 0; long nDecreaseColCount = 0; if( eCmd == DEL_CELLSUP || eCmd == DEL_DELROWS ) { if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() ) nDecreaseRowCount = nEndRow-nStartRow+1; else if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow >= aRange.aStart.Row() && nEndRow >= aRange.aEnd.Row() ) nDecreaseRowCount = aRange.aEnd.Row()-nStartRow+1; else if( nStartRow >= aRange.aStart.Row() && nStartRow >= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() ) nDecreaseRowCount = aRange.aEnd.Row()-nEndRow+1; } else if( eCmd == DEL_CELLSLEFT || eCmd == DEL_DELCOLS ) { if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() ) nDecreaseColCount = nEndCol-nStartCol+1; else if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol >= aRange.aStart.Col() && nEndCol >= aRange.aEnd.Col() ) nDecreaseColCount = aRange.aEnd.Col()-nStartCol+1; else if( nStartCol >= aRange.aStart.Col() && nStartCol >= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() ) nDecreaseColCount = aRange.aEnd.Col()-nEndCol+1; } switch (eCmd) { case DEL_CELLSUP: case DEL_DELROWS: aRange.aEnd.SetRow(static_cast( aRange.aEnd.Row()-nDecreaseRowCount)); break; case DEL_CELLSLEFT: case DEL_DELCOLS: aRange.aEnd.SetCol(static_cast( aRange.aEnd.Col()-nDecreaseColCount)); break; default: break; } if( !rDoc.HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) { ScCellMergeOption aMergeOption(aRange); MergeCells( aMergeOption, false, true, true ); } qDecreaseRange.pop_back(); } if( bDeletingMerge ) rDocShell.GetUndoManager()->LeaveListAction(); if ( bNeedRefresh ) { // #i51445# old merge flag attributes must be deleted also for single cells, // not only for whole columns/rows if ( eCmd==DEL_DELCOLS || eCmd==DEL_CELLSLEFT ) nMergeTestEndCol = MAXCOL; if ( eCmd==DEL_DELROWS || eCmd==DEL_CELLSUP ) nMergeTestEndRow = MAXROW; ScPatternAttr aPattern( rDoc.GetPool() ); aPattern.GetItemSet().Put( ScMergeFlagAttr() ); rDoc.ApplyPatternArea( nExtendStartCol, nExtendStartRow, nMergeTestEndCol, nMergeTestEndRow, aMark, aPattern ); itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { SCTAB nScenarioCount = 0; for( SCTAB j = *itr+1; jBroadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); return true; } bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos, bool bCut, bool bRecord, bool bPaint, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); SCCOL nStartCol = rSource.aStart.Col(); SCROW nStartRow = rSource.aStart.Row(); SCTAB nStartTab = rSource.aStart.Tab(); SCCOL nEndCol = rSource.aEnd.Col(); SCROW nEndRow = rSource.aEnd.Row(); SCTAB nEndTab = rSource.aEnd.Tab(); SCCOL nDestCol = rDestPos.Col(); SCROW nDestRow = rDestPos.Row(); SCTAB nDestTab = rDestPos.Tab(); if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) || !ValidRow(nDestRow) ) { OSL_FAIL("invalid row in MoveBlock"); return false; } // zugehoerige Szenarien auch anpassen - nur wenn innerhalb einer Tabelle verschoben wird! bool bScenariosAdded = false; ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; SCTAB nTabCount = rDoc.GetTableCount(); if ( nDestTab == nStartTab && !rDoc.IsScenario(nEndTab) ) while ( nEndTab+1 < nTabCount && rDoc.IsScenario(nEndTab+1) ) { ++nEndTab; bScenariosAdded = true; } SCTAB nSrcTabCount = nEndTab-nStartTab+1; SCTAB nDestEndTab = nDestTab+nSrcTabCount-1; SCTAB nTab; ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP ); ScMarkData aSourceMark; for (nTab=nStartTab; nTab<=nEndTab; nTab++) aSourceMark.SelectTable( nTab, true ); // Source selektieren aSourceMark.SetMarkArea( rSource ); ScDocShellRef aDragShellRef; if ( rDoc.HasOLEObjectsInArea( rSource ) ) { aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately aDragShellRef->DoInitNew(NULL); } ScDrawLayer::SetGlobalDrawPersist(aDragShellRef); ScClipParam aClipParam(ScRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nStartTab), bCut); rDoc.CopyToClip(aClipParam, pClipDoc, &aSourceMark, false, bScenariosAdded, true); ScDrawLayer::SetGlobalDrawPersist(NULL); SCCOL nOldEndCol = nEndCol; SCROW nOldEndRow = nEndRow; bool bClipOver = false; for (nTab=nStartTab; nTab<=nEndTab; nTab++) { SCCOL nTmpEndCol = nOldEndCol; SCROW nTmpEndRow = nOldEndRow; if (rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab )) bClipOver = true; if ( nTmpEndCol > nEndCol ) nEndCol = nTmpEndCol; if ( nTmpEndRow > nEndRow ) nEndRow = nTmpEndRow; } SCCOL nDestEndCol = nDestCol + ( nOldEndCol-nStartCol ); SCROW nDestEndRow = nDestRow + ( nOldEndRow-nStartRow ); SCCOL nUndoEndCol = nDestCol + ( nEndCol-nStartCol ); // erweitert im Zielblock SCROW nUndoEndRow = nDestRow + ( nEndRow-nStartRow ); bool bIncludeFiltered = bCut; if ( !bIncludeFiltered ) { // adjust sizes to include only non-filtered rows SCCOL nClipX; SCROW nClipY; pClipDoc->GetClipArea( nClipX, nClipY, false ); SCROW nUndoAdd = nUndoEndRow - nDestEndRow; nDestEndRow = nDestRow + nClipY; nUndoEndRow = nDestEndRow + nUndoAdd; } if (!ValidCol(nUndoEndCol) || !ValidRow(nUndoEndRow)) { if (!bApi) rDocShell.ErrorMessage(STR_PASTE_FULL); delete pClipDoc; return false; } // Test auf Zellschutz ScEditableTester aTester; for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) aTester.TestBlock( &rDoc, nTab, nDestCol,nDestRow, nUndoEndCol,nUndoEndRow ); if (bCut) for (nTab=nStartTab; nTab<=nEndTab; nTab++) aTester.TestBlock( &rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); delete pClipDoc; return false; } // Test auf zusammengefasste - beim Verschieben erst nach dem Loeschen if (bClipOver && !bCut) if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab, nUndoEndCol,nUndoEndRow,nDestEndTab, HASATTR_MERGED | HASATTR_OVERLAPPED )) { // "Zusammenfassen nicht verschachteln !" if (!bApi) rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0); delete pClipDoc; return false; } // Are there borders in the cells? (for painting) sal_uInt16 nSourceExt = 0; rDocShell.UpdatePaintExt( nSourceExt, nStartCol,nStartRow,nStartTab, nEndCol,nEndRow,nEndTab ); sal_uInt16 nDestExt = 0; rDocShell.UpdatePaintExt( nDestExt, nDestCol,nDestRow,nDestTab, nDestEndCol,nDestEndRow,nDestEndTab ); // ausfuehren ScDocument* pUndoDoc = NULL; if (bRecord) { bool bWholeCols = ( nStartRow == 0 && nEndRow == MAXROW ); bool bWholeRows = ( nStartCol == 0 && nEndCol == MAXCOL ); InsertDeleteFlags nUndoFlags = (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS; pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab, bWholeCols, bWholeRows ); if (bCut) { rDoc.CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab, nUndoFlags, false, pUndoDoc ); } if ( nDestTab != nStartTab ) pUndoDoc->AddUndoTab( nDestTab, nDestEndTab, bWholeCols, bWholeRows ); rDoc.CopyToDocument( nDestCol, nDestRow, nDestTab, nDestEndCol, nDestEndRow, nDestEndTab, nUndoFlags, false, pUndoDoc ); rDoc.BeginDrawUndo(); } bool bSourceHeight = false; // Hoehen angepasst? if (bCut) { ScMarkData aDelMark; // only for tables for (nTab=nStartTab; nTab<=nEndTab; nTab++) { rDoc.DeleteAreaTab( nStartCol,nStartRow, nOldEndCol,nOldEndRow, nTab, IDF_ALL ); aDelMark.SelectTable( nTab, true ); } rDoc.DeleteObjectsInArea( nStartCol,nStartRow, nOldEndCol,nOldEndRow, aDelMark ); // Test auf zusammengefasste if (bClipOver) if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab, nUndoEndCol,nUndoEndRow,nDestEndTab, HASATTR_MERGED | HASATTR_OVERLAPPED )) { rDoc.CopyFromClip( rSource, aSourceMark, IDF_ALL, NULL, pClipDoc ); for (nTab=nStartTab; nTab<=nEndTab; nTab++) { SCCOL nTmpEndCol = nEndCol; SCROW nTmpEndRow = nEndRow; rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab, true ); } // Fehlermeldung erst nach dem Wiederherstellen des Inhalts if (!bApi) // "Zusammenfassen nicht verschachteln !" rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0); delete pUndoDoc; delete pClipDoc; return false; } bSourceHeight = AdjustRowHeight( rSource, false ); } ScRange aPasteDest( nDestCol, nDestRow, nDestTab, nDestEndCol, nDestEndRow, nDestEndTab ); ScMarkData aDestMark; for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) aDestMark.SelectTable( nTab, true ); // Destination selektieren aDestMark.SetMarkArea( aPasteDest ); /* Do not drawing objects here. While pasting, the function ScDocument::UpdateReference() is called which calls ScDrawLayer::MoveCells() which may move away inserted objects to wrong positions (e.g. if source and destination range overlaps).*/ rDoc.CopyFromClip( aPasteDest, aDestMark, IDF_ALL & ~(IDF_OBJECTS), NULL, pClipDoc, true, false, bIncludeFiltered ); // skipped rows and merged cells don't mix if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() ) UnmergeCells( aPasteDest, false ); VirtualDevice aVirtDev; bool bDestHeight = AdjustRowHeight( ScRange( 0,nDestRow,nDestTab, MAXCOL,nDestEndRow,nDestEndTab ), false ); /* Paste drawing objects after adjusting formula references and row heights. There are no cell notes or drawing objects, if the clipdoc does not contain a drawing layer.*/ if ( pClipDoc->GetDrawLayer() ) rDoc.CopyFromClip( aPasteDest, aDestMark, IDF_OBJECTS, NULL, pClipDoc, true, false, bIncludeFiltered ); if (bRecord) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDragDrop( &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nOldEndCol, nOldEndRow, nEndTab ), ScAddress( nDestCol, nDestRow, nDestTab ), bCut, pUndoDoc, NULL, bScenariosAdded ) ); } SCCOL nDestPaintEndCol = nDestEndCol; SCROW nDestPaintEndRow = nDestEndRow; for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) { SCCOL nTmpEndCol = nDestEndCol; SCROW nTmpEndRow = nDestEndRow; rDoc.ExtendMerge( nDestCol, nDestRow, nTmpEndCol, nTmpEndRow, nTab, true ); if (nTmpEndCol > nDestPaintEndCol) nDestPaintEndCol = nTmpEndCol; if (nTmpEndRow > nDestPaintEndRow) nDestPaintEndRow = nTmpEndRow; } if (bCut) for (nTab=nStartTab; nTab<=nEndTab; nTab++) rDoc.RefreshAutoFilter( nStartCol, nStartRow, nEndCol, nEndRow, nTab ); if (bPaint) { // Zielbereich: SCCOL nPaintStartX = nDestCol; SCROW nPaintStartY = nDestRow; SCCOL nPaintEndX = nDestPaintEndCol; SCROW nPaintEndY = nDestPaintEndRow; sal_uInt16 nFlags = PAINT_GRID; if ( nStartRow==0 && nEndRow==MAXROW ) // Breiten mitkopiert? { nPaintEndX = MAXCOL; nPaintStartY = 0; nPaintEndY = MAXROW; nFlags |= PAINT_TOP; } if ( bDestHeight || ( nStartCol == 0 && nEndCol == MAXCOL ) ) { nPaintEndY = MAXROW; nPaintStartX = 0; nPaintEndX = MAXCOL; nFlags |= PAINT_LEFT; } if ( bScenariosAdded ) { nPaintStartX = 0; nPaintStartY = 0; nPaintEndX = MAXCOL; nPaintEndY = MAXROW; } rDocShell.PostPaint( nPaintStartX,nPaintStartY,nDestTab, nPaintEndX,nPaintEndY,nDestEndTab, nFlags, nSourceExt | nDestExt ); if ( bCut ) { // Quellbereich: nPaintStartX = nStartCol; nPaintStartY = nStartRow; nPaintEndX = nEndCol; nPaintEndY = nEndRow; nFlags = PAINT_GRID; if ( bSourceHeight ) { nPaintEndY = MAXROW; nPaintStartX = 0; nPaintEndX = MAXCOL; nFlags |= PAINT_LEFT; } if ( bScenariosAdded ) { nPaintStartX = 0; nPaintStartY = 0; nPaintEndX = MAXCOL; nPaintEndY = MAXROW; } rDocShell.PostPaint( nPaintStartX,nPaintStartY,nStartTab, nPaintEndX,nPaintEndY,nEndTab, nFlags, nSourceExt ); } } aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); delete pClipDoc; return true; } uno::Reference< uno::XInterface > GetDocModuleObject( SfxObjectShell& rDocSh, OUString& sCodeName ) { uno::Reference< lang::XMultiServiceFactory> xSF(rDocSh.GetModel(), uno::UNO_QUERY); uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess; uno::Reference< uno::XInterface > xDocModuleApiObject; if ( xSF.is() ) { xVBACodeNamedObjectAccess.set( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY ); xDocModuleApiObject.set( xVBACodeNamedObjectAccess->getByName( sCodeName ), uno::UNO_QUERY ); } return xDocModuleApiObject; } static script::ModuleInfo lcl_InitModuleInfo( SfxObjectShell& rDocSh, OUString& sModule ) { script::ModuleInfo sModuleInfo; sModuleInfo.ModuleType = script::ModuleType::DOCUMENT; sModuleInfo.ModuleObject = GetDocModuleObject( rDocSh, sModule ); return sModuleInfo; } void VBA_InsertModule( ScDocument& rDoc, SCTAB nTab, const OUString& sModuleName, const OUString& sSource ) { SfxObjectShell& rDocSh = *rDoc.GetDocumentShell(); uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer(); OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" ); uno::Reference< container::XNameContainer > xLib; if( xLibContainer.is() ) { OUString aLibName( "Standard" ); if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() ) { aLibName = rDocSh.GetBasicManager()->GetName(); } uno::Any aLibAny = xLibContainer->getByName( aLibName ); aLibAny >>= xLib; } if( xLib.is() ) { // if the Module with codename exists then find a new name sal_Int32 nNum = 0; OUString genModuleName; if ( !sModuleName.isEmpty() ) genModuleName = sModuleName; else { genModuleName = "Sheet1"; nNum = 1; } while( xLib->hasByName( genModuleName ) ) genModuleName = "Sheet" + OUString::number( ++nNum ); uno::Any aSourceAny; OUString sTmpSource = sSource; if ( sTmpSource.isEmpty() ) sTmpSource = "Rem Attribute VBA_ModuleType=VBADocumentModule\nOption VBASupport 1\n"; aSourceAny <<= sTmpSource; uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY ); if ( xVBAModuleInfo.is() ) { rDoc.SetCodeName( nTab, genModuleName ); script::ModuleInfo sModuleInfo = lcl_InitModuleInfo( rDocSh, genModuleName ); xVBAModuleInfo->insertModuleInfo( genModuleName, sModuleInfo ); xLib->insertByName( genModuleName, aSourceAny ); } } } void VBA_DeleteModule( ScDocShell& rDocSh, const OUString& sModuleName ) { uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer(); OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" ); uno::Reference< container::XNameContainer > xLib; if( xLibContainer.is() ) { OUString aLibName( "Standard" ); if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() ) { aLibName = rDocSh.GetBasicManager()->GetName(); } uno::Any aLibAny = xLibContainer->getByName( aLibName ); aLibAny >>= xLib; } if( xLib.is() ) { uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY ); if( xLib->hasByName( sModuleName ) ) xLib->removeByName( sModuleName ); if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo(sModuleName) ) xVBAModuleInfo->removeModuleInfo( sModuleName ); } } bool ScDocFunc::InsertTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi ) { bool bSuccess = false; WaitObject aWait( rDocShell.GetActiveDialogParent() ); ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); // Strange loop, also basic is loaded too early ( InsertTable ) // is called via the xml import for sheets in described in ODF bool bInsertDocModule = false; if( !rDocShell.GetDocument().IsImportingXML() ) { bInsertDocModule = rDoc.IsInVBAMode(); } if ( bInsertDocModule || ( bRecord && !rDoc.IsUndoEnabled() ) ) bRecord = false; if (bRecord) rDoc.BeginDrawUndo(); // InsertTab erzeugt ein SdrUndoNewPage SCTAB nTabCount = rDoc.GetTableCount(); bool bAppend = ( nTab >= nTabCount ); if ( bAppend ) nTab = nTabCount; // wichtig fuer Undo if (rDoc.InsertTab( nTab, rName )) { if (bRecord) rDocShell.GetUndoManager()->AddUndoAction( new ScUndoInsertTab( &rDocShell, nTab, bAppend, rName)); // Views updaten: // Only insert vba modules if vba mode ( and not currently importing XML ) if( bInsertDocModule ) { OUString sSource, sCodeName; VBA_InsertModule( rDoc, nTab, sCodeName, sSource ); } rDocShell.Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab ) ); rDocShell.PostPaintExtras(); aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); bSuccess = true; } else if (!bApi) rDocShell.ErrorMessage(STR_TABINSERT_ERROR); return bSuccess; } bool ScDocFunc::DeleteTable( SCTAB nTab, bool bRecord, bool /* bApi */ ) { WaitObject aWait( rDocShell.GetActiveDialogParent() ); ScDocShellModificator aModificator( rDocShell ); bool bSuccess = false; ScDocument& rDoc = rDocShell.GetDocument(); bool bVbaEnabled = rDoc.IsInVBAMode(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; if ( bVbaEnabled ) bRecord = false; bool bWasLinked = rDoc.IsLinked(nTab); ScDocument* pUndoDoc = NULL; ScRefUndoData* pUndoData = NULL; if (bRecord) { pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); SCTAB nCount = rDoc.GetTableCount(); pUndoDoc->InitUndo( &rDoc, nTab, nTab, true, true ); // nur nTab mit Flags pUndoDoc->AddUndoTab( 0, nCount-1 ); // alle Tabs fuer Referenzen rDoc.CopyToDocument(0,0,nTab, MAXCOL,MAXROW,nTab, IDF_ALL,false, pUndoDoc ); OUString aOldName; rDoc.GetName( nTab, aOldName ); pUndoDoc->RenameTab( nTab, aOldName, false ); if (bWasLinked) pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab), rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab), rDoc.GetLinkTab(nTab), rDoc.GetLinkRefreshDelay(nTab) ); if ( rDoc.IsScenario(nTab) ) { pUndoDoc->SetScenario( nTab, true ); OUString aComment; Color aColor; sal_uInt16 nScenFlags; rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags ); pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags ); bool bActive = rDoc.IsActiveScenario( nTab ); pUndoDoc->SetActiveScenario( nTab, bActive ); } pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) ); pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) ); pUndoDoc->SetSheetEvents( nTab, rDoc.GetSheetEvents( nTab ) ); // Drawing-Layer muss sein Undo selbst in der Hand behalten !!! rDoc.BeginDrawUndo(); // DeleteTab erzeugt ein SdrUndoDelPage pUndoData = new ScRefUndoData( &rDoc ); } if (rDoc.DeleteTab(nTab)) { if (bRecord) { vector theTabs; theTabs.push_back(nTab); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDeleteTab( &rDocShell, theTabs, pUndoDoc, pUndoData )); } // Views updaten: if( bVbaEnabled ) { OUString sCodeName; if( rDoc.GetCodeName( nTab, sCodeName ) ) { VBA_DeleteModule( rDocShell, sCodeName ); } } rDocShell.Broadcast( ScTablesHint( SC_TAB_DELETED, nTab ) ); if (bWasLinked) { rDocShell.UpdateLinks(); // Link-Manager updaten SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate(SID_LINKS); } rDocShell.PostPaintExtras(); aModificator.SetDocumentModified(); SfxApplication* pSfxApp = SfxGetpApp(); // Navigator pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) ); pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); bSuccess = true; } else { delete pUndoDoc; delete pUndoData; } return bSuccess; } bool ScDocFunc::SetTableVisible( SCTAB nTab, bool bVisible, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo(rDoc.IsUndoEnabled()); if ( rDoc.IsVisible( nTab ) == bVisible ) return true; // nichts zu tun - ok if ( !rDoc.IsDocEditable() ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); return false; } ScDocShellModificator aModificator( rDocShell ); if ( !bVisible && !rDoc.IsImportingXML() ) // #i57869# allow hiding in any order for loading { // nicht alle Tabellen ausblenden sal_uInt16 nVisCount = 0; SCTAB nCount = rDoc.GetTableCount(); for (SCTAB i=0; i undoTabs; undoTabs.push_back(nTab); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoShowHideTab( &rDocShell, undoTabs, bVisible ) ); } // Views updaten: if (!bVisible) rDocShell.Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) ); SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); rDocShell.PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS); aModificator.SetDocumentModified(); return true; } bool ScDocFunc::SetLayoutRTL( SCTAB nTab, bool bRTL, bool /* bApi */ ) { ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo(rDoc.IsUndoEnabled()); if ( rDoc.IsLayoutRTL( nTab ) == bRTL ) return true; // nothing to do - ok //! protection (sheet or document?) ScDocShellModificator aModificator( rDocShell ); rDoc.SetLayoutRTL( nTab, bRTL ); if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoLayoutRTL( &rDocShell, nTab, bRTL ) ); } rDocShell.PostPaint( 0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_ALL ); aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) { pBindings->Invalidate( FID_TAB_RTL ); pBindings->Invalidate( SID_ATTR_SIZE ); } return true; } bool ScDocFunc::RenameTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; if ( !rDoc.IsDocEditable() ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); return false; } ScDocShellModificator aModificator( rDocShell ); bool bSuccess = false; OUString sOldName; rDoc.GetName(nTab, sOldName); if (rDoc.RenameTab( nTab, rName )) { if (bRecord) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoRenameTab( &rDocShell, nTab, sOldName, rName)); } rDocShell.PostPaintExtras(); aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); bSuccess = true; } return bSuccess; } bool ScDocFunc::SetTabBgColor( SCTAB nTab, const Color& rColor, bool bRecord, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; if ( !rDoc.IsDocEditable() || rDoc.IsTabProtected(nTab) ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Check to see what this string is... return false; } Color aOldTabBgColor; aOldTabBgColor = rDoc.GetTabBgColor(nTab); bool bSuccess = false; rDoc.SetTabBgColor(nTab, rColor); if ( rDoc.GetTabBgColor(nTab) == rColor) bSuccess = true; if (bSuccess) { if (bRecord) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoTabColor( &rDocShell, nTab, aOldTabBgColor, rColor)); } rDocShell.PostPaintExtras(); ScDocShellModificator aModificator( rDocShell ); aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); bSuccess = true; } return bSuccess; } bool ScDocFunc::SetTabBgColor( ScUndoTabColorInfo::List& rUndoTabColorList, bool bRecord, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; if ( !rDoc.IsDocEditable() ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error... return false; } sal_uInt16 nTab; Color aNewTabBgColor; bool bSuccess = true; size_t nTabProtectCount = 0; size_t nTabListCount = rUndoTabColorList.size(); for ( size_t i = 0; i < nTabListCount; ++i ) { ScUndoTabColorInfo& rInfo = rUndoTabColorList[i]; nTab = rInfo.mnTabId; if ( !rDoc.IsTabProtected(nTab) ) { aNewTabBgColor = rInfo.maNewTabBgColor; rInfo.maOldTabBgColor = rDoc.GetTabBgColor(nTab); rDoc.SetTabBgColor(nTab, aNewTabBgColor); if ( rDoc.GetTabBgColor(nTab) != aNewTabBgColor) { bSuccess = false; break; } } else { nTabProtectCount++; } } if ( nTabProtectCount == nTabListCount ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error... return false; } if (bSuccess) { if (bRecord) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoTabColor( &rDocShell, rUndoTabColorList)); } rDocShell.PostPaintExtras(); ScDocShellModificator aModificator( rDocShell ); aModificator.SetDocumentModified(); } return bSuccess; } //! SetWidthOrHeight - noch doppelt zu ViewFunc !!!!!! //! Probleme: //! - Optimale Hoehe fuer Edit-Zellen ist unterschiedlich zwischen Drucker und Bildschirm //! - Optimale Breite braucht Selektion, um evtl. nur selektierte Zellen zu beruecksichtigen static sal_uInt16 lcl_GetOptimalColWidth( ScDocShell& rDocShell, SCCOL nCol, SCTAB nTab, bool bFormula ) { ScSizeDeviceProvider aProv(&rDocShell); OutputDevice* pDev = aProv.GetDevice(); // has pixel MapMode double nPPTX = aProv.GetPPTX(); double nPPTY = aProv.GetPPTY(); ScDocument& rDoc = rDocShell.GetDocument(); Fraction aOne(1,1); sal_uInt16 nTwips = rDoc.GetOptimalColWidth( nCol, nTab, pDev, nPPTX, nPPTY, aOne, aOne, bFormula, NULL ); return nTwips; } bool ScDocFunc::SetWidthOrHeight( bool bWidth, const std::vector& rRanges, SCTAB nTab, ScSizeMode eMode, sal_uInt16 nSizeTwips, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); if (rRanges.empty()) return true; ScDocument& rDoc = rDocShell.GetDocument(); if ( bRecord && !rDoc.IsUndoEnabled() ) bRecord = false; // import into read-only document is possible if ( !rDoc.IsChangeReadOnlyEnabled() && !rDocShell.IsEditable() ) { if (!bApi) rDocShell.ErrorMessage(STR_PROTECTIONERR); //! eigene Meldung? return false; } bool bSuccess = false; SCCOLROW nStart = rRanges[0].mnStart; SCCOLROW nEnd = rRanges[0].mnEnd; bool bFormula = false; if ( eMode == SC_SIZE_OPTIMAL ) { //! Option "Formeln anzeigen" - woher nehmen? } ScDocument* pUndoDoc = NULL; ScOutlineTable* pUndoTab = NULL; std::vector aUndoRanges; if ( bRecord ) { rDoc.BeginDrawUndo(); // Drawing Updates pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); if (bWidth) { pUndoDoc->InitUndo( &rDoc, nTab, nTab, true, false ); rDoc.CopyToDocument( static_cast(nStart), 0, nTab, static_cast(nEnd), MAXROW, nTab, IDF_NONE, false, pUndoDoc ); } else { pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, true ); rDoc.CopyToDocument( 0, static_cast(nStart), nTab, MAXCOL, static_cast(nEnd), nTab, IDF_NONE, false, pUndoDoc ); } aUndoRanges = rRanges; ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab ); if (pTable) pUndoTab = new ScOutlineTable( *pTable ); } bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT; bool bOutline = false; for (size_t i = 0, n = rRanges.size(); i < n; ++i) { SCCOLROW nStartNo = rRanges[i].mnStart; SCCOLROW nEndNo = rRanges[i].mnEnd; if ( !bWidth ) // Hoehen immer blockweise { if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT ) { bool bAll = ( eMode==SC_SIZE_OPTIMAL ); if (!bAll) { // fuer alle eingeblendeten CR_MANUALSIZE loeschen, // dann SetOptimalHeight mit bShrink = FALSE for (SCROW nRow=nStartNo; nRow<=nEndNo; nRow++) { sal_uInt8 nOld = rDoc.GetRowFlags(nRow,nTab); SCROW nLastRow = -1; bool bHidden = rDoc.RowHidden(nRow, nTab, NULL, &nLastRow); if ( !bHidden && ( nOld & CR_MANUALSIZE ) ) rDoc.SetRowFlags( nRow, nTab, nOld & ~CR_MANUALSIZE ); } } ScSizeDeviceProvider aProv( &rDocShell ); Fraction aOne(1,1); sc::RowHeightContext aCxt(aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice()); aCxt.setForceAutoSize(bAll); rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab); if (bAll) rDoc.ShowRows( nStartNo, nEndNo, nTab, true ); // Manual-Flag wird bei bAll=sal_True schon in SetOptimalHeight gesetzt // (an bei Extra-Height, sonst aus). } else if ( eMode==SC_SIZE_DIRECT || eMode==SC_SIZE_ORIGINAL ) { if (nSizeTwips) { rDoc.SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips ); rDoc.SetManualHeight( nStartNo, nEndNo, nTab, true ); // height was set manually } if ( eMode != SC_SIZE_ORIGINAL ) rDoc.ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 ); } else if ( eMode==SC_SIZE_SHOW ) { rDoc.ShowRows( nStartNo, nEndNo, nTab, true ); } } else // Spaltenbreiten { for (SCCOL nCol=static_cast(nStartNo); nCol<=static_cast(nEndNo); nCol++) { if ( eMode != SC_SIZE_VISOPT || !rDoc.ColHidden(nCol, nTab) ) { sal_uInt16 nThisSize = nSizeTwips; if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT ) nThisSize = nSizeTwips + lcl_GetOptimalColWidth( rDocShell, nCol, nTab, bFormula ); if ( nThisSize ) rDoc.SetColWidth( nCol, nTab, nThisSize ); if ( eMode != SC_SIZE_ORIGINAL ) rDoc.ShowCol( nCol, nTab, bShow ); } } } // adjust outlines if ( eMode != SC_SIZE_ORIGINAL ) { if (bWidth) bOutline = bOutline || rDoc.UpdateOutlineCol( static_cast(nStartNo), static_cast(nEndNo), nTab, bShow ); else bOutline = bOutline || rDoc.UpdateOutlineRow( static_cast(nStartNo), static_cast(nEndNo), nTab, bShow ); } } rDoc.SetDrawPageSize(nTab); if (!bOutline) DELETEZ(pUndoTab); if (bRecord) { ScMarkData aMark; aMark.SelectOneTable( nTab ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoWidthOrHeight( &rDocShell, aMark, nStart, nTab, nEnd, nTab, pUndoDoc, aUndoRanges, pUndoTab, eMode, nSizeTwips, bWidth)); } rDoc.UpdatePageBreaks( nTab ); rDocShell.PostPaint(0,0,nTab,MAXCOL,MAXROW,nTab,PAINT_ALL); aModificator.SetDocumentModified(); return bSuccess; } bool ScDocFunc::InsertPageBreak( bool bColumn, const ScAddress& rPos, bool bRecord, bool bSetModified, bool /* bApi */ ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; SCTAB nTab = rPos.Tab(); SfxBindings* pBindings = rDocShell.GetViewBindings(); SCCOLROW nPos = bColumn ? static_cast(rPos.Col()) : static_cast(rPos.Row()); if (nPos == 0) return false; // erste Spalte / Zeile ScBreakType nBreak = bColumn ? rDoc.HasColBreak(static_cast(nPos), nTab) : rDoc.HasRowBreak(static_cast(nPos), nTab); if (nBreak & BREAK_MANUAL) return true; if (bRecord) rDocShell.GetUndoManager()->AddUndoAction( new ScUndoPageBreak( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, true ) ); if (bColumn) rDoc.SetColBreak(static_cast(nPos), nTab, false, true); else rDoc.SetRowBreak(static_cast(nPos), nTab, false, true); rDoc.InvalidatePageBreaks(nTab); rDoc.UpdatePageBreaks( nTab ); if (rDoc.IsStreamValid(nTab)) rDoc.SetStreamValid(nTab, false); if (bColumn) { rDocShell.PostPaint( static_cast(nPos)-1, 0, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); if (pBindings) { pBindings->Invalidate( FID_INS_COLBRK ); pBindings->Invalidate( FID_DEL_COLBRK ); } } else { rDocShell.PostPaint( 0, static_cast(nPos)-1, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); if (pBindings) { pBindings->Invalidate( FID_INS_ROWBRK ); pBindings->Invalidate( FID_DEL_ROWBRK ); } } if (pBindings) pBindings->Invalidate( FID_DEL_MANUALBREAKS ); if (bSetModified) aModificator.SetDocumentModified(); return true; } bool ScDocFunc::RemovePageBreak( bool bColumn, const ScAddress& rPos, bool bRecord, bool bSetModified, bool /* bApi */ ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; SCTAB nTab = rPos.Tab(); SfxBindings* pBindings = rDocShell.GetViewBindings(); SCCOLROW nPos = bColumn ? static_cast(rPos.Col()) : static_cast(rPos.Row()); ScBreakType nBreak; if (bColumn) nBreak = rDoc.HasColBreak(static_cast(nPos), nTab); else nBreak = rDoc.HasRowBreak(static_cast(nPos), nTab); if ((nBreak & BREAK_MANUAL) == 0) // There is no manual break. return false; if (bRecord) rDocShell.GetUndoManager()->AddUndoAction( new ScUndoPageBreak( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, false ) ); if (bColumn) rDoc.RemoveColBreak(static_cast(nPos), nTab, false, true); else rDoc.RemoveRowBreak(static_cast(nPos), nTab, false, true); rDoc.UpdatePageBreaks( nTab ); if (rDoc.IsStreamValid(nTab)) rDoc.SetStreamValid(nTab, false); if (bColumn) { rDocShell.PostPaint( static_cast(nPos)-1, 0, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); if (pBindings) { pBindings->Invalidate( FID_INS_COLBRK ); pBindings->Invalidate( FID_DEL_COLBRK ); } } else { rDocShell.PostPaint( 0, nPos-1, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); if (pBindings) { pBindings->Invalidate( FID_INS_ROWBRK ); pBindings->Invalidate( FID_DEL_ROWBRK ); } } if (pBindings) pBindings->Invalidate( FID_DEL_MANUALBREAKS ); if (bSetModified) aModificator.SetDocumentModified(); return true; } void ScDocFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect ) { ScDocument& rDoc = rDocShell.GetDocument(); rDoc.SetTabProtection(nTab, &rProtect); if (rDoc.IsUndoEnabled()) { ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); OSL_ENSURE(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!"); if (pProtect) { ::std::unique_ptr p(new ScTableProtection(*pProtect)); p->setProtected(true); // just in case ... rDocShell.GetUndoManager()->AddUndoAction( new ScUndoTabProtect(&rDocShell, nTab, std::move(p)) ); // ownership of unique_ptr now transferred to ScUndoTabProtect. } } rDocShell.PostPaintGridAll(); ScDocShellModificator aModificator(rDocShell); aModificator.SetDocumentModified(); } bool ScDocFunc::Protect( SCTAB nTab, const OUString& rPassword, bool /*bApi*/ ) { ScDocument& rDoc = rDocShell.GetDocument(); if (nTab == TABLEID_DOC) { // document protection ScDocProtection aProtection; aProtection.setProtected(true); aProtection.setPassword(rPassword); rDoc.SetDocProtection(&aProtection); if (rDoc.IsUndoEnabled()) { ScDocProtection* pProtect = rDoc.GetDocProtection(); OSL_ENSURE(pProtect, "ScDocFunc::Unprotect: ScDocProtection pointer is NULL!"); if (pProtect) { ::std::unique_ptr p(new ScDocProtection(*pProtect)); p->setProtected(true); // just in case ... rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDocProtect(&rDocShell, std::move(p)) ); // ownership of unique_ptr is transferred to ScUndoDocProtect. } } } else { // sheet protection ScTableProtection aProtection; aProtection.setProtected(true); aProtection.setPassword(rPassword); rDoc.SetTabProtection(nTab, &aProtection); if (rDoc.IsUndoEnabled()) { ScTableProtection* pProtect = rDoc.GetTabProtection(nTab); OSL_ENSURE(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!"); if (pProtect) { ::std::unique_ptr p(new ScTableProtection(*pProtect)); p->setProtected(true); // just in case ... rDocShell.GetUndoManager()->AddUndoAction( new ScUndoTabProtect(&rDocShell, nTab, std::move(p)) ); // ownership of unique_ptr now transferred to ScUndoTabProtect. } } } rDocShell.PostPaintGridAll(); ScDocShellModificator aModificator( rDocShell ); aModificator.SetDocumentModified(); return true; } bool ScDocFunc::Unprotect( SCTAB nTab, const OUString& rPassword, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); if (nTab == TABLEID_DOC) { // document protection ScDocProtection* pDocProtect = rDoc.GetDocProtection(); if (!pDocProtect || !pDocProtect->isProtected()) // already unprotected (should not happen)! return true; // save the protection state before unprotect (for undo). ::std::unique_ptr pProtectCopy(new ScDocProtection(*pDocProtect)); if (!pDocProtect->verifyPassword(rPassword)) { if (!bApi) { InfoBox aBox( rDocShell.GetActiveDialogParent(), OUString( ScResId( SCSTR_WRONGPASSWORD ) ) ); aBox.Execute(); } return false; } rDoc.SetDocProtection(NULL); if (rDoc.IsUndoEnabled()) { pProtectCopy->setProtected(false); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDocProtect(&rDocShell, std::move(pProtectCopy)) ); // ownership of unique_ptr now transferred to ScUndoDocProtect. } } else { // sheet protection ScTableProtection* pTabProtect = rDoc.GetTabProtection(nTab); if (!pTabProtect || !pTabProtect->isProtected()) // already unprotected (should not happen)! return true; // save the protection state before unprotect (for undo). ::std::unique_ptr pProtectCopy(new ScTableProtection(*pTabProtect)); if (!pTabProtect->verifyPassword(rPassword)) { if (!bApi) { InfoBox aBox( rDocShell.GetActiveDialogParent(), OUString( ScResId( SCSTR_WRONGPASSWORD ) ) ); aBox.Execute(); } return false; } rDoc.SetTabProtection(nTab, NULL); if (rDoc.IsUndoEnabled()) { pProtectCopy->setProtected(false); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoTabProtect(&rDocShell, nTab, std::move(pProtectCopy)) ); // ownership of unique_ptr now transferred to ScUndoTabProtect. } } rDocShell.PostPaintGridAll(); ScDocShellModificator aModificator( rDocShell ); aModificator.SetDocumentModified(); return true; } bool ScDocFunc::ClearItems( const ScMarkData& rMark, const sal_uInt16* pWhich, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); ScEditableTester aTester( &rDoc, rMark ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } // #i12940# ClearItems is called (from setPropertyToDefault) directly with uno object's cached // MarkData (GetMarkData), so rMark must be changed to multi selection for ClearSelectionItems // here. ScRange aMarkRange; ScMarkData aMultiMark = rMark; aMultiMark.SetMarking(false); // for MarkToMulti aMultiMark.MarkToMulti(); aMultiMark.GetMultiMarkArea( aMarkRange ); if (bUndo) { SCTAB nStartTab = aMarkRange.aStart.Tab(); SCTAB nEndTab = aMarkRange.aEnd.Tab(); ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab ); rDoc.CopyToDocument( aMarkRange, IDF_ATTRIB, true, pUndoDoc, (ScMarkData*)&aMultiMark ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoClearItems( &rDocShell, aMultiMark, pUndoDoc, pWhich ) ); } rDoc.ClearSelectionItems( pWhich, aMultiMark ); rDocShell.PostPaint( aMarkRange, PAINT_GRID, SC_PF_LINES | SC_PF_TESTMERGE ); aModificator.SetDocumentModified(); //! Bindings-Invalidate etc.? return true; } bool ScDocFunc::ChangeIndent( const ScMarkData& rMark, bool bIncrement, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo(rDoc.IsUndoEnabled()); ScEditableTester aTester( &rDoc, rMark ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } ScRange aMarkRange; rMark.GetMultiMarkArea( aMarkRange ); if (bUndo) { SCTAB nStartTab = aMarkRange.aStart.Tab(); SCTAB nTabCount = rDoc.GetTableCount(); ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab ); ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) if (*itr != nStartTab) pUndoDoc->AddUndoTab( *itr, *itr ); ScRange aCopyRange = aMarkRange; aCopyRange.aStart.SetTab(0); aCopyRange.aEnd.SetTab(nTabCount-1); rDoc.CopyToDocument( aCopyRange, IDF_ATTRIB, true, pUndoDoc, (ScMarkData*)&rMark ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoIndent( &rDocShell, rMark, pUndoDoc, bIncrement ) ); } rDoc.ChangeSelectionIndent( bIncrement, rMark ); rDocShell.PostPaint( aMarkRange, PAINT_GRID, SC_PF_LINES | SC_PF_TESTMERGE ); aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) { pBindings->Invalidate( SID_ALIGNLEFT ); // ChangeIndent setzt auf links pBindings->Invalidate( SID_ALIGNRIGHT ); pBindings->Invalidate( SID_ALIGNBLOCK ); pBindings->Invalidate( SID_ALIGNCENTERHOR ); pBindings->Invalidate( SID_ATTR_LRSPACE ); pBindings->Invalidate( SID_ATTR_PARA_ADJUST_LEFT ); pBindings->Invalidate( SID_ATTR_PARA_ADJUST_RIGHT ); pBindings->Invalidate( SID_ATTR_PARA_ADJUST_BLOCK ); pBindings->Invalidate( SID_ATTR_PARA_ADJUST_CENTER); // pseudo slots for Format menu pBindings->Invalidate( SID_ALIGN_ANY_HDEFAULT ); pBindings->Invalidate( SID_ALIGN_ANY_LEFT ); pBindings->Invalidate( SID_ALIGN_ANY_HCENTER ); pBindings->Invalidate( SID_ALIGN_ANY_RIGHT ); pBindings->Invalidate( SID_ALIGN_ANY_JUSTIFIED ); } return true; } bool ScDocFunc::AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark, sal_uInt16 nFormatNo, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); bool bSuccess = false; ScDocument& rDoc = rDocShell.GetDocument(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCTAB nStartTab = rRange.aStart.Tab(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nEndTab = rRange.aEnd.Tab(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) aMark.SelectTable( nTab, true ); } ScAutoFormat* pAutoFormat = ScGlobal::GetOrCreateAutoFormat(); ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); if ( nFormatNo < pAutoFormat->size() && aTester.IsEditable() ) { WaitObject aWait( rDocShell.GetActiveDialogParent() ); bool bSize = pAutoFormat->findByIndex(nFormatNo)->GetIncludeWidthHeight(); SCTAB nTabCount = rDoc.GetTableCount(); ScDocument* pUndoDoc = NULL; if ( bRecord ) { pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab, bSize, bSize ); ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) if (*itr != nStartTab) pUndoDoc->AddUndoTab( *itr, *itr, bSize, bSize ); ScRange aCopyRange = rRange; aCopyRange.aStart.SetTab(0); aCopyRange.aStart.SetTab(nTabCount-1); rDoc.CopyToDocument( aCopyRange, IDF_ATTRIB, false, pUndoDoc, &aMark ); if (bSize) { rDoc.CopyToDocument( nStartCol,0,0, nEndCol,MAXROW,nTabCount-1, IDF_NONE, false, pUndoDoc, &aMark ); rDoc.CopyToDocument( 0,nStartRow,0, MAXCOL,nEndRow,nTabCount-1, IDF_NONE, false, pUndoDoc, &aMark ); } rDoc.BeginDrawUndo(); } rDoc.AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo, aMark ); if (bSize) { std::vector aCols(1, sc::ColRowSpan(nStartCol,nEndCol)); std::vector aRows(1, sc::ColRowSpan(nStartRow,nEndRow)); ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { SetWidthOrHeight(true, aCols, *itr, SC_SIZE_VISOPT, STD_EXTRA_WIDTH, false, true); SetWidthOrHeight(false, aRows, *itr, SC_SIZE_VISOPT, 0, false, false); rDocShell.PostPaint( 0,0,*itr, MAXCOL,MAXROW,*itr, PAINT_GRID | PAINT_LEFT | PAINT_TOP ); } } else { ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) { bool bAdj = AdjustRowHeight( ScRange(nStartCol, nStartRow, *itr, nEndCol, nEndRow, *itr), false ); if (bAdj) rDocShell.PostPaint( 0,nStartRow,*itr, MAXCOL,MAXROW,*itr, PAINT_GRID | PAINT_LEFT ); else rDocShell.PostPaint( nStartCol, nStartRow, *itr, nEndCol, nEndRow, *itr, PAINT_GRID ); } } if ( bRecord ) // Draw-Undo erst jetzt verfuegbar { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFormat( &rDocShell, rRange, pUndoDoc, aMark, bSize, nFormatNo ) ); } aModificator.SetDocumentModified(); } else if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return bSuccess; } bool ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark, const ScTokenArray* pTokenArray, const OUString& rString, bool bApi, bool bEnglish, const OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { ScDocShellModificator aModificator( rDocShell ); bool bSuccess = false; ScDocument& rDoc = rDocShell.GetDocument(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCTAB nStartTab = rRange.aStart.Tab(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nEndTab = rRange.aEnd.Tab(); bool bUndo(rDoc.IsUndoEnabled()); ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) aMark.SelectTable( nTab, true ); } ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); if ( aTester.IsEditable() ) { WaitObject aWait( rDocShell.GetActiveDialogParent() ); ScDocument* pUndoDoc = NULL; if (bUndo) { //! auch bei Undo selektierte Tabellen beruecksichtigen pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab ); rDoc.CopyToDocument( rRange, IDF_ALL & ~IDF_NOTE, false, pUndoDoc ); } // use TokenArray if given, string (and flags) otherwise if ( pTokenArray ) { rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, aMark, EMPTY_OUSTRING, pTokenArray, eGrammar); } else if ( rDoc.IsImportingXML() ) { ScTokenArray* pCode = lcl_ScDocFunc_CreateTokenArrayXML( rString, rFormulaNmsp, eGrammar ); rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, aMark, EMPTY_OUSTRING, pCode, eGrammar); delete pCode; rDoc.IncXMLImportedFormulaCount( rString.getLength() ); } else if (bEnglish) { ScCompiler aComp( &rDoc, rRange.aStart); aComp.SetGrammar(eGrammar); ScTokenArray* pCode = aComp.CompileString( rString ); rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, aMark, EMPTY_OUSTRING, pCode, eGrammar); delete pCode; } else rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, aMark, rString, NULL, eGrammar); if (bUndo) { //! auch bei Undo selektierte Tabellen beruecksichtigen rDocShell.GetUndoManager()->AddUndoAction( new ScUndoEnterMatrix( &rDocShell, rRange, pUndoDoc, rString ) ); } // Err522 beim Paint von DDE-Formeln werden jetzt beim Interpretieren abgefangen rDocShell.PostPaint( nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab, PAINT_GRID ); aModificator.SetDocumentModified(); bSuccess = true; } else if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return bSuccess; } bool ScDocFunc::TabOp( const ScRange& rRange, const ScMarkData* pTabMark, const ScTabOpParam& rParam, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); bool bSuccess = false; ScDocument& rDoc = rDocShell.GetDocument(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCTAB nStartTab = rRange.aStart.Tab(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nEndTab = rRange.aEnd.Tab(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) aMark.SelectTable( nTab, true ); } ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); if ( aTester.IsEditable() ) { WaitObject aWait( rDocShell.GetActiveDialogParent() ); rDoc.SetDirty( rRange, false ); if ( bRecord ) { //! auch bei Undo selektierte Tabellen beruecksichtigen ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nStartTab, nEndTab ); rDoc.CopyToDocument( rRange, IDF_ALL & ~IDF_NOTE, false, pUndoDoc ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoTabOp( &rDocShell, nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab, pUndoDoc, rParam.aRefFormulaCell, rParam.aRefFormulaEnd, rParam.aRefRowCell, rParam.aRefColCell, rParam.meMode) ); } rDoc.InsertTableOp(rParam, nStartCol, nStartRow, nEndCol, nEndRow, aMark); rDocShell.PostPaintGridAll(); aModificator.SetDocumentModified(); bSuccess = true; } else if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return bSuccess; } inline ScDirection DirFromFillDir( FillDir eDir ) { if (eDir==FILL_TO_BOTTOM) return DIR_BOTTOM; else if (eDir==FILL_TO_RIGHT) return DIR_RIGHT; else if (eDir==FILL_TO_TOP) return DIR_TOP; else // if (eDir==FILL_TO_LEFT) return DIR_LEFT; } namespace { /** * Expand the fill range as necessary, to allow copying of adjacent cell(s) * even when those cells are not in the original range. */ void adjustFillRangeForAdjacentCopy(ScRange& rRange, FillDir eDir) { switch (eDir) { case FILL_TO_BOTTOM: { if (rRange.aStart.Row() == 0) return; if (rRange.aStart.Row() != rRange.aEnd.Row()) return; // Include the above row. ScAddress& s = rRange.aStart; s.SetRow(s.Row()-1); } break; case FILL_TO_TOP: { if (rRange.aStart.Row() == MAXROW) return; if (rRange.aStart.Row() != rRange.aEnd.Row()) return; // Include the row below. ScAddress& e = rRange.aEnd; e.SetRow(e.Row()+1); } break; case FILL_TO_LEFT: { if (rRange.aStart.Col() == MAXCOL) return; if (rRange.aStart.Col() != rRange.aEnd.Col()) return; // Include the column to the right. ScAddress& e = rRange.aEnd; e.SetCol(e.Col()+1); } break; case FILL_TO_RIGHT: { if (rRange.aStart.Col() == 0) return; if (rRange.aStart.Col() != rRange.aEnd.Col()) return; // Include the column to the left. ScAddress& s = rRange.aStart; s.SetCol(s.Col()-1); } break; default: ; } } } bool ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMark, FillDir eDir, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); bool bSuccess = false; ScRange aRange = rRange; adjustFillRangeForAdjacentCopy(aRange, eDir); SCCOL nStartCol = aRange.aStart.Col(); SCROW nStartRow = aRange.aStart.Row(); SCTAB nStartTab = aRange.aStart.Tab(); SCCOL nEndCol = aRange.aEnd.Col(); SCROW nEndRow = aRange.aEnd.Row(); SCTAB nEndTab = aRange.aEnd.Tab(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) aMark.SelectTable( nTab, true ); } ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); if ( aTester.IsEditable() ) { WaitObject aWait( rDocShell.GetActiveDialogParent() ); ScRange aSourceArea = aRange; ScRange aDestArea = aRange; SCCOLROW nCount = 0; switch (eDir) { case FILL_TO_BOTTOM: nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row(); aSourceArea.aEnd.SetRow( aSourceArea.aStart.Row() ); break; case FILL_TO_RIGHT: nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col(); aSourceArea.aEnd.SetCol( aSourceArea.aStart.Col() ); break; case FILL_TO_TOP: nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row(); aSourceArea.aStart.SetRow( aSourceArea.aEnd.Row() ); break; case FILL_TO_LEFT: nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col(); aSourceArea.aStart.SetCol( aSourceArea.aEnd.Col() ); break; } ScDocument* pUndoDoc = NULL; if ( bRecord ) { SCTAB nTabCount = rDoc.GetTableCount(); SCTAB nDestStartTab = aDestArea.aStart.Tab(); pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nDestStartTab, nDestStartTab ); ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) if (*itr != nDestStartTab) pUndoDoc->AddUndoTab( *itr, *itr ); ScRange aCopyRange = aDestArea; aCopyRange.aStart.SetTab(0); aCopyRange.aEnd.SetTab(nTabCount-1); rDoc.CopyToDocument( aCopyRange, IDF_AUTOFILL, false, pUndoDoc, &aMark ); } sal_uLong nProgCount; if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP) nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1; else nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1; nProgCount *= nCount; ScProgress aProgress( rDoc.GetDocumentShell(), ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount ); rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress, aMark, nCount, eDir, FILL_SIMPLE ); AdjustRowHeight(aRange); if ( bRecord ) // Draw-Undo erst jetzt verfuegbar { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307) ); } rDocShell.PostPaintGridAll(); aModificator.SetDocumentModified(); bSuccess = true; } else if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return bSuccess; } bool ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark, FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, double fStart, double fStep, double fMax, bool bRecord, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); bool bSuccess = false; ScDocument& rDoc = rDocShell.GetDocument(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCTAB nStartTab = rRange.aStart.Tab(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nEndTab = rRange.aEnd.Tab(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) aMark.SelectTable( nTab, true ); } ScEditableTester aTester( &rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); if ( aTester.IsEditable() ) { WaitObject aWait( rDocShell.GetActiveDialogParent() ); ScRange aSourceArea = rRange; ScRange aDestArea = rRange; SCSIZE nCount = rDoc.GetEmptyLinesInBlock( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aStart.Tab(), aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aSourceArea.aEnd.Tab(), DirFromFillDir(eDir) ); // mindestens eine Zeile/Spalte als Quellbereich behalten: SCSIZE nTotLines = ( eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP ) ? static_cast( aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1 ) : static_cast( aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1 ); if ( nCount >= nTotLines ) nCount = nTotLines - 1; switch (eDir) { case FILL_TO_BOTTOM: aSourceArea.aEnd.SetRow( sal::static_int_cast( aSourceArea.aEnd.Row() - nCount ) ); break; case FILL_TO_RIGHT: aSourceArea.aEnd.SetCol( sal::static_int_cast( aSourceArea.aEnd.Col() - nCount ) ); break; case FILL_TO_TOP: aSourceArea.aStart.SetRow( sal::static_int_cast( aSourceArea.aStart.Row() + nCount ) ); break; case FILL_TO_LEFT: aSourceArea.aStart.SetCol( sal::static_int_cast( aSourceArea.aStart.Col() + nCount ) ); break; } ScDocument* pUndoDoc = NULL; if ( bRecord ) { SCTAB nTabCount = rDoc.GetTableCount(); SCTAB nDestStartTab = aDestArea.aStart.Tab(); pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nDestStartTab, nDestStartTab ); ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && *itr < nTabCount; ++itr) if (*itr != nDestStartTab) pUndoDoc->AddUndoTab( *itr, *itr ); rDoc.CopyToDocument( aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0, aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1, IDF_AUTOFILL, false, pUndoDoc, &aMark ); } if (aDestArea.aStart.Col() <= aDestArea.aEnd.Col() && aDestArea.aStart.Row() <= aDestArea.aEnd.Row()) { if ( fStart != MAXDOUBLE ) { SCCOL nValX = (eDir == FILL_TO_LEFT) ? aDestArea.aEnd.Col() : aDestArea.aStart.Col(); SCROW nValY = (eDir == FILL_TO_TOP ) ? aDestArea.aEnd.Row() : aDestArea.aStart.Row(); SCTAB nTab = aDestArea.aStart.Tab(); rDoc.SetValue( nValX, nValY, nTab, fStart ); } sal_uLong nProgCount; if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP) nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1; else nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1; nProgCount *= nCount; ScProgress aProgress( rDoc.GetDocumentShell(), ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount ); rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress, aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax ); AdjustRowHeight(rRange); rDocShell.PostPaintGridAll(); aModificator.SetDocumentModified(); } if ( bRecord ) // Draw-Undo erst jetzt verfuegbar { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, eDir, eCmd, eDateCmd, fStart, fStep, fMax) ); } bSuccess = true; } else if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return bSuccess; } bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, FillDir eDir, sal_uLong nCount, bool bRecord, bool bApi ) { double fStep = 1.0; double fMax = MAXDOUBLE; return FillAuto( rRange, pTabMark, eDir, FILL_AUTO, FILL_DAY, nCount, fStep, fMax, bRecord, bApi ); } 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 ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCTAB nStartTab = rRange.aStart.Tab(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nEndTab = rRange.aEnd.Tab(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScMarkData aMark; if (pTabMark) aMark = *pTabMark; else { for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) aMark.SelectTable( nTab, true ); } ScRange aSourceArea = rRange; ScRange aDestArea = rRange; switch (eDir) { case FILL_TO_BOTTOM: aDestArea.aEnd.SetRow( sal::static_int_cast( aSourceArea.aEnd.Row() + nCount ) ); break; case FILL_TO_TOP: if (nCount > sal::static_int_cast( aSourceArea.aStart.Row() )) { OSL_FAIL("FillAuto: Row < 0"); nCount = aSourceArea.aStart.Row(); } aDestArea.aStart.SetRow( sal::static_int_cast( aSourceArea.aStart.Row() - nCount ) ); break; case FILL_TO_RIGHT: aDestArea.aEnd.SetCol( sal::static_int_cast( aSourceArea.aEnd.Col() + nCount ) ); break; case FILL_TO_LEFT: if (nCount > sal::static_int_cast( aSourceArea.aStart.Col() )) { OSL_FAIL("FillAuto: Col < 0"); nCount = aSourceArea.aStart.Col(); } aDestArea.aStart.SetCol( sal::static_int_cast( aSourceArea.aStart.Col() - nCount ) ); break; default: OSL_FAIL("Falsche Richtung bei FillAuto"); break; } // Zellschutz testen //! Quellbereich darf geschuetzt sein !!! //! aber kein Matrixfragment enthalten !!! ScEditableTester aTester( &rDoc, aDestArea ); if ( !aTester.IsEditable() ) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } if ( rDoc.HasSelectedBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow, aMark ) ) { if (!bApi) rDocShell.ErrorMessage(STR_MATRIXFRAGMENTERR); return false; } WaitObject aWait( rDocShell.GetActiveDialogParent() ); ScDocument* pUndoDoc = NULL; if ( bRecord ) { SCTAB nTabCount = rDoc.GetTableCount(); SCTAB nDestStartTab = aDestArea.aStart.Tab(); pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nDestStartTab, nDestStartTab ); ScMarkData::iterator itr = aMark.begin(), itrEnd = aMark.end(); for (; itr != itrEnd && nTabCount; ++itr) if (*itr != nDestStartTab) pUndoDoc->AddUndoTab( *itr, *itr ); // do not clone note captions in undo document rDoc.CopyToDocument( aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0, aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1, IDF_AUTOFILL, false, pUndoDoc, &aMark ); } sal_uLong nProgCount; if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP) nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1; else nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1; nProgCount *= nCount; ScProgress aProgress( rDoc.GetDocumentShell(), ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount ); rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress, aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax ); AdjustRowHeight(aDestArea); if ( bRecord ) // Draw-Undo erst jetzt verfuegbar { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax) ); } rDocShell.PostPaintGridAll(); aModificator.SetDocumentModified(); rRange = aDestArea; // Zielbereich zurueckgeben (zum Markieren) return true; } bool ScDocFunc::MergeCells( const ScCellMergeOption& rOption, bool bContents, bool bRecord, bool bApi ) { using ::std::set; ScDocShellModificator aModificator( rDocShell ); SCCOL nStartCol = rOption.mnStartCol; SCROW nStartRow = rOption.mnStartRow; SCCOL nEndCol = rOption.mnEndCol; SCROW nEndRow = rOption.mnEndRow; if ((nStartCol == nEndCol && nStartRow == nEndRow) || rOption.maTabs.empty()) { // Nothing to do. Bail out quick. return true; } ScDocument& rDoc = rDocShell.GetDocument(); set::const_iterator itrBeg = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end(); SCTAB nTab1 = *itrBeg, nTab2 = *rOption.maTabs.rbegin(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; for (set::const_iterator itr = itrBeg; itr != itrEnd; ++itr) { ScEditableTester aTester( &rDoc, *itr, nStartCol, nStartRow, nEndCol, nEndRow ); if (!aTester.IsEditable()) { if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); return false; } if ( rDoc.HasAttrib( nStartCol, nStartRow, *itr, nEndCol, nEndRow, *itr, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) { // "Zusammenfassen nicht verschachteln !" if (!bApi) rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0); return false; } } ScDocument* pUndoDoc = NULL; bool bNeedContentsUndo = false; for (set::const_iterator itr = itrBeg; itr != itrEnd; ++itr) { SCTAB nTab = *itr; bool bNeedContents = bContents && ( !rDoc.IsBlockEmpty( nTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) || !rDoc.IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) ); if (bRecord) { // test if the range contains other notes which also implies that we need an undo document bool bHasNotes = false; for( ScAddress aPos( nStartCol, nStartRow, nTab ); !bHasNotes && (aPos.Col() <= nEndCol); aPos.IncCol() ) for( aPos.SetRow( nStartRow ); !bHasNotes && (aPos.Row() <= nEndRow); aPos.IncRow() ) bHasNotes = ((aPos.Col() != nStartCol) || (aPos.Row() != nStartRow)) && (rDoc.HasNote(aPos)); if (!pUndoDoc) { pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo(&rDoc, nTab1, nTab2); } // note captions are collected by drawing undo rDoc.CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc ); if( bHasNotes ) rDoc.BeginDrawUndo(); } if (bNeedContents) rDoc.DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); rDoc.DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); if (rOption.mbCenter) { rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) ); rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxVerJustifyItem( SVX_VER_JUSTIFY_CENTER, ATTR_VER_JUSTIFY ) ); } if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab ) ) ) rDocShell.PostPaint( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, PAINT_GRID ); if (bNeedContents || rOption.mbCenter) { ScRange aRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab); rDoc.SetDirty(aRange, true); } bNeedContentsUndo |= bNeedContents; } if (pUndoDoc) { SdrUndoGroup* pDrawUndo = rDoc.GetDrawLayer() ? rDoc.GetDrawLayer()->GetCalcUndo() : NULL; rDocShell.GetUndoManager()->AddUndoAction( new ScUndoMerge(&rDocShell, rOption, bNeedContentsUndo, pUndoDoc, pDrawUndo) ); } aModificator.SetDocumentModified(); SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) { pBindings->Invalidate( FID_MERGE_ON ); pBindings->Invalidate( FID_MERGE_OFF ); pBindings->Invalidate( FID_MERGE_TOGGLE ); } return true; } bool ScDocFunc::UnmergeCells( const ScRange& rRange, bool bRecord ) { ScCellMergeOption aOption(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab(); for (SCTAB i = nTab1; i <= nTab2; ++i) aOption.maTabs.insert(i); return UnmergeCells(aOption, bRecord); } bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord ) { using ::std::set; if (rOption.maTabs.empty()) // Nothing to unmerge. return true; ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; ScDocument* pUndoDoc = NULL; for (set::const_iterator itr = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end(); itr != itrEnd; ++itr) { SCTAB nTab = *itr; ScRange aRange = rOption.getSingleRange(nTab); if ( !rDoc.HasAttrib(aRange, HASATTR_MERGED) ) continue; ScRange aExtended = aRange; rDoc.ExtendMerge(aExtended); ScRange aRefresh = aExtended; rDoc.ExtendOverlapped(aRefresh); if (bRecord) { if (!pUndoDoc) { pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo(&rDoc, *rOption.maTabs.begin(), *rOption.maTabs.rbegin()); } rDoc.CopyToDocument(aExtended, IDF_ATTRIB, false, pUndoDoc); } const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE ); ScPatternAttr aPattern( rDoc.GetPool() ); aPattern.GetItemSet().Put( rDefAttr ); rDoc.ApplyPatternAreaTab( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, aPattern ); rDoc.RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(), aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab, SC_MF_HOR | SC_MF_VER ); rDoc.ExtendMerge( aRefresh, true ); if ( !AdjustRowHeight( aExtended ) ) rDocShell.PostPaint( aExtended, PAINT_GRID ); } if (bRecord) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoRemoveMerge( &rDocShell, rOption, pUndoDoc ) ); } aModificator.SetDocumentModified(); return true; } void ScDocFunc::ModifyRangeNames( const ScRangeName& rNewRanges, SCTAB nTab ) { SetNewRangeNames( new ScRangeName(rNewRanges), true, nTab ); } void ScDocFunc::SetNewRangeNames( ScRangeName* pNewRanges, bool bModifyDoc, SCTAB nTab ) // takes ownership of pNewRanges { ScDocShellModificator aModificator( rDocShell ); OSL_ENSURE( pNewRanges, "pNewRanges is 0" ); ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo(rDoc.IsUndoEnabled()); if (bUndo) { ScRangeName* pOld; if (nTab >=0) { pOld = rDoc.GetRangeName(nTab); } else { pOld = rDoc.GetRangeName(); } ScRangeName* pUndoRanges = new ScRangeName(*pOld); ScRangeName* pRedoRanges = new ScRangeName(*pNewRanges); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoRangeNames( &rDocShell, pUndoRanges, pRedoRanges, nTab ) ); } // #i55926# While loading XML, formula cells only have a single string token, // so CompileNameFormula would never find any name (index) tokens, and would // unnecessarily loop through all cells. bool bCompile = ( !rDoc.IsImportingXML() && rDoc.GetNamedRangesLockCount() == 0 ); if ( bCompile ) rDoc.PreprocessRangeNameUpdate(); if (nTab >= 0) rDoc.SetRangeName( nTab, pNewRanges ); // takes ownership else rDoc.SetRangeName( pNewRanges ); // takes ownership if ( bCompile ) rDoc.CompileHybridFormula(); if (bModifyDoc) { aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast( SfxSimpleHint(SC_HINT_AREAS_CHANGED) ); } } void ScDocFunc::ModifyAllRangeNames( const boost::ptr_map& rRangeMap ) { ScDocShellModificator aModificator(rDocShell); ScDocument& rDoc = rDocShell.GetDocument(); if (rDoc.IsUndoEnabled()) { std::map aOldRangeMap; rDoc.GetRangeNameMap(aOldRangeMap); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAllRangeNames(&rDocShell, aOldRangeMap, rRangeMap)); } rDoc.PreprocessRangeNameUpdate(); rDoc.SetAllRangeNames(rRangeMap); rDoc.CompileHybridFormula(); aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED)); } void ScDocFunc::CreateOneName( ScRangeName& rList, SCCOL nPosX, SCROW nPosY, SCTAB nTab, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, bool& rCancel, bool bApi ) { if (rCancel) return; ScDocument& rDoc = rDocShell.GetDocument(); if (!rDoc.HasValueData( nPosX, nPosY, nTab )) { OUString aName = rDoc.GetString(nPosX, nPosY, nTab); ScRangeData::MakeValidName(aName); if (!aName.isEmpty()) { OUString aContent(ScRange( nX1, nY1, nTab, nX2, nY2, nTab ).Format(SCR_ABS_3D, &rDoc)); bool bInsert = false; ScRangeData* pOld = rList.findByUpperName(ScGlobal::pCharClass->uppercase(aName)); if (pOld) { OUString aOldStr; pOld->GetSymbol( aOldStr ); if (aOldStr != aContent) { if (bApi) bInsert = true; // per API nicht nachfragen else { OUString aTemplate = ScGlobal::GetRscString( STR_CREATENAME_REPLACE ); OUString aMessage = aTemplate.getToken( 0, '#' ); aMessage += aName; aMessage += aTemplate.getToken( 1, '#' ); short nResult = QueryBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO_CANCEL | WB_DEF_YES), aMessage ).Execute(); if ( nResult == RET_YES ) { rList.erase(*pOld); bInsert = true; } else if ( nResult == RET_CANCEL ) rCancel = true; } } } else bInsert = true; if (bInsert) { ScRangeData* pData = new ScRangeData( &rDoc, aName, aContent, ScAddress( nPosX, nPosY, nTab)); if (!rList.insert(pData)) { OSL_FAIL("nanu?"); } } } } } bool ScDocFunc::CreateNames( const ScRange& rRange, sal_uInt16 nFlags, bool bApi, SCTAB aTab ) { if (!nFlags) return false; // war nix ScDocShellModificator aModificator( rDocShell ); bool bDone = false; SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); SCCOL nEndCol = rRange.aEnd.Col(); SCROW nEndRow = rRange.aEnd.Row(); SCTAB nTab = rRange.aStart.Tab(); OSL_ENSURE(rRange.aEnd.Tab() == nTab, "CreateNames: mehrere Tabellen geht nicht"); bool bValid = true; if ( nFlags & ( NAME_TOP | NAME_BOTTOM ) ) if ( nStartRow == nEndRow ) bValid = false; if ( nFlags & ( NAME_LEFT | NAME_RIGHT ) ) if ( nStartCol == nEndCol ) bValid = false; if (bValid) { ScDocument& rDoc = rDocShell.GetDocument(); ScRangeName* pNames; if (aTab >=0) pNames = rDoc.GetRangeName(nTab); else pNames = rDoc.GetRangeName(); if (!pNames) return false; // soll nicht sein ScRangeName aNewRanges( *pNames ); bool bTop = ( ( nFlags & NAME_TOP ) != 0 ); bool bLeft = ( ( nFlags & NAME_LEFT ) != 0 ); bool bBottom = ( ( nFlags & NAME_BOTTOM ) != 0 ); bool bRight = ( ( nFlags & NAME_RIGHT ) != 0 ); SCCOL nContX1 = nStartCol; SCROW nContY1 = nStartRow; SCCOL nContX2 = nEndCol; SCROW nContY2 = nEndRow; if ( bTop ) ++nContY1; if ( bLeft ) ++nContX1; if ( bBottom ) --nContY2; if ( bRight ) --nContX2; bool bCancel = false; SCCOL i; SCROW j; if ( bTop ) for (i=nContX1; i<=nContX2; i++) CreateOneName( aNewRanges, i,nStartRow,nTab, i,nContY1,i,nContY2, bCancel, bApi ); if ( bLeft ) for (j=nContY1; j<=nContY2; j++) CreateOneName( aNewRanges, nStartCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi ); if ( bBottom ) for (i=nContX1; i<=nContX2; i++) CreateOneName( aNewRanges, i,nEndRow,nTab, i,nContY1,i,nContY2, bCancel, bApi ); if ( bRight ) for (j=nContY1; j<=nContY2; j++) CreateOneName( aNewRanges, nEndCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi ); if ( bTop && bLeft ) CreateOneName( aNewRanges, nStartCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); if ( bTop && bRight ) CreateOneName( aNewRanges, nEndCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); if ( bBottom && bLeft ) CreateOneName( aNewRanges, nStartCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); if ( bBottom && bRight ) CreateOneName( aNewRanges, nEndCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); ModifyRangeNames( aNewRanges, aTab ); bDone = true; } return bDone; } bool ScDocFunc::InsertNameList( const ScAddress& rStartPos, bool bApi ) { ScDocShellModificator aModificator( rDocShell ); bool bDone = false; ScDocument& rDoc = rDocShell.GetDocument(); const bool bRecord = rDoc.IsUndoEnabled(); SCTAB nTab = rStartPos.Tab(); ScDocument* pUndoDoc = NULL; //local names have higher priority than global names ScRangeName* pLocalList = rDoc.GetRangeName(nTab); sal_uInt16 nValidCount = 0; ScRangeName::iterator itrLocalBeg = pLocalList->begin(), itrLocalEnd = pLocalList->end(); for (ScRangeName::iterator itr = itrLocalBeg; itr != itrLocalEnd; ++itr) { const ScRangeData& r = *itr->second; if (!r.HasType(RT_DATABASE)) ++nValidCount; } ScRangeName* pList = rDoc.GetRangeName(); ScRangeName::iterator itrBeg = pList->begin(), itrEnd = pList->end(); for (ScRangeName::iterator itr = itrBeg; itr != itrEnd; ++itr) { const ScRangeData& r = *itr->second; if (!r.HasType(RT_DATABASE) && !pLocalList->findByUpperName(r.GetUpperName())) ++nValidCount; } if (nValidCount) { SCCOL nStartCol = rStartPos.Col(); SCROW nStartRow = rStartPos.Row(); SCCOL nEndCol = nStartCol + 1; SCROW nEndRow = nStartRow + static_cast(nValidCount) - 1; ScEditableTester aTester( &rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow ); if (aTester.IsEditable()) { if (bRecord) { pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); pUndoDoc->InitUndo( &rDoc, nTab, nTab ); rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, IDF_ALL, false, pUndoDoc ); rDoc.BeginDrawUndo(); // wegen Hoehenanpassung } boost::scoped_array ppSortArray(new ScRangeData* [ nValidCount ]); sal_uInt16 j = 0; for (ScRangeName::iterator itr = itrLocalBeg; itr != itrLocalEnd; ++itr) { ScRangeData& r = *itr->second; if (!r.HasType(RT_DATABASE)) ppSortArray[j++] = &r; } for (ScRangeName::iterator itr = itrBeg; itr != itrEnd; ++itr) { ScRangeData& r = *itr->second; if (!r.HasType(RT_DATABASE) && !pLocalList->findByUpperName(itr->first)) ppSortArray[j++] = &r; } qsort( (void*)ppSortArray.get(), nValidCount, sizeof(ScRangeData*), &ScRangeData_QsortNameCompare ); OUString aName; OUStringBuffer aContent; OUString aFormula; SCROW nOutRow = nStartRow; for (j=0; jGetName(aName); // relative Referenzen Excel-konform auf die linke Spalte anpassen: pData->UpdateSymbol(aContent, ScAddress( nStartCol, nOutRow, nTab )); aFormula = "=" + aContent.toString(); ScSetStringParam aParam; aParam.setTextInput(); rDoc.SetString(ScAddress(nStartCol,nOutRow,nTab), aName, &aParam); rDoc.SetString(ScAddress(nEndCol,nOutRow,nTab), aFormula, &aParam); ++nOutRow; } ppSortArray.reset(); if (bRecord) { ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO ); pRedoDoc->InitUndo( &rDoc, nTab, nTab ); rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, IDF_ALL, false, pRedoDoc ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoListNames( &rDocShell, ScRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab ), pUndoDoc, pRedoDoc ) ); } if (!AdjustRowHeight(ScRange(0,nStartRow,nTab,MAXCOL,nEndRow,nTab))) rDocShell.PostPaint( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, PAINT_GRID ); aModificator.SetDocumentModified(); bDone = true; } else if (!bApi) rDocShell.ErrorMessage(aTester.GetMessageId()); } return bDone; } bool ScDocFunc::ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); SCCOL nStartCol = rOldRange.aStart.Col(); SCROW nStartRow = rOldRange.aStart.Row(); SCTAB nTab = rOldRange.aStart.Tab(); bool bUndo(rDoc.IsUndoEnabled()); bool bRet = false; OUString aFormula; rDoc.GetFormula( nStartCol, nStartRow, nTab, aFormula ); if ( aFormula.startsWith("{") && aFormula.endsWith("}") ) { OUString aUndo = ScGlobal::GetRscString( STR_UNDO_RESIZEMATRIX ); if (bUndo) rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); aFormula = aFormula.copy(1, aFormula.getLength()-2); ScMarkData aMark; aMark.SetMarkArea( rOldRange ); aMark.SelectTable( nTab, true ); ScRange aNewRange( rOldRange.aStart, rNewEnd ); if ( DeleteContents( aMark, IDF_CONTENTS, true, bApi ) ) { // GRAM_PODF_A1 for API compatibility. bRet = EnterMatrix( aNewRange, &aMark, NULL, aFormula, bApi, false, EMPTY_OUSTRING, formula::FormulaGrammar::GRAM_PODF_A1 ); if (!bRet) { // versuchen, alten Zustand wiederherzustellen EnterMatrix( rOldRange, &aMark, NULL, aFormula, bApi, false, EMPTY_OUSTRING, formula::FormulaGrammar::GRAM_PODF_A1 ); } } if (bUndo) rDocShell.GetUndoManager()->LeaveListAction(); } return bRet; } bool ScDocFunc::InsertAreaLink( const OUString& rFile, const OUString& rFilter, const OUString& rOptions, const OUString& rSource, const ScRange& rDestRange, sal_uLong nRefresh, bool bFitBlock, bool bApi ) { ScDocument& rDoc = rDocShell.GetDocument(); bool bUndo (rDoc.IsUndoEnabled()); sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager(); // #i52120# if other area links exist at the same start position, // remove them first (file format specifies only one link definition // for a cell) sal_uInt16 nLinkCount = pLinkManager->GetLinks().size(); sal_uInt16 nRemoved = 0; sal_uInt16 nLinkPos = 0; while (nLinkPosGetLinks()[nLinkPos]; if ( pBase->ISA(ScAreaLink) && static_cast(pBase)->GetDestArea().aStart == rDestRange.aStart ) { if ( bUndo ) { if ( !nRemoved ) { // group all remove and the insert action OUString aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTAREALINK ); rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); } ScAreaLink* pOldArea = static_cast(pBase); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoRemoveAreaLink( &rDocShell, pOldArea->GetFile(), pOldArea->GetFilter(), pOldArea->GetOptions(), pOldArea->GetSource(), pOldArea->GetDestArea(), pOldArea->GetRefreshDelay() ) ); } pLinkManager->Remove( pBase ); nLinkCount = pLinkManager->GetLinks().size(); ++nRemoved; } else ++nLinkPos; } OUString aFilterName = rFilter; OUString aNewOptions = rOptions; if (aFilterName.isEmpty()) ScDocumentLoader::GetFilterName( rFile, aFilterName, aNewOptions, true, !bApi ); // remove application prefix from filter name here, so the filter options // aren't reset when the filter name is changed in ScAreaLink::DataChanged ScDocumentLoader::RemoveAppPrefix( aFilterName ); ScAreaLink* pLink = new ScAreaLink( &rDocShell, rFile, aFilterName, aNewOptions, rSource, rDestRange, nRefresh ); OUString aTmp = aFilterName; pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, rFile, &aTmp, &rSource ); // Undo fuer den leeren Link if (bUndo) { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoInsertAreaLink( &rDocShell, rFile, aFilterName, aNewOptions, rSource, rDestRange, nRefresh ) ); if ( nRemoved ) rDocShell.GetUndoManager()->LeaveListAction(); // undo for link update is still separate } // Update hat sein eigenes Undo if (rDoc.IsExecuteLinkEnabled()) { pLink->SetDoInsert(bFitBlock); // beim ersten Update ggf. nichts einfuegen pLink->Update(); // kein SetInCreate -> Update ausfuehren } pLink->SetDoInsert(true); // Default = true SfxBindings* pBindings = rDocShell.GetViewBindings(); if (pBindings) pBindings->Invalidate( SID_LINKS ); SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); // Navigator return true; } namespace { void RemoveCondFormatAttributes(ScDocument* pDoc, const ScConditionalFormat* pFormat, SCTAB nTab) { const ScRangeList& rRangeList = pFormat->GetRange(); pDoc->RemoveCondFormatData( rRangeList, nTab, pFormat->GetKey() ); } void SetConditionalFormatAttributes(ScDocument* pDoc, const ScRangeList& rRanges, sal_uLong nIndex, SCTAB nTab) { pDoc->AddCondFormatData( rRanges, nTab, nIndex ); } } void ScDocFunc::ReplaceConditionalFormat( sal_uLong nOldFormat, ScConditionalFormat* pFormat, SCTAB nTab, const ScRangeList& rRanges ) { ScDocShellModificator aModificator(rDocShell); ScDocument& rDoc = rDocShell.GetDocument(); if(rDoc.IsTabProtected(nTab)) return; bool bUndo = rDoc.IsUndoEnabled(); ScDocument* pUndoDoc = NULL; ScRange aCombinedRange = rRanges.Combine(); ScRange aCompleteRange; if(bUndo) { pUndoDoc = new ScDocument(SCDOCMODE_UNDO); pUndoDoc->InitUndo( &rDoc, nTab, nTab ); if(pFormat) { aCompleteRange = aCombinedRange; } if(nOldFormat) { ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat); if(pOldFormat) aCompleteRange.ExtendTo(pOldFormat->GetRange().Combine()); } rDoc.CopyToDocument( aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab, aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab, IDF_ALL, false, pUndoDoc ); } boost::scoped_ptr pRepaintRange; if(nOldFormat) { ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat); if(pOldFormat) { pRepaintRange.reset(new ScRange( pOldFormat->GetRange().Combine() )); RemoveCondFormatAttributes(&rDoc, pOldFormat, nTab); } rDoc.DeleteConditionalFormat(nOldFormat, nTab); rDoc.SetStreamValid(nTab, false); } if(pFormat) { if(pRepaintRange) pRepaintRange->ExtendTo(aCombinedRange); else pRepaintRange.reset(new ScRange(aCombinedRange)); sal_uLong nIndex = rDoc.AddCondFormat(pFormat, nTab); SetConditionalFormatAttributes(&rDoc, rRanges, nIndex, nTab); rDoc.SetStreamValid(nTab, false); } if(bUndo) { ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO); pRedoDoc->InitUndo( &rDoc, nTab, nTab ); rDoc.CopyToDocument( aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab, aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab, IDF_ALL, false, pRedoDoc ); rDocShell.GetUndoManager()->AddUndoAction( new ScUndoConditionalFormat(&rDocShell, pUndoDoc, pRedoDoc, aCompleteRange)); } if(pRepaintRange) rDocShell.PostPaint(*pRepaintRange, PAINT_GRID); aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED)); } void ScDocFunc::SetConditionalFormatList( ScConditionalFormatList* pList, SCTAB nTab ) { ScDocShellModificator aModificator(rDocShell); ScDocument& rDoc = rDocShell.GetDocument(); if(rDoc.IsTabProtected(nTab)) return; // first remove all old entries ScConditionalFormatList* pOldList = rDoc.GetCondFormList(nTab); for(ScConditionalFormatList::const_iterator itr = pOldList->begin(), itrEnd = pOldList->end(); itr != itrEnd; ++itr) { RemoveCondFormatAttributes(&rDoc, &(*itr), nTab); } // then set new entries for(ScConditionalFormatList::iterator itr = pList->begin(); itr != pList->end(); ++itr) { sal_uLong nIndex = itr->GetKey(); const ScRangeList& rRange = itr->GetRange(); SetConditionalFormatAttributes(&rDoc, rRange, nIndex, nTab); } rDoc.SetCondFormList(pList, nTab); rDocShell.PostPaintGridAll(); rDoc.SetStreamValid(nTab, false); aModificator.SetDocumentModified(); SfxGetpApp()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED)); } void ScDocFunc::ConvertFormulaToValue( const ScRange& rRange, bool bRecord, bool bInteraction ) { ScDocShellModificator aModificator(rDocShell); ScDocument& rDoc = rDocShell.GetDocument(); if (!rDoc.IsUndoEnabled()) bRecord = false; ScEditableTester aTester(&rDoc, rRange); if (!aTester.IsEditable()) { if (bInteraction) rDocShell.ErrorMessage(aTester.GetMessageId()); return; } sc::TableValues aUndoVals(rRange); sc::TableValues* pUndoVals = bRecord ? &aUndoVals : NULL; rDoc.ConvertFormulaToValue(rRange, pUndoVals); if (bRecord && pUndoVals) { rDocShell.GetUndoManager()->AddUndoAction( new sc::UndoFormulaToValue(&rDocShell, *pUndoVals)); } rDocShell.PostPaint(rRange, PAINT_GRID); rDocShell.PostDataChanged(); rDoc.BroadcastCells(rRange, SC_HINT_DATACHANGED); aModificator.SetDocumentModified(); } void ScDocFunc::EnterListAction( sal_uInt16 nNameResId ) { OUString aUndo( ScGlobal::GetRscString( nNameResId ) ); rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); } void ScDocFunc::EndListAction() { rDocShell.GetUndoManager()->LeaveListAction(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */