Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / docvw / edtdd.cxx
blobbf23cc24391e3611e9db0308ca92fbce74f11412
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
30 #include <fmturl.hxx>
31 #include <frmfmt.hxx>
32 #include <wrtsh.hxx>
33 #include <edtdd.hxx>
34 #include <edtwin.hxx>
35 #include <view.hxx>
36 #include <viewopt.hxx>
37 #include <swdtflvr.hxx>
38 #include <swmodule.hxx>
39 #include <docsh.hxx>
40 #include <wdocsh.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);
52 m_aTimer.Start();
53 g_bDDTimerStarted = true;
56 void SwEditWin::StopDDTimer(SwWrtShell *pSh, const Point &rPt)
58 m_aTimer.Stop();
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())
68 return;
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())
82 return;
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
90 bStart = true;
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
102 // already active
103 bStart = true;
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;
111 else
112 rSh.UnlockPaint();
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,
118 aSwContentAtPos );
121 if ( !bStart || m_bIsInDrag )
122 return;
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.
128 if (g_bModePushed)
130 rSh.PopMode();
131 g_bModePushed = false;
134 m_bMBPressed = false;
135 ReleaseMouse();
136 g_bFrameDrag = false;
137 g_bExecuteDrag = true;
138 SwEditWin::s_nDDStartPosY = aDocPos.Y();
139 SwEditWin::s_nDDStartPosX = aDocPos.X();
140 m_aMovePos = aDocPos;
141 StartExecuteDrag();
142 if( bDelSelect )
144 rSh.UnSelectFrame();
145 rSh.UnlockPaint();
149 void SwEditWin::StartExecuteDrag()
151 if( !g_bExecuteDrag || m_bIsInDrag )
152 return;
154 m_bIsInDrag = true;
156 rtl::Reference<SwTransferable> pTransfer = new SwTransferable( m_rView.GetWrtShell() );
158 pTransfer->StartDrag( this, m_aMovePos );
161 void SwEditWin::DragFinished()
163 DropCleanup();
164 m_aTimer.SetInvokeHandler( LINK(this,SwEditWin, TimerHandler) );
165 m_bIsInDrag = false;
168 void SwEditWin::DropCleanup()
170 SwWrtShell &rSh = m_rView.GetWrtShell();
172 // reset statuses
173 g_bNoInterrupt = false;
174 if ( m_bOldIdleSet )
176 rSh.GetViewOptions()->SetIdle( m_bOldIdle );
177 m_bOldIdleSet = false;
179 if ( m_pUserMarker )
180 CleanupDropUserMarker();
181 else
182 rSh.UnSetVisibleCursor();
186 void SwEditWin::CleanupDropUserMarker()
188 if ( m_pUserMarker )
190 m_pUserMarker.reset();
191 m_pUserMarkerObj = nullptr;
195 //exhibition hack (MA,MBA)
196 void SwView::SelectShellForDrop()
198 if ( !GetCurShell() )
199 SelectShell();
202 sal_Int8 SwEditWin::ExecuteDrop( const ExecuteDropEvent& rEvt )
204 GetView().SelectShellForDrop();
205 DropCleanup();
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;
212 OutlinerView* pOLV;
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();
223 rSh.EndAllAction();
224 return nRet;
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
234 // Transferable.
235 sal_uInt8 nEventAction;
236 sal_Int8 nUserOpt = rEvt.mbDefault ? EXCHG_IN_ACTION_DEFAULT
237 : rEvt.mnAction;
238 SotExchangeActionFlags nActionFlags;
239 m_nDropAction = SotExchange::GetExchangeAction(
240 GetDataFlavorExVector(),
241 m_nDropDestination,
242 rEvt.mnAction,
243 nUserOpt, m_nDropFormat, nEventAction, SotClipboardFormatId::NONE,
244 &rEvt.maDropEvent.Transferable,
245 &nActionFlags );
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 );
256 return nRet;
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!
272 if( pObj )
274 OutlinerView* pOLV = rSh.GetDrawView()->GetTextEditOutlinerView();
275 if ( pOLV )
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 )
291 switch ( eType )
293 case OBJCNT_GRF:
295 bool bLink,
296 bIMap = nullptr != rSh.GetFormatFromObj( aDocPt )->GetURL().GetMap();
297 OUString aDummy;
298 rSh.GetGrfAtPos( aDocPt, aDummy, bLink );
299 if ( bLink && bIMap )
300 nDropDestination = SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP;
301 else if ( bLink )
302 nDropDestination = SotExchangeDest::DOC_LNKD_GRAPHOBJ;
303 else if ( bIMap )
304 nDropDestination = SotExchangeDest::DOC_GRAPH_W_IMAP;
305 else
306 nDropDestination = SotExchangeDest::DOC_GRAPHOBJ;
308 break;
309 case OBJCNT_FLY:
310 if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr )
311 nDropDestination = SotExchangeDest::DOC_TEXTFRAME_WEB;
312 else
313 nDropDestination = SotExchangeDest::DOC_TEXTFRAME;
314 break;
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;
328 else
329 nDropDestination = SotExchangeDest::SWDOC_FREE_AREA;
331 if( ppObj )
332 *ppObj = pObj;
333 return nDropDestination;
336 sal_Int8 SwEditWin::AcceptDrop( const AcceptDropEvent& rEvt )
338 if( rEvt.mbLeaving )
340 DropCleanup();
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;
364 if(!m_bOldIdleSet) {
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);
380 if(m_bOldIdleSet) {
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
392 : rEvt.mnAction;
394 m_nDropAction = SotExchange::GetExchangeAction(
395 GetDataFlavorExVector(),
396 m_nDropDestination,
397 rEvt.mnAction,
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)) )
416 bCleanup = true;
418 // don't more position protected objects!
419 else if( DND_ACTION_MOVE == rEvt.mnAction &&
420 pSrcSh->IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
422 bCleanup = true;
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()
429 ? DND_ACTION_MOVE
430 : DND_ACTION_COPY;
432 if ( bCleanup )
434 CleanupDropUserMarker();
435 rSh.UnSetVisibleCursor();
436 return DND_ACTION_NONE;
439 else
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 );
468 else
470 rSh.UnSetVisibleCursor();
472 if ( m_pUserMarkerObj != pObj )
474 CleanupDropUserMarker();
475 m_pUserMarkerObj = pObj;
477 if(m_pUserMarkerObj)
479 m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), *m_pUserMarkerObj ));
483 return nUserOpt;
486 CleanupDropUserMarker();
487 rSh.UnSetVisibleCursor();
488 return DND_ACTION_NONE;
491 IMPL_LINK_NOARG(SwEditWin, DDHandler, Timer *, void)
493 g_bDDTimerStarted = false;
494 m_aTimer.Stop();
495 m_aTimer.SetTimeout(240);
496 m_bMBPressed = false;
497 ReleaseMouse();
498 g_bFrameDrag = false;
499 g_bExecuteDrag = true;
500 StartExecuteDrag();
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */