blob: 3b62077c97004a262dc89006dc5d25481bd7af2e [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
// INCLUDE ---------------------------------------------------------------
#include "scitems.hxx"
#include <editeng/eeitem.hxx>
#include <sfx2/app.hxx>
#include <editeng/editobj.hxx>
#include <sfx2/linkmgr.hxx>
#include <svx/svdundo.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/printer.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/sound.hxx>
#include <vcl/virdev.hxx>
#include <vcl/waitobj.hxx>
#include <svl/zforlist.hxx>
#include <svl/PasswordHelper.hxx>
#include <basic/sbstar.hxx>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/script/ModuleType.hpp>
#include <com/sun/star/script/XLibraryContainer.hpp>
#include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
#include <list>
#include "docfunc.hxx"
#include "sc.hrc"
#include "arealink.hxx"
#include "attrib.hxx"
#include "dociter.hxx"
#include "autoform.hxx"
#include "cell.hxx"
#include "detdata.hxx"
#include "detfunc.hxx"
#include "docpool.hxx"
#include "docsh.hxx"
#include "drwlayer.hxx"
#include "editutil.hxx"
#include "globstr.hrc"
//CHINA001 #include "namecrea.hxx" // NAME_TOP etc.
#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" //CHINA001
#include "tabprotection.hxx"
#include "clipparam.hxx"
#include "externalrefmgr.hxx"
#include <memory>
#include <basic/basmgr.hxx>
#include <boost/scoped_ptr.hpp>
using namespace com::sun::star;
using ::com::sun::star::uno::Sequence;
// 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->IsUndoAllowed() && 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* pDoc = rDocShell.GetDocument();
SCTAB nTabCount = pDoc->GetTableCount();
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
if (pDoc->IsStreamValid(nTab))
pDoc->SetStreamValid(nTab, sal_False);
return 0;
}
//------------------------------------------------------------------------
// Zeile ueber dem Range painten (fuer Linien nach AdjustRowHeight)
void lcl_PaintAbove( ScDocShell& rDocShell, const ScRange& rRange )
{
SCROW nRow = rRange.aStart.Row();
if ( nRow > 0 )
{
SCTAB nTab = rRange.aStart.Tab(); //! alle?
--nRow;
rDocShell.PostPaint( ScRange(0,nRow,nTab, MAXCOL,nRow,nTab), PAINT_GRID );
}
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::AdjustRowHeight( const ScRange& rRange, sal_Bool bPaint )
{
ScDocument* pDoc = rDocShell.GetDocument();
if ( pDoc->IsImportingXML() )
{
// for XML import, all row heights are updated together after importing
return sal_False;
}
if ( !pDoc->IsAdjustHeightEnabled() )
{
return sal_False;
}
SCTAB nTab = rRange.aStart.Tab();
SCROW nStartRow = rRange.aStart.Row();
SCROW nEndRow = rRange.aEnd.Row();
ScSizeDeviceProvider aProv( &rDocShell );
Fraction aOne(1,1);
sal_Bool bChanged = pDoc->SetOptimalHeight( nStartRow, nEndRow, nTab, 0, aProv.GetDevice(),
aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, sal_False );
if ( bPaint && bChanged )
rDocShell.PostPaint( 0, nStartRow, nTab, MAXCOL, MAXROW, nTab,
PAINT_GRID | PAINT_LEFT );
return bChanged;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::DetectiveAddPred(const ScAddress& rPos)
{
ScDocShellModificator aModificator( rDocShell );
rDocShell.MakeDrawLayer();
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
ScDrawLayer* pModel = pDoc->GetDrawLayer();
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
if (bUndo)
pModel->BeginCalcUndo(false);
sal_Bool bDone = ScDetectiveFunc( pDoc,nTab ).ShowPred( nCol, nRow );
SdrUndoGroup* pUndo = NULL;
if (bUndo)
pUndo = pModel->GetCalcUndo();
if (bDone)
{
ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDPRED );
pDoc->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;
}
sal_Bool ScDocFunc::DetectiveDelPred(const ScAddress& rPos)
{
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo(pDoc->IsUndoEnabled());
ScDrawLayer* pModel = pDoc->GetDrawLayer();
if (!pModel)
return sal_False;
ScDocShellModificator aModificator( rDocShell );
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
if (bUndo)
pModel->BeginCalcUndo(false);
sal_Bool bDone = ScDetectiveFunc( pDoc,nTab ).DeletePred( nCol, nRow );
SdrUndoGroup* pUndo = NULL;
if (bUndo)
pUndo = pModel->GetCalcUndo();
if (bDone)
{
ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELPRED );
pDoc->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;
}
sal_Bool ScDocFunc::DetectiveAddSucc(const ScAddress& rPos)
{
ScDocShellModificator aModificator( rDocShell );
rDocShell.MakeDrawLayer();
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo(pDoc->IsUndoEnabled());
ScDrawLayer* pModel = pDoc->GetDrawLayer();
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
if (bUndo)
pModel->BeginCalcUndo(false);
sal_Bool bDone = ScDetectiveFunc( pDoc,nTab ).ShowSucc( nCol, nRow );
SdrUndoGroup* pUndo = NULL;
if (bUndo)
pUndo = pModel->GetCalcUndo();
if (bDone)
{
ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDSUCC );
pDoc->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;
}
sal_Bool ScDocFunc::DetectiveDelSucc(const ScAddress& rPos)
{
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
ScDrawLayer* pModel = pDoc->GetDrawLayer();
if (!pModel)
return sal_False;
ScDocShellModificator aModificator( rDocShell );
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
if (bUndo)
pModel->BeginCalcUndo(false);
sal_Bool bDone = ScDetectiveFunc( pDoc,nTab ).DeleteSucc( nCol, nRow );
SdrUndoGroup* pUndo = NULL;
if (bUndo)
pUndo = pModel->GetCalcUndo();
if (bDone)
{
ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELSUCC );
pDoc->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;
}
sal_Bool ScDocFunc::DetectiveAddError(const ScAddress& rPos)
{
ScDocShellModificator aModificator( rDocShell );
rDocShell.MakeDrawLayer();
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
ScDrawLayer* pModel = pDoc->GetDrawLayer();
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
if (bUndo)
pModel->BeginCalcUndo(false);
sal_Bool bDone = ScDetectiveFunc( pDoc,nTab ).ShowError( nCol, nRow );
SdrUndoGroup* pUndo = NULL;
if (bUndo)
pUndo = pModel->GetCalcUndo();
if (bDone)
{
ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDERROR );
pDoc->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;
}
sal_Bool ScDocFunc::DetectiveMarkInvalid(SCTAB nTab)
{
ScDocShellModificator aModificator( rDocShell );
rDocShell.MakeDrawLayer();
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
ScDrawLayer* pModel = pDoc->GetDrawLayer();
Window* pWaitWin = rDocShell.GetActiveDialogParent();
if (pWaitWin)
pWaitWin->EnterWait();
if (bUndo)
pModel->BeginCalcUndo(false);
sal_Bool bOverflow;
sal_Bool bDone = ScDetectiveFunc( pDoc,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;
}
sal_Bool ScDocFunc::DetectiveDelAll(SCTAB nTab)
{
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
ScDrawLayer* pModel = pDoc->GetDrawLayer();
if (!pModel)
return sal_False;
ScDocShellModificator aModificator( rDocShell );
if (bUndo)
pModel->BeginCalcUndo(false);
sal_Bool bDone = ScDetectiveFunc( pDoc,nTab ).DeleteAll( SC_DET_DETECTIVE );
SdrUndoGroup* pUndo = NULL;
if (bUndo)
pUndo = pModel->GetCalcUndo();
if (bDone)
{
ScDetOpList* pOldList = pDoc->GetDetOpList();
ScDetOpList* pUndoList = NULL;
if (bUndo)
pUndoList = pOldList ? new ScDetOpList(*pOldList) : NULL;
pDoc->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;
}
sal_Bool ScDocFunc::DetectiveRefresh( sal_Bool bAutomatic )
{
sal_Bool bDone = sal_False;
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
ScDetOpList* pList = pDoc->GetDetOpList();
if ( pList && pList->Count() )
{
rDocShell.MakeDrawLayer();
ScDrawLayer* pModel = pDoc->GetDrawLayer();
if (bUndo)
pModel->BeginCalcUndo(false);
// Loeschen auf allen Tabellen
SCTAB nTabCount = pDoc->GetTableCount();
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
ScDetectiveFunc( pDoc,nTab ).DeleteAll( SC_DET_ARROWS ); // don't remove circles
// Wiederholen
sal_uInt16 nCount = pList->Count();
for (sal_uInt16 i=0; i<nCount; i++)
{
ScDetOpData* pData = (*pList)[i];
if (pData)
{
ScAddress aPos = pData->GetPos();
ScDetectiveFunc aFunc( pDoc, 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:
DBG_ERROR("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 = sal_True;
}
return bDone;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::DeleteContents( const ScMarkData& rMark, sal_uInt16 nFlags,
sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
{
DBG_ERROR("ScDocFunc::DeleteContents ohne Markierung");
return sal_False;
}
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScEditableTester aTester( pDoc, rMark );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
ScRange aMarkRange;
sal_Bool bSimple = sal_False;
ScMarkData aMultiMark = rMark;
aMultiMark.SetMarking(sal_False); // fuer MarkToMulti
ScDocument* pUndoDoc = NULL;
sal_Bool bMulti = !bSimple && aMultiMark.IsMultiMarked();
if (!bSimple)
{
aMultiMark.MarkToMulti();
aMultiMark.GetMultiMarkArea( aMarkRange );
}
ScRange aExtendedRange(aMarkRange);
if (!bSimple)
{
if ( pDoc->ExtendMerge( aExtendedRange, sal_True ) )
bMulti = sal_False;
}
// keine Objekte auf geschuetzten Tabellen
sal_Bool bObjects = sal_False;
if ( nFlags & IDF_OBJECTS )
{
bObjects = sal_True;
SCTAB nTabCount = pDoc->GetTableCount();
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
if (aMultiMark.GetTableSelect(nTab) && pDoc->IsTabProtected(nTab))
bObjects = sal_False;
}
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)
pDoc->BeginDrawUndo();
if (bObjects)
{
if (bMulti)
pDoc->DeleteObjectsInSelection( aMultiMark );
else
pDoc->DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
aMultiMark );
}
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, aMarkRange.aStart.Tab(), aMarkRange.aEnd.Tab() );
// bei "Format/Standard" alle Attribute kopieren, weil CopyToDocument
// nur mit IDF_HARDATTR zu langsam ist:
sal_uInt16 nUndoDocFlags = nFlags;
if (nFlags & IDF_ATTRIB)
nUndoDocFlags |= IDF_ATTRIB;
if (nFlags & IDF_EDITATTR) // Edit-Engine-Attribute
nUndoDocFlags |= IDF_STRING; // -> Zellen werden geaendert
if (nFlags & IDF_NOTE)
nUndoDocFlags |= IDF_CONTENTS; // #68795# copy all cells with their notes
// note captions are handled in drawing undo
nUndoDocFlags |= IDF_NOCAPTIONS;
pDoc->CopyToDocument( aExtendedRange, nUndoDocFlags, bMulti, pUndoDoc, &aMultiMark );
}
//! HideAllCursors(); // falls Zusammenfassung aufgehoben wird
if (bSimple)
pDoc->DeleteArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
aMultiMark, nFlags );
else
{
pDoc->DeleteSelection( nFlags, aMultiMark );
// aMultiMark.MarkToSimple();
}
// add undo action after drawing undo is complete (objects and note captions)
if( bRecord )
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDeleteContents( &rDocShell, aMultiMark, aExtendedRange,
pUndoDoc, bMulti, nFlags, 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
// rDocShell.UpdateOle(GetViewData()); //! an der View?
aModificator.SetDocumentModified();
//! CellContentChanged();
//! ShowAllCursors();
#if 0
//! muss an der View bleiben !!!!
if ( nFlags & IDF_ATTRIB )
{
if ( nFlags & IDF_CONTENTS )
ForgetFormatArea();
else
StartFormatArea(); // Attribute loeschen ist auch Attributierung
}
#endif
return sal_True;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::TransliterateText( const ScMarkData& rMark, sal_Int32 nType,
sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScEditableTester aTester( pDoc, rMark );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
ScRange aMarkRange;
ScMarkData aMultiMark = rMark;
aMultiMark.SetMarking(sal_False); // for MarkToMulti
aMultiMark.MarkToMulti();
aMultiMark.GetMultiMarkArea( aMarkRange );
if (bRecord)
{
SCTAB nStartTab = aMarkRange.aStart.Tab();
SCTAB nTabCount = pDoc->GetTableCount();
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nStartTab && rMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i );
ScRange aCopyRange = aMarkRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(nTabCount-1);
pDoc->CopyToDocument( aCopyRange, IDF_CONTENTS, sal_True, pUndoDoc, &aMultiMark );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoTransliterate( &rDocShell, aMultiMark, pUndoDoc, nType ) );
}
pDoc->TransliterateText( aMultiMark, nType );
if (!AdjustRowHeight( aMarkRange ))
rDocShell.PostPaint( aMarkRange, PAINT_GRID );
aModificator.SetDocumentModified();
return sal_True;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::SetNormalString( const ScAddress& rPos, const String& rText, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo(pDoc->IsUndoEnabled());
ScEditableTester aTester( pDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
SCTAB* pTabs = NULL;
ScBaseCell** ppOldCells = NULL;
sal_Bool* pHasFormat = NULL;
sal_uLong* pOldFormats = NULL;
ScBaseCell* pDocCell = pDoc->GetCell( rPos );
sal_Bool bEditDeleted = (pDocCell && pDocCell->GetCellType() == CELLTYPE_EDIT);
if (bUndo)
{
pTabs = new SCTAB[1];
pTabs[0] = rPos.Tab();
ppOldCells = new ScBaseCell*[1];
ppOldCells[0] = pDocCell ? pDocCell->CloneWithoutNote( *pDoc ) : 0;
pHasFormat = new sal_Bool[1];
pOldFormats = new sal_uLong[1];
const SfxPoolItem* pItem;
const ScPatternAttr* pPattern = pDoc->GetPattern( rPos.Col(),rPos.Row(),rPos.Tab() );
if ( SFX_ITEM_SET == pPattern->GetItemSet().GetItemState(
ATTR_VALUE_FORMAT,sal_False,&pItem) )
{
pHasFormat[0] = sal_True;
pOldFormats[0] = ((const SfxUInt32Item*)pItem)->GetValue();
}
else
pHasFormat[0] = sal_False;
}
pDoc->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.Col(),rPos.Row(),rPos.Tab(), 1,pTabs,
ppOldCells, pHasFormat, pOldFormats, rText, NULL ) );
}
if ( bEditDeleted || pDoc->HasAttrib( ScRange(rPos), HASATTR_NEEDHEIGHT ) )
AdjustRowHeight( ScRange(rPos) );
rDocShell.PostPaintCell( rPos );
aModificator.SetDocumentModified();
// #107160# notify input handler here the same way as in PutCell
if (bApi)
NotifyInputHandler( rPos );
return sal_True;
}
sal_Bool ScDocFunc::PutCell( const ScAddress& rPos, ScBaseCell* pNewCell, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
sal_Bool bXMLLoading(pDoc->IsImportingXML());
// #i925#; it is not neccessary to test whether the cell is editable on loading a XML document
if (!bXMLLoading)
{
ScEditableTester aTester( pDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
pNewCell->Delete();
return sal_False;
}
}
sal_Bool bEditCell = ( pNewCell->GetCellType() == CELLTYPE_EDIT );
ScBaseCell* pDocCell = pDoc->GetCell( rPos );
sal_Bool bEditDeleted = (pDocCell && pDocCell->GetCellType() == CELLTYPE_EDIT);
sal_Bool bHeight = ( bEditDeleted || bEditCell ||
pDoc->HasAttrib( ScRange(rPos), HASATTR_NEEDHEIGHT ) );
ScBaseCell* pUndoCell = (bUndo && pDocCell) ? pDocCell->CloneWithoutNote( *pDoc, rPos ) : 0;
ScBaseCell* pRedoCell = (bUndo && pNewCell) ? pNewCell->CloneWithoutNote( *pDoc, rPos ) : 0;
pDoc->PutCell( rPos, pNewCell );
// wegen ChangeTracking darf UndoAction erst nach PutCell angelegt werden
if (bUndo)
{
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoPutCell( &rDocShell, rPos, pUndoCell, pRedoCell, bHeight ) );
}
if (bHeight)
AdjustRowHeight( ScRange(rPos) );
if (!bXMLLoading)
rDocShell.PostPaintCell( rPos );
aModificator.SetDocumentModified();
// #i925#; it is not neccessary to notify on loading a XML document
// #103934#; notify editline and cell in edit mode
if (bApi && !bXMLLoading)
NotifyInputHandler( rPos );
return sal_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 )
{
sal_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(sal_False, !bIsEditMode);
}
}
}
struct ScMyRememberItem
{
sal_uInt16 nIndex;
SfxItemSet aItemSet;
ScMyRememberItem(const SfxItemSet& rItemSet, sal_uInt16 nTempIndex) :
nIndex(nTempIndex), aItemSet(rItemSet) {}
};
typedef ::std::list<ScMyRememberItem*> ScMyRememberItemList;
sal_Bool ScDocFunc::PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, sal_Bool bInterpret, sal_Bool bApi )
{
// PutData ruft PutCell oder SetNormalString
sal_Bool bRet = sal_False;
ScDocument* pDoc = rDocShell.GetDocument();
ScEditAttrTester aTester( &rEngine );
sal_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 obejct's
// EditEngine isn't accessed again.
sal_Bool bLoseContent = pDoc->IsImportingXML();
sal_Bool bUpdateMode(rEngine.GetUpdateMode());
if (bUpdateMode)
rEngine.SetUpdateMode(sal_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_uInt16 nCount = rEngine.GetParagraphCount();
for (sal_uInt16 i=0; i<nCount; i++)
{
const SfxItemSet& rOld = rEngine.GetParaAttribs( i );
if ( rOld.Count() )
{
if ( !bLoseContent )
{
pRememberItem = new ScMyRememberItem(rEngine.GetParaAttribs(i), i);
aRememberItems.push_back(pRememberItem);
}
rEngine.SetParaAttribs( i, SfxItemSet( *rOld.GetPool(), rOld.GetRanges() ) );
}
}
EditTextObject* pNewData = rEngine.CreateTextObject();
bRet = PutCell( rPos,
new ScEditCell( pNewData, pDoc, rEngine.GetEditTextObjectPool() ),
bApi );
delete pNewData;
// Set the paragraph attributes back to the EditEngine.
if (!aRememberItems.empty())
{
// ScMyRememberItem* pRememberItem = NULL;
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(sal_True);
}
else
{
String aText = rEngine.GetText();
if ( bInterpret || !aText.Len() )
bRet = SetNormalString( rPos, aText, bApi );
else
bRet = PutCell( rPos, new ScStringCell( aText ), bApi );
}
if ( bRet && aTester.NeedsCellAttr() )
{
const SfxItemSet& rEditAttr = aTester.GetAttribs();
ScPatternAttr aPattern( pDoc->GetPool() );
aPattern.GetFromEditItemSet( &rEditAttr );
aPattern.DeleteUnchanged( pDoc->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(), sal_True );
aMark.SetMarkArea( ScRange( rPos ) );
ApplyAttributes( aMark, aPattern, sal_True, bApi );
}
}
return bRet;
}
ScTokenArray* lcl_ScDocFunc_CreateTokenArrayXML( const String& rText, const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar )
{
ScTokenArray* pCode = new ScTokenArray;
pCode->AddString( rText );
if( (eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) && (rFormulaNmsp.Len() > 0) )
pCode->AddString( rFormulaNmsp );
return pCode;
}
ScBaseCell* ScDocFunc::InterpretEnglishString( const ScAddress& rPos,
const String& rText, const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar, short* pRetFormatType )
{
ScDocument* pDoc = rDocShell.GetDocument();
ScBaseCell* pNewCell = NULL;
if ( rText.Len() > 1 && rText.GetChar(0) == '=' )
{
ScTokenArray* pCode;
if ( pDoc->IsImportingXML() )
{ // temporary formula string as string tokens
pCode = lcl_ScDocFunc_CreateTokenArrayXML( rText, rFormulaNmsp, eGrammar );
pDoc->IncXMLImportedFormulaCount( rText.Len() );
}
else
{
ScCompiler aComp( pDoc, rPos );
aComp.SetGrammar(eGrammar);
pCode = aComp.CompileString( rText );
}
pNewCell = new ScFormulaCell( pDoc, rPos, pCode, eGrammar, MM_NONE );
delete pCode; // Zell-ctor hat das TokenArray kopiert
}
else if ( rText.Len() > 1 && rText.GetChar(0) == '\'' )
{
// for bEnglish, "'" at the beginning is always interpreted as text
// marker and stripped
pNewCell = ScBaseCell::CreateTextCell( rText.Copy( 1 ), pDoc );
}
else // (nur) auf englisches Zahlformat testen
{
SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
sal_uInt32 nEnglish = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
double fVal;
if ( pFormatter->IsNumberFormat( rText, nEnglish, fVal ) )
{
pNewCell = new ScValueCell( fVal );
// return the format type from the English format, so a localized format can be created
if ( pRetFormatType )
*pRetFormatType = pFormatter->GetType( nEnglish );
}
else if ( rText.Len() )
pNewCell = ScBaseCell::CreateTextCell( rText, pDoc );
// das (englische) Zahlformat wird nicht gesetzt
//! passendes lokales Format suchen und setzen???
}
return pNewCell;
}
sal_Bool ScDocFunc::SetCellText( const ScAddress& rPos, const String& rText,
sal_Bool bInterpret, sal_Bool bEnglish, sal_Bool bApi,
const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar )
{
// SetCellText ruft PutCell oder SetNormalString
ScDocument* pDoc = rDocShell.GetDocument();
ScBaseCell* pNewCell = NULL;
if ( bInterpret )
{
if ( bEnglish )
{
::boost::scoped_ptr<ScExternalRefManager::ApiGuard> pExtRefGuard;
if (bApi)
pExtRefGuard.reset(new ScExternalRefManager::ApiGuard(pDoc));
// code moved to own method InterpretEnglishString because it is also used in
// ScCellRangeObj::setFormulaArray
pNewCell = InterpretEnglishString( rPos, rText, rFormulaNmsp, eGrammar );
}
// sonst Null behalten -> SetString mit lokalen Formeln/Zahlformat
}
else if ( rText.Len() )
{
OSL_ENSURE( rFormulaNmsp.Len() == 0, "ScDocFunc::SetCellText - formula namespace, but do not interpret?" );
pNewCell = ScBaseCell::CreateTextCell( rText, pDoc ); // immer Text
}
if (pNewCell)
return PutCell( rPos, pNewCell, bApi );
else
return SetNormalString( rPos, rText, bApi );
}
//------------------------------------------------------------------------
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(), sal_False);
rDocShell.SetDocumentModified();
return true;
}
//------------------------------------------------------------------------
bool ScDocFunc::SetNoteText( const ScAddress& rPos, const String& rText, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
ScEditableTester aTester( pDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return false;
}
String aNewText = rText;
aNewText.ConvertLineEnd(); //! ist das noetig ???
if( ScPostIt* pNote = (aNewText.Len() > 0) ? pDoc->GetOrCreateNote( rPos ) : pDoc->GetNote( rPos ) )
pNote->SetText( rPos, aNewText );
//! Undo !!!
if (pDoc->IsStreamValid(rPos.Tab()))
pDoc->SetStreamValid(rPos.Tab(), sal_False);
rDocShell.PostPaintCell( rPos );
aModificator.SetDocumentModified();
return true;
}
//------------------------------------------------------------------------
bool ScDocFunc::ReplaceNote( const ScAddress& rPos, const String& rNoteText, const String* pAuthor, const String* pDate, sal_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 obejcts
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(), sal_False);
aModificator.SetDocumentModified();
bDone = true;
}
else if (!bApi)
{
rDocShell.ErrorMessage(aTester.GetMessageId());
}
return bDone;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern,
sal_Bool bRecord, sal_Bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
if ( bRecord && !pDoc->IsUndoEnabled() )
bRecord = sal_False;
sal_Bool bImportingXML = pDoc->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.
sal_Bool bOnlyNotBecauseOfMatrix;
if ( !bImportingXML && !pDoc->IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix )
&& !bOnlyNotBecauseOfMatrix )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PROTECTIONERR);
return sal_False;
}
ScDocShellModificator aModificator( rDocShell );
//! Umrandung
ScRange aMultiRange;
sal_Bool bMulti = rMark.IsMultiMarked();
if ( bMulti )
rMark.GetMultiMarkArea( aMultiRange );
else
rMark.GetMarkArea( aMultiRange );
if ( bRecord )
{
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, aMultiRange.aStart.Tab(), aMultiRange.aEnd.Tab() );
pDoc->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 neccessary to ask HasAttrib. It needs too much time.
sal_uInt16 nExtFlags = 0;
if ( !bImportingXML )
rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content before the change
pDoc->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 sal_True;
}
sal_Bool ScDocFunc::ApplyStyle( const ScMarkData& rMark, const String& rStyleName,
sal_Bool bRecord, sal_Bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
if ( bRecord && !pDoc->IsUndoEnabled() )
bRecord = sal_False;
sal_Bool bImportingXML = pDoc->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.
sal_Bool bOnlyNotBecauseOfMatrix;
if ( !bImportingXML && !pDoc->IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix )
&& !bOnlyNotBecauseOfMatrix )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PROTECTIONERR);
return sal_False;
}
ScStyleSheet* pStyleSheet = (ScStyleSheet*) pDoc->GetStyleSheetPool()->Find(
rStyleName, SFX_STYLE_FAMILY_PARA );
if (!pStyleSheet)
return sal_False;
ScDocShellModificator aModificator( rDocShell );
ScRange aMultiRange;
sal_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 = pDoc->GetTableCount();
pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nStartTab && rMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i );
ScRange aCopyRange = aMultiRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(nTabCount-1);
pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &rMark );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoSelectionStyle(
&rDocShell, rMark, aMultiRange, rStyleName, pUndoDoc ) );
}
// sal_Bool bPaintExt = pDoc->HasAttrib( aMultiRange, HASATTR_PAINTEXT );
// pDoc->ApplySelectionPattern( rPattern, rMark );
pDoc->ApplySelectionStyle( (ScStyleSheet&)*pStyleSheet, rMark );
// if (!bPaintExt)
// bPaintExt = pDoc->HasAttrib( aMultiRange, HASATTR_PAINTEXT );
// sal_uInt16 nExtFlags = bPaintExt ? SC_PF_LINES : 0;
sal_uInt16 nExtFlags = 0;
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 sal_True;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, InsCellCmd eCmd,
sal_Bool bRecord, sal_Bool bApi, sal_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) )
{
DBG_ERROR("invalid row in InsertCells");
return sal_False;
}
ScDocument* pDoc = rDocShell.GetDocument();
SCTAB nTabCount = pDoc->GetTableCount();
SCCOL nPaintStartX = nStartCol;
SCROW nPaintStartY = nStartRow;
SCCOL nPaintEndX = nEndCol;
SCROW nPaintEndY = nEndRow;
sal_uInt16 nPaintFlags = PAINT_GRID;
sal_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 && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
SCTAB nCount = 0;
for( i=0; i<nTabCount; i++ )
{
if( !pDoc->IsScenario(i) )
{
nCount++;
if( nCount == nEndTab+1 )
{
aMark.SelectTable( i, sal_True );
break;
}
}
}
}
ScMarkData aFullMark( aMark ); // including scenario sheets
for( i=0; i<nTabCount; i++ )
if( aMark.GetTableSelect( i ) )
{
for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
aFullMark.SelectTable( j, sal_True );
}
SCTAB nSelCount = aMark.GetSelectCount();
// zugehoerige Szenarien auch anpassen
// Test zusammengefasste
SCCOL nMergeTestStartX = nStartCol;
SCROW nMergeTestStartY = nStartRow;
SCCOL nMergeTestEndX = nEndCol;
SCROW nMergeTestEndY = nEndRow;
ScRange aExtendMergeRange( rRange );
if( rRange.aStart == rRange.aEnd && pDoc->HasAttrib(rRange, HASATTR_MERGED) )
{
pDoc->ExtendMerge( aExtendMergeRange );
pDoc->ExtendOverlapped( aExtendMergeRange );
nMergeTestEndX = aExtendMergeRange.aEnd.Col();
nMergeTestEndY = aExtendMergeRange.aEnd.Row();
nPaintEndX = nMergeTestEndX;
nPaintEndY = nMergeTestEndY;
}
if ( eCmd == INS_INSROWS )
{
nMergeTestStartX = 0;
nMergeTestEndX = MAXCOL;
}
if ( eCmd == INS_INSCOLS )
{
nMergeTestStartY = 0;
nMergeTestEndY = MAXROW;
}
if ( eCmd == INS_CELLSDOWN )
nMergeTestEndY = MAXROW;
if ( eCmd == INS_CELLSRIGHT )
nMergeTestEndX = MAXCOL;
sal_Bool bNeedRefresh = sal_False;
SCCOL nEditTestEndX = (eCmd==INS_INSCOLS) ? MAXCOL : nMergeTestEndX;
SCROW nEditTestEndY = (eCmd==INS_INSROWS) ? MAXROW : nMergeTestEndY;
ScEditableTester aTester( pDoc, nMergeTestStartX, nMergeTestStartY, nEditTestEndX, nEditTestEndY, aMark );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
WaitObject aWait( rDocShell.GetActiveDialogParent() ); // wichtig wegen TrackFormulas bei UpdateReference
ScDocument* pRefUndoDoc = NULL;
ScRefUndoData* pUndoData = NULL;
if ( bRecord )
{
pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, sal_False, sal_False );
// pRefUndoDoc is filled in InsertCol / InsertRow
pUndoData = new ScRefUndoData( pDoc );
pDoc->BeginDrawUndo();
}
// #i8302 : we unmerge overwhelming ranges, before insertion all the actions are put in the same ListAction
// the patch comes from mloiseleur and maoyg
sal_Bool bInsertMerge = sal_False;
std::vector<ScRange> qIncreaseRange;
String aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTCELLS );
if (bRecord)
rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect(i) )
{
if( pDoc->HasAttrib( nMergeTestStartX, nMergeTestStartY, i, nMergeTestEndX, nMergeTestEndY, i, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
{
if (eCmd==INS_CELLSRIGHT)
bNeedRefresh = sal_True;
SCCOL nMergeStartX = nMergeTestStartX;
SCROW nMergeStartY = nMergeTestStartY;
SCCOL nMergeEndX = nMergeTestEndX;
SCROW nMergeEndY = nMergeTestEndY;
pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i );
pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i );
if(( eCmd == INS_CELLSDOWN && ( nMergeStartX != nMergeTestStartX || nMergeEndX != nMergeTestEndX )) ||
(eCmd == INS_CELLSRIGHT && ( nMergeStartY != nMergeTestStartY || nMergeEndY != nMergeTestEndY )) )
{
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0);
rDocShell.GetUndoManager()->LeaveListAction();
return sal_False;
}
SCCOL nTestCol = -1;
SCROW nTestRow1 = -1;
SCROW nTestRow2 = -1;
ScDocAttrIterator aTestIter( pDoc, i, nMergeTestStartX, nMergeTestStartY, nMergeTestEndX, nMergeTestEndY );
ScRange aExtendRange( nMergeTestStartX, nMergeTestStartY, i, nMergeTestEndX, nMergeTestEndY, i );
const ScPatternAttr* pPattern = NULL;
const ScMergeAttr* pMergeFlag = NULL;
const ScMergeFlagAttr* pMergeFlagAttr = NULL;
while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != NULL )
{
pMergeFlag = (const ScMergeAttr*) &pPattern->GetItem(ATTR_MERGE);
pMergeFlagAttr = (const ScMergeFlagAttr*) &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 );
pDoc->ExtendOverlapped(aRange);
pDoc->ExtendMerge(aRange, sal_True, sal_True);
if( nTestRow1 < nTestRow2 && nNewFlags == SC_MF_HOR )
{
for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ )
{
ScRange aTestRange( nTestCol, nTestRow, i );
pDoc->ExtendOverlapped( aTestRange );
pDoc->ExtendMerge( aTestRange, sal_True, sal_True);
ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i );
if( !aExtendRange.In( aMergeRange ) )
{
qIncreaseRange.push_back( aTestRange );
bInsertMerge = sal_True;
}
}
}
else
{
ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i );
if( !aExtendRange.In( aMergeRange ) )
{
qIncreaseRange.push_back( aRange );
}
bInsertMerge = sal_True;
}
}
}
if( bInsertMerge )
{
if( eCmd == INS_INSROWS || eCmd == INS_CELLSDOWN )
{
nStartRow = aExtendMergeRange.aStart.Row();
nEndRow = aExtendMergeRange.aEnd.Row();
if( eCmd == INS_CELLSDOWN )
nEndCol = nMergeTestEndX;
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 = nMergeTestEndY;
}
else
{
nStartRow = 0;
nEndRow = MAXROW;
}
}
if( !qIncreaseRange.empty() )
{
for( ::std::vector<ScRange>::const_iterator iIter( qIncreaseRange.begin()); iIter != qIncreaseRange.end(); iIter++ )
{
ScRange aRange( *iIter );
if( pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
{
UnmergeCells( aRange, sal_True, sal_True );
}
}
}
}
else
{
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0);
rDocShell.GetUndoManager()->LeaveListAction();
return sal_False;
}
}
}
}
switch (eCmd)
{
case INS_CELLSDOWN:
bSuccess = pDoc->InsertRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark );
nPaintEndY = MAXROW;
break;
case INS_INSROWS:
bSuccess = pDoc->InsertRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark );
nPaintStartX = 0;
nPaintEndX = MAXCOL;
nPaintEndY = MAXROW;
nPaintFlags |= PAINT_LEFT;
break;
case INS_CELLSRIGHT:
bSuccess = pDoc->InsertCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark );
nPaintEndX = MAXCOL;
break;
case INS_INSCOLS:
bSuccess = pDoc->InsertCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark );
nPaintStartY = 0;
nPaintEndY = MAXROW;
nPaintEndX = MAXCOL;
nPaintFlags |= PAINT_TOP;
break;
default:
DBG_ERROR("Falscher Code beim Einfuegen");
bSuccess = sal_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;
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect( i ) )
{
SCTAB nCount = 0;
for( SCTAB j=i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
nCount ++;
pScenarios[nUndoPos] = nCount;
pTabs[nUndoPos] = i;
nUndoPos ++;
}
}
if( !bInsertMerge )
{
rDocShell.GetUndoManager()->LeaveListAction();
}
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( !pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
{
switch (eCmd)
{
case INS_CELLSDOWN:
case INS_INSROWS:
aRange.aEnd.IncRow(static_cast<SCsCOL>(nEndRow-nStartRow+1));
break;
case INS_CELLSRIGHT:
case INS_INSCOLS:
aRange.aEnd.IncCol(static_cast<SCsCOL>(nEndCol-nStartCol+1));
break;
default:
break;
}
MergeCells(aRange, sal_False, sal_True, sal_True);
}
qIncreaseRange.pop_back();
}
if( bInsertMerge )
rDocShell.GetUndoManager()->LeaveListAction();
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect( i ) )
{
if (bNeedRefresh)
pDoc->ExtendMerge( nMergeTestStartX, nMergeTestStartY, nMergeTestEndX, nMergeTestEndY, i, sal_True );
else
pDoc->RefreshAutoFilter( nMergeTestStartX, nMergeTestStartY, nMergeTestEndX, nMergeTestEndY, i );
if ( eCmd == INS_INSROWS || eCmd == INS_INSCOLS )
pDoc->UpdatePageBreaks( i );
sal_uInt16 nExtFlags = 0;
rDocShell.UpdatePaintExt( nExtFlags, nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i );
SCTAB nScenarioCount = 0;
for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
nScenarioCount ++;
sal_Bool bAdjusted = ( eCmd == INS_INSROWS ) ? AdjustRowHeight(ScRange(0, nStartRow, i, MAXCOL, nEndRow, i+nScenarioCount )) :
AdjustRowHeight(ScRange(0, nPaintStartY, i, MAXCOL, nPaintEndY, i+nScenarioCount ));
if (bAdjusted)
{
// paint only what is not done by AdjustRowHeight
if (nPaintFlags & PAINT_TOP)
rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, PAINT_TOP );
}
else
rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, nPaintFlags, nExtFlags );
}
}
//aModificator.SetDocumentModified();
}
else
{
if( bInsertMerge )
{
while( !qIncreaseRange.empty() )
{
ScRange aRange = qIncreaseRange.back();
MergeCells(aRange, sal_False, sal_True, sal_True);
qIncreaseRange.pop_back();
}
if( pViewSh )
{
pViewSh->MarkRange( rRange, sal_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();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
return bSuccess;
}
sal_Bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, DelCellCmd eCmd,
sal_Bool bRecord, sal_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) )
{
DBG_ERROR("invalid row in DeleteCells");
return sal_False;
}
ScDocument* pDoc = rDocShell.GetDocument();
SCTAB nTabCount = pDoc->GetTableCount();
SCCOL nPaintStartX = nStartCol;
SCROW nPaintStartY = nStartRow;
SCCOL nPaintEndX = nEndCol;
SCROW nPaintEndY = nEndRow;
sal_uInt16 nPaintFlags = PAINT_GRID;
SCTAB i;
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
SCTAB nCount = 0;
for( i=0; i<nTabCount; i++ )
{
if( !pDoc->IsScenario(i) )
{
nCount++;
if( nCount == nEndTab+1 )
{
aMark.SelectTable( i, sal_True );
break;
}
}
}
}
ScMarkData aFullMark( aMark ); // including scenario sheets
for( i=0; i<nTabCount; i++ )
if( aMark.GetTableSelect( i ) )
{
for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
aFullMark.SelectTable( j, sal_True );
}
SCTAB nSelCount = aMark.GetSelectCount();
SCCOL nUndoStartX = nStartCol;
SCROW nUndoStartY = nStartRow;
SCCOL nUndoEndX = nEndCol;
SCROW nUndoEndY = nEndRow;
ScRange aExtendMergeRange( rRange );
if( rRange.aStart == rRange.aEnd && pDoc->HasAttrib(rRange, HASATTR_MERGED) )
{
pDoc->ExtendMerge( aExtendMergeRange );
pDoc->ExtendOverlapped( aExtendMergeRange );
nUndoEndX = aExtendMergeRange.aEnd.Col();
nUndoEndY = aExtendMergeRange.aEnd.Row();
nPaintEndX = nUndoEndX;
nPaintEndY = nUndoEndY;
}
if (eCmd==DEL_DELROWS)
{
nUndoStartX = 0;
nUndoEndX = MAXCOL;
}
if (eCmd==DEL_DELCOLS)
{
nUndoStartY = 0;
nUndoEndY = MAXROW;
}
// Test Zellschutz
SCCOL nEditTestEndX = nUndoEndX;
if ( eCmd==DEL_DELCOLS || eCmd==DEL_CELLSLEFT )
nEditTestEndX = MAXCOL;
SCROW nEditTestEndY = nUndoEndY;
if ( eCmd==DEL_DELROWS || eCmd==DEL_CELLSUP )
nEditTestEndY = MAXROW;
ScEditableTester aTester( pDoc, nUndoStartX, nUndoStartY, nEditTestEndX, nEditTestEndY, aMark );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
// Test zusammengefasste
SCCOL nMergeTestEndX = (eCmd==DEL_CELLSLEFT) ? MAXCOL : nUndoEndX;
SCROW nMergeTestEndY = (eCmd==DEL_CELLSUP) ? MAXROW : nUndoEndY;
SCCOL nExtendStartCol = nUndoStartX;
SCROW nExtendStartRow = nUndoStartY;
sal_Bool bNeedRefresh = sal_False;
//Issue 8302 want to be able to insert into the middle of merged cells
//the patch comes from maoyg
::std::vector<ScRange> qDecreaseRange;
sal_Bool bDeletingMerge = sal_False;
String aUndo = ScGlobal::GetRscString( STR_UNDO_DELETECELLS );
if (bRecord)
rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect(i) )
{
if ( pDoc->HasAttrib( nUndoStartX, nUndoStartY, i, nMergeTestEndX, nMergeTestEndY, i, HASATTR_MERGED | HASATTR_OVERLAPPED ))
{
SCCOL nMergeStartX = nUndoStartX;
SCROW nMergeStartY = nUndoStartY;
SCCOL nMergeEndX = nMergeTestEndX;
SCROW nMergeEndY = nMergeTestEndY;
pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i );
pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i );
if( ( eCmd == DEL_CELLSUP && ( nMergeStartX != nUndoStartX || nMergeEndX != nMergeTestEndX))||
( eCmd == DEL_CELLSLEFT && ( nMergeStartY != nUndoStartY || nMergeEndY != nMergeTestEndY)))
{
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0);
rDocShell.GetUndoManager()->LeaveListAction();
return sal_False;
}
nExtendStartCol = nMergeStartX;
nExtendStartRow = nMergeStartY;
SCCOL nTestCol = -1;
SCROW nTestRow1 = -1;
SCROW nTestRow2 = -1;
ScDocAttrIterator aTestIter( pDoc, i, nUndoStartX, nUndoStartY, nMergeTestEndX, nMergeTestEndY );
ScRange aExtendRange( nUndoStartX, nUndoStartY, i, nMergeTestEndX, nMergeTestEndY, i );
const ScPatternAttr* pPattern = NULL;
const ScMergeAttr* pMergeFlag = NULL;
const ScMergeFlagAttr* pMergeFlagAttr = NULL;
while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != NULL )
{
pMergeFlag = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
pMergeFlagAttr = (const ScMergeFlagAttr*) &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 );
pDoc->ExtendOverlapped( aRange );
pDoc->ExtendMerge( aRange, sal_True, sal_True );
if( nTestRow1 < nTestRow2 && nNewFlags == SC_MF_HOR )
{
for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ )
{
ScRange aTestRange( nTestCol, nTestRow, i );
pDoc->ExtendOverlapped( aTestRange );
pDoc->ExtendMerge( aTestRange, sal_True, sal_True);
ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i );
if( !aExtendRange.In( aMergeRange ) )
{
qDecreaseRange.push_back( aTestRange );
bDeletingMerge = sal_True;
}
}
}
else
{
ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i );
if( !aExtendRange.In( aMergeRange ) )
{
qDecreaseRange.push_back( aRange );
}
bDeletingMerge = sal_True;
}
}
}
if( bDeletingMerge )
{
if( eCmd == DEL_DELROWS || eCmd == DEL_CELLSUP )
{
nStartRow = aExtendMergeRange.aStart.Row();
nEndRow = aExtendMergeRange.aEnd.Row();
bNeedRefresh = sal_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 = sal_True;
}
else
{
nStartRow = 0;
nEndRow = MAXROW;
}
}
if( !qDecreaseRange.empty() )
{
for( ::std::vector<ScRange>::const_iterator iIter( qDecreaseRange.begin()); iIter != qDecreaseRange.end(); iIter++ )
{
ScRange aRange( *iIter );
if( pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
{
UnmergeCells( aRange, sal_True, sal_True );
}
}
}
}
else
{
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0);
rDocShell.GetUndoManager()->LeaveListAction();
return sal_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( pDoc, 0, nTabCount-1, (eCmd==DEL_DELCOLS), (eCmd==DEL_DELROWS) );
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect( i ) )
{
SCTAB nScenarioCount = 0;
for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
nScenarioCount ++;
pDoc->CopyToDocument( nUndoStartX, nUndoStartY, i, nUndoEndX, nUndoEndY, i+nScenarioCount,
IDF_ALL | IDF_NOCAPTIONS, sal_False, pUndoDoc );
}
}
pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, sal_False, sal_False );
pUndoData = new ScRefUndoData( pDoc );
pDoc->BeginDrawUndo();
}
sal_uInt16 nExtFlags = 0;
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect( i ) )
rDocShell.UpdatePaintExt( nExtFlags, nStartCol, nStartRow, i, nEndCol, nEndRow, i );
}
sal_Bool bUndoOutline = sal_False;
switch (eCmd)
{
case DEL_CELLSUP:
pDoc->DeleteRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, NULL, &aFullMark );
nPaintEndY = MAXROW;
break;
case DEL_DELROWS:
pDoc->DeleteRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &bUndoOutline, &aFullMark );
nPaintStartX = 0;
nPaintEndX = MAXCOL;
nPaintEndY = MAXROW;
nPaintFlags |= PAINT_LEFT;
break;
case DEL_CELLSLEFT:
pDoc->DeleteCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, NULL, &aFullMark );
nPaintEndX = MAXCOL;
break;
case DEL_DELCOLS:
pDoc->DeleteCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &bUndoOutline, &aFullMark );
nPaintStartY = 0;
nPaintEndY = MAXROW;
nPaintEndX = MAXCOL;
nPaintFlags |= PAINT_TOP;
break;
default:
DBG_ERROR("Falscher Code beim Loeschen");
break;
}
//! Test, ob Outline in Groesse geaendert
if ( bRecord )
{
for( i=0; i<nTabCount; i++ )
if( aFullMark.GetTableSelect( i ) )
pRefUndoDoc->DeleteAreaTab(nUndoStartX,nUndoStartY,nUndoEndX,nUndoEndY, i, IDF_ALL);
// alle Tabellen anlegen, damit Formeln kopiert werden koennen:
pUndoDoc->AddUndoTab( 0, nTabCount-1, sal_False, sal_False );
// kopieren mit bColRowFlags=sal_False (#54194#)
pRefUndoDoc->CopyToDocument(0,0,0,MAXCOL,MAXROW,MAXTAB,IDF_FORMULA,sal_False,pUndoDoc,NULL,sal_False);
delete pRefUndoDoc;
SCTAB* pTabs = new SCTAB[nSelCount];
SCTAB* pScenarios = new SCTAB[nSelCount];
SCTAB nUndoPos = 0;
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect( i ) )
{
SCTAB nCount = 0;
for( SCTAB j=i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
nCount ++;
pScenarios[nUndoPos] = nCount;
pTabs[nUndoPos] = i;
nUndoPos ++;
}
}
if( !bDeletingMerge )
{
rDocShell.GetUndoManager()->LeaveListAction();
}
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<SCsCOL>( aRange.aEnd.Row()-nDecreaseRowCount));
break;
case DEL_CELLSLEFT:
case DEL_DELCOLS:
aRange.aEnd.SetCol(static_cast<SCsCOL>( aRange.aEnd.Col()-nDecreaseColCount));
break;
default:
break;
}
if( !pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
{
MergeCells( aRange, sal_False, sal_True, sal_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 )
nMergeTestEndX = MAXCOL;
if ( eCmd==DEL_DELROWS || eCmd==DEL_CELLSUP )
nMergeTestEndY = MAXROW;
ScPatternAttr aPattern( pDoc->GetPool() );
aPattern.GetItemSet().Put( ScMergeFlagAttr() );
pDoc->ApplyPatternArea( nExtendStartCol, nExtendStartRow, nMergeTestEndX, nMergeTestEndY, aMark, aPattern );
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect( i ) )
{
SCTAB nScenarioCount = 0;
for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
nScenarioCount ++;
ScRange aMergedRange( nExtendStartCol, nExtendStartRow, i, nMergeTestEndX, nMergeTestEndY, i+nScenarioCount );
pDoc->ExtendMerge( aMergedRange, sal_True );
}
}
}
for( i=0; i<nTabCount; i++ )
{
if( aMark.GetTableSelect( i ) )
{
if ( eCmd == DEL_DELCOLS || eCmd == DEL_DELROWS )
pDoc->UpdatePageBreaks( i );
rDocShell.UpdatePaintExt( nExtFlags, nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i );
SCTAB nScenarioCount = 0;
for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ )
nScenarioCount ++;
// ganze Zeilen loeschen: nichts anpassen
if ( eCmd == DEL_DELROWS || !AdjustRowHeight(ScRange( 0, nPaintStartY, i, MAXCOL, nPaintEndY, i+nScenarioCount )) )
rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, nPaintFlags, nExtFlags );
else
{
// paint only what is not done by AdjustRowHeight
if (nExtFlags & SC_PF_LINES)
lcl_PaintAbove( rDocShell, ScRange( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount) );
if (nPaintFlags & PAINT_TOP)
rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, PAINT_TOP );
}
}
}
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
return sal_True;
}
sal_Bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos,
sal_Bool bCut, sal_Bool bRecord, sal_Bool bPaint, sal_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) )
{
DBG_ERROR("invalid row in MoveBlock");
return sal_False;
}
// zugehoerige Szenarien auch anpassen - nur wenn innerhalb einer Tabelle verschoben wird!
sal_Bool bScenariosAdded = sal_False;
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
SCTAB nTabCount = pDoc->GetTableCount();
if ( nDestTab == nStartTab && !pDoc->IsScenario(nEndTab) )
while ( nEndTab+1 < nTabCount && pDoc->IsScenario(nEndTab+1) )
{
++nEndTab;
bScenariosAdded = sal_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, sal_True ); // Source selektieren
aSourceMark.SetMarkArea( rSource );
ScDocShellRef aDragShellRef;
if ( pDoc->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);
pDoc->CopyToClip(aClipParam, pClipDoc, &aSourceMark, false, bScenariosAdded, true);
ScDrawLayer::SetGlobalDrawPersist(NULL);
SCCOL nOldEndCol = nEndCol;
SCROW nOldEndRow = nEndRow;
sal_Bool bClipOver = sal_False;
for (nTab=nStartTab; nTab<=nEndTab; nTab++)
{
SCCOL nTmpEndCol = nOldEndCol;
SCROW nTmpEndRow = nOldEndRow;
if (pDoc->ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab ))
bClipOver = sal_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 );
sal_Bool bIncludeFiltered = bCut;
if ( !bIncludeFiltered )
{
// adjust sizes to include only non-filtered rows
SCCOL nClipX;
SCROW nClipY;
pClipDoc->GetClipArea( nClipX, nClipY, sal_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 sal_False;
}
// Test auf Zellschutz
ScEditableTester aTester;
for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
aTester.TestBlock( pDoc, nTab, nDestCol,nDestRow, nUndoEndCol,nUndoEndRow );
if (bCut)
for (nTab=nStartTab; nTab<=nEndTab; nTab++)
aTester.TestBlock( pDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
delete pClipDoc;
return sal_False;
}
// Test auf zusammengefasste - beim Verschieben erst nach dem Loeschen
if (bClipOver && !bCut)
if (pDoc->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 sal_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;
ScDocument* pRefUndoDoc = NULL;
ScRefUndoData* pUndoData = NULL;
if (bRecord)
{
sal_Bool bWholeCols = ( nStartRow == 0 && nEndRow == MAXROW );
sal_Bool bWholeRows = ( nStartCol == 0 && nEndCol == MAXCOL );
sal_uInt16 nUndoFlags = (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS;
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab, bWholeCols, bWholeRows );
if (bCut)
{
pDoc->CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
nUndoFlags, sal_False, pUndoDoc );
pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, sal_False, sal_False );
}
if ( nDestTab != nStartTab )
pUndoDoc->AddUndoTab( nDestTab, nDestEndTab, bWholeCols, bWholeRows );
pDoc->CopyToDocument( nDestCol, nDestRow, nDestTab,
nDestEndCol, nDestEndRow, nDestEndTab,
nUndoFlags, sal_False, pUndoDoc );
pUndoData = new ScRefUndoData( pDoc );
pDoc->BeginDrawUndo();
}
sal_Bool bSourceHeight = sal_False; // Hoehen angepasst?
if (bCut)
{
ScMarkData aDelMark; // only for tables
for (nTab=nStartTab; nTab<=nEndTab; nTab++)
{
pDoc->DeleteAreaTab( nStartCol,nStartRow, nOldEndCol,nOldEndRow, nTab, IDF_ALL );
aDelMark.SelectTable( nTab, sal_True );
}
pDoc->DeleteObjectsInArea( nStartCol,nStartRow, nOldEndCol,nOldEndRow, aDelMark );
// Test auf zusammengefasste
if (bClipOver)
if (pDoc->HasAttrib( nDestCol,nDestRow,nDestTab,
nUndoEndCol,nUndoEndRow,nDestEndTab,
HASATTR_MERGED | HASATTR_OVERLAPPED ))
{
pDoc->CopyFromClip( rSource, aSourceMark, IDF_ALL, pRefUndoDoc, pClipDoc );
for (nTab=nStartTab; nTab<=nEndTab; nTab++)
{
SCCOL nTmpEndCol = nEndCol;
SCROW nTmpEndRow = nEndRow;
pDoc->ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab, sal_True );
}
// Fehlermeldung erst nach dem Wiederherstellen des Inhalts
if (!bApi) // "Zusammenfassen nicht verschachteln !"
rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0);
delete pUndoDoc;
delete pRefUndoDoc;
delete pUndoData;
delete pClipDoc;
return sal_False;
}
bSourceHeight = AdjustRowHeight( rSource, sal_False );
}
ScRange aPasteDest( nDestCol, nDestRow, nDestTab, nDestEndCol, nDestEndRow, nDestEndTab );
ScMarkData aDestMark;
for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
aDestMark.SelectTable( nTab, sal_True ); // Destination selektieren
aDestMark.SetMarkArea( aPasteDest );
/* Do not copy cell notes and 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). Cell notes
and drawing objects are pasted below after doing all adjusting. */
pDoc->CopyFromClip( aPasteDest, aDestMark, IDF_ALL & ~(IDF_NOTE | IDF_OBJECTS),
pRefUndoDoc, pClipDoc, sal_True, sal_False, bIncludeFiltered );
// skipped rows and merged cells don't mix
if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
UnmergeCells( aPasteDest, sal_False, sal_True );
VirtualDevice aVirtDev;
sal_Bool bDestHeight = AdjustRowHeight(
ScRange( 0,nDestRow,nDestTab, MAXCOL,nDestEndRow,nDestEndTab ),
sal_False );
/* Paste cell notes and 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.
#i102056# Passing IDF_NOTE only would overwrite cell contents with
empty note cells, therefore the special modifier IDF_ADDNOTES is passed
here too which changes the behaviour of ScColumn::CopyFromClip() to not
touch existing cells. */
if ( pClipDoc->GetDrawLayer() )
pDoc->CopyFromClip( aPasteDest, aDestMark, IDF_NOTE | IDF_ADDNOTES | IDF_OBJECTS,
pRefUndoDoc, pClipDoc, sal_True, sal_False, bIncludeFiltered );
if (bRecord)
{
if (pRefUndoDoc)
{
// alle Tabellen anlegen, damit Formeln kopiert werden koennen:
pUndoDoc->AddUndoTab( 0, nTabCount-1, sal_False, sal_False );
pRefUndoDoc->DeleteArea( nDestCol, nDestRow, nDestEndCol, nDestEndRow, aSourceMark, IDF_ALL );
// kopieren mit bColRowFlags=sal_False (#54194#)
pRefUndoDoc->CopyToDocument( 0, 0, 0, MAXCOL, MAXROW, MAXTAB,
IDF_FORMULA, sal_False, pUndoDoc, NULL, sal_False );
delete pRefUndoDoc;
}
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDragDrop( &rDocShell, ScRange(
nStartCol, nStartRow, nStartTab,
nOldEndCol, nOldEndRow, nEndTab ),
ScAddress( nDestCol, nDestRow, nDestTab ),
bCut, pUndoDoc, pUndoData, bScenariosAdded ) );
}
SCCOL nDestPaintEndCol = nDestEndCol;
SCROW nDestPaintEndRow = nDestEndRow;
for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
{
SCCOL nTmpEndCol = nDestEndCol;
SCROW nTmpEndRow = nDestEndRow;
pDoc->ExtendMerge( nDestCol, nDestRow, nTmpEndCol, nTmpEndRow, nTab, sal_True );
if (nTmpEndCol > nDestPaintEndCol) nDestPaintEndCol = nTmpEndCol;
if (nTmpEndRow > nDestPaintEndRow) nDestPaintEndRow = nTmpEndRow;
}
if (bCut)
for (nTab=nStartTab; nTab<=nEndTab; nTab++)
pDoc->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();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
delete pClipDoc;
return sal_True;
}
//------------------------------------------------------------------------
uno::Reference< uno::XInterface > GetDocModuleObject( SfxObjectShell& rDocSh, String& 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( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAObjectModuleObjectProvider"))), uno::UNO_QUERY );
xDocModuleApiObject.set( xVBACodeNamedObjectAccess->getByName( sCodeName ), uno::UNO_QUERY );
}
return xDocModuleApiObject;
}
script::ModuleInfo lcl_InitModuleInfo( SfxObjectShell& rDocSh, String& sModule )
{
script::ModuleInfo sModuleInfo;
sModuleInfo.ModuleType = script::ModuleType::DOCUMENT;
sModuleInfo.ModuleObject = GetDocModuleObject( rDocSh, sModule );
return sModuleInfo;
}
void VBA_InsertModule( ScDocument& rDoc, SCTAB nTab, String& sModuleName, String& sSource )
{
SfxObjectShell& rDocSh = *rDoc.GetDocumentShell();
uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer();
DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" );
uno::Reference< container::XNameContainer > xLib;
if( xLibContainer.is() )
{
String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
if ( rDocSh.GetBasicManager() && rDocSh.GetBasicManager()->GetName().Len() )
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;
String genModuleName;
if ( sModuleName.Len() )
sModuleName = sModuleName;
else
{
genModuleName = String::CreateFromAscii( "Sheet1" );
nNum = 1;
}
while( xLib->hasByName( genModuleName ) )
genModuleName = rtl::OUString::createFromAscii( "Sheet" ) + rtl::OUString::valueOf( ++nNum );
uno::Any aSourceAny;
rtl::OUString sTmpSource = sSource;
if ( sTmpSource.getLength() == 0 )
sTmpSource = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "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, String& sModuleName )
{
uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer();
DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" );
uno::Reference< container::XNameContainer > xLib;
if( xLibContainer.is() )
{
String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
if ( rDocSh.GetBasicManager() && rDocSh.GetBasicManager()->GetName().Len() )
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->removeModuleInfo( sModuleName );
}
}
sal_Bool ScDocFunc::InsertTable( SCTAB nTab, const String& rName, sal_Bool bRecord, sal_Bool bApi )
{
sal_Bool bSuccess = sal_False;
WaitObject aWait( rDocShell.GetActiveDialogParent() );
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
// Strange loop, also basic is loaded too early ( InsertTable )
// is called via the xml import for sheets in described in odf
sal_Bool bInsertDocModule = false;
if( !rDocShell.GetDocument()->IsImportingXML() )
{
bInsertDocModule = pDoc ? pDoc->IsInVBAMode() : false;
}
if ( bInsertDocModule || ( bRecord && !pDoc->IsUndoEnabled() ) )
bRecord = sal_False;
if (bRecord)
pDoc->BeginDrawUndo(); // InsertTab erzeugt ein SdrUndoNewPage
SCTAB nTabCount = pDoc->GetTableCount();
sal_Bool bAppend = ( nTab >= nTabCount );
if ( bAppend )
nTab = nTabCount; // wichtig fuer Undo
if (pDoc->InsertTab( nTab, rName ))
{
String sCodeName;
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 )
{
String sSource;
VBA_InsertModule( *pDoc, nTab, sCodeName, sSource );
}
rDocShell.Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab ) );
rDocShell.PostPaintExtras();
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
bSuccess = sal_True;
}
else if (!bApi)
rDocShell.ErrorMessage(STR_TABINSERT_ERROR);
return bSuccess;
}
sal_Bool ScDocFunc::DeleteTable( SCTAB nTab, sal_Bool bRecord, sal_Bool /* bApi */ )
{
WaitObject aWait( rDocShell.GetActiveDialogParent() );
ScDocShellModificator aModificator( rDocShell );
sal_Bool bSuccess = sal_False;
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bVbaEnabled = pDoc ? pDoc->IsInVBAMode() : false;
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
if ( bVbaEnabled )
bRecord = sal_False;
sal_Bool bWasLinked = pDoc->IsLinked(nTab);
ScDocument* pUndoDoc = NULL;
ScRefUndoData* pUndoData = NULL;
if (bRecord)
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
SCTAB nCount = pDoc->GetTableCount();
pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True ); // nur nTab mit Flags
pUndoDoc->AddUndoTab( 0, nCount-1 ); // alle Tabs fuer Referenzen
pDoc->CopyToDocument(0,0,nTab, MAXCOL,MAXROW,nTab, IDF_ALL,sal_False, pUndoDoc );
String aOldName;
pDoc->GetName( nTab, aOldName );
pUndoDoc->RenameTab( nTab, aOldName, sal_False );
if (bWasLinked)
pUndoDoc->SetLink( nTab, pDoc->GetLinkMode(nTab), pDoc->GetLinkDoc(nTab),
pDoc->GetLinkFlt(nTab), pDoc->GetLinkOpt(nTab),
pDoc->GetLinkTab(nTab),
pDoc->GetLinkRefreshDelay(nTab) );
if ( pDoc->IsScenario(nTab) )
{
pUndoDoc->SetScenario( nTab, sal_True );
String aComment;
Color aColor;
sal_uInt16 nScenFlags;
pDoc->GetScenarioData( nTab, aComment, aColor, nScenFlags );
pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags );
sal_Bool bActive = pDoc->IsActiveScenario( nTab );
pUndoDoc->SetActiveScenario( nTab, bActive );
}
pUndoDoc->SetVisible( nTab, pDoc->IsVisible( nTab ) );
pUndoDoc->SetTabBgColor( nTab, pDoc->GetTabBgColor(nTab) );
pUndoDoc->SetSheetEvents( nTab, pDoc->GetSheetEvents( nTab ) );
// Drawing-Layer muss sein Undo selbst in der Hand behalten !!!
pDoc->BeginDrawUndo(); // DeleteTab erzeugt ein SdrUndoDelPage
pUndoData = new ScRefUndoData( pDoc );
}
String sCodeName;
sal_Bool bHasCodeName = pDoc->GetCodeName( nTab, sCodeName );
if (pDoc->DeleteTab( nTab, pUndoDoc ))
{
if (bRecord)
{
SvShorts theTabs;
theTabs.push_back(nTab);
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDeleteTab( &rDocShell, theTabs, pUndoDoc, pUndoData ));
}
// Views updaten:
if( bVbaEnabled )
{
if( bHasCodeName )
{
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 = SFX_APP(); // Navigator
pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
bSuccess = sal_True;
}
else
{
delete pUndoDoc;
delete pUndoData;
}
return bSuccess;
}
sal_Bool ScDocFunc::SetTableVisible( SCTAB nTab, sal_Bool bVisible, sal_Bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo(pDoc->IsUndoEnabled());
if ( pDoc->IsVisible( nTab ) == bVisible )
return sal_True; // nichts zu tun - ok
if ( !pDoc->IsDocEditable() )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PROTECTIONERR);
return sal_False;
}
ScDocShellModificator aModificator( rDocShell );
if ( !bVisible && !pDoc->IsImportingXML() ) // #i57869# allow hiding in any order for loading
{
// nicht alle Tabellen ausblenden
sal_uInt16 nVisCount = 0;
SCTAB nCount = pDoc->GetTableCount();
for (SCTAB i=0; i<nCount; i++)
if (pDoc->IsVisible(i))
++nVisCount;
if (nVisCount <= 1)
{
if (!bApi)
rDocShell.ErrorMessage(STR_PROTECTIONERR); //! eigene Meldung?
return sal_False;
}
}
pDoc->SetVisible( nTab, bVisible );
if (bUndo)
rDocShell.GetUndoManager()->AddUndoAction( new ScUndoShowHideTab( &rDocShell, nTab, bVisible ) );
// Views updaten:
if (!bVisible)
rDocShell.Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) );
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
rDocShell.PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS);
aModificator.SetDocumentModified();
return sal_True;
}
sal_Bool ScDocFunc::SetLayoutRTL( SCTAB nTab, sal_Bool bRTL, sal_Bool /* bApi */ )
{
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo(pDoc->IsUndoEnabled());
if ( pDoc->IsLayoutRTL( nTab ) == bRTL )
return sal_True; // nothing to do - ok
//! protection (sheet or document?)
ScDocShellModificator aModificator( rDocShell );
pDoc->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 sal_True;
}
//UNUSED2009-05 sal_Bool ScDocFunc::SetGrammar( formula::FormulaGrammar::Grammar eGrammar )
//UNUSED2009-05 {
//UNUSED2009-05 ScDocument* pDoc = rDocShell.GetDocument();
//UNUSED2009-05
//UNUSED2009-05 if ( pDoc->GetGrammar() == eGrammar )
//UNUSED2009-05 return sal_True;
//UNUSED2009-05
//UNUSED2009-05 sal_Bool bUndo(pDoc->IsUndoEnabled());
//UNUSED2009-05 ScDocShellModificator aModificator( rDocShell );
//UNUSED2009-05
//UNUSED2009-05 pDoc->SetGrammar( eGrammar );
//UNUSED2009-05
//UNUSED2009-05 if (bUndo)
//UNUSED2009-05 {
//UNUSED2009-05 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoSetGrammar( &rDocShell, eGrammar ) );
//UNUSED2009-05 }
//UNUSED2009-05
//UNUSED2009-05 rDocShell.PostPaint( 0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_ALL );
//UNUSED2009-05
//UNUSED2009-05 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
//UNUSED2009-05 if (NULL != pViewSh)
//UNUSED2009-05 {
//UNUSED2009-05 pViewSh->UpdateInputHandler( sal_False, sal_False );
//UNUSED2009-05 }
//UNUSED2009-05
//UNUSED2009-05 aModificator.SetDocumentModified();
//UNUSED2009-05
//UNUSED2009-05 SfxBindings* pBindings = rDocShell.GetViewBindings();
//UNUSED2009-05 if (pBindings)
//UNUSED2009-05 {
//UNUSED2009-05 // erAck: 2006-09-07T22:19+0200 commented out in CWS scr1c1
//UNUSED2009-05 //pBindings->Invalidate( FID_TAB_USE_R1C1 );
//UNUSED2009-05 }
//UNUSED2009-05
//UNUSED2009-05 return sal_True;
//UNUSED2009-05 }
sal_Bool ScDocFunc::RenameTable( SCTAB nTab, const String& rName, sal_Bool bRecord, sal_Bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
if ( !pDoc->IsDocEditable() )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PROTECTIONERR);
return sal_False;
}
ScDocShellModificator aModificator( rDocShell );
sal_Bool bSuccess = sal_False;
String sOldName;
pDoc->GetName(nTab, sOldName);
if (pDoc->RenameTab( nTab, rName ))
{
if (bRecord)
{
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoRenameTab( &rDocShell, nTab, sOldName, rName));
}
rDocShell.PostPaintExtras();
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
bSuccess = sal_True;
}
return bSuccess;
}
bool ScDocFunc::SetTabBgColor( SCTAB nTab, const Color& rColor, bool bRecord, bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = false;
if ( !pDoc->IsDocEditable() || pDoc->IsTabProtected(nTab) )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Check to see what this string is...
return false;
}
Color aOldTabBgColor;
aOldTabBgColor = pDoc->GetTabBgColor(nTab);
bool bSuccess = false;
pDoc->SetTabBgColor(nTab, rColor);
if ( pDoc->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();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
bSuccess = true;
}
return bSuccess;
}
bool ScDocFunc::SetTabBgColor(
ScUndoTabColorInfo::List& rUndoTabColorList, bool bRecord, bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = false;
if ( !pDoc->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 ( !pDoc->IsTabProtected(nTab) )
{
aNewTabBgColor = rInfo.maNewTabBgColor;
rInfo.maOldTabBgColor = pDoc->GetTabBgColor(nTab);
pDoc->SetTabBgColor(nTab, aNewTabBgColor);
if ( pDoc->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
sal_uInt16 lcl_GetOptimalColWidth( ScDocShell& rDocShell, SCCOL nCol, SCTAB nTab, sal_Bool bFormula )
{
sal_uInt16 nTwips = 0;
ScSizeDeviceProvider aProv(&rDocShell);
OutputDevice* pDev = aProv.GetDevice(); // has pixel MapMode
double nPPTX = aProv.GetPPTX();
double nPPTY = aProv.GetPPTY();
ScDocument* pDoc = rDocShell.GetDocument();
Fraction aOne(1,1);
nTwips = pDoc->GetOptimalColWidth( nCol, nTab, pDev, nPPTX, nPPTY, aOne, aOne,
bFormula, NULL );
return nTwips;
}
sal_Bool ScDocFunc::SetWidthOrHeight( sal_Bool bWidth, SCCOLROW nRangeCnt, SCCOLROW* pRanges, SCTAB nTab,
ScSizeMode eMode, sal_uInt16 nSizeTwips,
sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
if (!nRangeCnt)
return sal_True;
ScDocument* pDoc = rDocShell.GetDocument();
if ( bRecord && !pDoc->IsUndoEnabled() )
bRecord = sal_False;
// import into read-only document is possible
if ( !pDoc->IsChangeReadOnlyEnabled() && !rDocShell.IsEditable() )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PROTECTIONERR); //! eigene Meldung?
return sal_False;
}
sal_Bool bSuccess = sal_False;
SCCOLROW nStart = pRanges[0];
SCCOLROW nEnd = pRanges[2*nRangeCnt-1];
sal_Bool bFormula = sal_False;
if ( eMode == SC_SIZE_OPTIMAL )
{
//! Option "Formeln anzeigen" - woher nehmen?
}
ScDocument* pUndoDoc = NULL;
ScOutlineTable* pUndoTab = NULL;
SCCOLROW* pUndoRanges = NULL;
if ( bRecord )
{
pDoc->BeginDrawUndo(); // Drawing Updates
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
if (bWidth)
{
pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_False );
pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, static_cast<SCCOL>(nEnd), MAXROW, nTab, IDF_NONE, sal_False, pUndoDoc );
}
else
{
pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_False, sal_True );
pDoc->CopyToDocument( 0, static_cast<SCROW>(nStart), nTab, MAXCOL, static_cast<SCROW>(nEnd), nTab, IDF_NONE, sal_False, pUndoDoc );
}
pUndoRanges = new SCCOLROW[ 2*nRangeCnt ];
memmove( pUndoRanges, pRanges, 2*nRangeCnt*sizeof(SCCOLROW) );
ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
if (pTable)
pUndoTab = new ScOutlineTable( *pTable );
}
sal_Bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
sal_Bool bOutline = sal_False;
pDoc->IncSizeRecalcLevel( nTab ); // nicht fuer jede Spalte einzeln
for (SCCOLROW nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
{
SCCOLROW nStartNo = *(pRanges++);
SCCOLROW nEndNo = *(pRanges++);
if ( !bWidth ) // Hoehen immer blockweise
{
if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
{
sal_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 = pDoc->GetRowFlags(nRow,nTab);
SCROW nLastRow = -1;
bool bHidden = pDoc->RowHidden(nRow, nTab, nLastRow);
if ( !bHidden && ( nOld & CR_MANUALSIZE ) )
pDoc->SetRowFlags( nRow, nTab, nOld & ~CR_MANUALSIZE );
}
}
ScSizeDeviceProvider aProv( &rDocShell );
Fraction aOne(1,1);
pDoc->SetOptimalHeight( nStartNo, nEndNo, nTab, 0, aProv.GetDevice(),
aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, bAll );
if (bAll)
pDoc->ShowRows( nStartNo, nEndNo, nTab, sal_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)
{
pDoc->SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
pDoc->SetManualHeight( nStartNo, nEndNo, nTab, sal_True ); // height was set manually
}
if ( eMode != SC_SIZE_ORIGINAL )
pDoc->ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
}
else if ( eMode==SC_SIZE_SHOW )
{
pDoc->ShowRows( nStartNo, nEndNo, nTab, sal_True );
}
}
else // Spaltenbreiten
{
for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
{
SCCOL nLastCol = -1;
if ( eMode != SC_SIZE_VISOPT || !pDoc->ColHidden(nCol, nTab, nLastCol) )
{
sal_uInt16 nThisSize = nSizeTwips;
if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
nThisSize = nSizeTwips +
lcl_GetOptimalColWidth( rDocShell, nCol, nTab, bFormula );
if ( nThisSize )
pDoc->SetColWidth( nCol, nTab, nThisSize );
if ( eMode != SC_SIZE_ORIGINAL )
pDoc->ShowCol( nCol, nTab, bShow );
}
}
}
// adjust outlines
if ( eMode != SC_SIZE_ORIGINAL )
{
if (bWidth)
bOutline = bOutline || pDoc->UpdateOutlineCol(
static_cast<SCCOL>(nStartNo),
static_cast<SCCOL>(nEndNo), nTab, bShow );
else
bOutline = bOutline || pDoc->UpdateOutlineRow(
static_cast<SCROW>(nStartNo),
static_cast<SCROW>(nEndNo), nTab, bShow );
}
}
pDoc->DecSizeRecalcLevel( nTab ); // nicht fuer jede Spalte einzeln
if (!bOutline)
DELETEZ(pUndoTab);
if (bRecord)
{
ScMarkData aMark;
aMark.SelectOneTable( nTab );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoWidthOrHeight( &rDocShell, aMark,
nStart, nTab, nEnd, nTab,
pUndoDoc, nRangeCnt, pUndoRanges,
pUndoTab, eMode, nSizeTwips, bWidth ) );
}
pDoc->UpdatePageBreaks( nTab );
rDocShell.PostPaint(0,0,nTab,MAXCOL,MAXROW,nTab,PAINT_ALL);
aModificator.SetDocumentModified();
return bSuccess;
}
sal_Bool ScDocFunc::InsertPageBreak( sal_Bool bColumn, const ScAddress& rPos,
sal_Bool bRecord, sal_Bool bSetModified, sal_Bool /* bApi */ )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
SCTAB nTab = rPos.Tab();
SfxBindings* pBindings = rDocShell.GetViewBindings();
SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) :
static_cast<SCCOLROW>(rPos.Row());
if (nPos == 0)
return sal_False; // erste Spalte / Zeile
ScBreakType nBreak = bColumn ?
pDoc->HasColBreak(static_cast<SCCOL>(nPos), nTab) :
pDoc->HasRowBreak(static_cast<SCROW>(nPos), nTab);
if (nBreak & BREAK_MANUAL)
return true;
if (bRecord)
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoPageBreak( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, sal_True ) );
if (bColumn)
pDoc->SetColBreak(static_cast<SCCOL>(nPos), nTab, false, true);
else
pDoc->SetRowBreak(static_cast<SCROW>(nPos), nTab, false, true);
pDoc->InvalidatePageBreaks(nTab);
pDoc->UpdatePageBreaks( nTab );
if (pDoc->IsStreamValid(nTab))
pDoc->SetStreamValid(nTab, sal_False);
if (bColumn)
{
rDocShell.PostPaint( static_cast<SCCOL>(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<SCROW>(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 sal_True;
}
sal_Bool ScDocFunc::RemovePageBreak( sal_Bool bColumn, const ScAddress& rPos,
sal_Bool bRecord, sal_Bool bSetModified, sal_Bool /* bApi */ )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
SCTAB nTab = rPos.Tab();
SfxBindings* pBindings = rDocShell.GetViewBindings();
SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) :
static_cast<SCCOLROW>(rPos.Row());
ScBreakType nBreak;
if (bColumn)
nBreak = pDoc->HasColBreak(static_cast<SCCOL>(nPos), nTab);
else
nBreak = pDoc->HasRowBreak(static_cast<SCROW>(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, sal_False ) );
if (bColumn)
pDoc->RemoveColBreak(static_cast<SCCOL>(nPos), nTab, false, true);
else
pDoc->RemoveRowBreak(static_cast<SCROW>(nPos), nTab, false, true);
pDoc->UpdatePageBreaks( nTab );
if (pDoc->IsStreamValid(nTab))
pDoc->SetStreamValid(nTab, sal_False);
if (bColumn)
{
rDocShell.PostPaint( static_cast<SCCOL>(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 sal_True;
}
//------------------------------------------------------------------------
void ScDocFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
{
ScDocument* pDoc = rDocShell.GetDocument();
pDoc->SetTabProtection(nTab, &rProtect);
if (pDoc->IsUndoEnabled())
{
ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!");
if (pProtect)
{
::std::auto_ptr<ScTableProtection> p(new ScTableProtection(*pProtect));
p->setProtected(true); // just in case ...
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoTabProtect(&rDocShell, nTab, p) );
// ownership of auto_ptr now transferred to ScUndoTabProtect.
}
}
rDocShell.PostPaintGridAll();
ScDocShellModificator aModificator(rDocShell);
aModificator.SetDocumentModified();
}
sal_Bool ScDocFunc::Protect( SCTAB nTab, const String& rPassword, sal_Bool /*bApi*/ )
{
ScDocument* pDoc = rDocShell.GetDocument();
if (nTab == TABLEID_DOC)
{
// document protection
ScDocProtection aProtection;
aProtection.setProtected(true);
aProtection.setPassword(rPassword);
pDoc->SetDocProtection(&aProtection);
if (pDoc->IsUndoEnabled())
{
ScDocProtection* pProtect = pDoc->GetDocProtection();
DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScDocProtection pointer is NULL!");
if (pProtect)
{
::std::auto_ptr<ScDocProtection> p(new ScDocProtection(*pProtect));
p->setProtected(true); // just in case ...
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDocProtect(&rDocShell, p) );
// ownership of auto_ptr is transferred to ScUndoDocProtect.
}
}
}
else
{
// sheet protection
ScTableProtection aProtection;
aProtection.setProtected(true);
aProtection.setPassword(rPassword);
pDoc->SetTabProtection(nTab, &aProtection);
if (pDoc->IsUndoEnabled())
{
ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!");
if (pProtect)
{
::std::auto_ptr<ScTableProtection> p(new ScTableProtection(*pProtect));
p->setProtected(true); // just in case ...
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoTabProtect(&rDocShell, nTab, p) );
// ownership of auto_ptr now transferred to ScUndoTabProtect.
}
}
}
rDocShell.PostPaintGridAll();
ScDocShellModificator aModificator( rDocShell );
aModificator.SetDocumentModified();
return true;
}
sal_Bool ScDocFunc::Unprotect( SCTAB nTab, const String& rPassword, sal_Bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
if (nTab == TABLEID_DOC)
{
// document protection
ScDocProtection* pDocProtect = pDoc->GetDocProtection();
if (!pDocProtect || !pDocProtect->isProtected())
// already unprotected (should not happen)!
return true;
// save the protection state before unprotect (for undo).
::std::auto_ptr<ScDocProtection> pProtectCopy(new ScDocProtection(*pDocProtect));
if (!pDocProtect->verifyPassword(rPassword))
{
if (!bApi)
{
InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) );
aBox.Execute();
}
return false;
}
pDoc->SetDocProtection(NULL);
if (pDoc->IsUndoEnabled())
{
pProtectCopy->setProtected(false);
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDocProtect(&rDocShell, pProtectCopy) );
// ownership of auto_ptr now transferred to ScUndoDocProtect.
}
}
else
{
// sheet protection
ScTableProtection* pTabProtect = pDoc->GetTabProtection(nTab);
if (!pTabProtect || !pTabProtect->isProtected())
// already unprotected (should not happen)!
return true;
// save the protection state before unprotect (for undo).
::std::auto_ptr<ScTableProtection> pProtectCopy(new ScTableProtection(*pTabProtect));
if (!pTabProtect->verifyPassword(rPassword))
{
if (!bApi)
{
InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) );
aBox.Execute();
}
return false;
}
pDoc->SetTabProtection(nTab, NULL);
if (pDoc->IsUndoEnabled())
{
pProtectCopy->setProtected(false);
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoTabProtect(&rDocShell, nTab, pProtectCopy) );
// ownership of auto_ptr now transferred to ScUndoTabProtect.
}
}
rDocShell.PostPaintGridAll();
ScDocShellModificator aModificator( rDocShell );
aModificator.SetDocumentModified();
return true;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::ClearItems( const ScMarkData& rMark, const sal_uInt16* pWhich, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
ScEditableTester aTester( pDoc, rMark );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_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(sal_False); // for MarkToMulti
aMultiMark.MarkToMulti();
aMultiMark.GetMultiMarkArea( aMarkRange );
// if (bRecord)
if (bUndo)
{
SCTAB nStartTab = aMarkRange.aStart.Tab();
SCTAB nEndTab = aMarkRange.aEnd.Tab();
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab );
pDoc->CopyToDocument( aMarkRange, IDF_ATTRIB, sal_True, pUndoDoc, (ScMarkData*)&aMultiMark );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoClearItems( &rDocShell, aMultiMark, pUndoDoc, pWhich ) );
}
pDoc->ClearSelectionItems( pWhich, aMultiMark );
rDocShell.PostPaint( aMarkRange, PAINT_GRID, SC_PF_LINES | SC_PF_TESTMERGE );
aModificator.SetDocumentModified();
//! Bindings-Invalidate etc.?
return sal_True;
}
sal_Bool ScDocFunc::ChangeIndent( const ScMarkData& rMark, sal_Bool bIncrement, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo(pDoc->IsUndoEnabled());
ScEditableTester aTester( pDoc, rMark );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
ScRange aMarkRange;
rMark.GetMultiMarkArea( aMarkRange );
// if (bRecord)
if (bUndo)
{
SCTAB nStartTab = aMarkRange.aStart.Tab();
SCTAB nTabCount = pDoc->GetTableCount();
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nStartTab && rMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i );
ScRange aCopyRange = aMarkRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(nTabCount-1);
pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, sal_True, pUndoDoc, (ScMarkData*)&rMark );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoIndent( &rDocShell, rMark, pUndoDoc, bIncrement ) );
}
pDoc->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 sal_True;
}
sal_Bool ScDocFunc::AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark,
sal_uInt16 nFormatNo, sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
sal_Bool bSuccess = sal_False;
ScDocument* pDoc = 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 && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
aMark.SelectTable( nTab, sal_True );
}
ScAutoFormat* pAutoFormat = ScGlobal::GetAutoFormat();
ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
if ( pAutoFormat && nFormatNo < pAutoFormat->GetCount() && aTester.IsEditable() )
{
WaitObject aWait( rDocShell.GetActiveDialogParent() );
sal_Bool bSize = (*pAutoFormat)[nFormatNo]->GetIncludeWidthHeight();
SCTAB nTabCount = pDoc->GetTableCount();
ScDocument* pUndoDoc = NULL;
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab, bSize, bSize );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nStartTab && aMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i, bSize, bSize );
ScRange aCopyRange = rRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aStart.SetTab(nTabCount-1);
pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, sal_False, pUndoDoc, &aMark );
if (bSize)
{
pDoc->CopyToDocument( nStartCol,0,0, nEndCol,MAXROW,nTabCount-1,
IDF_NONE, sal_False, pUndoDoc, &aMark );
pDoc->CopyToDocument( 0,nStartRow,0, MAXCOL,nEndRow,nTabCount-1,
IDF_NONE, sal_False, pUndoDoc, &aMark );
}
pDoc->BeginDrawUndo();
}
pDoc->AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo, aMark );
if (bSize)
{
/* SCCOL nCols[2];
nCols[0] = nStartCol;
nCols[1] = nEndCol;
SCROW nRows[2];
nRows[0] = nStartRow;
nRows[1] = nEndRow;
*/
SCCOLROW nCols[2] = { nStartCol, nEndCol };
SCCOLROW nRows[2] = { nStartRow, nEndRow };
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
if (aMark.GetTableSelect(nTab))
{
SetWidthOrHeight( sal_True, 1,nCols, nTab, SC_SIZE_VISOPT, STD_EXTRA_WIDTH, sal_False, sal_True);
SetWidthOrHeight( sal_False,1,nRows, nTab, SC_SIZE_VISOPT, 0, sal_False, sal_False);
rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
PAINT_GRID | PAINT_LEFT | PAINT_TOP );
}
}
else
{
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
if (aMark.GetTableSelect(nTab))
{
sal_Bool bAdj = AdjustRowHeight( ScRange(nStartCol, nStartRow, nTab,
nEndCol, nEndRow, nTab), sal_False );
if (bAdj)
rDocShell.PostPaint( 0,nStartRow,nTab, MAXCOL,MAXROW,nTab,
PAINT_GRID | PAINT_LEFT );
else
rDocShell.PostPaint( nStartCol, nStartRow, nTab,
nEndCol, nEndRow, nTab, 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;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark,
const ScTokenArray* pTokenArray, const String& rString, sal_Bool bApi, sal_Bool bEnglish,
const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar )
{
ScDocShellModificator aModificator( rDocShell );
sal_Bool bSuccess = sal_False;
ScDocument* pDoc = 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();
sal_Bool bUndo(pDoc->IsUndoEnabled());
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
aMark.SelectTable( nTab, sal_True );
}
ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
if ( aTester.IsEditable() )
{
WaitObject aWait( rDocShell.GetActiveDialogParent() );
ScDocument* pUndoDoc = NULL;
// if (bRecord) // immer
if (bUndo)
{
//! auch bei Undo selektierte Tabellen beruecksichtigen
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab );
pDoc->CopyToDocument( rRange, IDF_ALL & ~IDF_NOTE, sal_False, pUndoDoc );
}
// use TokenArray if given, string (and flags) otherwise
if ( pTokenArray )
{
pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
aMark, EMPTY_STRING, pTokenArray, eGrammar);
}
else if ( pDoc->IsImportingXML() )
{
ScTokenArray* pCode = lcl_ScDocFunc_CreateTokenArrayXML( rString, rFormulaNmsp, eGrammar );
pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
aMark, EMPTY_STRING, pCode, eGrammar);
delete pCode;
pDoc->IncXMLImportedFormulaCount( rString.Len() );
}
else if (bEnglish)
{
ScCompiler aComp( pDoc, rRange.aStart);
aComp.SetGrammar(eGrammar);
ScTokenArray* pCode = aComp.CompileString( rString );
pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
aMark, EMPTY_STRING, pCode, eGrammar);
delete pCode;
}
else
pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
aMark, rString, NULL, eGrammar);
// if (bRecord) // immer
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 = sal_True;
}
else if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return bSuccess;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::TabOp( const ScRange& rRange, const ScMarkData* pTabMark,
const ScTabOpParam& rParam, sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
sal_Bool bSuccess = sal_False;
ScDocument* pDoc = 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 && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
aMark.SelectTable( nTab, sal_True );
}
ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
if ( aTester.IsEditable() )
{
WaitObject aWait( rDocShell.GetActiveDialogParent() );
pDoc->SetDirty( rRange );
if ( bRecord )
{
//! auch bei Undo selektierte Tabellen beruecksichtigen
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab );
pDoc->CopyToDocument( rRange, IDF_ALL & ~IDF_NOTE, sal_False, pUndoDoc );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoTabOp( &rDocShell,
nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab, pUndoDoc,
rParam.aRefFormulaCell,
rParam.aRefFormulaEnd,
rParam.aRefRowCell,
rParam.aRefColCell,
rParam.nMode) );
}
pDoc->InsertTableOp(rParam, nStartCol, nStartRow, nEndCol, nEndRow, aMark);
rDocShell.PostPaintGridAll();
aModificator.SetDocumentModified();
bSuccess = sal_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;
}
sal_Bool ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMark,
FillDir eDir, sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
sal_Bool bSuccess = sal_False;
ScDocument* pDoc = 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 && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
aMark.SelectTable( nTab, sal_True );
}
ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
if ( aTester.IsEditable() )
{
WaitObject aWait( rDocShell.GetActiveDialogParent() );
ScRange aSourceArea = rRange;
ScRange aDestArea = rRange;
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 = pDoc->GetTableCount();
SCTAB nDestStartTab = aDestArea.aStart.Tab();
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nDestStartTab, nDestStartTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nDestStartTab && aMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i );
ScRange aCopyRange = aDestArea;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(nTabCount-1);
pDoc->CopyToDocument( aCopyRange, IDF_AUTOFILL, sal_False, pUndoDoc, &aMark );
}
pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark,
nCount, eDir, FILL_SIMPLE );
AdjustRowHeight(rRange);
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,
pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) );
}
rDocShell.PostPaintGridAll();
// rDocShell.PostPaintDataChanged();
aModificator.SetDocumentModified();
bSuccess = sal_True;
}
else if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return bSuccess;
}
sal_Bool ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark,
FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
double fStart, double fStep, double fMax,
sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
sal_Bool bSuccess = sal_False;
ScDocument* pDoc = 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 && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
aMark.SelectTable( nTab, sal_True );
}
ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
if ( aTester.IsEditable() )
{
WaitObject aWait( rDocShell.GetActiveDialogParent() );
ScRange aSourceArea = rRange;
ScRange aDestArea = rRange;
SCSIZE nCount = pDoc->GetEmptyLinesInBlock(
aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aStart.Tab(),
aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aSourceArea.aEnd.Tab(),
DirFromFillDir(eDir) );
// #27665# mindestens eine Zeile/Spalte als Quellbereich behalten:
SCSIZE nTotLines = ( eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP ) ?
static_cast<SCSIZE>( aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1 ) :
static_cast<SCSIZE>( 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<SCROW>( aSourceArea.aEnd.Row() - nCount ) );
break;
case FILL_TO_RIGHT:
aSourceArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() - nCount ) );
break;
case FILL_TO_TOP:
aSourceArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() + nCount ) );
break;
case FILL_TO_LEFT:
aSourceArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() + nCount ) );
break;
}
ScDocument* pUndoDoc = NULL;
if ( bRecord )
{
SCTAB nTabCount = pDoc->GetTableCount();
SCTAB nDestStartTab = aDestArea.aStart.Tab();
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nDestStartTab, nDestStartTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nDestStartTab && aMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i );
pDoc->CopyToDocument(
aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0,
aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1,
IDF_AUTOFILL, sal_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();
pDoc->SetValue( nValX, nValY, nTab, fStart );
}
pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark,
nCount, eDir, eCmd, eDateCmd, fStep, fMax );
AdjustRowHeight(rRange);
rDocShell.PostPaintGridAll();
// rDocShell.PostPaintDataChanged();
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,
pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) );
}
bSuccess = sal_True;
}
else if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return bSuccess;
}
sal_Bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark,
FillDir eDir, sal_uLong nCount, sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = 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 && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScMarkData aMark;
if (pTabMark)
aMark = *pTabMark;
else
{
for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
aMark.SelectTable( nTab, sal_True );
}
ScRange aSourceArea = rRange;
ScRange aDestArea = rRange;
FillCmd eCmd = FILL_AUTO;
FillDateCmd eDateCmd = FILL_DAY;
double fStep = 1.0;
double fMax = MAXDOUBLE;
switch (eDir)
{
case FILL_TO_BOTTOM:
aDestArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() + nCount ) );
break;
case FILL_TO_TOP:
if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Row() ))
{
DBG_ERROR("FillAuto: Row < 0");
nCount = aSourceArea.aStart.Row();
}
aDestArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() - nCount ) );
break;
case FILL_TO_RIGHT:
aDestArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() + nCount ) );
break;
case FILL_TO_LEFT:
if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Col() ))
{
DBG_ERROR("FillAuto: Col < 0");
nCount = aSourceArea.aStart.Col();
}
aDestArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() - nCount ) );
break;
default:
DBG_ERROR("Falsche Richtung bei FillAuto");
break;
}
// Zellschutz testen
//! Quellbereich darf geschuetzt sein !!!
//! aber kein Matrixfragment enthalten !!!
ScEditableTester aTester( pDoc, aDestArea );
if ( !aTester.IsEditable() )
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
if ( pDoc->HasSelectedBlockMatrixFragment( nStartCol, nStartRow,
nEndCol, nEndRow, aMark ) )
{
if (!bApi)
rDocShell.ErrorMessage(STR_MATRIXFRAGMENTERR);
return sal_False;
}
WaitObject aWait( rDocShell.GetActiveDialogParent() );
ScDocument* pUndoDoc = NULL;
if ( bRecord )
{
SCTAB nTabCount = pDoc->GetTableCount();
SCTAB nDestStartTab = aDestArea.aStart.Tab();
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nDestStartTab, nDestStartTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nDestStartTab && aMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i );
// do not clone note captions in undo document
pDoc->CopyToDocument(
aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0,
aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1,
IDF_AUTOFILL, sal_False, pUndoDoc, &aMark );
}
pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), 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,
pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) );
}
rDocShell.PostPaintGridAll();
// rDocShell.PostPaintDataChanged();
aModificator.SetDocumentModified();
rRange = aDestArea; // Zielbereich zurueckgeben (zum Markieren)
return sal_True;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::MergeCells( const ScRange& rRange, sal_Bool bContents, sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
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();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
ScEditableTester aTester( pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow );
if (!aTester.IsEditable())
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return sal_False;
}
if ( nStartCol == nEndCol && nStartRow == nEndRow )
{
// nichts zu tun
return sal_True;
}
if ( pDoc->HasAttrib( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
HASATTR_MERGED | HASATTR_OVERLAPPED ) )
{
// "Zusammenfassen nicht verschachteln !"
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0);
return sal_False;
}
sal_Bool bNeedContents = bContents &&
( !pDoc->IsBlockEmpty( nTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) ||
!pDoc->IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) );
ScDocument* pUndoDoc = 0;
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)) && (pDoc->GetNote( aPos ) != 0);
if (bNeedContents || bHasNotes)
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab );
// note captions are collected by drawing undo
pDoc->CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
IDF_ALL|IDF_NOCAPTIONS, sal_False, pUndoDoc );
}
if( bHasNotes )
pDoc->BeginDrawUndo();
}
if (bNeedContents)
pDoc->DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
pDoc->DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
if( bRecord )
{
SdrUndoGroup* pDrawUndo = pDoc->GetDrawLayer() ? pDoc->GetDrawLayer()->GetCalcUndo() : 0;
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoMerge( &rDocShell,
nStartCol, nStartRow, nTab,
nEndCol, nEndRow, nTab, bNeedContents, pUndoDoc, pDrawUndo ) );
}
if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab ) ) )
rDocShell.PostPaint( nStartCol, nStartRow, nTab,
nEndCol, nEndRow, nTab, PAINT_GRID );
if (bNeedContents)
pDoc->SetDirty( rRange );
aModificator.SetDocumentModified();
SfxBindings* pBindings = rDocShell.GetViewBindings();
if (pBindings)
{
pBindings->Invalidate( FID_MERGE_ON );
pBindings->Invalidate( FID_MERGE_OFF );
pBindings->Invalidate( FID_MERGE_TOGGLE );
}
return sal_True;
}
sal_Bool ScDocFunc::UnmergeCells( const ScRange& rRange, sal_Bool bRecord, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
SCTAB nTab = rRange.aStart.Tab();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = sal_False;
if ( pDoc->HasAttrib( rRange, HASATTR_MERGED ) )
{
ScRange aExtended = rRange;
pDoc->ExtendMerge( aExtended );
ScRange aRefresh = aExtended;
pDoc->ExtendOverlapped( aRefresh );
if (bRecord)
{
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab );
pDoc->CopyToDocument( aExtended, IDF_ATTRIB, sal_False, pUndoDoc );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoRemoveMerge( &rDocShell, rRange, pUndoDoc ) );
}
const SfxPoolItem& rDefAttr = pDoc->GetPool()->GetDefaultItem( ATTR_MERGE );
ScPatternAttr aPattern( pDoc->GetPool() );
aPattern.GetItemSet().Put( rDefAttr );
pDoc->ApplyPatternAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
rRange.aEnd.Col(), rRange.aEnd.Row(), nTab,
aPattern );
pDoc->RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(),
aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab,
SC_MF_HOR | SC_MF_VER );
pDoc->ExtendMerge( aRefresh, sal_True, sal_False );
if ( !AdjustRowHeight( aExtended ) )
rDocShell.PostPaint( aExtended, PAINT_GRID );
aModificator.SetDocumentModified();
}
else if (!bApi)
Sound::Beep(); //! sal_False zurueck???
return sal_True;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::ModifyRangeNames( const ScRangeName& rNewRanges, sal_Bool bApi )
{
return SetNewRangeNames( new ScRangeName( rNewRanges ), bApi );
}
sal_Bool ScDocFunc::SetNewRangeNames( ScRangeName* pNewRanges, sal_Bool /* bApi */ ) // takes ownership of pNewRanges
{
ScDocShellModificator aModificator( rDocShell );
DBG_ASSERT( pNewRanges, "pNewRanges is 0" );
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo(pDoc->IsUndoEnabled());
if (bUndo)
{
ScRangeName* pOld = pDoc->GetRangeName();
ScRangeName* pUndoRanges = new ScRangeName(*pOld);
ScRangeName* pRedoRanges = new ScRangeName(*pNewRanges);
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoRangeNames( &rDocShell, pUndoRanges, pRedoRanges ) );
}
// #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.
sal_Bool bCompile = ( !pDoc->IsImportingXML() && pDoc->GetNamedRangesLockCount() == 0 );
if ( bCompile )
pDoc->CompileNameFormula( sal_True ); // CreateFormulaString
pDoc->SetRangeName( pNewRanges ); // takes ownership
if ( bCompile )
pDoc->CompileNameFormula( sal_False ); // CompileFormulaString
aModificator.SetDocumentModified();
// #i114072# don't broadcast while loading a file
// (navigator and input line for other open documents would be notified)
if ( bCompile )
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
return sal_True;
}
//------------------------------------------------------------------------
void ScDocFunc::CreateOneName( ScRangeName& rList,
SCCOL nPosX, SCROW nPosY, SCTAB nTab,
SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
sal_Bool& rCancel, sal_Bool bApi )
{
if (rCancel)
return;
ScDocument* pDoc = rDocShell.GetDocument();
if (!pDoc->HasValueData( nPosX, nPosY, nTab ))
{
String aName;
pDoc->GetString( nPosX, nPosY, nTab, aName );
ScRangeData::MakeValidName(aName);
if (aName.Len())
{
String aContent;
ScRange( nX1, nY1, nTab, nX2, nY2, nTab ).Format( aContent, SCR_ABS_3D, pDoc );
sal_Bool bInsert = sal_False;
sal_uInt16 nOldPos;
if (rList.SearchName( aName, nOldPos )) // vorhanden ?
{
ScRangeData* pOld = rList[nOldPos];
String aOldStr;
pOld->GetSymbol( aOldStr );
if (aOldStr != aContent)
{
if (bApi)
bInsert = sal_True; // per API nicht nachfragen
else
{
String aTemplate = ScGlobal::GetRscString( STR_CREATENAME_REPLACE );
String 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.AtFree(nOldPos);
bInsert = sal_True;
}
else if ( nResult == RET_CANCEL )
rCancel = sal_True;
}
}
}
else
bInsert = sal_True;
if (bInsert)
{
ScRangeData* pData = new ScRangeData( pDoc, aName, aContent,
ScAddress( nPosX, nPosY, nTab));
if (!rList.Insert(pData))
{
DBG_ERROR("nanu?");
delete pData;
}
}
}
}
}
sal_Bool ScDocFunc::CreateNames( const ScRange& rRange, sal_uInt16 nFlags, sal_Bool bApi )
{
if (!nFlags)
return sal_False; // war nix
ScDocShellModificator aModificator( rDocShell );
sal_Bool bDone = sal_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();
DBG_ASSERT(rRange.aEnd.Tab() == nTab, "CreateNames: mehrere Tabellen geht nicht");
sal_Bool bValid = sal_True;
if ( nFlags & ( NAME_TOP | NAME_BOTTOM ) )
if ( nStartRow == nEndRow )
bValid = sal_False;
if ( nFlags & ( NAME_LEFT | NAME_RIGHT ) )
if ( nStartCol == nEndCol )
bValid = sal_False;
if (bValid)
{
ScDocument* pDoc = rDocShell.GetDocument();
ScRangeName* pNames = pDoc->GetRangeName();
if (!pNames)
return sal_False; // soll nicht sein
ScRangeName aNewRanges( *pNames );
sal_Bool bTop = ( ( nFlags & NAME_TOP ) != 0 );
sal_Bool bLeft = ( ( nFlags & NAME_LEFT ) != 0 );
sal_Bool bBottom = ( ( nFlags & NAME_BOTTOM ) != 0 );
sal_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;
sal_Bool bCancel = sal_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 );
bDone = ModifyRangeNames( aNewRanges, bApi );
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
}
return bDone;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::InsertNameList( const ScAddress& rStartPos, sal_Bool bApi )
{
ScDocShellModificator aModificator( rDocShell );
sal_Bool bDone = sal_False;
ScDocument* pDoc = rDocShell.GetDocument();
const sal_Bool bRecord = pDoc->IsUndoEnabled();
SCTAB nTab = rStartPos.Tab();
ScDocument* pUndoDoc = NULL;
ScRangeName* pList = pDoc->GetRangeName();
sal_uInt16 nCount = pList->GetCount();
sal_uInt16 nValidCount = 0;
sal_uInt16 i;
for (i=0; i<nCount; i++)
{
ScRangeData* pData = (*pList)[i];
if ( !pData->HasType( RT_DATABASE ) && !pData->HasType( RT_SHARED ) )
++nValidCount;
}
if (nValidCount)
{
SCCOL nStartCol = rStartPos.Col();
SCROW nStartRow = rStartPos.Row();
SCCOL nEndCol = nStartCol + 1;
SCROW nEndRow = nStartRow + static_cast<SCROW>(nValidCount) - 1;
ScEditableTester aTester( pDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow );
if (aTester.IsEditable())
{
if (bRecord)
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab );
pDoc->CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
IDF_ALL, sal_False, pUndoDoc );
pDoc->BeginDrawUndo(); // wegen Hoehenanpassung
}
ScRangeData** ppSortArray = new ScRangeData* [ nValidCount ];
sal_uInt16 j = 0;
for (i=0; i<nCount; i++)
{
ScRangeData* pData = (*pList)[i];
if ( !pData->HasType( RT_DATABASE ) && !pData->HasType( RT_SHARED ) )
ppSortArray[j++] = pData;
}
#ifndef ICC
qsort( (void*)ppSortArray, nValidCount, sizeof(ScRangeData*),
&ScRangeData_QsortNameCompare );
#else
qsort( (void*)ppSortArray, nValidCount, sizeof(ScRangeData*),
ICCQsortNameCompare );
#endif
String aName;
rtl::OUStringBuffer aContent;
String aFormula;
SCROW nOutRow = nStartRow;
for (j=0; j<nValidCount; j++)
{
ScRangeData* pData = ppSortArray[j];
pData->GetName(aName);
// relative Referenzen Excel-konform auf die linke Spalte anpassen:
pData->UpdateSymbol(aContent, ScAddress( nStartCol, nOutRow, nTab ));
aFormula = '=';
aFormula += aContent;
pDoc->PutCell( nStartCol,nOutRow,nTab, new ScStringCell( aName ) );
pDoc->PutCell( nEndCol ,nOutRow,nTab, new ScStringCell( aFormula ) );
++nOutRow;
}
delete [] ppSortArray;
if (bRecord)
{
ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
pRedoDoc->InitUndo( pDoc, nTab, nTab );
pDoc->CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
IDF_ALL, sal_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 );
//! rDocShell.UpdateOle(GetViewData());
aModificator.SetDocumentModified();
bDone = sal_True;
}
else if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
}
return bDone;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd, sal_Bool bApi )
{
ScDocument* pDoc = rDocShell.GetDocument();
SCCOL nStartCol = rOldRange.aStart.Col();
SCROW nStartRow = rOldRange.aStart.Row();
SCTAB nTab = rOldRange.aStart.Tab();
sal_Bool bUndo(pDoc->IsUndoEnabled());
sal_Bool bRet = sal_False;
String aFormula;
pDoc->GetFormula( nStartCol, nStartRow, nTab, aFormula );
if ( aFormula.GetChar(0) == '{' && aFormula.GetChar(aFormula.Len()-1) == '}' )
{
String aUndo = ScGlobal::GetRscString( STR_UNDO_RESIZEMATRIX );
if (bUndo)
rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
aFormula.Erase(0,1);
aFormula.Erase(aFormula.Len()-1,1);
ScMarkData aMark;
aMark.SetMarkArea( rOldRange );
aMark.SelectTable( nTab, sal_True );
ScRange aNewRange( rOldRange.aStart, rNewEnd );
if ( DeleteContents( aMark, IDF_CONTENTS, sal_True, bApi ) )
{
// GRAM_PODF_A1 for API compatibility.
bRet = EnterMatrix( aNewRange, &aMark, NULL, aFormula, bApi, sal_False, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 );
if (!bRet)
{
// versuchen, alten Zustand wiederherzustellen
EnterMatrix( rOldRange, &aMark, NULL, aFormula, bApi, sal_False, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 );
}
}
if (bUndo)
rDocShell.GetUndoManager()->LeaveListAction();
}
return bRet;
}
//------------------------------------------------------------------------
sal_Bool ScDocFunc::InsertAreaLink( const String& rFile, const String& rFilter,
const String& rOptions, const String& rSource,
const ScRange& rDestRange, sal_uLong nRefresh,
sal_Bool bFitBlock, sal_Bool bApi )
{
//! auch fuer ScViewFunc::InsertAreaLink benutzen!
ScDocument* pDoc = rDocShell.GetDocument();
sal_Bool bUndo (pDoc->IsUndoEnabled());
sfx2::LinkManager* pLinkManager = pDoc->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().Count();
sal_uInt16 nRemoved = 0;
sal_uInt16 nLinkPos = 0;
while (nLinkPos<nLinkCount)
{
::sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[nLinkPos];
if ( pBase->ISA(ScAreaLink) &&
static_cast<ScAreaLink*>(pBase)->GetDestArea().aStart == rDestRange.aStart )
{
if ( bUndo )
{
if ( !nRemoved )
{
// group all remove and the insert action
String aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTAREALINK );
rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
}
ScAreaLink* pOldArea = static_cast<ScAreaLink*>(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().Count();
++nRemoved;
}
else
++nLinkPos;
}
String aFilterName = rFilter;
String aNewOptions = rOptions;
if (!aFilterName.Len())
ScDocumentLoader::GetFilterName( rFile, aFilterName, aNewOptions, sal_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 );
pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, rFile, &aFilterName, &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 (pDoc->IsExecuteLinkEnabled())
{
pLink->SetDoInsert(bFitBlock); // beim ersten Update ggf. nichts einfuegen
pLink->Update(); // kein SetInCreate -> Update ausfuehren
}
pLink->SetDoInsert(sal_True); // Default = sal_True
SfxBindings* pBindings = rDocShell.GetViewBindings();
if (pBindings)
pBindings->Invalidate( SID_LINKS );
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); // Navigator
return sal_True;
}