1991 lines
74 KiB
C++
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: */
|