1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/svdview.hxx>
21 #include <editeng/outliner.hxx>
22 #include <svx/svdobj.hxx>
23 #include <sot/exchange.hxx>
24 #include <sot/formats.hxx>
25 #include <sfx2/bindings.hxx>
26 #include <vcl/commandevent.hxx>
27 #include <osl/diagnose.h>
29 #include <sfx2/viewfrm.hxx>
36 #include <viewopt.hxx>
37 #include <swdtflvr.hxx>
38 #include <swmodule.hxx>
42 using namespace ::com::sun::star
;
44 // no include "dbgoutsw.hxx" here!!!!!!
46 bool g_bExecuteDrag
= false;
48 void SwEditWin::StartDDTimer()
50 m_aTimer
.SetInvokeHandler(LINK(this, SwEditWin
, DDHandler
));
51 m_aTimer
.SetTimeout(480);
53 g_bDDTimerStarted
= true;
56 void SwEditWin::StopDDTimer(SwWrtShell
*pSh
, const Point
&rPt
)
59 g_bDDTimerStarted
= false;
60 if(!pSh
->IsSelFrameMode())
61 pSh
->CallSetCursor(&rPt
, false);
62 m_aTimer
.SetInvokeHandler(LINK(this,SwEditWin
, TimerHandler
));
65 void SwEditWin::StartDrag( sal_Int8
/*nAction*/, const Point
& rPosPixel
)
67 if (m_rView
.GetObjectShell()->isContentExtractionLocked())
70 SwWrtShell
&rSh
= m_rView
.GetWrtShell();
71 if( rSh
.GetDrawView() )
73 CommandEvent
aDragEvent( rPosPixel
, CommandEventId::StartDrag
, true );
74 if( rSh
.GetDrawView()->Command( aDragEvent
, this ) )
76 m_rView
.GetViewFrame().GetBindings().InvalidateAll(false);
77 return; // Event evaluated by SdrView
81 if ( m_pApplyTempl
|| rSh
.IsDrawCreate() || IsDrawAction())
84 bool bStart
= false, bDelSelect
= false;
85 SdrObject
*pObj
= nullptr;
86 Point
aDocPos( PixelToLogic( rPosPixel
) );
87 const bool bInSelect
= rSh
.IsInSelect();
88 if (!bInSelect
&& rSh
.TestCurrPam(aDocPos
, true))
89 //We are not selecting and aren't at a selection
91 else if ( !g_bFrameDrag
&& rSh
.IsSelFrameMode() &&
92 rSh
.IsInsideSelectedObj( aDocPos
) &&
93 nullptr == m_pAnchorMarker
)
95 //We are not dragging internally and are not at an
96 //object (frame, draw object)
98 // #i106131# *and* AnchorDrag is *not* active: When active,
99 // entering global drag mode will destroy the AnchorHdl but
100 // keep the now invalid ptr in place, next access will crash.
101 // It is indeed wrong to enter drag mode when AnchorDrag is
105 else if( !g_bFrameDrag
&& m_rView
.GetDocShell()->IsReadOnly() &&
106 OBJCNT_NONE
!= rSh
.GetObjCntType( aDocPos
, pObj
))
108 rSh
.LockPaint(LockPaintReason::StartDrag
);
109 if( rSh
.SelectObj( aDocPos
, 0, pObj
))
110 bStart
= bDelSelect
= true;
114 else if (!bInSelect
)// tdf#116384 only drag hyperlink if user's not currently setting the selection
116 SwContentAtPos
aSwContentAtPos( IsAttrAtPos::InetAttr
);
117 bStart
= rSh
.GetContentAtPos( aDocPos
,
121 if ( !bStart
|| m_bIsInDrag
)
124 // If the add selection mode has been pushed in the MouseButtonDown handler it needs to be
125 // popped or it will remain active and noticeable in the statusbar selection control until the
126 // next MouseButtonUp event after the DnD, since a MouseButtonUp event is not received by the
127 // edit window when DnD is done.
131 g_bModePushed
= false;
134 m_bMBPressed
= false;
136 g_bFrameDrag
= false;
137 g_bExecuteDrag
= true;
138 SwEditWin::s_nDDStartPosY
= aDocPos
.Y();
139 SwEditWin::s_nDDStartPosX
= aDocPos
.X();
140 m_aMovePos
= aDocPos
;
149 void SwEditWin::StartExecuteDrag()
151 if( !g_bExecuteDrag
|| m_bIsInDrag
)
156 rtl::Reference
<SwTransferable
> pTransfer
= new SwTransferable( m_rView
.GetWrtShell() );
158 pTransfer
->StartDrag( this, m_aMovePos
);
161 void SwEditWin::DragFinished()
164 m_aTimer
.SetInvokeHandler( LINK(this,SwEditWin
, TimerHandler
) );
168 void SwEditWin::DropCleanup()
170 SwWrtShell
&rSh
= m_rView
.GetWrtShell();
173 g_bNoInterrupt
= false;
176 rSh
.GetViewOptions()->SetIdle( m_bOldIdle
);
177 m_bOldIdleSet
= false;
180 CleanupDropUserMarker();
182 rSh
.UnSetVisibleCursor();
186 void SwEditWin::CleanupDropUserMarker()
190 m_pUserMarker
.reset();
191 m_pUserMarkerObj
= nullptr;
195 //exhibition hack (MA,MBA)
196 void SwView::SelectShellForDrop()
198 if ( !GetCurShell() )
202 sal_Int8
SwEditWin::ExecuteDrop( const ExecuteDropEvent
& rEvt
)
204 GetView().SelectShellForDrop();
206 sal_Int8 nRet
= DND_ACTION_NONE
;
208 //A Drop to an open OutlinerView doesn't concern us (also see QueryDrop)
209 SwWrtShell
&rSh
= m_rView
.GetWrtShell();
210 const Point
aDocPt( PixelToLogic( rEvt
.maPosPixel
));
211 SdrObject
*pObj
= nullptr;
213 rSh
.GetObjCntType( aDocPt
, pObj
);
215 if( pObj
&& nullptr != ( pOLV
= rSh
.GetDrawView()->GetTextEditOutlinerView() ))
217 tools::Rectangle
aRect( pOLV
->GetOutputArea() );
218 aRect
.Union( pObj
->GetLogicRect() );
219 const Point aPos
= pOLV
->GetWindow()->PixelToLogic(rEvt
.maPosPixel
);
220 if ( aRect
.Contains(aPos
) )
222 rSh
.StartAllAction();
228 // There's a special treatment for file lists with a single
229 // element, that depends on the actual content of the
230 // Transferable to be accessible. Since the transferable
231 // may only be accessed after the drop has been accepted
232 // (according to KA due to Java D&D), we'll have to
233 // reevaluate the drop action once more _with_ the
235 sal_uInt8 nEventAction
;
236 sal_Int8 nUserOpt
= rEvt
.mbDefault
? EXCHG_IN_ACTION_DEFAULT
238 SotExchangeActionFlags nActionFlags
;
239 m_nDropAction
= SotExchange::GetExchangeAction(
240 GetDataFlavorExVector(),
243 nUserOpt
, m_nDropFormat
, nEventAction
, SotClipboardFormatId::NONE
,
244 &rEvt
.maDropEvent
.Transferable
,
247 TransferableDataHelper
aData( rEvt
.maDropEvent
.Transferable
);
248 nRet
= rEvt
.mnAction
;
249 if( !SwTransferable::PasteData( aData
, rSh
, m_nDropAction
, nActionFlags
, m_nDropFormat
,
250 m_nDropDestination
, false, rEvt
.mbDefault
, &aDocPt
, nRet
))
251 nRet
= DND_ACTION_NONE
;
252 else if ( SW_MOD()->m_pDragDrop
)
253 //Don't clean up anymore at internal D&D!
254 SW_MOD()->m_pDragDrop
->SetCleanUp( false );
259 SotExchangeDest
SwEditWin::GetDropDestination( const Point
& rPixPnt
, SdrObject
** ppObj
)
261 SwWrtShell
&rSh
= m_rView
.GetWrtShell();
262 const Point
aDocPt( PixelToLogic( rPixPnt
) );
263 if( rSh
.TestCurrPam( aDocPt
)
264 || rSh
.IsOverReadOnlyPos( aDocPt
)
265 || rSh
.DocPtInsideInputField( aDocPt
) )
266 return SotExchangeDest::NONE
;
268 SdrObject
*pObj
= nullptr;
269 const ObjCntType eType
= rSh
.GetObjCntType( aDocPt
, pObj
);
271 //Drop to OutlinerView (TextEdit in Drawing) should decide it on its own!
274 OutlinerView
* pOLV
= rSh
.GetDrawView()->GetTextEditOutlinerView();
277 tools::Rectangle
aRect( pOLV
->GetOutputArea() );
278 aRect
.Union( pObj
->GetLogicRect() );
279 const Point aPos
= pOLV
->GetWindow()->PixelToLogic( rPixPnt
);
280 if( aRect
.Contains( aPos
) )
281 return SotExchangeDest::NONE
;
285 //What do we want to drop on now?
286 SotExchangeDest nDropDestination
= SotExchangeDest::NONE
;
288 //Did anything else arrive from the DrawingEngine?
289 if( OBJCNT_NONE
!= eType
)
296 bIMap
= nullptr != rSh
.GetFormatFromObj( aDocPt
)->GetURL().GetMap();
298 rSh
.GetGrfAtPos( aDocPt
, aDummy
, bLink
);
299 if ( bLink
&& bIMap
)
300 nDropDestination
= SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP
;
302 nDropDestination
= SotExchangeDest::DOC_LNKD_GRAPHOBJ
;
304 nDropDestination
= SotExchangeDest::DOC_GRAPH_W_IMAP
;
306 nDropDestination
= SotExchangeDest::DOC_GRAPHOBJ
;
310 if( dynamic_cast< const SwWebDocShell
*>( rSh
.GetView().GetDocShell() ) != nullptr )
311 nDropDestination
= SotExchangeDest::DOC_TEXTFRAME_WEB
;
313 nDropDestination
= SotExchangeDest::DOC_TEXTFRAME
;
315 case OBJCNT_OLE
: nDropDestination
= SotExchangeDest::DOC_OLEOBJ
; break;
316 case OBJCNT_CONTROL
: /* no Action avail */
317 case OBJCNT_SIMPLE
: nDropDestination
= SotExchangeDest::DOC_DRAWOBJ
; break;
318 case OBJCNT_URLBUTTON
: nDropDestination
= SotExchangeDest::DOC_URLBUTTON
; break;
319 case OBJCNT_GROUPOBJ
: nDropDestination
= SotExchangeDest::DOC_GROUPOBJ
; break;
321 default: OSL_ENSURE( false, "new ObjectType?" );
324 if ( nDropDestination
== SotExchangeDest::NONE
)
326 if( dynamic_cast< const SwWebDocShell
*>( rSh
.GetView().GetDocShell() ) != nullptr )
327 nDropDestination
= SotExchangeDest::SWDOC_FREE_AREA_WEB
;
329 nDropDestination
= SotExchangeDest::SWDOC_FREE_AREA
;
333 return nDropDestination
;
336 sal_Int8
SwEditWin::AcceptDrop( const AcceptDropEvent
& rEvt
)
341 return rEvt
.mnAction
;
344 if( m_rView
.GetDocShell()->IsReadOnly() )
345 return DND_ACTION_NONE
;
347 SwWrtShell
&rSh
= m_rView
.GetWrtShell();
349 Point
aPixPt( rEvt
.maPosPixel
);
351 // If the cursor is near the inner boundary
352 // we attempt to scroll towards the desired direction.
353 tools::Rectangle
aWin(Point(), GetOutputSizePixel());
354 const int nMargin
= 10;
355 aWin
.AdjustLeft(nMargin
);
356 aWin
.AdjustTop(nMargin
);
357 aWin
.AdjustRight( -nMargin
);
358 aWin
.AdjustBottom( -nMargin
);
359 if(!aWin
.Contains(aPixPt
)) {
360 static sal_uInt64 last_tick
= 0;
361 sal_uInt64 current_tick
= tools::Time::GetSystemTicks();
362 if((current_tick
-last_tick
) > 500) {
363 last_tick
= current_tick
;
365 m_bOldIdle
= rSh
.GetViewOptions()->IsIdle();
366 rSh
.GetViewOptions()->SetIdle(false);
367 m_bOldIdleSet
= true;
369 CleanupDropUserMarker();
370 if(aPixPt
.X() > aWin
.Right()) aPixPt
.AdjustX(nMargin
);
371 if(aPixPt
.X() < aWin
.Left()) aPixPt
.AdjustX( -nMargin
);
372 if(aPixPt
.Y() > aWin
.Bottom()) aPixPt
.AdjustY(nMargin
);
373 if(aPixPt
.Y() < aWin
.Top()) aPixPt
.AdjustY( -nMargin
);
374 Point
aDocPt(PixelToLogic(aPixPt
));
375 SwRect
rect(aDocPt
,Size(1,1));
376 rSh
.MakeVisible(rect
);
381 rSh
.GetViewOptions()->SetIdle( m_bOldIdle
);
382 m_bOldIdleSet
= false;
385 SdrObject
*pObj
= nullptr;
386 m_nDropDestination
= GetDropDestination( aPixPt
, &pObj
);
387 if( m_nDropDestination
== SotExchangeDest::NONE
)
388 return DND_ACTION_NONE
;
390 sal_uInt8 nEventAction
;
391 sal_Int8 nUserOpt
= rEvt
.mbDefault
? EXCHG_IN_ACTION_DEFAULT
394 m_nDropAction
= SotExchange::GetExchangeAction(
395 GetDataFlavorExVector(),
398 nUserOpt
, m_nDropFormat
, nEventAction
);
400 if( EXCHG_INOUT_ACTION_NONE
!= m_nDropAction
)
402 const Point
aDocPt( PixelToLogic( aPixPt
) );
404 //With the default action we still want to have a say.
405 SwModule
*pMod
= SW_MOD();
406 if( pMod
->m_pDragDrop
)
408 bool bCleanup
= false;
409 //Drawing objects in Headers/Footers are not allowed
411 SwWrtShell
*pSrcSh
= pMod
->m_pDragDrop
->GetShell();
412 if( (pSrcSh
->GetSelFrameType() == FrameTypeFlags::DRAWOBJ
) &&
413 pSrcSh
->IsSelContainsControl() &&
414 (rSh
.GetFrameType( &aDocPt
, false ) & (FrameTypeFlags::HEADER
|FrameTypeFlags::FOOTER
)) )
418 // don't more position protected objects!
419 else if( DND_ACTION_MOVE
== rEvt
.mnAction
&&
420 pSrcSh
->IsSelObjProtected( FlyProtectFlags::Pos
) != FlyProtectFlags::NONE
)
424 else if( rEvt
.mbDefault
)
426 // internal Drag&Drop: within same Doc a Move
427 // otherwise a Copy - Task 54974
428 nEventAction
= pSrcSh
->GetDoc() == rSh
.GetDoc()
434 CleanupDropUserMarker();
435 rSh
.UnSetVisibleCursor();
436 return DND_ACTION_NONE
;
441 //D&D from outside of SW should be a Copy per default.
442 if( EXCHG_IN_ACTION_DEFAULT
== nEventAction
&&
443 DND_ACTION_MOVE
== rEvt
.mnAction
)
444 nEventAction
= DND_ACTION_COPY
;
446 if( (SotClipboardFormatId::SBA_FIELDDATAEXCHANGE
== m_nDropFormat
&&
447 EXCHG_IN_ACTION_LINK
== m_nDropAction
) ||
448 SotClipboardFormatId::SBA_CTRLDATAEXCHANGE
== m_nDropFormat
)
450 SdrMarkView
* pMView
= rSh
.GetDrawView();
451 if( pMView
&& !pMView
->IsDesignMode() )
452 return DND_ACTION_NONE
;
456 if ( EXCHG_IN_ACTION_DEFAULT
!= nEventAction
)
457 nUserOpt
= static_cast<sal_Int8
>(nEventAction
);
459 // show DropCursor or UserMarker ?
460 if( SotExchangeDest::SWDOC_FREE_AREA_WEB
== m_nDropDestination
||
461 SotExchangeDest::SWDOC_FREE_AREA
== m_nDropDestination
)
463 CleanupDropUserMarker();
464 SwContentAtPos
aCont( IsAttrAtPos::ContentCheck
);
465 if(rSh
.GetContentAtPos(aDocPt
, aCont
))
466 rSh
.SwCursorShell::SetVisibleCursor( aDocPt
);
470 rSh
.UnSetVisibleCursor();
472 if ( m_pUserMarkerObj
!= pObj
)
474 CleanupDropUserMarker();
475 m_pUserMarkerObj
= pObj
;
479 m_pUserMarker
.reset(new SdrDropMarkerOverlay( *rSh
.GetDrawView(), *m_pUserMarkerObj
));
486 CleanupDropUserMarker();
487 rSh
.UnSetVisibleCursor();
488 return DND_ACTION_NONE
;
491 IMPL_LINK_NOARG(SwEditWin
, DDHandler
, Timer
*, void)
493 g_bDDTimerStarted
= false;
495 m_aTimer
.SetTimeout(240);
496 m_bMBPressed
= false;
498 g_bFrameDrag
= false;
499 g_bExecuteDrag
= true;
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */