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 <editeng/flditem.hxx>
21 #include <svx/svddrgmt.hxx>
22 #include <svx/svdoole2.hxx>
23 #include <svx/svdotext.hxx>
24 #include <sfx2/dispatch.hxx>
25 #include <vcl/imapobj.hxx>
26 #include <svx/svdouno.hxx>
27 #include <svx/svdomedia.hxx>
28 #include <svx/svdpagv.hxx>
29 #include <svx/ImageMapInfo.hxx>
30 #include <editeng/outlobj.hxx>
31 #include <sfx2/app.hxx>
32 #include <sfx2/ipclient.hxx>
33 #include <sfx2/viewfrm.hxx>
39 #include <drawview.hxx>
40 #include <tabvwsh.hxx>
41 #include <drwlayer.hxx>
42 #include <userdat.hxx>
44 #include <charthelper.hxx>
48 // maximal permitted mouse movement to start Drag&Drop
49 //! fusel,fuconstr,futext - combine them!
50 #define SC_MAXDRAGMOVE 3
51 // Min necessary mouse motion for normal dragging
52 #define SC_MINDRAGMOVE 2
54 using namespace com::sun::star
;
56 FuSelection::FuSelection(ScTabViewShell
& rViewSh
, vcl::Window
* pWin
, ScDrawView
* pViewP
,
57 SdrModel
* pDoc
, const SfxRequest
& rReq
)
58 : FuDraw(rViewSh
, pWin
, pViewP
, pDoc
, rReq
)
62 FuSelection::~FuSelection()
66 bool FuSelection::MouseButtonDown(const MouseEvent
& rMEvt
)
68 // remember button state for creation of own MouseEvents
69 SetMouseButtonCode(rMEvt
.GetButtons());
70 const bool bSelectionOnly
= rMEvt
.IsRight();
71 if ( pView
->IsAction() )
78 bIsInDragMode
= false; // somewhere it has to be reset (#50033#)
80 bool bReturn
= FuDraw::MouseButtonDown(rMEvt
);
82 aMDPos
= pWindow
->PixelToLogic( rMEvt
.GetPosPixel() );
86 SdrHdl
* pHdl
= pView
->PickHandle(aMDPos
);
88 if ( pHdl
!=nullptr || pView
->IsMarkedHit(aMDPos
) )
90 // Determine if this is the tail of a SdrCaptionObj i.e.
91 // we need to disable the drag option on the tail of a note
92 // object. Also, disable the ability to use the circular
93 // drag of a note object.
95 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
96 if( rMarkList
.GetMarkCount() == 1 )
98 SdrObject
* pMarkedObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
99 if( ScDrawLayer::IsNoteCaption( pMarkedObj
) )
101 // move using the valid caption handles for note text box.
102 if(pHdl
&& (pHdl
->GetKind() != SdrHdlKind::Poly
&& pHdl
->GetKind() != SdrHdlKind::Circle
))
104 // move the complete note box.
109 bDrag
= true; // different object
112 bDrag
= true; // several objects
117 if (pView
->BegDragObj(aMDPos
, nullptr, pHdl
))
118 pView
->GetDragMethod()->SetShiftPressed( rMEvt
.IsShift() );
124 SdrPageView
* pPV
= nullptr;
125 bool bAlt
= rMEvt
.IsMod2();
126 SdrObject
* pObj
= !bAlt
? pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::PICKMACRO
) : nullptr;
129 pView
->BegMacroObj(aMDPos
, pObj
, pPV
, pWindow
);
134 OUString sURL
, sTarget
;
135 pObj
= !bAlt
? pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::ALSOONMASTER
) : nullptr;
138 // Support for imported Excel docs
139 // Excel is of course not consistent and allows
140 // a hyperlink to be assigned for an object group
141 // and even though the hyperlink is exported in the Escher layer
142 // its never used, when dealing with a group object the link
143 // associated with the clicked object is used only
145 // additionally you can also select a macro in Excel for a grouped
146 // objects and this *usually* results in the macro being set
147 // for the elements in the group and no macro is exported
148 // for the group itself ( this however is not always true )
149 // if a macro and hlink are defined favour the hlink
150 // If a group object has no hyperlink use the hyperlink of the
153 if ( pObj
->IsGroupObject() )
155 ScMacroInfo
* pTmpInfo
= ScDrawLayer::GetMacroInfo( pObj
);
156 if ( !pTmpInfo
|| pTmpInfo
->GetMacro().isEmpty() )
158 SdrObject
* pHit
= pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::DEEP
);
164 ScMacroInfo
* pInfo
= ScDrawLayer::GetMacroInfo( pObj
, true );
165 // For interoperability favour links over macros if both are defined
166 if ( !pInfo
->GetHlink().isEmpty() )
168 sURL
= pInfo
->GetHlink();
170 else if ( !pInfo
->GetMacro().isEmpty() )
172 SfxObjectShell
* pObjSh
= SfxObjectShell::Current();
173 if ( pObjSh
&& SfxApplication::IsXScriptURL( pInfo
->GetMacro() ) )
175 uno::Reference
< beans::XPropertySet
> xProps( pObj
->getUnoShape(), uno::UNO_QUERY
);
181 aCaller
= xProps
->getPropertyValue("Name");
183 catch( uno::Exception
& ) {}
186 uno::Sequence
< sal_Int16
> aOutArgsIndex
;
187 uno::Sequence
< uno::Any
> aOutArgs
;
188 uno::Sequence
< uno::Any
> aInArgs
;
189 pObjSh
->CallXScript( pInfo
->GetMacro(),
190 aInArgs
, aRet
, aOutArgsIndex
, aOutArgs
, true, &aCaller
);
191 rViewShell
.FakeButtonUp( rViewShell
.GetViewData().GetActivePart() );
192 return true; // no CaptureMouse etc.
201 pView
->PickAnything( rMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
) != SdrHitKind::NONE
&&
202 aVEvt
.pObj
!= nullptr )
204 if ( SvxIMapInfo::GetIMapInfo( aVEvt
.pObj
) ) // ImageMap
206 const IMapObject
* pIMapObj
=
207 SvxIMapInfo::GetHitIMapObject( aVEvt
.pObj
, aMDPos
, pWindow
);
208 if ( pIMapObj
&& !pIMapObj
->GetURL().isEmpty() )
210 sURL
= pIMapObj
->GetURL();
211 sTarget
= pIMapObj
->GetTarget();
214 if ( aVEvt
.eEvent
== SdrEventKind::ExecuteUrl
&& aVEvt
.pURLField
) // URL
216 sURL
= aVEvt
.pURLField
->GetURL();
217 sTarget
= aVEvt
.pURLField
->GetTargetFrame();
221 // open hyperlink, if found at object or in object's text
222 if ( !sURL
.isEmpty() && ScGlobal::ShouldOpenURL() )
224 ScGlobal::OpenURL( sURL
, sTarget
);
225 rViewShell
.FakeButtonUp( rViewShell
.GetViewData().GetActivePart() );
226 return true; // no CaptureMouse etc.
229 // Is another object being edited in this view?
230 // (Editing is ended in MarkListHasChanged - test before UnmarkAll)
231 SfxInPlaceClient
* pClient
= rViewShell
.GetIPClient();
232 bool bWasOleActive
= ( pClient
&& pClient
->IsObjectInPlaceActive() );
236 // do not allow multiselection with note caption
237 bool bCaptionClicked
= IsNoteCaptionClicked( aMDPos
);
238 if ( !rMEvt
.IsShift() || bCaptionClicked
|| IsNoteCaptionMarked() )
241 /* Unlock internal layer, if a note caption is clicked. The
242 layer will be relocked in ScDrawView::MarkListHasChanged(). */
243 if( bCaptionClicked
)
244 pView
->UnlockInternalLayer();
246 // try to select the clicked object
247 if ( pView
->MarkObj( aMDPos
, -2, false, rMEvt
.IsMod1() ) )
252 if (pView
->IsMarkedHit(aMDPos
))
254 // Don't start drag timer if inplace editing of an OLE object
255 // was just ended with this mouse click - the view will be moved
256 // (different tool bars) and the object that was clicked on would
257 // be moved unintentionally.
258 if ( !bWasOleActive
)
261 pHdl
=pView
->PickHandle(aMDPos
);
262 pView
->BegDragObj(aMDPos
, nullptr, pHdl
);
265 else // object at the edge
266 if (rViewShell
.IsDrawSelMode())
271 if (rViewShell
.IsDrawSelMode())
276 pView
->BegMarkObj(aMDPos
);
287 // VC calls CaptureMouse itself
288 pWindow
->CaptureMouse();
289 ForcePointer(&rMEvt
);
295 bool FuSelection::MouseMove(const MouseEvent
& rMEvt
)
297 bool bReturn
= FuDraw::MouseMove(rMEvt
);
299 if (aDragTimer
.IsActive() )
301 Point aOldPixel
= pWindow
->LogicToPixel( aMDPos
);
302 Point aNewPixel
= rMEvt
.GetPosPixel();
303 if ( std::abs( aOldPixel
.X() - aNewPixel
.X() ) > SC_MAXDRAGMOVE
||
304 std::abs( aOldPixel
.Y() - aNewPixel
.Y() ) > SC_MAXDRAGMOVE
)
308 if ( pView
->IsAction() )
310 Point
aPix(rMEvt
.GetPosPixel());
311 Point
aPnt(pWindow
->PixelToLogic(aPix
));
314 pView
->MovAction(aPnt
);
318 ForcePointer(&rMEvt
);
323 bool FuSelection::MouseButtonUp(const MouseEvent
& rMEvt
)
325 // remember button state for creation of own MouseEvents
326 SetMouseButtonCode(rMEvt
.GetButtons());
328 bool bReturn
= FuDraw::MouseButtonUp(rMEvt
);
329 bool bOle
= rViewShell
.GetViewFrame()->GetFrame().IsInPlace();
331 SdrObject
* pObj
= nullptr;
332 if (aDragTimer
.IsActive() )
337 sal_uInt16 nDrgLog
= sal_uInt16 ( pWindow
->PixelToLogic(Size(SC_MINDRAGMOVE
,0)).Width() );
338 Point
aPnt( pWindow
->PixelToLogic( rMEvt
.GetPosPixel() ) );
341 ScViewData
& rViewData
= rViewShell
.GetViewData();
342 ScDocument
* pDocument
= rViewData
.GetDocument();
343 SdrPageView
* pPageView
= ( pView
? pView
->GetSdrPageView() : nullptr );
344 SdrPage
* pPage
= ( pPageView
? pPageView
->GetPage() : nullptr );
345 ::std::vector
< OUString
> aExcludedChartNames
;
346 ScRangeListVector aProtectedChartRangesVector
;
348 if (pView
&& rMEvt
.IsLeft())
350 if ( pView
->IsDragObj() )
353 if ( rMEvt
.IsMod1() )
357 ScChartHelper::GetChartNames( aExcludedChartNames
, pPage
);
359 if ( pView
&& pDocument
)
361 const SdrMarkList
& rSdrMarkList
= pView
->GetMarkedObjectList();
362 const size_t nMarkCount
= rSdrMarkList
.GetMarkCount();
363 for ( size_t i
= 0; i
< nMarkCount
; ++i
)
365 SdrMark
* pMark
= rSdrMarkList
.GetMark( i
);
366 pObj
= ( pMark
? pMark
->GetMarkedSdrObj() : nullptr );
369 ScChartHelper::AddRangesIfProtectedChart( aProtectedChartRangesVector
, pDocument
, pObj
);
376 if (!rMEvt
.IsShift() && !rMEvt
.IsMod1() && !rMEvt
.IsMod2() &&
377 std::abs(aPnt
.X() - aMDPos
.X()) < nDrgLog
&&
378 std::abs(aPnt
.Y() - aMDPos
.Y()) < nDrgLog
)
380 /* If a user wants to click on an object in front of a marked
381 one, he releases the mouse button immediately */
382 SdrPageView
* pPV
= nullptr;
383 pObj
= pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::ALSOONMASTER
| SdrSearchOptions::BEFOREMARK
);
386 pView
->UnmarkAllObj();
387 pView
->MarkObj(pObj
,pPV
);
391 pView
->EndDragObj( rMEvt
.IsMod1() );
392 pView
->ForceMarkedToAnotherPage();
396 else if (pView
->IsAction() )
398 // unlock internal layer to include note captions
399 pView
->UnlockInternalLayer();
401 if ( pView
->AreObjectsMarked() )
405 /* if multi-selection contains a note caption object, remove
406 all other objects from selection. */
407 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
408 const size_t nCount
= rMarkList
.GetMarkCount();
412 for( size_t nIdx
= 0; !bFound
&& (nIdx
< nCount
); ++nIdx
)
414 pObj
= rMarkList
.GetMark( nIdx
)->GetMarkedSdrObj();
415 bFound
= ScDrawLayer::IsNoteCaption( pObj
);
419 pView
->MarkObj( pObj
, pView
->GetSdrPageView() );
427 // maybe consider OLE object
428 SfxInPlaceClient
* pIPClient
= rViewShell
.GetIPClient();
432 ScModule
* pScMod
= SC_MOD();
433 bool bUnoRefDialog
= pScMod
->IsRefDialogOpen() && pScMod
->GetCurRefDlgId() == WID_SIMPLE_REF
;
435 if ( pIPClient
->IsObjectInPlaceActive() && !bUnoRefDialog
)
436 pIPClient
->DeactivateObject();
439 sal_uInt16 nClicks
= rMEvt
.GetClicks();
440 if (pView
&& nClicks
== 2 && rMEvt
.IsLeft())
442 if ( pView
->AreObjectsMarked() )
444 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
445 if (rMarkList
.GetMarkCount() == 1)
447 SdrMark
* pMark
= rMarkList
.GetMark(0);
448 pObj
= pMark
->GetMarkedSdrObj();
450 // only activate, when the mouse also is over the selected object
453 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
);
454 if (eHit
!= SdrHitKind::NONE
&& aVEvt
.pObj
== pObj
)
456 sal_uInt16 nSdrObjKind
= pObj
->GetObjIdentifier();
460 if (nSdrObjKind
== OBJ_OLE2
)
464 if (static_cast<SdrOle2Obj
*>(pObj
)->GetObjRef().is())
466 rViewShell
.ActivateObject( static_cast<SdrOle2Obj
*>(pObj
), 0 );
472 // not in UNO controls
473 // #i32352# not in media objects
475 else if ( dynamic_cast<const SdrTextObj
*>( pObj
) != nullptr && dynamic_cast<const SdrUnoObj
*>( pObj
) == nullptr && dynamic_cast<const SdrMediaObj
*>( pObj
) == nullptr )
477 OutlinerParaObject
* pOPO
= pObj
->GetOutlinerParaObject();
478 bool bVertical
= ( pOPO
&& pOPO
->IsVertical() );
479 sal_uInt16 nTextSlotId
= bVertical
? SID_DRAW_TEXT_VERTICAL
: SID_DRAW_TEXT
;
481 rViewShell
.GetViewData().GetDispatcher().
482 Execute(nTextSlotId
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
484 // Get the created FuText now and change into EditMode
485 FuPoor
* pPoor
= rViewShell
.GetViewData().GetView()->GetDrawFuncPtr();
486 if ( pPoor
&& pPoor
->GetSlotID() == nTextSlotId
) // has no RTTI
488 FuText
* pText
= static_cast<FuText
*>(pPoor
);
489 Point aMousePixel
= rMEvt
.GetPosPixel();
490 pText
->SetInEditMode( pObj
, &aMousePixel
);
497 else if ( TestDetective( pView
->GetSdrPageView(), aPnt
) )
501 ForcePointer(&rMEvt
);
503 if (pWindow
->IsMouseCaptured())
504 pWindow
->ReleaseMouse();
506 // command handler for context menu follows after MouseButtonUp,
507 // therefore here the hard IsLeft call
508 if ( !bReturn
&& rMEvt
.IsLeft() )
509 if (rViewShell
.IsDrawSelMode())
510 rViewShell
.GetViewData().GetDispatcher().
511 Execute(SID_OBJECT_SELECT
, SfxCallMode::SLOT
| SfxCallMode::RECORD
);
513 if ( bCopy
&& pDocument
&& pPage
)
515 ScDocShell
* pDocShell
= rViewData
.GetDocShell();
516 ScModelObj
* pModelObj
= ( pDocShell
? comphelper::getUnoTunnelImplementation
<ScModelObj
>( pDocShell
->GetModel() ) : nullptr );
519 SCTAB nTab
= rViewData
.GetTabNo();
520 ScChartHelper::CreateProtectedChartListenersAndNotify( pDocument
, pPage
, pModelObj
, nTab
,
521 aProtectedChartRangesVector
, aExcludedChartNames
);
528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */