diff options
Diffstat (limited to '')
-rw-r--r-- | sw/source/uibase/docvw/edtdd.cxx | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/sw/source/uibase/docvw/edtdd.cxx b/sw/source/uibase/docvw/edtdd.cxx new file mode 100644 index 0000000000..287d2969f6 --- /dev/null +++ b/sw/source/uibase/docvw/edtdd.cxx @@ -0,0 +1,501 @@ +/* -*- 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 <svx/svdview.hxx> +#include <editeng/outliner.hxx> +#include <svx/svdobj.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> +#include <sfx2/bindings.hxx> +#include <vcl/commandevent.hxx> +#include <osl/diagnose.h> + +#include <sfx2/viewfrm.hxx> +#include <fmturl.hxx> +#include <frmfmt.hxx> +#include <wrtsh.hxx> +#include <edtdd.hxx> +#include <edtwin.hxx> +#include <view.hxx> +#include <viewopt.hxx> +#include <swdtflvr.hxx> +#include <swmodule.hxx> +#include <docsh.hxx> +#include <wdocsh.hxx> + +using namespace ::com::sun::star; + +// no include "dbgoutsw.hxx" here!!!!!! + +bool g_bExecuteDrag = false; + +void SwEditWin::StartDDTimer() +{ + m_aTimer.SetInvokeHandler(LINK(this, SwEditWin, DDHandler)); + m_aTimer.SetTimeout(480); + m_aTimer.Start(); + g_bDDTimerStarted = true; +} + +void SwEditWin::StopDDTimer(SwWrtShell *pSh, const Point &rPt) +{ + m_aTimer.Stop(); + g_bDDTimerStarted = false; + if(!pSh->IsSelFrameMode()) + pSh->CallSetCursor(&rPt, false); + m_aTimer.SetInvokeHandler(LINK(this,SwEditWin, TimerHandler)); +} + +void SwEditWin::StartDrag( sal_Int8 /*nAction*/, const Point& rPosPixel ) +{ + if (m_rView.GetObjectShell()->isContentExtractionLocked()) + return; + + SwWrtShell &rSh = m_rView.GetWrtShell(); + if( rSh.GetDrawView() ) + { + CommandEvent aDragEvent( rPosPixel, CommandEventId::StartDrag, true ); + if( rSh.GetDrawView()->Command( aDragEvent, this ) ) + { + m_rView.GetViewFrame().GetBindings().InvalidateAll(false); + return; // Event evaluated by SdrView + } + } + + if ( m_pApplyTempl || rSh.IsDrawCreate() || IsDrawAction()) + return; + + bool bStart = false, bDelSelect = false; + SdrObject *pObj = nullptr; + Point aDocPos( PixelToLogic( rPosPixel ) ); + const bool bInSelect = rSh.IsInSelect(); + if (!bInSelect && rSh.TestCurrPam(aDocPos, true)) + //We are not selecting and aren't at a selection + bStart = true; + else if ( !g_bFrameDrag && rSh.IsSelFrameMode() && + rSh.IsInsideSelectedObj( aDocPos ) && + nullptr == m_pAnchorMarker) + { + //We are not dragging internally and are not at an + //object (frame, draw object) + + // #i106131# *and* AnchorDrag is *not* active: When active, + // entering global drag mode will destroy the AnchorHdl but + // keep the now invalid ptr in place, next access will crash. + // It is indeed wrong to enter drag mode when AnchorDrag is + // already active + bStart = true; + } + else if( !g_bFrameDrag && m_rView.GetDocShell()->IsReadOnly() && + OBJCNT_NONE != rSh.GetObjCntType( aDocPos, pObj )) + { + rSh.LockPaint(LockPaintReason::StartDrag); + if( rSh.SelectObj( aDocPos, 0, pObj )) + bStart = bDelSelect = true; + else + rSh.UnlockPaint(); + } + else if (!bInSelect)// tdf#116384 only drag hyperlink if user's not currently setting the selection + { + SwContentAtPos aSwContentAtPos( IsAttrAtPos::InetAttr ); + bStart = rSh.GetContentAtPos( aDocPos, + aSwContentAtPos ); + } + + if ( !bStart || m_bIsInDrag ) + return; + + // If the add selection mode has been pushed in the MouseButtonDown handler it needs to be + // popped or it will remain active and noticeable in the statusbar selection control until the + // next MouseButtonUp event after the DnD, since a MouseButtonUp event is not received by the + // edit window when DnD is done. + if (g_bModePushed) + { + rSh.PopMode(); + g_bModePushed = false; + } + + m_bMBPressed = false; + ReleaseMouse(); + g_bFrameDrag = false; + g_bExecuteDrag = true; + SwEditWin::s_nDDStartPosY = aDocPos.Y(); + SwEditWin::s_nDDStartPosX = aDocPos.X(); + m_aMovePos = aDocPos; + StartExecuteDrag(); + if( bDelSelect ) + { + rSh.UnSelectFrame(); + rSh.UnlockPaint(); + } +} + +void SwEditWin::StartExecuteDrag() +{ + if( !g_bExecuteDrag || m_bIsInDrag ) + return; + + m_bIsInDrag = true; + + rtl::Reference<SwTransferable> pTransfer = new SwTransferable( m_rView.GetWrtShell() ); + + pTransfer->StartDrag( this, m_aMovePos ); +} + +void SwEditWin::DragFinished() +{ + DropCleanup(); + m_aTimer.SetInvokeHandler( LINK(this,SwEditWin, TimerHandler) ); + m_bIsInDrag = false; +} + +void SwEditWin::DropCleanup() +{ + SwWrtShell &rSh = m_rView.GetWrtShell(); + + // reset statuses + g_bNoInterrupt = false; + if ( m_bOldIdleSet ) + { + rSh.GetViewOptions()->SetIdle( m_bOldIdle ); + m_bOldIdleSet = false; + } + if ( m_pUserMarker ) + CleanupDropUserMarker(); + else + rSh.UnSetVisibleCursor(); + +} + +void SwEditWin::CleanupDropUserMarker() +{ + if ( m_pUserMarker ) + { + m_pUserMarker.reset(); + m_pUserMarkerObj = nullptr; + } +} + +//exhibition hack (MA,MBA) +void SwView::SelectShellForDrop() +{ + if ( !GetCurShell() ) + SelectShell(); +} + +sal_Int8 SwEditWin::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + GetView().SelectShellForDrop(); + DropCleanup(); + sal_Int8 nRet = DND_ACTION_NONE; + + //A Drop to an open OutlinerView doesn't concern us (also see QueryDrop) + SwWrtShell &rSh = m_rView.GetWrtShell(); + const Point aDocPt( PixelToLogic( rEvt.maPosPixel )); + SdrObject *pObj = nullptr; + OutlinerView* pOLV; + rSh.GetObjCntType( aDocPt, pObj ); + + if( pObj && nullptr != ( pOLV = rSh.GetDrawView()->GetTextEditOutlinerView() )) + { + tools::Rectangle aRect( pOLV->GetOutputArea() ); + aRect.Union( pObj->GetLogicRect() ); + const Point aPos = pOLV->GetWindow()->PixelToLogic(rEvt.maPosPixel); + if ( aRect.Contains(aPos) ) + { + rSh.StartAllAction(); + rSh.EndAllAction(); + return nRet; + } + } + + // There's a special treatment for file lists with a single + // element, that depends on the actual content of the + // Transferable to be accessible. Since the transferable + // may only be accessed after the drop has been accepted + // (according to KA due to Java D&D), we'll have to + // reevaluate the drop action once more _with_ the + // Transferable. + sal_uInt8 nEventAction; + sal_Int8 nUserOpt = rEvt.mbDefault ? EXCHG_IN_ACTION_DEFAULT + : rEvt.mnAction; + SotExchangeActionFlags nActionFlags; + m_nDropAction = SotExchange::GetExchangeAction( + GetDataFlavorExVector(), + m_nDropDestination, + rEvt.mnAction, + nUserOpt, m_nDropFormat, nEventAction, SotClipboardFormatId::NONE, + &rEvt.maDropEvent.Transferable, + &nActionFlags ); + + TransferableDataHelper aData( rEvt.maDropEvent.Transferable ); + nRet = rEvt.mnAction; + if( !SwTransferable::PasteData( aData, rSh, m_nDropAction, nActionFlags, m_nDropFormat, + m_nDropDestination, false, rEvt.mbDefault, &aDocPt, nRet)) + nRet = DND_ACTION_NONE; + else if ( SW_MOD()->m_pDragDrop ) + //Don't clean up anymore at internal D&D! + SW_MOD()->m_pDragDrop->SetCleanUp( false ); + + return nRet; +} + +SotExchangeDest SwEditWin::GetDropDestination( const Point& rPixPnt, SdrObject ** ppObj ) +{ + SwWrtShell &rSh = m_rView.GetWrtShell(); + const Point aDocPt( PixelToLogic( rPixPnt ) ); + if (rSh.IsOverReadOnlyPos(aDocPt) || rSh.DocPtInsideInputField(aDocPt)) + return SotExchangeDest::NONE; + + SdrObject *pObj = nullptr; + const ObjCntType eType = rSh.GetObjCntType( aDocPt, pObj ); + + //Drop to OutlinerView (TextEdit in Drawing) should decide it on its own! + if( pObj ) + { + OutlinerView* pOLV = rSh.GetDrawView()->GetTextEditOutlinerView(); + if ( pOLV ) + { + tools::Rectangle aRect( pOLV->GetOutputArea() ); + aRect.Union( pObj->GetLogicRect() ); + const Point aPos = pOLV->GetWindow()->PixelToLogic( rPixPnt ); + if( aRect.Contains( aPos ) ) + return SotExchangeDest::NONE; + } + } + + //What do we want to drop on now? + SotExchangeDest nDropDestination = SotExchangeDest::NONE; + + //Did anything else arrive from the DrawingEngine? + if( OBJCNT_NONE != eType ) + { + switch ( eType ) + { + case OBJCNT_GRF: + { + bool bLink, + bIMap = nullptr != rSh.GetFormatFromObj( aDocPt )->GetURL().GetMap(); + OUString aDummy; + rSh.GetGrfAtPos( aDocPt, aDummy, bLink ); + if ( bLink && bIMap ) + nDropDestination = SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP; + else if ( bLink ) + nDropDestination = SotExchangeDest::DOC_LNKD_GRAPHOBJ; + else if ( bIMap ) + nDropDestination = SotExchangeDest::DOC_GRAPH_W_IMAP; + else + nDropDestination = SotExchangeDest::DOC_GRAPHOBJ; + } + break; + case OBJCNT_FLY: + if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr ) + nDropDestination = SotExchangeDest::DOC_TEXTFRAME_WEB; + else + nDropDestination = SotExchangeDest::DOC_TEXTFRAME; + break; + case OBJCNT_OLE: nDropDestination = SotExchangeDest::DOC_OLEOBJ; break; + case OBJCNT_CONTROL: /* no Action avail */ + case OBJCNT_SIMPLE: nDropDestination = SotExchangeDest::DOC_DRAWOBJ; break; + case OBJCNT_URLBUTTON: nDropDestination = SotExchangeDest::DOC_URLBUTTON; break; + case OBJCNT_GROUPOBJ: nDropDestination = SotExchangeDest::DOC_GROUPOBJ; break; + + default: OSL_ENSURE( false, "new ObjectType?" ); + } + } + if ( nDropDestination == SotExchangeDest::NONE ) + { + if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr ) + nDropDestination = SotExchangeDest::SWDOC_FREE_AREA_WEB; + else + nDropDestination = SotExchangeDest::SWDOC_FREE_AREA; + } + if( ppObj ) + *ppObj = pObj; + return nDropDestination; +} + +sal_Int8 SwEditWin::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + if( rEvt.mbLeaving ) + { + DropCleanup(); + return rEvt.mnAction; + } + + if( m_rView.GetDocShell()->IsReadOnly() ) + return DND_ACTION_NONE; + + SwWrtShell &rSh = m_rView.GetWrtShell(); + + Point aPixPt( rEvt.maPosPixel ); + + // If the cursor is near the inner boundary + // we attempt to scroll towards the desired direction. + tools::Rectangle aWin(Point(), GetOutputSizePixel()); + const int nMargin = 10; + aWin.AdjustLeft(nMargin ); + aWin.AdjustTop(nMargin ); + aWin.AdjustRight( -nMargin ); + aWin.AdjustBottom( -nMargin ); + if(!aWin.Contains(aPixPt)) { + static sal_uInt64 last_tick = 0; + sal_uInt64 current_tick = tools::Time::GetSystemTicks(); + if((current_tick-last_tick) > 500) { + last_tick = current_tick; + if(!m_bOldIdleSet) { + m_bOldIdle = rSh.GetViewOptions()->IsIdle(); + rSh.GetViewOptions()->SetIdle(false); + m_bOldIdleSet = true; + } + CleanupDropUserMarker(); + if(aPixPt.X() > aWin.Right()) aPixPt.AdjustX(nMargin ); + if(aPixPt.X() < aWin.Left()) aPixPt.AdjustX( -nMargin ); + if(aPixPt.Y() > aWin.Bottom()) aPixPt.AdjustY(nMargin ); + if(aPixPt.Y() < aWin.Top()) aPixPt.AdjustY( -nMargin ); + Point aDocPt(PixelToLogic(aPixPt)); + SwRect rect(aDocPt,Size(1,1)); + rSh.MakeVisible(rect); + } + } + + if(m_bOldIdleSet) { + rSh.GetViewOptions()->SetIdle( m_bOldIdle ); + m_bOldIdleSet = false; + } + + SdrObject *pObj = nullptr; + m_nDropDestination = GetDropDestination( aPixPt, &pObj ); + if( m_nDropDestination == SotExchangeDest::NONE ) + return DND_ACTION_NONE; + + sal_uInt8 nEventAction; + sal_Int8 nUserOpt = rEvt.mbDefault ? EXCHG_IN_ACTION_DEFAULT + : rEvt.mnAction; + + m_nDropAction = SotExchange::GetExchangeAction( + GetDataFlavorExVector(), + m_nDropDestination, + rEvt.mnAction, + nUserOpt, m_nDropFormat, nEventAction ); + + if( EXCHG_INOUT_ACTION_NONE != m_nDropAction ) + { + const Point aDocPt( PixelToLogic( aPixPt ) ); + + //With the default action we still want to have a say. + SwModule *pMod = SW_MOD(); + if( pMod->m_pDragDrop ) + { + bool bCleanup = false; + //Drawing objects in Headers/Footers are not allowed + + SwWrtShell *pSrcSh = pMod->m_pDragDrop->GetShell(); + if( (pSrcSh->GetSelFrameType() == FrameTypeFlags::DRAWOBJ) && + pSrcSh->IsSelContainsControl() && + (rSh.GetFrameType( &aDocPt, false ) & (FrameTypeFlags::HEADER|FrameTypeFlags::FOOTER)) ) + { + bCleanup = true; + } + // don't more position protected objects! + else if( DND_ACTION_MOVE == rEvt.mnAction && + pSrcSh->IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE ) + { + bCleanup = true; + } + else if( rEvt.mbDefault ) + { + // internal Drag&Drop: within same Doc a Move + // otherwise a Copy - Task 54974 + nEventAction = pSrcSh->GetDoc() == rSh.GetDoc() + ? DND_ACTION_MOVE + : DND_ACTION_COPY; + } + if ( bCleanup ) + { + CleanupDropUserMarker(); + rSh.UnSetVisibleCursor(); + return DND_ACTION_NONE; + } + } + else + { + //D&D from outside of SW should be a Copy per default. + if( EXCHG_IN_ACTION_DEFAULT == nEventAction && + DND_ACTION_MOVE == rEvt.mnAction ) + nEventAction = DND_ACTION_COPY; + + if( (SotClipboardFormatId::SBA_FIELDDATAEXCHANGE == m_nDropFormat && + EXCHG_IN_ACTION_LINK == m_nDropAction) || + SotClipboardFormatId::SBA_CTRLDATAEXCHANGE == m_nDropFormat ) + { + SdrMarkView* pMView = rSh.GetDrawView(); + if( pMView && !pMView->IsDesignMode() ) + return DND_ACTION_NONE; + } + } + + if ( EXCHG_IN_ACTION_DEFAULT != nEventAction ) + nUserOpt = static_cast<sal_Int8>(nEventAction); + + // show DropCursor or UserMarker ? + if( SotExchangeDest::SWDOC_FREE_AREA_WEB == m_nDropDestination || + SotExchangeDest::SWDOC_FREE_AREA == m_nDropDestination ) + { + CleanupDropUserMarker(); + SwContentAtPos aCont( IsAttrAtPos::ContentCheck ); + if(rSh.GetContentAtPos(aDocPt, aCont)) + rSh.SwCursorShell::SetVisibleCursor( aDocPt ); + } + else + { + rSh.UnSetVisibleCursor(); + + if ( m_pUserMarkerObj != pObj ) + { + CleanupDropUserMarker(); + m_pUserMarkerObj = pObj; + + if(m_pUserMarkerObj) + { + m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), *m_pUserMarkerObj )); + } + } + } + return nUserOpt; + } + + CleanupDropUserMarker(); + rSh.UnSetVisibleCursor(); + return DND_ACTION_NONE; +} + +IMPL_LINK_NOARG(SwEditWin, DDHandler, Timer *, void) +{ + g_bDDTimerStarted = false; + m_aTimer.Stop(); + m_aTimer.SetTimeout(240); + m_bMBPressed = false; + ReleaseMouse(); + g_bFrameDrag = false; + g_bExecuteDrag = true; + StartExecuteDrag(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |