Files
libreoffice/sc/source/ui/view/viewfun3.cxx
Stephan Bergmann 7df89ec7a2 Remove unnecessary includes of sot/storage.hxx from include/
Change-Id: I242cd126814bbebdb99ea38d9e66513189c313d9
2015-05-07 11:05:05 +02:00

1991 lines
74 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "scitems.hxx"
#include <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 <comphelper/classids.hxx>
#include <sot/formats.hxx>
#include <sot/storage.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 "dbdata.hxx"
#include "impex.hxx"
#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 "docuno.hxx"
#include "clipparam.hxx"
#include "undodat.hxx"
#include "drawview.hxx"
#include "cliputil.hxx"
#include <gridwin.hxx>
#include <boost/scoped_ptr.hpp>
using namespace com::sun::star;
// STATIC DATA ---------------------------------------------------------------
// GlobalName of writer-DocShell from comphelper/classids.hxx
// C U T
void ScViewFunc::CutToClip( ScDocument* pClipDoc, bool bIncludeObjects )
{
UpdateInputLine();
ScEditableTester aTester( this );
if (!aTester.IsEditable()) // selection editable?
{
ErrorMessage( aTester.GetMessageId() );
return;
}
ScRange aRange; // delete this range
if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
{
ScDocument* pDoc = GetViewData().GetDocument();
ScDocShell* pDocSh = GetViewData().GetDocShell();
ScMarkData& rMark = GetViewData().GetMarkData();
const 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, true, false, bIncludeObjects ); // copy to clipboard
ScAddress aOldEnd( aRange.aEnd ); // combined cells in this range?
pDoc->ExtendMerge( aRange, 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, false, pUndoDoc );
pDoc->BeginDrawUndo();
}
sal_uInt16 nExtFlags = 0;
pDocSh->UpdatePaintExt( nExtFlags, aRange );
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 ) // Draw-Undo now available
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoCut( pDocSh, aRange, aOldEnd, rMark, pUndoDoc ) );
aModificator.SetDocumentModified();
pDocSh->UpdateOle(&GetViewData());
CellContentChanged();
}
else
ErrorMessage( STR_NOMULTISELECT );
}
// C O P Y
bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, bool bCut, bool bApi, bool bIncludeObjects, bool bStopEdit )
{
ScRange aRange;
ScMarkType eMarkType = GetViewData().GetSimpleArea( aRange );
ScMarkData& rMark = GetViewData().GetMarkData();
bool bDone = false;
if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
{
ScRangeList aRangeList;
aRangeList.Append( aRange );
bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit, false );
}
else if (eMarkType == SC_MARK_MULTI)
{
ScRangeList aRangeList;
rMark.MarkToSimple();
rMark.FillRangeListWithMarks(&aRangeList, false);
bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit, false );
}
else
{
if (!bApi)
ErrorMessage(STR_NOMULTISELECT);
}
return bDone;
}
// Copy the content of the Range into clipboard.
bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut, bool bApi, bool bIncludeObjects, bool bStopEdit, bool bUseRangeForVBA )
{
if ( rRanges.empty() )
return false;
bool bDone = false;
if ( bStopEdit )
UpdateInputLine();
ScRange aRange = *rRanges[0];
ScClipParam aClipParam( aRange, bCut );
aClipParam.maRanges = rRanges;
ScDocument* pDoc = GetViewData().GetDocument();
ScMarkData& rMark = GetViewData().GetMarkData();
if ( !aClipParam.isMultiRange() )
{
if ( pDoc && ( !pDoc->HasSelectedBlockMatrixFragment( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), rMark ) ) )
{
bool bSysClip = false;
if ( !pClipDoc ) // no clip doc specified
{
// Create one (deleted by ScTransferObj).
pClipDoc = new ScDocument( SCDOCMODE_CLIP );
bSysClip = true; // and copy into system
}
if ( !bCut )
{
ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
if ( pChangeTrack )
pChangeTrack->ResetLastCut();
}
if ( bSysClip && bIncludeObjects )
{
bool bAnyOle = pDoc->HasOLEObjectsInArea( aRange );
// Update ScGlobal::pDrawClipDocShellRef.
ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
}
if ( !bUseRangeForVBA )
// is this necessary?, will setting the doc id upset the
// following paste operation with range? would be nicer to just set this always
// and lose the 'if' above
aClipParam.setSourceDocID( pDoc->GetDocumentID() );
pDoc->CopyToClip( aClipParam, pClipDoc, &rMark, false, false, bIncludeObjects, true, bUseRangeForVBA );
if ( !bUseRangeForVBA && 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, 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() );
SC_MOD()->SetClipObject( pTransferObj, NULL );
}
bDone = true;
}
}
else
{
bool bSuccess = false;
aClipParam.mbCutMode = false;
do
{
if (bCut)
// We con't support cutting of multi-selections.
break;
if (pClipDoc)
// TODO: What's this for?
break;
::std::unique_ptr<ScDocument> pDocClip(new ScDocument(SCDOCMODE_CLIP));
// Check for geometrical feasibility of the ranges.
bool bValidRanges = true;
ScRange* p = aClipParam.maRanges.front();
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 ( size_t i = 1; i < aClipParam.maRanges.size(); ++i )
{
p = aClipParam.maRanges[i];
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, true, bUseRangeForVBA );
ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
if ( pChangeTrack )
pChangeTrack->ResetLastCut(); // no more cut-mode
{
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;
}
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)
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, 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& rViewData = GetViewData();
SCCOL nPosX = rViewData.GetCurX();
SCROW nPosY = rViewData.GetCurY();
vcl::Window* pWin = GetActiveWin();
Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY,
rViewData.GetActivePart() ) );
ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard( pWin );
if (pDrawClip)
{
OUString aSrcShellID = pDrawClip->GetShellID();
OUString aDestShellID = SfxObjectShell::CreateShellID(rViewData.GetDocShell());
PasteDraw(aPos, pDrawClip->GetModel(), false, aSrcShellID, aDestShellID);
}
}
void ScViewFunc::PasteFromSystem()
{
UpdateInputLine();
vcl::Window* pWin = GetActiveWin();
ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard( pWin );
ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard( pWin );
if (pOwnClip)
{
// keep a reference in case the clipboard is changed during PasteFromClip
uno::Reference<datatransfer::XTransferable> aOwnClipRef( pOwnClip );
PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
PASTE_NOFUNC, false, false, false, INS_NONE, IDF_NONE,
true ); // allow warning dialog
}
else if (pDrawClip)
PasteDraw();
else
{
TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
{
SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(OUString("Biff8"));
SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(OUString("Biff5"));
SotExchangeDest nDestination = SotExchangeDest::SCDOC_FREE_AREA;
sal_uInt16 nSourceOptions = EXCHG_IN_ACTION_COPY;
SotClipboardFormatId nFormat; // output param for GetExchangeAction
sal_uInt16 nEventAction; // output param for GetExchangeAction
uno::Reference<com::sun::star::datatransfer::XTransferable> xTransferable( aDataHelper.GetXTransferable() );
sal_uInt16 nAction = SotExchange::GetExchangeAction(
aDataHelper.GetDataFlavorExVector(),
nDestination,
nSourceOptions,
EXCHG_IN_ACTION_DEFAULT,
nFormat, nEventAction, SotClipboardFormatId::NONE,
&xTransferable );
if ( nAction != EXCHG_INOUT_ACTION_NONE )
{
nAction = ( nAction & EXCHG_ACTION_MASK );
switch( nAction )
{
case EXCHG_OUT_ACTION_INSERT_SVXB:
case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
case EXCHG_OUT_ACTION_INSERT_BITMAP:
case EXCHG_OUT_ACTION_INSERT_GRAPH:
// SotClipboardFormatId::BITMAP
// SotClipboardFormatId::PNG
// SotClipboardFormatId::GDIMETAFILE
// SotClipboardFormatId::SVXB
PasteFromSystem(nFormat);
break;
default:
nAction = EXCHG_INOUT_ACTION_NONE;
}
}
if ( nAction == EXCHG_INOUT_ACTION_NONE )
{
// first SvDraw-model, then drawing
// (only one drawing is allowed)
if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
{
// special case for tables from drawing
if( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
{
PasteFromSystem( SotClipboardFormatId::RTF );
}
else
{
PasteFromSystem( SotClipboardFormatId::DRAWING );
}
}
else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
{
// If it's a Writer object, insert RTF instead of OLE
// Else, if the class id is all-zero, and SYLK is available,
// it probably is spreadsheet cells that have been put
// on the clipboard by OOo, so use the SYLK. (fdo#31077)
bool bDoRtf = false;
TransferableObjectDescriptor aObjDesc;
if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
{
bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
&& aDataHelper.HasFormat( SotClipboardFormatId::RTF ) );
}
if ( bDoRtf )
PasteFromSystem( SotClipboardFormatId::RTF );
else if ( aObjDesc.maClassName == SvGlobalName( 0,0,0,0,0,0,0,0,0,0,0 )
&& aDataHelper.HasFormat( SotClipboardFormatId::SYLK ))
PasteFromSystem( SotClipboardFormatId::SYLK );
else
PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE );
}
else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
PasteFromSystem( SotClipboardFormatId::LINK_SOURCE );
// the following format can not affect scenario from #89579#
else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
PasteFromSystem( SotClipboardFormatId::EMBEDDED_OBJ_OLE );
// SotClipboardFormatId::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(SotClipboardFormatId::RTF))
PasteFromSystem(SotClipboardFormatId::RTF);
else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
PasteFromSystem(SotClipboardFormatId::HTML);
else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
PasteFromSystem(SotClipboardFormatId::HTML_SIMPLE);
else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
PasteFromSystem(SotClipboardFormatId::SYLK);
else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
PasteFromSystem(SotClipboardFormatId::STRING);
// xxx_OLE formats come last, like in SotExchange tables
else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE_OLE );
else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
PasteFromSystem( SotClipboardFormatId::LINK_SOURCE_OLE );
}
}
}
// no exception-> SID_PASTE has FastCall-flag from idl
// will be called in case of empty clipboard (#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 = reinterpret_cast<ScTransferObj*>( (sal_IntPtr) nHandle);
else
{
nHandle = xTunnel->getSomething( ScDrawTransferObj::getUnoTunnelId() );
if ( nHandle )
pDrawClip = reinterpret_cast<ScDrawTransferObj*>( (sal_IntPtr) nHandle );
}
}
if (pOwnClip)
{
PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
PASTE_NOFUNC, false, false, false, INS_NONE, IDF_NONE,
true ); // allow warning dialog
}
else if (pDrawClip)
{
ScViewData& rViewData = GetViewData();
SCCOL nPosX = rViewData.GetCurX();
SCROW nPosY = rViewData.GetCurY();
vcl::Window* pWin = GetActiveWin();
Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY, rViewData.GetActivePart() ) );
PasteDraw(
aPos, pDrawClip->GetModel(), false,
pDrawClip->GetShellID(), SfxObjectShell::CreateShellID(rViewData.GetDocShell()));
}
else
{
TransferableDataHelper aDataHelper( rxTransferable );
{
SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(OUString("Biff8"));
SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(OUString("Biff5"));
SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
// first SvDraw-model, then drawing
// (only one drawing is allowed)
if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
nFormatId = SotClipboardFormatId::DRAWING;
else if (aDataHelper.HasFormat( SotClipboardFormatId::SVXB ))
nFormatId = SotClipboardFormatId::SVXB;
else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
{
// If it's a Writer object, insert RTF instead of OLE
bool bDoRtf = false;
TransferableObjectDescriptor aObjDesc;
if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
{
bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
&& aDataHelper.HasFormat( SotClipboardFormatId::RTF ) );
}
if ( bDoRtf )
nFormatId = SotClipboardFormatId::RTF;
else
nFormatId = SotClipboardFormatId::EMBED_SOURCE;
}
else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
nFormatId = SotClipboardFormatId::LINK_SOURCE;
// the following format can not affect scenario from #89579#
else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
// SotClipboardFormatId::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(SotClipboardFormatId::RTF))
nFormatId = SotClipboardFormatId::RTF;
else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
nFormatId = SotClipboardFormatId::HTML;
else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
nFormatId = SotClipboardFormatId::HTML_SIMPLE;
else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
nFormatId = SotClipboardFormatId::SYLK;
else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
nFormatId = SotClipboardFormatId::STRING;
else if (aDataHelper.HasFormat(SotClipboardFormatId::GDIMETAFILE))
nFormatId = SotClipboardFormatId::GDIMETAFILE;
else if (aDataHelper.HasFormat(SotClipboardFormatId::BITMAP))
nFormatId = SotClipboardFormatId::BITMAP;
// xxx_OLE formats come last, like in SotExchange tables
else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
else
return;
PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
GetViewData().GetCurX(), GetViewData().GetCurY(),
NULL, false, false );
}
}
}
bool ScViewFunc::PasteFromSystem( SotClipboardFormatId nFormatId, bool bApi )
{
UpdateInputLine();
bool bRet = true;
vcl::Window* pWin = GetActiveWin();
ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard( pWin );
if ( nFormatId == SotClipboardFormatId::NONE && pOwnClip )
{
// keep a reference in case the clipboard is changed during PasteFromClip
uno::Reference<datatransfer::XTransferable> aOwnClipRef( pOwnClip );
PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
PASTE_NOFUNC, false, false, false, INS_NONE, IDF_NONE,
!bApi ); // allow warning dialog
}
else
{
TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
if ( !aDataHelper.GetTransferable().is() )
return false;
SCCOL nPosX = 0;
SCROW nPosY = 0;
ScViewData& rViewData = GetViewData();
ScRange aRange;
if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
{
nPosX = aRange.aStart.Col();
nPosY = aRange.aStart.Row();
}
else
{
nPosX = rViewData.GetCurX();
nPosY = rViewData.GetCurY();
}
bRet = PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
nPosX, nPosY,
NULL, false, !bApi ); // allow warning dialog
if ( !bRet && !bApi )
ErrorMessage(STR_PASTE_ERROR);
}
return bRet;
}
// P A S T E
bool ScViewFunc::PasteOnDrawObjectLinked(
const uno::Reference<datatransfer::XTransferable>& rxTransferable,
SdrObject& rHitObj)
{
TransferableDataHelper aDataHelper( rxTransferable );
if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
{
tools::SvRef<SotStorageStream> xStm;
ScDrawView* pScDrawView = GetScDrawView();
if( pScDrawView && aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ) )
{
Graphic aGraphic;
ReadGraphic( *xStm, aGraphic );
const OUString aEmpty;
const OUString aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
if(pScDrawView->ApplyGraphicToObject( rHitObj, aGraphic, aBeginUndo, aEmpty, aEmpty ))
{
return true;
}
}
}
else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
{
GDIMetaFile aMtf;
ScDrawView* pScDrawView = GetScDrawView();
if( pScDrawView && aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) )
{
const OUString aEmpty;
const OUString aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aMtf), aBeginUndo, aEmpty, aEmpty ))
{
return true;
}
}
}
else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) || aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
{
BitmapEx aBmpEx;
ScDrawView* pScDrawView = GetScDrawView();
if( pScDrawView && aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx ) )
{
const OUString aEmpty;
const OUString aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aBmpEx), aBeginUndo, aEmpty, aEmpty ))
{
return true;
}
}
}
return false;
}
static bool lcl_SelHasAttrib( ScDocument* pDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
const ScMarkData& rTabSelection, sal_uInt16 nMask )
{
ScMarkData::const_iterator itr = rTabSelection.begin(), itrEnd = rTabSelection.end();
for (; itr != itrEnd; ++itr)
if ( pDoc->HasAttrib( nCol1, nRow1, *itr, nCol2, nRow2, *itr, nMask ) )
return true;
return false;
}
// paste into sheet:
// internal paste
namespace {
bool checkDestRangeForOverwrite(const ScRangeList& rDestRanges, const ScDocument* pDoc, const ScMarkData& rMark, vcl::Window* pParentWnd)
{
bool bIsEmpty = true;
ScMarkData::const_iterator itrTab = rMark.begin(), itrTabEnd = rMark.end();
size_t nRangeSize = rDestRanges.size();
for (; itrTab != itrTabEnd && bIsEmpty; ++itrTab)
{
for (size_t i = 0; i < nRangeSize && bIsEmpty; ++i)
{
const ScRange& rRange = *rDestRanges[i];
bIsEmpty = pDoc->IsBlockEmpty(
*itrTab, rRange.aStart.Col(), rRange.aStart.Row(),
rRange.aEnd.Col(), rRange.aEnd.Row());
}
}
if (!bIsEmpty)
{
ScopedVclPtrInstance< ScReplaceWarnBox > aBox(pParentWnd);
if (aBox->Execute() != RET_YES)
{
// changing the configuration is within the ScReplaceWarnBox
return false;
}
}
return true;
}
}
bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
sal_uInt16 nFunction, bool bSkipEmpty,
bool bTranspose, bool bAsLink,
InsCellCmd eMoveMode, InsertDeleteFlags nUndoExtraFlags,
bool bAllowDialogs )
{
if (!pClipDoc)
{
OSL_FAIL("PasteFromClip: pClipDoc=0 not allowed");
return false;
}
// undo: save all or no content
InsertDeleteFlags nContFlags = IDF_NONE;
if (nFlags & IDF_CONTENTS)
nContFlags |= IDF_CONTENTS;
if (nFlags & IDF_ATTRIB)
nContFlags |= IDF_ATTRIB;
// move attributes to undo without copying them from clip to doc
InsertDeleteFlags 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())
{
// Source data is multi-range.
return PasteMultiRangesFromClip(
nFlags, pClipDoc, nFunction, bSkipEmpty, bTranspose, bAsLink, bAllowDialogs,
eMoveMode, nUndoFlags);
}
ScMarkData& rMark = GetViewData().GetMarkData();
if (rMark.IsMultiMarked())
{
// Source data is single-range but destination is multi-range.
return PasteFromClipToMultiRanges(
nFlags, pClipDoc, nFunction, bSkipEmpty, bTranspose, bAsLink, bAllowDialogs,
eMoveMode, nUndoFlags);
}
bool bCutMode = pClipDoc->IsCutMode(); // if transposing, take from original clipdoc
bool bIncludeFiltered = bCutMode;
// paste drawing: also if IDF_NOTE is set (to create drawing layer for note captions)
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::unique_ptr< ScDocument > xTransClip;
if ( bTranspose )
{
SCCOL nX;
SCROW nY;
// include filtered rows until TransposeClip can skip them
bIncludeFiltered = true;
pClipDoc->GetClipArea( nX, nY, true );
if ( nY > static_cast<sal_Int32>(MAXCOL) ) // to many lines for transpose
{
ErrorMessage(STR_PASTE_FULL);
return false;
}
pOrigClipDoc = pClipDoc; // refs
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, 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();
::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
const 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)
{
if (!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);
}
else
{
// Expand the marked area when the destination area is larger than the
// current selection, to get the undo do the right thing. (i#106711)
ScRange aRange;
aFilteredMark.GetMarkArea( aRange );
if( (aRange.aEnd.Col() - aRange.aStart.Col()) < nDestSizeX )
{
aRange.aEnd.SetCol(aRange.aStart.Col() + nDestSizeX);
aFilteredMark.SetMarkArea(aRange);
}
}
}
if (bNoPaste)
{
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
return false;
}
SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
ScRangeList aRangeList;
if (bMarkIsFiltered)
{
ScViewUtil::UnmarkFiltered( aFilteredMark, pDoc);
aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
nUnfilteredRows = 0;
size_t ListSize = aRangeList.size();
for ( size_t i = 0; i < ListSize; ++i )
{
ScRange* p = aRangeList[i];
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 false;
}
#endif
}
// 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;
// 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() );
OUString aMessage = ScGlobal::GetRscString( STR_PASTE_BIGGER );
ScopedVclPtrInstance<QueryBox> aBox( GetViewData().GetDialogParent(),
WinBits(WB_YES_NO | WB_DEF_NO), aMessage );
if ( aBox->Execute() != RET_YES )
{
return false;
}
}
if (nBlockAddX <= nDestSizeX)
nEndCol = nStartCol + nDestSizeX;
if (nBlockAddY <= nDestSizeY)
{
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 false;
}
}
aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
aFilteredMark.SetMarkArea( aMarkRange);
if (bMarkIsFiltered)
{
ScViewUtil::UnmarkFiltered( aFilteredMark, pDoc);
aFilteredMark.FillRangeListWithMarks( &aRangeList, 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);
// target-range, as displayed:
ScRange aUserRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
// should lines be inserted?
// ( too large nEndCol/nEndRow are detected below)
bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits );
if ( bInsertCells )
{
// Instead of EnterListAction, the paste undo action is merged into the
// insert action, so Repeat can insert the right cells
MarkRange( aUserRange ); // set through CopyFromClip
// CutMode is reset on insertion of cols/rows but needed again on cell move
bool bCut = pClipDoc->IsCutMode();
if (!InsertCells( eMoveMode, bRecord, true )) // is inserting possible?
{
return 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)
{
bool bAskIfNotEmpty = bAllowDialogs &&
( nFlags & IDF_CONTENTS ) &&
nFunction == PASTE_NOFUNC &&
SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
if ( bAskIfNotEmpty )
{
ScRangeList aTestRanges;
aTestRanges.Append(aUserRange);
if (!checkDestRangeForOverwrite(aTestRanges, pDoc, aFilteredMark, GetViewData().GetDialogParent()))
return false;
}
}
SCCOL nClipStartX; // enlarge clipboard-range
SCROW nClipStartY;
pClipDoc->GetClipStart( nClipStartX, nClipStartY );
SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
SCROW nUndoEndRow = nClipStartY + nClipSizeY; // end of source area in clipboard document
bool bClipOver = 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 < pClipDoc->GetTableCount(); nClipTab++)
if ( pClipDoc->HasTable(nClipTab) )
if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab, false ) )
bClipOver = 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>MAXCOL || nUndoEndRow>MAXROW)
{
ErrorMessage(STR_PASTE_FULL);
return false;
}
pDoc->ExtendMergeSel( nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, false );
// check cell-protection
ScEditableTester aTester( pDoc, nStartTab, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow );
if (!aTester.IsEditable())
{
ErrorMessage(aTester.GetMessageId());
return false;
}
//! check overlapping
//! just check truly intersection !!!!!!!
ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
if ( bRecord )
{
OUString 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;
SCCOL nCol = -1;
SCROW nRow1 = -1;
SCROW nRow2 = -1;
while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != NULL )
{
const ScMergeAttr* pMergeFlag = static_cast<const ScMergeAttr*>( &pPattern->GetItem(ATTR_MERGE) );
const ScMergeFlagAttr* pMergeFlagAttr = static_cast<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, true);
rDocFunc.UnmergeCells(aRange, bRecord);
}
}
}
if ( !bCutMode )
{
ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
if ( pChangeTrack )
pChangeTrack->ResetLastCut(); // no more cut-mode
}
bool bColInfo = ( nStartRow==0 && nEndRow==MAXROW );
bool bRowInfo = ( nStartCol==0 && nEndCol==MAXCOL );
ScDocument* pUndoDoc = NULL;
ScDocument* pRefUndoDoc = 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, false, pUndoDoc );
if ( bCutMode )
{
pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, false, 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();
// copy from clipboard
// save original data in case of calculation
boost::scoped_ptr<ScDocument> pMixDoc;
if (nFunction)
{
bSkipEmpty = false;
if ( nFlags & IDF_CONTENTS )
{
pMixDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
pMixDoc->InitUndo( pDoc, nStartTab, nEndTab );
pDoc->CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
IDF_CONTENTS, false, pMixDoc.get() );
}
}
/* 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();
InsertDeleteFlags nNoObjFlags = nFlags & ~IDF_OBJECTS;
if (!bAsLink)
{
// copy normally (original range)
pDoc->CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
pRefUndoDoc, pClipDoc, true, false, bIncludeFiltered,
bSkipEmpty, (bMarkIsFiltered ? &aRangeList : NULL) );
// adapt refs manually in case of transpose
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,
true, true, bIncludeFiltered, bSkipEmpty );
}
else
{
// copy all content (TransClipDoc contains only formula)
pDoc->CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc, pClipDoc );
}
// skipped rows and merged cells don't mix
if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
rDocFunc.UnmergeCells( aUserRange, false );
pDoc->ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, true ); // refresh
// new range
if ( pMixDoc ) // calculate with originial data ?
{
pDoc->MixDocument( aUserRange, nFunction, bSkipEmpty, pMixDoc.get() );
}
pMixDoc.reset();
AdjustBlockHeight(); // update row heights before pasting objects
::std::vector< 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,
true, false, bIncludeFiltered );
}
pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab ); // content after the change
// if necessary, delete autofilter-heads
if (bCutMode)
if (pDoc->RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
nClipStartY+nClipSizeY, nStartTab ))
{
pDocSh->PostPaint(
ScRange(nClipStartX, nClipStartY, nStartTab, nClipStartX+nClipSizeX, nClipStartY, nStartTab),
PAINT_GRID );
}
//! remove block-range on RefUndoDoc !!!
if ( bRecord )
{
ScDocument* pRedoDoc = NULL;
// copy redo data after appearance of the first undo
// don't create Redo-Doc without RefUndoDoc
if (pRefUndoDoc)
{
pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
pRedoDoc->InitUndo( pDoc, nStartTab, nEndTab, bColInfo, bRowInfo );
// move adapted refs to Redo-Doc
SCTAB nTabCount = pDoc->GetTableCount();
pRedoDoc->AddUndoTab( 0, nTabCount-1 );
pDoc->CopyUpdated( pRefUndoDoc, pRedoDoc );
// move old refs to Undo-Doc
// not charts?
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, 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, ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
aFilteredMark, pUndoDoc, pRedoDoc, nFlags | nUndoFlags, pUndoData,
false, &aOptions ); // 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 ), true );
}
else
pUndoMgr->AddUndoAction( pUndo );
pUndoMgr->LeaveListAction();
}
sal_uInt16 nPaint = PAINT_GRID;
if (bColInfo)
{
nPaint |= PAINT_TOP;
nUndoEndCol = MAXCOL; // just for drawing !
}
if (bRowInfo)
{
nPaint |= PAINT_LEFT;
nUndoEndRow = MAXROW; // just for drawing !
}
pDocSh->PostPaint(
ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
nPaint, nExtFlags);
// AdjustBlockHeight has already been called above
ResetAutoSpell();
aModificator.SetDocumentModified();
PostPasteFromClip(aUserRange, rMark);
if ( nFlags & IDF_OBJECTS )
{
ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
if ( pPage && pModelObj )
{
bool bSameDoc = ( rClipParam.getSourceDocID() == pDoc->GetDocumentID() );
const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
ScChartHelper::CreateProtectedChartListenersAndNotify( pDoc, pPage, pModelObj, nStartTab,
rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
}
}
return true;
}
bool ScViewFunc::PasteMultiRangesFromClip(
InsertDeleteFlags nFlags, ScDocument* pClipDoc, sal_uInt16 nFunction,
bool bSkipEmpty, bool bTranspose, bool bAsLink, bool bAllowDialogs,
InsCellCmd eMoveMode, InsertDeleteFlags 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::unique_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 = aMark.GetLastSelected();
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)
{
ScRangeList aTestRanges;
aTestRanges.Append(aMarkedRange);
if (!checkDestRangeForOverwrite(aTestRanges, 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::unique_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::unique_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();
InsertDeleteFlags 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);
}
ScRange aTmp = aMarkedRange;
aTmp.aStart.SetTab(nTab1);
aTmp.aEnd.SetTab(nTab1);
pDocSh->PostPaint(aTmp, PAINT_GRID);
if (pDoc->IsUndoEnabled())
{
::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
OUString 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, aMark, pUndoDoc.release(), NULL, nFlags|nUndoFlags, NULL, false, &aOptions);
if (bInsertCells)
pUndoMgr->AddUndoAction(new ScUndoWrapper(pUndo), true);
else
pUndoMgr->AddUndoAction(pUndo, false);
pUndoMgr->LeaveListAction();
}
ResetAutoSpell();
aModificator.SetDocumentModified();
PostPasteFromClip(aMarkedRange, aMark);
return true;
}
bool ScViewFunc::PasteFromClipToMultiRanges(
InsertDeleteFlags nFlags, ScDocument* pClipDoc, sal_uInt16 nFunction,
bool bSkipEmpty, bool bTranspose, bool bAsLink, bool bAllowDialogs,
InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags )
{
if (bTranspose)
{
// We don't allow transpose for this yet.
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
return false;
}
if (eMoveMode != INS_NONE)
{
// We don't allow insertion mode either. Too complicated.
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
return false;
}
ScViewData& rViewData = GetViewData();
ScClipParam& rClipParam = pClipDoc->GetClipParam();
if (rClipParam.mbCutMode)
{
// No cut and paste with this, please.
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
return false;
}
const ScAddress& rCurPos = rViewData.GetCurPos();
ScDocument* pDoc = rViewData.GetDocument();
ScRange aSrcRange = rClipParam.getWholeRange();
SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
if (!ValidCol(rCurPos.Col()+nColSize-1) || !ValidRow(rCurPos.Row()+nRowSize-1))
{
ErrorMessage(STR_PASTE_FULL);
return false;
}
ScMarkData aMark(rViewData.GetMarkData());
ScRangeList aRanges;
aMark.MarkToSimple();
aMark.FillRangeListWithMarks(&aRanges, false);
if (!ScClipUtil::CheckDestRanges(pDoc, nColSize, nRowSize, aMark, aRanges))
{
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
return false;
}
ScDocShell* pDocSh = rViewData.GetDocShell();
ScDocShellModificator aModificator(*pDocSh);
bool bAskIfNotEmpty =
bAllowDialogs && (nFlags & IDF_CONTENTS) &&
nFunction == PASTE_NOFUNC && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
if (bAskIfNotEmpty)
{
if (!checkDestRangeForOverwrite(aRanges, pDoc, aMark, rViewData.GetDialogParent()))
return false;
}
std::unique_ptr<ScDocument> pUndoDoc;
if (pDoc->IsUndoEnabled())
{
pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
pUndoDoc->InitUndoSelected(pDoc, aMark, false, false);
for (size_t i = 0, n = aRanges.size(); i < n; ++i)
{
pDoc->CopyToDocument(
*aRanges[i], nUndoFlags, false, pUndoDoc.get(), &aMark, true);
}
}
boost::scoped_ptr<ScDocument> pMixDoc;
if (bSkipEmpty || nFunction)
{
if (nFlags & IDF_CONTENTS)
{
pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
pMixDoc->InitUndoSelected(pDoc, aMark, false, false);
for (size_t i = 0, n = aRanges.size(); i < n; ++i)
{
pDoc->CopyToDocument(
*aRanges[i], IDF_CONTENTS, false, pMixDoc.get(), &aMark, true);
}
}
}
if (nFlags & IDF_OBJECTS)
pDocSh->MakeDrawLayer();
if (pDoc->IsUndoEnabled())
pDoc->BeginDrawUndo();
// First, paste everything but the drawing objects.
for (size_t i = 0, n = aRanges.size(); i < n; ++i)
{
pDoc->CopyFromClip(
*aRanges[i], aMark, (nFlags & ~IDF_OBJECTS), NULL, pClipDoc,
false, false, true, bSkipEmpty, NULL);
}
if (pMixDoc.get())
{
for (size_t i = 0, n = aRanges.size(); i < n; ++i)
pDoc->MixDocument(*aRanges[i], nFunction, bSkipEmpty, pMixDoc.get());
}
AdjustBlockHeight(); // update row heights before pasting objects
// Then paste the objects.
if (nFlags & IDF_OBJECTS)
{
for (size_t i = 0, n = aRanges.size(); i < n; ++i)
{
pDoc->CopyFromClip(
*aRanges[i], aMark, IDF_OBJECTS, NULL, pClipDoc,
false, false, true, bSkipEmpty, NULL);
}
}
// Refresh the range that includes all pasted ranges. We only need to
// refresh the current sheet.
pDocSh->PostPaint(aRanges, PAINT_GRID);
if (pDoc->IsUndoEnabled())
{
svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
OUString 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, aRanges, aMark, pUndoDoc.release(), NULL, nFlags|nUndoFlags, NULL, false, &aOptions);
pUndoMgr->AddUndoAction(pUndo, false);
pUndoMgr->LeaveListAction();
}
ResetAutoSpell();
aModificator.SetDocumentModified();
PostPasteFromClip(aRanges, aMark);
return false;
}
void ScViewFunc::PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark)
{
ScViewData& rViewData = GetViewData();
ScDocShell* pDocSh = rViewData.GetDocShell();
pDocSh->UpdateOle(&rViewData);
SelectionChanged();
ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh);
if (!pModelObj)
return;
ScRangeList aChangeRanges;
for (size_t i = 0, n = rPasteRanges.size(); i < n; ++i)
{
const ScRange& r = *rPasteRanges[i];
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd; ++itr)
{
ScRange aChangeRange(r);
aChangeRange.aStart.SetTab(*itr);
aChangeRange.aEnd.SetTab(*itr);
aChangeRanges.Append(aChangeRange);
}
}
HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
}
// D R A G A N D D R O P
// inside the doc
bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
bool bCut, bool bRecord, bool bPaint, bool bApi )
{
ScDocShell* pDocSh = GetViewData().GetDocShell();
HideAllCursors();
bool bSuccess = 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 )
{
OUString 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)
{
// mark destination range
ScAddress aDestEnd(
rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
nDestTab );
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 ), false ); //! sal_False ???
pDocSh->UpdateOle(&GetViewData());
SelectionChanged();
ResetAutoSpell();
}
return bSuccess;
}
// link inside the doc
bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos, bool bApi )
{
// check overlapping
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 false;
}
}
// run with paste
ScDocument* pDoc = GetViewData().GetDocument();
boost::scoped_ptr<ScDocument> pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
pDoc->CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
rSource.aEnd.Col(), rSource.aEnd.Row(),
rSource.aStart.Tab(), pClipDoc.get() );
// mark destination area (set cursor, no marks)
if ( GetViewData().GetTabNo() != rDestPos.Tab() )
SetTabNo( rDestPos.Tab() );
MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, false, false );
// Paste
PasteFromClip( IDF_ALL, pClipDoc.get(), PASTE_NOFUNC, false, false, true ); // as a link
return true;
}
void ScViewFunc::DataFormPutData( SCROW nCurrentRow ,
SCROW nStartRow , SCCOL nStartCol ,
SCROW nEndRow , SCCOL nEndCol ,
std::vector<VclPtr<Edit> >& aEdits,
sal_uInt16 aColLength )
{
ScDocument* pDoc = GetViewData().GetDocument();
ScDocShell* pDocSh = GetViewData().GetDocShell();
ScMarkData& rMark = GetViewData().GetMarkData();
ScDocShellModificator aModificator( *pDocSh );
::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
if ( pDoc )
{
const bool bRecord( pDoc->IsUndoEnabled());
ScDocument* pUndoDoc = NULL;
ScDocument* pRedoDoc = NULL;
ScRefUndoData* pUndoData = NULL;
SCTAB nTab = GetViewData().GetTabNo();
SCTAB nStartTab = nTab;
SCTAB nEndTab = nTab;
{
ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
if ( pChangeTrack )
pChangeTrack->ResetLastCut(); // no more cut-mode
}
ScRange aUserRange( nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );
bool bColInfo = ( nStartRow==0 && nEndRow==MAXROW );
bool bRowInfo = ( nStartCol==0 && nEndCol==MAXCOL );
SCCOL nUndoEndCol = nStartCol+aColLength-1;
SCROW nUndoEndRow = nCurrentRow;
InsertDeleteFlags nUndoFlags = IDF_NONE;
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndoSelected( pDoc , rMark , bColInfo , bRowInfo );
pDoc->CopyToDocument( aUserRange , IDF_VALUE , false , pUndoDoc );
}
sal_uInt16 nExtFlags = 0;
pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab , nEndCol, nEndRow, nEndTab ); // content before the change
pDoc->BeginDrawUndo();
for(sal_uInt16 i = 0; i < aColLength; i++)
{
if (aEdits[i] != nullptr)
{
OUString aFieldName=aEdits[i]->GetText();
pDoc->SetString( nStartCol + i, nCurrentRow, nTab, aFieldName );
}
}
pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab ); // content after the change
SfxUndoAction* pUndo = new ScUndoDataForm( pDocSh,
nStartCol, nCurrentRow, nStartTab,
nUndoEndCol, nUndoEndRow, nEndTab, rMark,
pUndoDoc, pRedoDoc, nUndoFlags,
pUndoData, NULL, NULL, NULL,
false ); // FALSE = Redo data not yet copied
pUndoMgr->AddUndoAction( new ScUndoWrapper( pUndo ), true );
sal_uInt16 nPaint = PAINT_GRID;
if (bColInfo)
{
nPaint |= PAINT_TOP;
nUndoEndCol = MAXCOL; // just for drawing !
}
if (bRowInfo)
{
nPaint |= PAINT_LEFT;
nUndoEndRow = MAXROW; // just for drawing !
}
pDocSh->PostPaint(
ScRange(nStartCol, nCurrentRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
nPaint, nExtFlags);
pDocSh->UpdateOle(&GetViewData());
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */