blob: a8f16a551014ff4d126409e3eb9745f819dae8e5 [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"
//----------------------------------------------------------------------------
#define _SV_NOXSOUND
#define _BASE_DLGS_HXX
#define _BIGINT_HXX
#define _CACHESTR_HXX
#define _CONFIG_HXX
#define _CURSOR_HXX
#define _CTRLTOOL_HXX
#define _DLGCFG_HXX
#define _DYNARR_HXX
#define _EXTATTR_HXX
#define _FILDLG_HXX
#define _FONTDLG_HXX
#define _FRM3D_HXX
#define _INTRO_HXX
#define _ISETBWR_HXX
#define _NO_SVRTF_PARSER_HXX
#define _MACRODLG_HXX
#define _MODALDLG_HXX
#define _MOREBUTTON_HXX
#define _OUTLINER_HXX
//#define _PRNDLG_HXX
//#define _POLY_HXX
#define _PVRWIN_HXX
//#define _QUEUE_HXX
#define _RULER_HXX
#define _SCRWIN_HXX
#define _SETBRW_HXX
//#define _STACK_HXX
//#define _STATUS_HXX ***
#define _STDCTRL_HXX
#define _STDMENU_HXX
//#define _TAB_HXX
#define _TABBAR_HXX
#define _TREELIST_HXX
#define _VALUESET_HXX
#define _VCATTR_HXX
#define _VCBRW_HXX
#define _VCTRLS_HXX
#define _VCSBX_HXX
#define _VCONT_HXX
#define _VDRWOBJ_HXX
//#define _SELENG_HXX
//#define _SOUND_HXX
//#define _SYSDLG_HXX
#define _PASSWD_HXX
#define _SFX_DOCFILE_HXX
//#define _SFX_DOCFILT_HXX
#define _SFX_DOCINF_HXX
#define _SFX_DOCSH_HXX
//#define _SFXDOCFILT_HXX
//#define _SFXDOCINF_HXX
//#define _SFXDOCSH_HXX
#define _SFX_PRNMON_HXX
#define _SFX_RESMGR_HXX
#define _SFX_TEMPLDLG_HXX
//#define _SFXAPPWIN_HXX
#define _SFXBASIC_HXX
#define _SFXCTRLITEM
#define _SFXDLGCFG_HXX
//#define _SFXDISPATCH_HXX
#define _SFXFILEDLG_HXX
//#define _SFXIMGMGR_HXX
#define _SFXIPFRM_HXX
#define _SFX_MACRO_HXX
#define _SFXMNUITEM_HXX
#define _SFXMNUMGR_HXX
#define _SFXMULTISEL_HXX
//#define _SFXMSG_HXX
#define _SFXMSGDESCR_HXX
#define _SFXMSGPOOL_HXX
#define _SFX_MINFITEM_HXX
#define _SFXOBJFACE_HXX
#define _SFXOBJFAC_HXX
#define _SFX_SAVEOPT_HXX
#define _SFXSTBITEM_HXX
#define _SFXSTBMGR_HXX
#define _SFXTBXCTRL_HXX
#define _SFXTBXMGR_HXX
#define _SI_HXX
//#define _SI_DLL_HXX
//#define _SIDLL_HXX
//#define _SI_NOITEMS
//#define _SI_NOOTHERFORMS
//#define _SI_NOSBXCONTROLS
//#define _SINOSBXCONTROLS
//#define _SI_NODRW
//#define _SI_NOCONTROL
#define _SVBOXITM_HXX
#define _SVCONTNR_HXX //
#define _SDR_NOTRANSFORM
#define _SVDRAG_HXX
#define _SVINCVW_HXX
//#define _SV_MULTISEL_HXX
#define _SVRTV_HXX
#define _SVTABBX_HXX
#define _SVTREEBOX_HXX
#define _SVTREELIST_HXX
#define _SVX_DAILDLL_HXX
#define _SVX_HYPHEN_HXX
#define _SVX_IMPGRF_HXX
#define _SVX_LAYCTRL_HXX
#define _SVX_OPTITEMS_HXX
#define _SVX_OPTGERL_HXX
#define _SVX_OPTSAVE_HXX
#define _SVX_OPTSPELL_HXX
#define _SVX_OPTPATH_HXX
#define _SVX_OPTLINGU_HXX
#define _SVX_RULER_HXX
#define _SVX_RULRITEM_HXX
#define _SVX_SELCTRL_HXX
#define _SVX_SPLWRAP_HXX
#define _SVX_SPLDLG_HXX
#define _SVX_STDDLG_HXX
#define _SVX_THESDLG_HXX
// INCLUDE -------------------------------------------------------------------
#include "scitems.hxx"
#include <svx/dbexch.hrc>
#include <svx/svdetc.hxx>
#include <svx/svditer.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdpage.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/docfile.hxx>
#include <svl/stritem.hxx>
#include <svl/ptitem.hxx>
#include <svl/urlbmk.hxx>
#include <sot/clsids.hxx>
#include <sot/formats.hxx>
#include <vcl/graph.hxx>
#include <vcl/virdev.hxx>
#include <vcl/msgbox.hxx>
#include <tools/urlobj.hxx>
#include <sot/exchange.hxx>
#include <memory>
#include "attrib.hxx"
#include "patattr.hxx"
#include "dociter.hxx"
#include "viewfunc.hxx"
#include "tabvwsh.hxx"
#include "docsh.hxx"
#include "docfunc.hxx"
#include "undoblk.hxx"
#include "refundo.hxx"
#include "globstr.hrc"
#include "global.hxx"
#include "transobj.hxx"
#include "drwtrans.hxx"
#include "rangenam.hxx"
#include "dbcolect.hxx"
#include "impex.hxx" // Sylk-ID fuer CB
#include "chgtrack.hxx"
#include "waitoff.hxx"
#include "scmod.hxx"
#include "sc.hrc"
#include "inputopt.hxx"
#include "warnbox.hxx"
#include "drwlayer.hxx"
#include "editable.hxx"
#include "transobj.hxx"
#include "drwtrans.hxx"
#include "docuno.hxx"
#include "clipparam.hxx"
#include "drawview.hxx"
#include "chartlis.hxx"
#include "charthelper.hxx"
using namespace com::sun::star;
// STATIC DATA ---------------------------------------------------------------
//============================================================================
// GlobalName der Writer-DocShell kommt jetzt aus comphelper/classids.hxx
//----------------------------------------------------------------------------
// C U T
void ScViewFunc::CutToClip( ScDocument* pClipDoc, sal_Bool bIncludeObjects )
{
UpdateInputLine();
ScEditableTester aTester( this );
if (!aTester.IsEditable()) // selection editable?
{
ErrorMessage( aTester.GetMessageId() );
return;
}
ScRange aRange; // zu loeschender Bereich
if ( GetViewData()->GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
{
ScDocument* pDoc = GetViewData()->GetDocument();
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScMarkData& rMark = GetViewData()->GetMarkData();
const sal_Bool bRecord(pDoc->IsUndoEnabled()); // Undo/Redo
ScDocShellModificator aModificator( *pDocSh );
if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) // mark the range if not marked yet
{
DoneBlockMode();
InitOwnBlockMode();
rMark.SetMarkArea( aRange );
MarkDataChanged();
}
CopyToClip( pClipDoc, sal_True, sal_False, bIncludeObjects ); // Ab ins Clipboard
ScAddress aOldEnd( aRange.aEnd ); // Zusammengefasste Zellen im Bereich?
pDoc->ExtendMerge( aRange, sal_True );
ScDocument* pUndoDoc = NULL;
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndoSelected( pDoc, rMark );
// all sheets - CopyToDocument skips those that don't exist in pUndoDoc
ScRange aCopyRange = aRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(pDoc->GetTableCount()-1);
pDoc->CopyToDocument( aCopyRange, (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS, sal_False, pUndoDoc );
pDoc->BeginDrawUndo();
}
sal_uInt16 nExtFlags = 0;
pDocSh->UpdatePaintExt( nExtFlags, aRange );
HideCursor(); // Cursor aendert sich !
rMark.MarkToMulti();
pDoc->DeleteSelection( IDF_ALL, rMark );
if ( bIncludeObjects )
pDoc->DeleteObjectsInSelection( rMark );
rMark.MarkToSimple();
if ( !AdjustRowHeight( aRange.aStart.Row(), aRange.aEnd.Row() ) )
pDocSh->PostPaint( aRange, PAINT_GRID, nExtFlags );
if ( bRecord ) // erst jetzt ist Draw-Undo verfuegbar
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoCut( pDocSh, aRange, aOldEnd, rMark, pUndoDoc ) );
aModificator.SetDocumentModified();
ShowCursor(); // Cursor aendert sich !
pDocSh->UpdateOle(GetViewData());
CellContentChanged();
}
else
ErrorMessage( STR_NOMULTISELECT );
}
//----------------------------------------------------------------------------
// C O P Y
sal_Bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, sal_Bool bCut, sal_Bool bApi, sal_Bool bIncludeObjects, sal_Bool bStopEdit )
{
sal_Bool bDone = sal_False;
if ( bStopEdit )
UpdateInputLine();
ScRange aRange;
ScMarkType eMarkType = GetViewData()->GetSimpleArea( aRange );
ScDocument* pDoc = GetViewData()->GetDocument();
ScMarkData& rMark = GetViewData()->GetMarkData();
if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
{
if ( !pDoc->HasSelectedBlockMatrixFragment(
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(),
rMark ) )
{
sal_Bool bSysClip = sal_False;
if ( !pClipDoc ) // no clip doc specified
{
pClipDoc = new ScDocument( SCDOCMODE_CLIP ); // create one (deleted by ScTransferObj)
bSysClip = sal_True; // and copy into system
}
if ( !bCut )
{
ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
if ( pChangeTrack )
pChangeTrack->ResetLastCut(); // kein CutMode mehr
}
if ( bSysClip && bIncludeObjects )
{
sal_Bool bAnyOle = pDoc->HasOLEObjectsInArea( aRange, &rMark );
// update ScGlobal::pDrawClipDocShellRef
ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
}
ScClipParam aClipParam(aRange, bCut);
aClipParam.setSourceDocID( pDoc->GetDocumentID() );
pDoc->CopyToClip(aClipParam, pClipDoc, &rMark, false, false, bIncludeObjects);
if ( pDoc && pClipDoc )
{
ScDrawLayer* pDrawLayer = pClipDoc->GetDrawLayer();
if ( pDrawLayer )
{
ScClipParam& rClipParam = pClipDoc->GetClipParam();
ScRangeListVector& rRangesVector = rClipParam.maProtectedChartRangesVector;
SCTAB nTabCount = pClipDoc->GetTableCount();
for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab )
{
SdrPage* pPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
if ( pPage )
{
ScChartHelper::FillProtectedChartRangesVector( rRangesVector, pDoc, pPage );
}
}
}
}
if (bSysClip)
{
ScDrawLayer::SetGlobalDrawPersist(NULL);
ScGlobal::SetClipDocName( pDoc->GetDocumentShell()->GetTitle( SFX_TITLE_FULLNAME ) );
}
pClipDoc->ExtendMerge( aRange, sal_True );
if (bSysClip)
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
TransferableObjectDescriptor aObjDesc;
pDocSh->FillTransferableObjectDescriptor( aObjDesc );
aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
// maSize is set in ScTransferObj ctor
ScTransferObj* pTransferObj = new ScTransferObj( pClipDoc, aObjDesc );
uno::Reference<datatransfer::XTransferable> xTransferable( pTransferObj );
if ( ScGlobal::pDrawClipDocShellRef )
{
SfxObjectShellRef aPersistRef( &(*ScGlobal::pDrawClipDocShellRef) );
pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
}
pTransferObj->CopyToClipboard( GetActiveWin() ); // system clipboard
SC_MOD()->SetClipObject( pTransferObj, NULL ); // internal clipboard
}
bDone = sal_True;
}
else
{
if (!bApi)
ErrorMessage(STR_MATRIXFRAGMENTERR);
}
}
else if (eMarkType == SC_MARK_MULTI)
{
bool bSuccess = false;
ScClipParam aClipParam;
aClipParam.mbCutMode = false;
rMark.MarkToSimple();
rMark.FillRangeListWithMarks(&aClipParam.maRanges, false);
do
{
if (bCut)
// We con't support cutting of multi-selections.
break;
if (pClipDoc)
// TODO: What's this for?
break;
::std::auto_ptr<ScDocument> pDocClip(new ScDocument(SCDOCMODE_CLIP));
// Check for geometrical feasibility of the ranges.
bool bValidRanges = true;
ScRangePtr p = aClipParam.maRanges.First();
SCCOL nPrevColDelta = 0;
SCROW nPrevRowDelta = 0;
SCCOL nPrevCol = p->aStart.Col();
SCROW nPrevRow = p->aStart.Row();
SCCOL nPrevColSize = p->aEnd.Col() - p->aStart.Col() + 1;
SCROW nPrevRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
for (p = aClipParam.maRanges.Next(); p; p = aClipParam.maRanges.Next())
{
if (pDoc->HasSelectedBlockMatrixFragment(
p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), rMark))
{
if (!bApi)
ErrorMessage(STR_MATRIXFRAGMENTERR);
return false;
}
SCCOL nColDelta = p->aStart.Col() - nPrevCol;
SCROW nRowDelta = p->aStart.Row() - nPrevRow;
if ((nColDelta && nRowDelta) || (nPrevColDelta && nRowDelta) || (nPrevRowDelta && nColDelta))
{
bValidRanges = false;
break;
}
if (aClipParam.meDirection == ScClipParam::Unspecified)
{
if (nColDelta)
aClipParam.meDirection = ScClipParam::Column;
if (nRowDelta)
aClipParam.meDirection = ScClipParam::Row;
}
SCCOL nColSize = p->aEnd.Col() - p->aStart.Col() + 1;
SCROW nRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
if (aClipParam.meDirection == ScClipParam::Column && nRowSize != nPrevRowSize)
{
// column-oriented ranges must have identical row size.
bValidRanges = false;
break;
}
if (aClipParam.meDirection == ScClipParam::Row && nColSize != nPrevColSize)
{
// likewise, row-oriented ranges must have identical
// column size.
bValidRanges = false;
break;
}
nPrevCol = p->aStart.Col();
nPrevRow = p->aStart.Row();
nPrevColDelta = nColDelta;
nPrevRowDelta = nRowDelta;
nPrevColSize = nColSize;
nPrevRowSize = nRowSize;
}
if (!bValidRanges)
break;
pDoc->CopyToClip(aClipParam, pDocClip.get(), &rMark, false, false, bIncludeObjects);
ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
if ( pChangeTrack )
pChangeTrack->ResetLastCut(); // kein CutMode mehr
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
TransferableObjectDescriptor aObjDesc;
pDocSh->FillTransferableObjectDescriptor( aObjDesc );
aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
// maSize is set in ScTransferObj ctor
ScTransferObj* pTransferObj = new ScTransferObj( pDocClip.release(), aObjDesc );
uno::Reference<datatransfer::XTransferable> xTransferable( pTransferObj );
if ( ScGlobal::pDrawClipDocShellRef )
{
SfxObjectShellRef aPersistRef( &(*ScGlobal::pDrawClipDocShellRef) );
pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
}
pTransferObj->CopyToClipboard( GetActiveWin() ); // system clipboard
SC_MOD()->SetClipObject( pTransferObj, NULL ); // internal clipboard
}
bSuccess = true;
}
while (false);
if (!bSuccess && !bApi)
ErrorMessage(STR_NOMULTISELECT);
bDone = bSuccess;
}
else
{
if (!bApi)
ErrorMessage(STR_NOMULTISELECT);
}
return bDone;
}
ScTransferObj* ScViewFunc::CopyToTransferable()
{
ScRange aRange;
if ( GetViewData()->GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
{
ScDocument* pDoc = GetViewData()->GetDocument();
ScMarkData& rMark = GetViewData()->GetMarkData();
if ( !pDoc->HasSelectedBlockMatrixFragment(
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(),
rMark ) )
{
ScDocument *pClipDoc = new ScDocument( SCDOCMODE_CLIP ); // create one (deleted by ScTransferObj)
sal_Bool bAnyOle = pDoc->HasOLEObjectsInArea( aRange, &rMark );
ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
ScClipParam aClipParam(aRange, false);
pDoc->CopyToClip(aClipParam, pClipDoc, &rMark, false, false, true);
ScDrawLayer::SetGlobalDrawPersist(NULL);
pClipDoc->ExtendMerge( aRange, sal_True );
ScDocShell* pDocSh = GetViewData()->GetDocShell();
TransferableObjectDescriptor aObjDesc;
pDocSh->FillTransferableObjectDescriptor( aObjDesc );
aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
ScTransferObj* pTransferObj = new ScTransferObj( pClipDoc, aObjDesc );
return pTransferObj;
}
}
return NULL;
}
//----------------------------------------------------------------------------
// P A S T E
void ScViewFunc::PasteDraw()
{
ScViewData* pViewData = GetViewData();
SCCOL nPosX = pViewData->GetCurX();
SCROW nPosY = pViewData->GetCurY();
Window* pWin = GetActiveWin();
Point aPos = pWin->PixelToLogic( pViewData->GetScrPos( nPosX, nPosY,
pViewData->GetActivePart() ) );
ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard( pWin );
if (pDrawClip)
PasteDraw( aPos, pDrawClip->GetModel(), sal_False,
pDrawClip->GetSourceDocID() == pViewData->GetDocument()->GetDocumentID() );
}
void ScViewFunc::PasteFromSystem()
{
UpdateInputLine();
Window* pWin = GetActiveWin();
ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard( pWin );
ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard( pWin );
if (pOwnClip)
{
// #129384# keep a reference in case the clipboard is changed during PasteFromClip
uno::Reference<datatransfer::XTransferable> aOwnClipRef( pOwnClip );
PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
PASTE_NOFUNC, sal_False, sal_False, sal_False, INS_NONE, IDF_NONE,
sal_True ); // allow warning dialog
}
else if (pDrawClip)
PasteDraw();
else
{
TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
// if (pClipObj.Is())
{
sal_uLong nBiff8 = SotExchange::RegisterFormatName(
String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff8")));
sal_uLong nBiff5 = SotExchange::RegisterFormatName(
String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff5")));
// als erstes SvDraw-Model, dann Grafik
// (Grafik darf nur bei einzelner Grafik drinstehen)
if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_DRAWING ))
{
// special case for tables from drawing
if( aDataHelper.HasFormat( SOT_FORMAT_RTF ) )
{
PasteFromSystem( FORMAT_RTF );
}
else
{
PasteFromSystem( SOT_FORMATSTR_ID_DRAWING );
}
}
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_SVXB ))
PasteFromSystem( SOT_FORMATSTR_ID_SVXB );
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE ))
{
// If it's a Writer object, insert RTF instead of OLE
sal_Bool bDoRtf = sal_False;
TransferableObjectDescriptor aObjDesc;
if( aDataHelper.GetTransferableObjectDescriptor( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR, aObjDesc ) )
{
bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
&& aDataHelper.HasFormat( SOT_FORMAT_RTF ) );
}
if ( bDoRtf )
PasteFromSystem( FORMAT_RTF );
else
PasteFromSystem( SOT_FORMATSTR_ID_EMBED_SOURCE );
}
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE ))
PasteFromSystem( SOT_FORMATSTR_ID_LINK_SOURCE );
// the following format can not affect scenario from #89579#
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE ))
PasteFromSystem( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE );
// FORMAT_PRIVATE no longer here (can't work if pOwnClip is NULL)
else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats
PasteFromSystem(nBiff8);
else if (aDataHelper.HasFormat(nBiff5))
PasteFromSystem(nBiff5);
else if (aDataHelper.HasFormat(FORMAT_RTF))
PasteFromSystem(FORMAT_RTF);
else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML))
PasteFromSystem(SOT_FORMATSTR_ID_HTML);
else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML_SIMPLE))
PasteFromSystem(SOT_FORMATSTR_ID_HTML_SIMPLE);
else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_SYLK))
PasteFromSystem(SOT_FORMATSTR_ID_SYLK);
else if (aDataHelper.HasFormat(FORMAT_STRING))
PasteFromSystem(FORMAT_STRING);
else if (aDataHelper.HasFormat(FORMAT_GDIMETAFILE))
PasteFromSystem(FORMAT_GDIMETAFILE);
else if (aDataHelper.HasFormat(FORMAT_BITMAP))
PasteFromSystem(FORMAT_BITMAP);
// #89579# xxx_OLE formats come last, like in SotExchange tables
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE ))
PasteFromSystem( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE );
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ))
PasteFromSystem( SOT_FORMATSTR_ID_LINK_SOURCE_OLE );
// else
// ErrorMessage(STR_PASTE_ERROR);
}
// else
// ErrorMessage(STR_PASTE_ERROR);
}
// keine Fehlermeldung, weil SID_PASTE in der idl das FastCall-Flag hat,
// also auch gerufen wird, wenn nichts im Clipboard steht (#42531#)
}
void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTransferable>& rxTransferable )
{
ScTransferObj *pOwnClip=0;
ScDrawTransferObj *pDrawClip=0;
uno::Reference<lang::XUnoTunnel> xTunnel( rxTransferable, uno::UNO_QUERY );
if ( xTunnel.is() )
{
sal_Int64 nHandle = xTunnel->getSomething( ScTransferObj::getUnoTunnelId() );
if ( nHandle )
pOwnClip = (ScTransferObj*) (sal_IntPtr) nHandle;
else
{
nHandle = xTunnel->getSomething( ScDrawTransferObj::getUnoTunnelId() );
if ( nHandle )
pDrawClip = (ScDrawTransferObj*) (sal_IntPtr) nHandle;
}
}
if (pOwnClip)
{
PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
PASTE_NOFUNC, sal_False, sal_False, sal_False, INS_NONE, IDF_NONE,
sal_True ); // allow warning dialog
}
else if (pDrawClip)
{
ScViewData* pViewData = GetViewData();
SCCOL nPosX = pViewData->GetCurX();
SCROW nPosY = pViewData->GetCurY();
Window* pWin = GetActiveWin();
Point aPos = pWin->PixelToLogic( pViewData->GetScrPos( nPosX, nPosY, pViewData->GetActivePart() ) );
PasteDraw( aPos, pDrawClip->GetModel(), sal_False, pDrawClip->GetSourceDocID() == pViewData->GetDocument()->GetDocumentID() );
}
else
{
TransferableDataHelper aDataHelper( rxTransferable );
{
sal_uLong nBiff8 = SotExchange::RegisterFormatName(
String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff8")));
sal_uLong nBiff5 = SotExchange::RegisterFormatName(
String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff5")));
sal_uLong nFormatId = 0;
// als erstes SvDraw-Model, dann Grafik
// (Grafik darf nur bei einzelner Grafik drinstehen)
if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_DRAWING ))
nFormatId = SOT_FORMATSTR_ID_DRAWING;
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_SVXB ))
nFormatId = SOT_FORMATSTR_ID_SVXB;
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE ))
{
// If it's a Writer object, insert RTF instead of OLE
sal_Bool bDoRtf = sal_False;
TransferableObjectDescriptor aObjDesc;
if( aDataHelper.GetTransferableObjectDescriptor( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR, aObjDesc ) )
{
bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
&& aDataHelper.HasFormat( SOT_FORMAT_RTF ) );
}
if ( bDoRtf )
nFormatId = FORMAT_RTF;
else
nFormatId = SOT_FORMATSTR_ID_EMBED_SOURCE;
}
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE ))
nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE;
// the following format can not affect scenario from #89579#
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE ))
nFormatId = SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE;
// FORMAT_PRIVATE no longer here (can't work if pOwnClip is NULL)
else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats
nFormatId = nBiff8;
else if (aDataHelper.HasFormat(nBiff5))
nFormatId = nBiff5;
else if (aDataHelper.HasFormat(FORMAT_RTF))
nFormatId = FORMAT_RTF;
else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML))
nFormatId = SOT_FORMATSTR_ID_HTML;
else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML_SIMPLE))
nFormatId = SOT_FORMATSTR_ID_HTML_SIMPLE;
else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_SYLK))
nFormatId = SOT_FORMATSTR_ID_SYLK;
else if (aDataHelper.HasFormat(FORMAT_STRING))
nFormatId = FORMAT_STRING;
else if (aDataHelper.HasFormat(FORMAT_GDIMETAFILE))
nFormatId = FORMAT_GDIMETAFILE;
else if (aDataHelper.HasFormat(FORMAT_BITMAP))
nFormatId = FORMAT_BITMAP;
// #89579# xxx_OLE formats come last, like in SotExchange tables
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE ))
nFormatId = SOT_FORMATSTR_ID_EMBED_SOURCE_OLE;
else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ))
nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE_OLE;
else
return;
PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
GetViewData()->GetCurX(), GetViewData()->GetCurY(),
NULL, sal_False, sal_False );
}
}
}
sal_Bool ScViewFunc::PasteFromSystem( sal_uLong nFormatId, sal_Bool bApi )
{
UpdateInputLine();
sal_Bool bRet = sal_True;
Window* pWin = GetActiveWin();
ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard( pWin );
if ( nFormatId == 0 && pOwnClip )
{
// #129384# keep a reference in case the clipboard is changed during PasteFromClip
uno::Reference<datatransfer::XTransferable> aOwnClipRef( pOwnClip );
PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
PASTE_NOFUNC, sal_False, sal_False, sal_False, INS_NONE, IDF_NONE,
!bApi ); // allow warning dialog
}
else
{
TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
if ( !aDataHelper.GetTransferable().is() )
return sal_False;
bRet = PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
GetViewData()->GetCurX(), GetViewData()->GetCurY(),
NULL, sal_False, !bApi ); // allow warning dialog
if ( !bRet && !bApi )
ErrorMessage(STR_PASTE_ERROR);
}
return bRet;
}
//----------------------------------------------------------------------------
// P A S T E
sal_Bool ScViewFunc::PasteOnDrawObjectLinked(
const uno::Reference<datatransfer::XTransferable>& rxTransferable,
SdrObject& rHitObj)
{
TransferableDataHelper aDataHelper( rxTransferable );
if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SVXB ) )
{
SotStorageStreamRef xStm;
ScDrawView* pScDrawView = GetScDrawView();
if( pScDrawView && aDataHelper.GetSotStorageStream( SOT_FORMATSTR_ID_SVXB, xStm ) )
{
Graphic aGraphic;
*xStm >> aGraphic;
const String aEmpty;
const String aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
if(pScDrawView->ApplyGraphicToObject( rHitObj, aGraphic, aBeginUndo, aEmpty, aEmpty ))
{
return sal_True;
}
}
}
else if ( aDataHelper.HasFormat( SOT_FORMAT_GDIMETAFILE ) )
{
GDIMetaFile aMtf;
ScDrawView* pScDrawView = GetScDrawView();
if( pScDrawView && aDataHelper.GetGDIMetaFile( FORMAT_GDIMETAFILE, aMtf ) )
{
const String aEmpty;
const String aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aMtf), aBeginUndo, aEmpty, aEmpty ))
{
return sal_True;
}
}
}
else if ( aDataHelper.HasFormat( SOT_FORMAT_BITMAP ) || aDataHelper.HasFormat( SOT_FORMATSTR_ID_PNG ) )
{
BitmapEx aBmpEx;
ScDrawView* pScDrawView = GetScDrawView();
if( pScDrawView && aDataHelper.GetBitmapEx( FORMAT_BITMAP, aBmpEx ) )
{
const String aEmpty;
const String aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aBmpEx), aBeginUndo, aEmpty, aEmpty ))
{
return sal_True;
}
}
}
return sal_False;
}
sal_Bool lcl_SelHasAttrib( ScDocument* pDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
const ScMarkData& rTabSelection, sal_uInt16 nMask )
{
SCTAB nTabCount = pDoc->GetTableCount();
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
if ( rTabSelection.GetTableSelect(nTab) && pDoc->HasAttrib( nCol1, nRow1, nTab, nCol2, nRow2, nTab, nMask ) )
return sal_True;
return sal_False;
}
//
// Einfuegen auf Tabelle:
//
// internes Paste
namespace {
class CursorSwitcher
{
public:
CursorSwitcher(ScViewFunc* pViewFunc) :
mpViewFunc(pViewFunc)
{
mpViewFunc->HideCursor();
}
~CursorSwitcher()
{
mpViewFunc->ShowCursor();
}
private:
ScViewFunc* mpViewFunc;
};
bool lcl_checkDestRangeForOverwrite(const ScRange& rDestRange, const ScDocument* pDoc, const ScMarkData& rMark, Window* pParentWnd)
{
bool bIsEmpty = true;
SCTAB nTabCount = pDoc->GetTableCount();
for (SCTAB nTab=0; nTab < nTabCount && bIsEmpty; ++nTab)
{
if (!rMark.GetTableSelect(nTab))
continue;
bIsEmpty = pDoc->IsBlockEmpty(nTab, rDestRange.aStart.Col(), rDestRange.aStart.Row(),
rDestRange.aEnd.Col(), rDestRange.aEnd.Row());
}
if (!bIsEmpty)
{
ScReplaceWarnBox aBox(pParentWnd);
if (aBox.Execute() != RET_YES)
{
// changing the configuration is within the ScReplaceWarnBox
return false;
}
}
return true;
}
}
sal_Bool ScViewFunc::PasteFromClip( sal_uInt16 nFlags, ScDocument* pClipDoc,
sal_uInt16 nFunction, sal_Bool bSkipEmpty,
sal_Bool bTranspose, sal_Bool bAsLink,
InsCellCmd eMoveMode, sal_uInt16 nUndoExtraFlags,
sal_Bool bAllowDialogs )
{
if (!pClipDoc)
{
DBG_ERROR("PasteFromClip: pClipDoc=0 not allowed");
return sal_False;
}
// fuer Undo etc. immer alle oder keine Inhalte sichern
sal_uInt16 nContFlags = IDF_NONE;
if (nFlags & IDF_CONTENTS)
nContFlags |= IDF_CONTENTS;
if (nFlags & IDF_ATTRIB)
nContFlags |= IDF_ATTRIB;
// evtl. Attribute ins Undo ohne sie vom Clip ins Doc zu kopieren
sal_uInt16 nUndoFlags = nContFlags;
if (nUndoExtraFlags & IDF_ATTRIB)
nUndoFlags |= IDF_ATTRIB;
// do not copy note captions into undo document
nUndoFlags |= IDF_NOCAPTIONS;
ScClipParam& rClipParam = pClipDoc->GetClipParam();
if (rClipParam.isMultiRange())
return PasteMultiRangesFromClip(
nFlags, pClipDoc, nFunction, bSkipEmpty, bTranspose, bAsLink, bAllowDialogs,
eMoveMode, nContFlags, nUndoFlags);
sal_Bool bCutMode = pClipDoc->IsCutMode(); // if transposing, take from original clipdoc
sal_Bool bIncludeFiltered = bCutMode;
// paste drawing: also if IDF_NOTE is set (to create drawing layer for note captions)
sal_Bool bPasteDraw = ( pClipDoc->GetDrawLayer() && ( nFlags & (IDF_OBJECTS|IDF_NOTE) ) );
ScDocShellRef aTransShellRef; // for objects in xTransClip - must remain valid as long as xTransClip
ScDocument* pOrigClipDoc = NULL;
::std::auto_ptr< ScDocument > xTransClip;
if ( bTranspose )
{
SCCOL nX;
SCROW nY;
// include filtered rows until TransposeClip can skip them
bIncludeFiltered = sal_True;
pClipDoc->GetClipArea( nX, nY, sal_True );
if ( nY > static_cast<sal_Int32>(MAXCOL) ) // zuviele Zeilen zum Transponieren
{
ErrorMessage(STR_PASTE_FULL);
return sal_False;
}
pOrigClipDoc = pClipDoc; // fuer Referenzen
if ( bPasteDraw )
{
aTransShellRef = new ScDocShell; // DocShell needs a Ref immediately
aTransShellRef->DoInitNew(NULL);
}
ScDrawLayer::SetGlobalDrawPersist(aTransShellRef);
xTransClip.reset( new ScDocument( SCDOCMODE_CLIP ));
pClipDoc->TransposeClip( xTransClip.get(), nFlags, bAsLink );
pClipDoc = xTransClip.get();
ScDrawLayer::SetGlobalDrawPersist(NULL);
}
SCCOL nStartCol;
SCROW nStartRow;
SCTAB nStartTab;
SCCOL nEndCol;
SCROW nEndRow;
SCTAB nEndTab;
SCCOL nClipSizeX;
SCROW nClipSizeY;
pClipDoc->GetClipArea( nClipSizeX, nClipSizeY, sal_True ); // size in clipboard doc
// size in target doc: include filtered rows only if CutMode is set
SCCOL nDestSizeX;
SCROW nDestSizeY;
pClipDoc->GetClipArea( nDestSizeX, nDestSizeY, bIncludeFiltered );
ScDocument* pDoc = GetViewData()->GetDocument();
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScMarkData& rMark = GetViewData()->GetMarkData();
::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
const sal_Bool bRecord(pDoc->IsUndoEnabled());
ScDocShellModificator aModificator( *pDocSh );
ScRange aMarkRange;
ScMarkData aFilteredMark( rMark); // local copy for all modifications
ScMarkType eMarkType = GetViewData()->GetSimpleArea( aMarkRange, aFilteredMark);
bool bMarkIsFiltered = (eMarkType == SC_MARK_SIMPLE_FILTERED);
bool bNoPaste = ((eMarkType != SC_MARK_SIMPLE && !bMarkIsFiltered) ||
(bMarkIsFiltered && (eMoveMode != INS_NONE || bAsLink)));
if (!bNoPaste && !rMark.IsMarked())
{
// Create a selection with clipboard row count and check that for
// filtered.
nStartCol = GetViewData()->GetCurX();
nStartRow = GetViewData()->GetCurY();
nStartTab = GetViewData()->GetTabNo();
nEndCol = nStartCol + nDestSizeX;
nEndRow = nStartRow + nDestSizeY;
nEndTab = nStartTab;
aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
if (ScViewUtil::HasFiltered( aMarkRange, pDoc))
{
bMarkIsFiltered = true;
// Fit to clipboard's row count unfiltered rows. If there is no
// fit assume that pasting is not possible. Note that nDestSizeY is
// size-1 (difference).
if (!ScViewUtil::FitToUnfilteredRows( aMarkRange, pDoc, nDestSizeY+1))
bNoPaste = true;
}
aFilteredMark.SetMarkArea( aMarkRange);
}
if (bNoPaste)
{
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
return sal_False;
}
SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
ScRangeList aRangeList;
if (bMarkIsFiltered)
{
ScViewUtil::UnmarkFiltered( aFilteredMark, pDoc);
aFilteredMark.FillRangeListWithMarks( &aRangeList, sal_False);
nUnfilteredRows = 0;
for (ScRange* p = aRangeList.First(); p; p = aRangeList.Next())
{
nUnfilteredRows += p->aEnd.Row() - p->aStart.Row() + 1;
}
#if 0
/* This isn't needed but could be a desired restriction. */
// For filtered, destination rows have to be an exact multiple of
// source rows. Note that nDestSizeY is size-1 (difference), so
// nDestSizeY==0 fits always.
if ((nUnfilteredRows % (nDestSizeY+1)) != 0)
{
/* FIXME: this should be a more descriptive error message then. */
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
return sal_False;
}
#endif
}
SCCOL nMarkAddX = 0;
SCROW nMarkAddY = 0;
// Also for a filtered selection the area is used, for undo et al.
if ( aFilteredMark.IsMarked() || bMarkIsFiltered )
{
aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
SCCOL nBlockAddX = nEndCol-nStartCol;
SCROW nBlockAddY = nEndRow-nStartRow;
// #58422# Nachfrage, wenn die Selektion groesser als 1 Zeile/Spalte, aber kleiner
// als das Clipboard ist (dann wird ueber die Selektion hinaus eingefuegt)
// ClipSize is not size, but difference
if ( ( nBlockAddX != 0 && nBlockAddX < nDestSizeX ) ||
( nBlockAddY != 0 && nBlockAddY < nDestSizeY ) ||
( bMarkIsFiltered && nUnfilteredRows < nDestSizeY+1 ) )
{
ScWaitCursorOff aWaitOff( GetFrameWin() );
String aMessage = ScGlobal::GetRscString( STR_PASTE_BIGGER );
QueryBox aBox( GetViewData()->GetDialogParent(),
WinBits(WB_YES_NO | WB_DEF_NO), aMessage );
if ( aBox.Execute() != RET_YES )
{
return sal_False;
}
}
if (nBlockAddX > nDestSizeX)
nMarkAddX = nBlockAddX - nDestSizeX; // fuer Merge-Test
else
{
nEndCol = nStartCol + nDestSizeX;
if (nEndCol > aMarkRange.aEnd.Col())
{
// #i113553# larger range has to be included in aFilteredMark (for undo), but extending columns can't changed the filtered status
aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
aFilteredMark.SetMarkArea( aMarkRange );
if (bMarkIsFiltered)
{
ScViewUtil::UnmarkFiltered( aFilteredMark, pDoc );
aFilteredMark.FillRangeListWithMarks( &aRangeList, sal_True );
}
}
}
if (nBlockAddY > nDestSizeY)
nMarkAddY = nBlockAddY - nDestSizeY; // fuer Merge-Test
else
{
nEndRow = nStartRow + nDestSizeY;
if (bMarkIsFiltered || nEndRow > aMarkRange.aEnd.Row())
{
// Same as above if nothing was marked: re-fit selection to
// unfiltered rows. Extending the selection actually may
// introduce filtered rows where there weren't any before, so
// we also need to test for that.
aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
if (bMarkIsFiltered || ScViewUtil::HasFiltered( aMarkRange, pDoc))
{
bMarkIsFiltered = true;
// Worst case: all rows up to the end of the sheet are filtered.
if (!ScViewUtil::FitToUnfilteredRows( aMarkRange, pDoc, nDestSizeY+1))
{
ErrorMessage(STR_PASTE_FULL);
return sal_False;
}
}
aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
aFilteredMark.SetMarkArea( aMarkRange);
if (bMarkIsFiltered)
{
ScViewUtil::UnmarkFiltered( aFilteredMark, pDoc);
aFilteredMark.FillRangeListWithMarks( &aRangeList, sal_True);
}
}
}
}
else
{
nStartCol = GetViewData()->GetCurX();
nStartRow = GetViewData()->GetCurY();
nStartTab = GetViewData()->GetTabNo();
nEndCol = nStartCol + nDestSizeX;
nEndRow = nStartRow + nDestSizeY;
nEndTab = nStartTab;
}
bool bOffLimits = !ValidCol(nEndCol) || !ValidRow(nEndRow);
// Zielbereich, wie er angezeigt wird:
ScRange aUserRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
// Sollen Zellen eingefuegt werden?
// (zu grosse nEndCol/nEndRow werden weiter unten erkannt)
sal_Bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits );
if ( bInsertCells )
{
// #94115# Instead of EnterListAction, the paste undo action is merged into the
// insert action, so Repeat can insert the right cells
MarkRange( aUserRange ); // wird vor CopyFromClip sowieso gesetzt
// #72930# CutMode is reset on insertion of cols/rows but needed again on cell move
sal_Bool bCut = pClipDoc->IsCutMode();
if (!InsertCells( eMoveMode, bRecord, sal_True )) // is inserting possible?
{
return sal_False;
// #i21036# EnterListAction isn't used, and InsertCells doesn't insert
// its undo action on failure, so no undo handling is needed here
}
if ( bCut )
pClipDoc->SetCutMode( bCut );
}
else if (!bOffLimits)
{
sal_Bool bAskIfNotEmpty = bAllowDialogs &&
( nFlags & IDF_CONTENTS ) &&
nFunction == PASTE_NOFUNC &&
SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
if ( bAskIfNotEmpty )
{
if (!lcl_checkDestRangeForOverwrite(aUserRange, pDoc, aFilteredMark, GetViewData()->GetDialogParent()))
return false;
}
}
SCCOL nClipStartX; // Clipboard-Bereich erweitern
SCROW nClipStartY;
pClipDoc->GetClipStart( nClipStartX, nClipStartY );
SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
SCROW nUndoEndRow = nClipStartY + nClipSizeY; // end of source area in clipboard document
sal_Bool bClipOver = sal_False;
// #i68690# ExtendMerge for the clip doc must be called with the clipboard's sheet numbers.
// The same end column/row can be used for all calls because the clip doc doesn't contain
// content outside the clip area.
for (SCTAB nClipTab=0; nClipTab<=MAXTAB; nClipTab++)
if ( pClipDoc->HasTable(nClipTab) )
if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab, sal_False ) )
bClipOver = sal_True;
nUndoEndCol -= nClipStartX + nClipSizeX;
nUndoEndRow -= nClipStartY + nClipSizeY; // now contains only the difference added by ExtendMerge
nUndoEndCol = sal::static_int_cast<SCCOL>( nUndoEndCol + nEndCol );
nUndoEndRow = sal::static_int_cast<SCROW>( nUndoEndRow + nEndRow ); // destination area, expanded for merged cells
// if (nUndoEndCol < nEndCol) nUndoEndCol = nEndCol;
// if (nUndoEndRow < nEndRow) nUndoEndRow = nEndRow;
// nUndoEndCol += nMarkAddX;
// nUndoEndRow += nMarkAddY;
if (nUndoEndCol>MAXCOL || nUndoEndRow>MAXROW)
{
ErrorMessage(STR_PASTE_FULL);
return sal_False;
}
pDoc->ExtendMergeSel( nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, sal_False );
// Test auf Zellschutz
ScEditableTester aTester( pDoc, nStartTab, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow );
if (!aTester.IsEditable())
{
ErrorMessage(aTester.GetMessageId());
return sal_False;
}
//! Test auf Ueberlappung
//! nur wirkliche Schnittmenge testen !!!!!!!
// pDoc->HasCommonAttr( StartCol,nStartRow, nUndoEndCol,nUndoEndRow, nStartTab,
// pClipDoc, nClipStartX, nClipStartY );
ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
if ( bRecord )
{
String aUndo = ScGlobal::GetRscString( pClipDoc->IsCutMode() ? STR_UNDO_MOVE : STR_UNDO_COPY );
pUndoMgr->EnterListAction( aUndo, aUndo );
}
if (bClipOver)
if (lcl_SelHasAttrib( pDoc, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, HASATTR_OVERLAPPED ))
{ // "Cell merge not possible if cells already merged"
ScDocAttrIterator aIter( pDoc, nStartTab, nStartCol, nStartRow, nUndoEndCol, nUndoEndRow );
const ScPatternAttr* pPattern = NULL;
const ScMergeAttr* pMergeFlag = NULL;
const ScMergeFlagAttr* pMergeFlagAttr = NULL;
SCCOL nCol = -1;
SCROW nRow1 = -1;
SCROW nRow2 = -1;
while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != NULL )
{
pMergeFlag = (const ScMergeAttr*) &pPattern->GetItem(ATTR_MERGE);
pMergeFlagAttr = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG);
if( ( pMergeFlag && pMergeFlag->IsMerged() ) || ( pMergeFlagAttr && pMergeFlagAttr->IsOverlapped() ) )
{
ScRange aRange(nCol, nRow1, nStartTab);
pDoc->ExtendOverlapped(aRange);
pDoc->ExtendMerge(aRange, sal_True, sal_True);
rDocFunc.UnmergeCells(aRange, bRecord, sal_True);
}
}
}
if ( !bCutMode )
{
ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
if ( pChangeTrack )
pChangeTrack->ResetLastCut(); // kein CutMode mehr
}
sal_Bool bColInfo = ( nStartRow==0 && nEndRow==MAXROW );
sal_Bool bRowInfo = ( nStartCol==0 && nEndCol==MAXCOL );
ScDocument* pUndoDoc = NULL;
ScDocument* pRefUndoDoc = NULL;
ScDocument* pRedoDoc = NULL;
ScRefUndoData* pUndoData = NULL;
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndoSelected( pDoc, aFilteredMark, bColInfo, bRowInfo );
// all sheets - CopyToDocument skips those that don't exist in pUndoDoc
SCTAB nTabCount = pDoc->GetTableCount();
pDoc->CopyToDocument( nStartCol, nStartRow, 0, nUndoEndCol, nUndoEndRow, nTabCount-1,
nUndoFlags, sal_False, pUndoDoc );
if ( bCutMode )
{
pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, sal_False, sal_False );
pUndoData = new ScRefUndoData( pDoc );
}
}
sal_uInt16 nExtFlags = 0;
pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab ); // content before the change
if (GetViewData()->IsActive())
{
DoneBlockMode();
InitOwnBlockMode();
}
rMark.SetMarkArea( aUserRange );
MarkDataChanged();
HideCursor(); // Cursor aendert sich !
//
// Aus Clipboard kopieren,
// wenn gerechnet werden soll, Originaldaten merken
//
ScDocument* pMixDoc = NULL;
if ( bSkipEmpty || nFunction )
{
if ( nFlags & IDF_CONTENTS )
{
pMixDoc = new ScDocument( SCDOCMODE_UNDO );
pMixDoc->InitUndo( pDoc, nStartTab, nEndTab );
pDoc->CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
IDF_CONTENTS, sal_False, pMixDoc );
}
}
/* Make draw layer and start drawing undo.
- Needed before AdjustBlockHeight to track moved drawing objects.
- Needed before pDoc->CopyFromClip to track inserted note caption objects.
*/
if ( bPasteDraw )
pDocSh->MakeDrawLayer();
if ( bRecord )
pDoc->BeginDrawUndo();
sal_uInt16 nNoObjFlags = nFlags & ~IDF_OBJECTS;
if (!bAsLink)
{
// copy normally (original range)
pDoc->CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
pRefUndoDoc, pClipDoc, sal_True, sal_False, bIncludeFiltered,
bSkipEmpty, (bMarkIsFiltered ? &aRangeList : NULL) );
// bei Transpose Referenzen per Hand anpassen
if ( bTranspose && bCutMode && (nFlags & IDF_CONTENTS) )
pDoc->UpdateTranspose( aUserRange.aStart, pOrigClipDoc, aFilteredMark, pRefUndoDoc );
}
else if (!bTranspose)
{
// copy with bAsLink=TRUE
pDoc->CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc, pClipDoc,
sal_True, sal_True, bIncludeFiltered, bSkipEmpty );
}
else
{
// alle Inhalte kopieren (im TransClipDoc stehen nur Formeln)
pDoc->CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc, pClipDoc );
}
// skipped rows and merged cells don't mix
if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
rDocFunc.UnmergeCells( aUserRange, sal_False, sal_True );
pDoc->ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, sal_True ); // Refresh
// und Bereich neu
if ( pMixDoc ) // Rechenfunktionen mit Original-Daten auszufuehren ?
{
pDoc->MixDocument( aUserRange, nFunction, bSkipEmpty, pMixDoc );
}
delete pMixDoc;
AdjustBlockHeight(); // update row heights before pasting objects
::std::vector< ::rtl::OUString > aExcludedChartNames;
SdrPage* pPage = NULL;
if ( nFlags & IDF_OBJECTS )
{
ScDrawView* pScDrawView = GetScDrawView();
SdrModel* pModel = ( pScDrawView ? pScDrawView->GetModel() : NULL );
pPage = ( pModel ? pModel->GetPage( static_cast< sal_uInt16 >( nStartTab ) ) : NULL );
if ( pPage )
{
ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
}
// Paste the drawing objects after the row heights have been updated.
pDoc->CopyFromClip( aUserRange, aFilteredMark, IDF_OBJECTS, pRefUndoDoc, pClipDoc,
sal_True, sal_False, bIncludeFiltered );
}
//
//
//
pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab ); // content after the change
// ggf. Autofilter-Koepfe loeschen
if (bCutMode)
if (pDoc->RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
nClipStartY+nClipSizeY, nStartTab ))
pDocSh->PostPaint( nClipStartX,nClipStartY,nStartTab,
nClipStartX+nClipSizeX,nClipStartY,nStartTab,
PAINT_GRID );
ShowCursor(); // Cursor aendert sich !
//! Block-Bereich bei RefUndoDoc weglassen !!!
if ( bRecord )
{
// Redo-Daten werden erst beim ersten Undo kopiert
// ohne RefUndoDoc muss das Redo-Doc noch nicht angelegt werden
if (pRefUndoDoc)
{
pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
pRedoDoc->InitUndo( pDoc, nStartTab, nEndTab, bColInfo, bRowInfo );
// angepasste Referenzen ins Redo-Doc
SCTAB nTabCount = pDoc->GetTableCount();
pRedoDoc->AddUndoTab( 0, nTabCount-1 );
pDoc->CopyUpdated( pRefUndoDoc, pRedoDoc );
// alte Referenzen ins Undo-Doc
//! Tabellen selektieren ?
pUndoDoc->AddUndoTab( 0, nTabCount-1 );
pRefUndoDoc->DeleteArea( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, IDF_ALL );
pRefUndoDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
IDF_FORMULA, sal_False, pUndoDoc );
delete pRefUndoDoc;
}
// DeleteUnchanged for pUndoData is in ScUndoPaste ctor,
// UndoData for redo is made during first undo
ScUndoPasteOptions aOptions; // store options for repeat
aOptions.nFunction = nFunction;
aOptions.bSkipEmpty = bSkipEmpty;
aOptions.bTranspose = bTranspose;
aOptions.bAsLink = bAsLink;
aOptions.eMoveMode = eMoveMode;
SfxUndoAction* pUndo = new ScUndoPaste( pDocSh,
nStartCol, nStartRow, nStartTab,
nUndoEndCol, nUndoEndRow, nEndTab, aFilteredMark,
pUndoDoc, pRedoDoc, nFlags | nUndoFlags,
pUndoData, NULL, NULL, NULL,
sal_False, &aOptions ); // sal_False = Redo data not yet copied
if ( bInsertCells )
{
// Merge the paste undo action into the insert action.
// Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.
pUndoMgr->AddUndoAction( new ScUndoWrapper( pUndo ), sal_True );
}
else
pUndoMgr->AddUndoAction( pUndo );
pUndoMgr->LeaveListAction();
}
sal_uInt16 nPaint = PAINT_GRID;
if (bColInfo)
{
nPaint |= PAINT_TOP;
nUndoEndCol = MAXCOL; // nur zum Zeichnen !
}
if (bRowInfo)
{
nPaint |= PAINT_LEFT;
nUndoEndRow = MAXROW; // nur zum Zeichnen !
}
pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
nUndoEndCol, nUndoEndRow, nEndTab, nPaint, nExtFlags );
// AdjustBlockHeight has already been called above
aModificator.SetDocumentModified();
PostPasteFromClip(aUserRange, rMark);
if ( nFlags & IDF_OBJECTS )
{
ScModelObj* pModelObj = ( pDocSh ? ScModelObj::getImplementation( pDocSh->GetModel() ) : NULL );
if ( pDoc && pPage && pModelObj )
{
bool bSameDoc = ( rClipParam.getSourceDocID() == pDoc->GetDocumentID() );
const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
ScChartHelper::CreateProtectedChartListenersAndNotify( pDoc, pPage, pModelObj, nStartTab,
rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
}
}
return sal_True;
}
bool ScViewFunc::PasteMultiRangesFromClip(
sal_uInt16 nFlags, ScDocument* pClipDoc, sal_uInt16 nFunction,
bool bSkipEmpty, bool bTranspose, bool bAsLink, bool bAllowDialogs,
InsCellCmd eMoveMode, sal_uInt16 /*nContFlags*/, sal_uInt16 nUndoFlags)
{
ScViewData& rViewData = *GetViewData();
ScDocument* pDoc = rViewData.GetDocument();
ScDocShell* pDocSh = rViewData.GetDocShell();
ScMarkData aMark(rViewData.GetMarkData());
const ScAddress& rCurPos = rViewData.GetCurPos();
ScClipParam& rClipParam = pClipDoc->GetClipParam();
SCCOL nColSize = rClipParam.getPasteColSize();
SCROW nRowSize = rClipParam.getPasteRowSize();
if (bTranspose)
{
if (static_cast<SCROW>(rCurPos.Col()) + nRowSize-1 > static_cast<SCROW>(MAXCOL))
{
ErrorMessage(STR_PASTE_FULL);
return false;
}
::std::auto_ptr<ScDocument> pTransClip(new ScDocument(SCDOCMODE_CLIP));
pClipDoc->TransposeClip(pTransClip.get(), nFlags, bAsLink);
pClipDoc = pTransClip.release();
SCCOL nTempColSize = nColSize;
nColSize = static_cast<SCCOL>(nRowSize);
nRowSize = static_cast<SCROW>(nTempColSize);
}
if (!ValidCol(rCurPos.Col()+nColSize-1) || !ValidRow(rCurPos.Row()+nRowSize-1))
{
ErrorMessage(STR_PASTE_FULL);
return false;
}
// Determine the first and last selected sheet numbers.
SCTAB nTab1 = aMark.GetFirstSelected();
SCTAB nTab2 = nTab1;
for (SCTAB i = nTab1+1; i <= MAXTAB; ++i)
if (aMark.GetTableSelect(i))
nTab2 = i;
ScDocShellModificator aModificator(*pDocSh);
// For multi-selection paste, we don't support cell duplication for larger
// destination range. In case the destination is marked, we reset it to
// the clip size.
ScRange aMarkedRange(rCurPos.Col(), rCurPos.Row(), nTab1,
rCurPos.Col()+nColSize-1, rCurPos.Row()+nRowSize-1, nTab2);
// Extend the marked range to account for filtered rows in the destination
// area.
if (ScViewUtil::HasFiltered(aMarkedRange, pDoc))
{
if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, pDoc, nRowSize))
return false;
}
bool bAskIfNotEmpty =
bAllowDialogs && (nFlags & IDF_CONTENTS) &&
nFunction == PASTE_NOFUNC && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
if (bAskIfNotEmpty)
{
if (!lcl_checkDestRangeForOverwrite(aMarkedRange, pDoc, aMark, rViewData.GetDialogParent()))
return false;
}
aMark.SetMarkArea(aMarkedRange);
MarkRange(aMarkedRange);
bool bInsertCells = (eMoveMode != INS_NONE);
if (bInsertCells)
{
if (!InsertCells(eMoveMode, pDoc->IsUndoEnabled(), true))
return false;
}
::std::auto_ptr<ScDocument> pUndoDoc;
if (pDoc->IsUndoEnabled())
{
pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
pUndoDoc->InitUndoSelected(pDoc, aMark, false, false);
pDoc->CopyToDocument(aMarkedRange, nUndoFlags, false, pUndoDoc.get(), &aMark, true);
}
::std::auto_ptr<ScDocument> pMixDoc;
if ( bSkipEmpty || nFunction )
{
if ( nFlags & IDF_CONTENTS )
{
pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
pMixDoc->InitUndoSelected(pDoc, aMark, false, false);
pDoc->CopyToDocument(aMarkedRange, IDF_CONTENTS, false, pMixDoc.get(), &aMark, true);
}
}
/* Make draw layer and start drawing undo.
- Needed before AdjustBlockHeight to track moved drawing objects.
- Needed before pDoc->CopyFromClip to track inserted note caption objects.
*/
if (nFlags & IDF_OBJECTS)
pDocSh->MakeDrawLayer();
if (pDoc->IsUndoEnabled())
pDoc->BeginDrawUndo();
CursorSwitcher aCursorSwitch(this);
sal_uInt16 nNoObjFlags = nFlags & ~IDF_OBJECTS;
pDoc->CopyMultiRangeFromClip(rCurPos, aMark, nNoObjFlags, pClipDoc,
true, bAsLink, false, bSkipEmpty);
if (pMixDoc.get())
pDoc->MixDocument(aMarkedRange, nFunction, bSkipEmpty, pMixDoc.get());
AdjustBlockHeight(); // update row heights before pasting objects
if (nFlags & IDF_OBJECTS)
{
// Paste the drawing objects after the row heights have been updated.
pDoc->CopyMultiRangeFromClip(rCurPos, aMark, IDF_OBJECTS, pClipDoc,
true, false, false, true);
}
pDocSh->PostPaint(
aMarkedRange.aStart.Col(), aMarkedRange.aStart.Row(), nTab1,
aMarkedRange.aEnd.Col(), aMarkedRange.aEnd.Row(), nTab1, PAINT_GRID);
if (pDoc->IsUndoEnabled())
{
::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
String aUndo = ScGlobal::GetRscString(
pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
pUndoMgr->EnterListAction(aUndo, aUndo);
ScUndoPasteOptions aOptions; // store options for repeat
aOptions.nFunction = nFunction;
aOptions.bSkipEmpty = bSkipEmpty;
aOptions.bTranspose = bTranspose;
aOptions.bAsLink = bAsLink;
aOptions.eMoveMode = eMoveMode;
ScUndoPaste* pUndo = new ScUndoPaste(pDocSh,
aMarkedRange.aStart.Col(),
aMarkedRange.aStart.Row(),
aMarkedRange.aStart.Tab(),
aMarkedRange.aEnd.Col(),
aMarkedRange.aEnd.Row(),
aMarkedRange.aEnd.Tab(),
aMark, pUndoDoc.release(), NULL, nFlags|nUndoFlags, NULL, NULL, NULL, NULL, false, &aOptions);
if (bInsertCells)
pUndoMgr->AddUndoAction(new ScUndoWrapper(pUndo), true);
else
pUndoMgr->AddUndoAction(pUndo, false);
pUndoMgr->LeaveListAction();
}
aModificator.SetDocumentModified();
PostPasteFromClip(aMarkedRange, aMark);
return true;
}
void ScViewFunc::PostPasteFromClip(const ScRange& rPasteRange, const ScMarkData& rMark)
{
ScViewData* pViewData = GetViewData();
ScDocShell* pDocSh = pViewData->GetDocShell();
ScDocument* pDoc = pViewData->GetDocument();
pDocSh->UpdateOle(pViewData);
SelectionChanged();
// #i97876# Spreadsheet data changes are not notified
ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
if ( pModelObj && pModelObj->HasChangesListeners() )
{
ScRangeList aChangeRanges;
SCTAB nTabCount = pDoc->GetTableCount();
for ( SCTAB i = 0; i < nTabCount; ++i )
{
if ( rMark.GetTableSelect( i ) )
{
ScRange aChangeRange(rPasteRange);
aChangeRange.aStart.SetTab( i );
aChangeRange.aEnd.SetTab( i );
aChangeRanges.Append( aChangeRange );
}
}
pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
}
}
//----------------------------------------------------------------------------
// D R A G A N D D R O P
//
// innerhalb des Dokuments
sal_Bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
sal_Bool bCut, sal_Bool bRecord, sal_Bool bPaint, sal_Bool bApi )
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
HideAllCursors(); // wegen zusammengefassten
sal_Bool bSuccess = sal_True;
SCTAB nDestTab = rDestPos.Tab();
const ScMarkData& rMark = GetViewData()->GetMarkData();
if ( rSource.aStart.Tab() == nDestTab && rSource.aEnd.Tab() == nDestTab && rMark.GetSelectCount() > 1 )
{
// moving within one table and several tables selected -> apply to all selected tables
if ( bRecord )
{
String aUndo = ScGlobal::GetRscString( bCut ? STR_UNDO_MOVE : STR_UNDO_COPY );
pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
}
// collect ranges of consecutive selected tables
ScRange aLocalSource = rSource;
ScAddress aLocalDest = rDestPos;
SCTAB nTabCount = pDocSh->GetDocument()->GetTableCount();
SCTAB nStartTab = 0;
while ( nStartTab < nTabCount && bSuccess )
{
while ( nStartTab < nTabCount && !rMark.GetTableSelect(nStartTab) )
++nStartTab;
if ( nStartTab < nTabCount )
{
SCTAB nEndTab = nStartTab;
while ( nEndTab+1 < nTabCount && rMark.GetTableSelect(nEndTab+1) )
++nEndTab;
aLocalSource.aStart.SetTab( nStartTab );
aLocalSource.aEnd.SetTab( nEndTab );
aLocalDest.SetTab( nStartTab );
bSuccess = pDocSh->GetDocFunc().MoveBlock(
aLocalSource, aLocalDest, bCut, bRecord, bPaint, bApi );
nStartTab = nEndTab + 1;
}
}
if ( bRecord )
pDocSh->GetUndoManager()->LeaveListAction();
}
else
{
// move the block as specified
bSuccess = pDocSh->GetDocFunc().MoveBlock(
rSource, rDestPos, bCut, bRecord, bPaint, bApi );
}
ShowAllCursors();
if (bSuccess)
{
// Zielbereich markieren
ScAddress aDestEnd(
rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
nDestTab );
sal_Bool bIncludeFiltered = bCut;
if ( !bIncludeFiltered )
{
// find number of non-filtered rows
SCROW nPastedCount = pDocSh->GetDocument()->CountNonFilteredRows(
rSource.aStart.Row(), rSource.aEnd.Row(), rSource.aStart.Tab());
if ( nPastedCount == 0 )
nPastedCount = 1;
aDestEnd.SetRow( rDestPos.Row() + nPastedCount - 1 );
}
MarkRange( ScRange( rDestPos, aDestEnd ), sal_False ); //! sal_False ???
pDocSh->UpdateOle(GetViewData());
SelectionChanged();
}
return bSuccess;
}
// Link innerhalb des Dokuments
sal_Bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos, sal_Bool bApi )
{
// Test auf Ueberlappung
if ( rSource.aStart.Tab() == rDestPos.Tab() )
{
SCCOL nDestEndCol = rDestPos.Col() + ( rSource.aEnd.Col() - rSource.aStart.Col() );
SCROW nDestEndRow = rDestPos.Row() + ( rSource.aEnd.Row() - rSource.aStart.Row() );
if ( rSource.aStart.Col() <= nDestEndCol && rDestPos.Col() <= rSource.aEnd.Col() &&
rSource.aStart.Row() <= nDestEndRow && rDestPos.Row() <= rSource.aEnd.Row() )
{
if (!bApi)
ErrorMessage( STR_ERR_LINKOVERLAP );
return sal_False;
}
}
// Ausfuehren per Paste
ScDocument* pDoc = GetViewData()->GetDocument();
ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
pDoc->CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
rSource.aEnd.Col(), rSource.aEnd.Row(),
rSource.aStart.Tab(), pClipDoc );
// Zielbereich markieren (Cursor setzen, keine Markierung)
if ( GetViewData()->GetTabNo() != rDestPos.Tab() )
SetTabNo( rDestPos.Tab() );
MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, sal_False, sal_False );
// Paste
PasteFromClip( IDF_ALL, pClipDoc, PASTE_NOFUNC, sal_False, sal_False, sal_True ); // als Link
delete pClipDoc;
return sal_True;
}