blob: 7a2cad5158ca67ed28a5f44d0549c1d0c4da4bcf [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
// INCLUDE ---------------------------------------------------------------
#include <svx/svditer.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdundo.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/xoutbmp.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/viewfrm.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <com/sun/star/embed/Aspects.hpp>
#include "document.hxx" // fuer MapMode Initialisierung in PasteDraw
#include "viewfunc.hxx"
#include "tabvwsh.hxx"
#include "drawview.hxx"
#include "scmod.hxx"
#include "drwlayer.hxx"
#include "drwtrans.hxx"
#include "globstr.hrc"
#include "chartlis.hxx"
#include "docuno.hxx"
#include "docsh.hxx"
#include "convuno.hxx"
extern Point aDragStartDiff;
// STATIC DATA -----------------------------------------------------------
sal_Bool bPasteIsMove = sal_False;
using namespace com::sun::star;
//==================================================================
void lcl_AdjustInsertPos( ScViewData* pData, Point& rPos, Size& rSize )
{
// SdrPage* pPage = pData->GetDocument()->GetDrawLayer()->GetPage( pData->GetTabNo() );
SdrPage* pPage = pData->GetScDrawView()->GetModel()->GetPage( static_cast<sal_uInt16>(pData->GetTabNo()) );
DBG_ASSERT(pPage,"pPage ???");
Size aPgSize( pPage->GetSize() );
if (aPgSize.Width() < 0)
aPgSize.Width() = -aPgSize.Width();
long x = aPgSize.Width() - rPos.X() - rSize.Width();
long y = aPgSize.Height() - rPos.Y() - rSize.Height();
// ggf. Ajustments (80/200) fuer Pixel-Rundungsfehler
if( x < 0 )
rPos.X() += x + 80;
if( y < 0 )
rPos.Y() += y + 200;
rPos.X() += rSize.Width() / 2; // Position bei Paste gibt Mittelpunkt an
rPos.Y() += rSize.Height() / 2;
}
void ScViewFunc::PasteDraw( const Point& rLogicPos, SdrModel* pModel,
sal_Bool bGroup, sal_Bool bSameDocClipboard )
{
MakeDrawLayer();
Point aPos( rLogicPos );
// #64184# MapMode am Outliner-RefDevice muss stimmen (wie in FuText::MakeOutliner)
//! mit FuText::MakeOutliner zusammenfassen?
MapMode aOldMapMode;
OutputDevice* pRef = GetViewData()->GetDocument()->GetDrawLayer()->GetRefDevice();
if (pRef)
{
aOldMapMode = pRef->GetMapMode();
pRef->SetMapMode( MapMode(MAP_100TH_MM) );
}
sal_Bool bNegativePage = GetViewData()->GetDocument()->IsNegativePage( GetViewData()->GetTabNo() );
SdrView* pDragEditView = NULL;
ScModule* pScMod = SC_MOD();
const ScDragData& rData = pScMod->GetDragData();
ScDrawTransferObj* pDrawTrans = rData.pDrawTransfer;
if (pDrawTrans)
{
pDragEditView = pDrawTrans->GetDragSourceView();
aPos -= aDragStartDiff;
if ( bNegativePage )
{
if (aPos.X() > 0) aPos.X() = 0;
}
else
{
if (aPos.X() < 0) aPos.X() = 0;
}
if (aPos.Y() < 0) aPos.Y() = 0;
}
ScDrawView* pScDrawView = GetScDrawView();
if (bGroup)
pScDrawView->BegUndo( ScGlobal::GetRscString( STR_UNDO_PASTE ) );
sal_Bool bSameDoc = ( pDragEditView && pDragEditView->GetModel() == pScDrawView->GetModel() );
if (bSameDoc)
{
// lokal kopieren - incl. Charts
Point aSourceStart = pDragEditView->GetAllMarkedRect().TopLeft();
long nDiffX = aPos.X() - aSourceStart.X();
long nDiffY = aPos.Y() - aSourceStart.Y();
// innerhalb einer Page verschieben?
if ( bPasteIsMove &&
pScDrawView->GetSdrPageView()->GetPage() ==
pDragEditView->GetSdrPageView()->GetPage() )
{
if ( nDiffX != 0 || nDiffY != 0 )
pDragEditView->MoveAllMarked(Size(nDiffX,nDiffY), sal_False);
}
else
{
SdrModel* pDrawModel = pDragEditView->GetModel();
SCTAB nTab = GetViewData()->GetTabNo();
SdrPage* pDestPage = pDrawModel->GetPage( static_cast< sal_uInt16 >( nTab ) );
DBG_ASSERT(pDestPage,"nanu, Page?");
::std::vector< ::rtl::OUString > aExcludedChartNames;
if ( pDestPage )
{
ScChartHelper::GetChartNames( aExcludedChartNames, pDestPage );
}
SdrMarkList aMark = pDragEditView->GetMarkedObjectList();
aMark.ForceSort();
sal_uLong nMarkAnz=aMark.GetMarkCount();
for (sal_uLong nm=0; nm<nMarkAnz; nm++) {
const SdrMark* pM=aMark.GetMark(nm);
const SdrObject* pObj=pM->GetMarkedSdrObj();
// #116235#
SdrObject* pNeuObj=pObj->Clone();
//SdrObject* pNeuObj=pObj->Clone(pDestPage,pDrawModel);
if (pNeuObj!=NULL)
{
pNeuObj->SetModel(pDrawModel);
pNeuObj->SetPage(pDestPage);
// #68787# copy graphics within the same model - always needs new name
if ( pNeuObj->ISA(SdrGrafObj) && !bPasteIsMove )
pNeuObj->SetName(((ScDrawLayer*)pDrawModel)->GetNewGraphicName());
if (nDiffX!=0 || nDiffY!=0)
pNeuObj->NbcMove(Size(nDiffX,nDiffY));
pDestPage->InsertObject( pNeuObj );
pScDrawView->AddUndo(new SdrUndoInsertObj( *pNeuObj ));
// Chart braucht nicht mehr getrennt behandelt zu werden,
// weil es seine Daten jetzt selber hat
}
}
if (bPasteIsMove)
pDragEditView->DeleteMarked();
ScDocument* pDocument = GetViewData()->GetDocument();
ScDocShell* pDocShell = GetViewData()->GetDocShell();
ScModelObj* pModelObj = ( pDocShell ? ScModelObj::getImplementation( pDocShell->GetModel() ) : NULL );
if ( pDocument && pDestPage && pModelObj && pDrawTrans )
{
const ScRangeListVector& rProtectedChartRangesVector( pDrawTrans->GetProtectedChartRangesVector() );
ScChartHelper::CreateProtectedChartListenersAndNotify( pDocument, pDestPage, pModelObj, nTab,
rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
}
}
}
else
{
bPasteIsMove = sal_False; // kein internes Verschieben passiert
SdrView aView(pModel); // #i71529# never create a base class of SdrView directly!
SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel()->GetPage(0));
aView.MarkAllObj(pPv);
Size aSize = aView.GetAllMarkedRect().GetSize();
lcl_AdjustInsertPos( GetViewData(), aPos, aSize );
// #41333# Markierung nicht aendern, wenn Ole-Objekt aktiv
// (bei Drop aus Ole-Objekt wuerde sonst mitten im ExecuteDrag deaktiviert!)
sal_uLong nOptions = 0;
SfxInPlaceClient* pClient = GetViewData()->GetViewShell()->GetIPClient();
if ( pClient && pClient->IsObjectInPlaceActive() )
nOptions |= SDRINSERT_DONTMARK;
::std::vector< ::rtl::OUString > aExcludedChartNames;
SCTAB nTab = GetViewData()->GetTabNo();
SdrPage* pPage = pScDrawView->GetModel()->GetPage( static_cast< sal_uInt16 >( nTab ) );
DBG_ASSERT( pPage, "Page?" );
if ( pPage )
{
ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
}
// #89247# Set flag for ScDocument::UpdateChartListeners() which is
// called during paste.
if ( !bSameDocClipboard )
GetViewData()->GetDocument()->SetPastingDrawFromOtherDoc( sal_True );
pScDrawView->Paste( *pModel, aPos, NULL, nOptions );
if ( !bSameDocClipboard )
GetViewData()->GetDocument()->SetPastingDrawFromOtherDoc( sal_False );
// #68991# Paste puts all objects on the active (front) layer
// controls must be on SC_LAYER_CONTROLS
if (pPage)
{
SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
SdrObject* pObject = aIter.Next();
while (pObject)
{
if ( pObject->ISA(SdrUnoObj) && pObject->GetLayer() != SC_LAYER_CONTROLS )
pObject->NbcSetLayer(SC_LAYER_CONTROLS);
pObject = aIter.Next();
}
}
// #75299# all graphics objects must have names
GetViewData()->GetDocument()->EnsureGraphicNames();
ScDocument* pDocument = GetViewData()->GetDocument();
ScDocShell* pDocShell = GetViewData()->GetDocShell();
ScModelObj* pModelObj = ( pDocShell ? ScModelObj::getImplementation( pDocShell->GetModel() ) : NULL );
ScDrawTransferObj* pTransferObj = ScDrawTransferObj::GetOwnClipboard( NULL );
if ( pDocument && pPage && pModelObj && ( pTransferObj || pDrawTrans ) )
{
const ScRangeListVector& rProtectedChartRangesVector(
pTransferObj ? pTransferObj->GetProtectedChartRangesVector() : pDrawTrans->GetProtectedChartRangesVector() );
ScChartHelper::CreateProtectedChartListenersAndNotify( pDocument, pPage, pModelObj, nTab,
rProtectedChartRangesVector, aExcludedChartNames, bSameDocClipboard );
}
}
if (bGroup)
{
pScDrawView->GroupMarked();
pScDrawView->EndUndo();
}
if (pRef)
pRef->SetMapMode( aOldMapMode );
// GetViewData()->GetViewShell()->SetDrawShell( sal_True );
// #99759# It is not sufficient to just set the DrawShell if we pasted, for
// example, a chart. SetDrawShellOrSub() would only work for D&D in the
// same document but not if inserting from the clipboard, therefore
// MarkListHasChanged() is what we need.
pScDrawView->MarkListHasChanged();
}
sal_Bool ScViewFunc::PasteObject( const Point& rPos, const uno::Reference < embed::XEmbeddedObject >& xObj,
const Size* pDescSize, const Graphic* pReplGraph, const ::rtl::OUString& aMediaType, sal_Int64 nAspect )
{
MakeDrawLayer();
if ( xObj.is() )
{
::rtl::OUString aName;
//TODO/MBA: is that OK?
comphelper::EmbeddedObjectContainer& aCnt = GetViewData()->GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer();
if ( !aCnt.HasEmbeddedObject( xObj ) )
aCnt.InsertEmbeddedObject( xObj, aName );
else
aName = aCnt.GetEmbeddedObjectName( xObj );
svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
if ( pReplGraph )
aObjRef.SetGraphic( *pReplGraph, aMediaType );
Size aSize;
if ( nAspect == embed::Aspects::MSOLE_ICON )
{
MapMode aMapMode( MAP_100TH_MM );
aSize = aObjRef.GetSize( &aMapMode );
}
else
{
// working with visual area can switch object to running state
MapUnit aMapObj = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
MapUnit aMap100 = MAP_100TH_MM;
if ( pDescSize && pDescSize->Width() && pDescSize->Height() )
{
// use size from object descriptor if given
aSize = OutputDevice::LogicToLogic( *pDescSize, aMap100, aMapObj );
awt::Size aSz;
aSz.Width = aSize.Width();
aSz.Height = aSize.Height();
xObj->setVisualAreaSize( nAspect, aSz );
}
awt::Size aSz;
try
{
aSz = xObj->getVisualAreaSize( nAspect );
}
catch ( embed::NoVisualAreaSizeException& )
{
// the default size will be set later
}
aSize = Size( aSz.Width, aSz.Height );
aSize = OutputDevice::LogicToLogic( aSize, aMapObj, aMap100 ); // fuer SdrOle2Obj
if( aSize.Height() == 0 || aSize.Width() == 0 )
{
DBG_ERROR("SvObjectDescriptor::GetSize == 0");
aSize.Width() = 5000;
aSize.Height() = 5000;
aSize = OutputDevice::LogicToLogic( aSize, aMap100, aMapObj );
aSz.Width = aSize.Width();
aSz.Height = aSize.Height();
xObj->setVisualAreaSize( nAspect, aSz );
}
}
// don't call AdjustInsertPos
Point aInsPos = rPos;
if ( GetViewData()->GetDocument()->IsNegativePage( GetViewData()->GetTabNo() ) )
aInsPos.X() -= aSize.Width();
Rectangle aRect( aInsPos, aSize );
ScDrawView* pDrView = GetScDrawView();
SdrOle2Obj* pSdrObj = new SdrOle2Obj( aObjRef, aName, aRect );
SdrPageView* pPV = pDrView->GetSdrPageView();
pDrView->InsertObjectSafe( pSdrObj, *pPV ); // nicht markieren wenn Ole
GetViewData()->GetViewShell()->SetDrawShell( sal_True );
return sal_True;
}
else
return sal_False;
}
sal_Bool ScViewFunc::PasteBitmapEx( const Point& rPos, const BitmapEx& rBmpEx )
{
String aEmpty;
Graphic aGraphic(rBmpEx);
return PasteGraphic( rPos, aGraphic, aEmpty, aEmpty );
}
sal_Bool ScViewFunc::PasteMetaFile( const Point& rPos, const GDIMetaFile& rMtf )
{
String aEmpty;
Graphic aGraphic(rMtf);
return PasteGraphic( rPos, aGraphic, aEmpty, aEmpty );
}
sal_Bool ScViewFunc::PasteGraphic( const Point& rPos, const Graphic& rGraphic,
const String& rFile, const String& rFilter )
{
MakeDrawLayer();
ScDrawView* pScDrawView = GetScDrawView();
// #123922# check if the drop was over an existing object; if yes, evtl. replace
// the graphic for a SdrGraphObj (including link state updates) or adapt the fill
// style for other objects
if(pScDrawView)
{
SdrObject* pPickObj = 0;
SdrPageView* pPageView = pScDrawView->GetSdrPageView();
if(pPageView)
{
pScDrawView->PickObj(rPos, pScDrawView->getHitTolLog(), pPickObj, pPageView);
}
if(pPickObj)
{
const String aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
SdrObject* pResult = pScDrawView->ApplyGraphicToObject(
*pPickObj,
rGraphic,
aBeginUndo,
rFile,
rFilter);
if(pResult)
{
// we are done; mark the modified/new object
pScDrawView->MarkObj(pResult, pScDrawView->GetSdrPageView());
return sal_True;
}
}
}
Point aPos( rPos );
Window* pWin = GetActiveWin();
MapMode aSourceMap = rGraphic.GetPrefMapMode();
MapMode aDestMap( MAP_100TH_MM );
if (aSourceMap.GetMapUnit() == MAP_PIXEL)
{
// Pixel-Korrektur beruecksichtigen, damit Bitmap auf dem Bildschirm stimmt
Fraction aScaleX, aScaleY;
pScDrawView->CalcNormScale( aScaleX, aScaleY );
aDestMap.SetScaleX(aScaleX);
aDestMap.SetScaleY(aScaleY);
}
Size aSize = pWin->LogicToLogic( rGraphic.GetPrefSize(), &aSourceMap, &aDestMap );
// lcl_AdjustInsertPos( GetViewData(), aPos, aSize );
if ( GetViewData()->GetDocument()->IsNegativePage( GetViewData()->GetTabNo() ) )
aPos.X() -= aSize.Width();
GetViewData()->GetViewShell()->SetDrawShell( sal_True );
Rectangle aRect(aPos, aSize);
SdrGrafObj* pGrafObj = new SdrGrafObj(rGraphic, aRect);
// #118522# calling SetGraphicLink here doesn't work
// #49961# Pfad wird nicht mehr als Name der Grafik gesetzt
ScDrawLayer* pLayer = (ScDrawLayer*) pScDrawView->GetModel();
String aName = pLayer->GetNewGraphicName(); // "Grafik x"
pGrafObj->SetName(aName);
// nicht markieren wenn Ole
pScDrawView->InsertObjectSafe(pGrafObj, *pScDrawView->GetSdrPageView());
// #118522# SetGraphicLink has to be used after inserting the object,
// otherwise an empty graphic is swapped in and the contact stuff crashes.
// See #i37444#.
if (rFile.Len())
pGrafObj->SetGraphicLink( rFile, rFilter );
return sal_True;
}