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 <com/sun/star/embed/EmbedVerbs.hpp>
21 #include <editeng/flditem.hxx>
22 #include <svx/svddrgmt.hxx>
23 #include <svx/svdoole2.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>
34 #include <comphelper/lok.hxx>
40 #include <drawview.hxx>
41 #include <tabvwsh.hxx>
42 #include <drwlayer.hxx>
43 #include <userdat.hxx>
45 #include <charthelper.hxx>
48 #include <stlpool.hxx>
50 // maximal permitted mouse movement to start Drag&Drop
51 //! fusel,fuconstr,futext - combine them!
52 #define SC_MAXDRAGMOVE 3
53 // Min necessary mouse motion for normal dragging
54 #define SC_MINDRAGMOVE 2
56 using namespace com::sun::star
;
58 FuSelection::FuSelection(ScTabViewShell
& rViewSh
, vcl::Window
* pWin
, ScDrawView
* pViewP
,
59 SdrModel
* pDoc
, const SfxRequest
& rReq
)
60 : FuDraw(rViewSh
, pWin
, pViewP
, pDoc
, rReq
)
64 FuSelection::~FuSelection()
68 bool FuSelection::MouseButtonDown(const MouseEvent
& rMEvt
)
70 // remember button state for creation of own MouseEvents
71 SetMouseButtonCode(rMEvt
.GetButtons());
72 const bool bSelectionOnly
= rMEvt
.IsRight();
73 if ( pView
->IsAction() )
80 bIsInDragMode
= false; // somewhere it has to be reset (#50033#)
82 bool bReturn
= FuDraw::MouseButtonDown(rMEvt
);
83 auto aLogicPosition
= rMEvt
.getLogicPosition();
85 aMDPos
= *aLogicPosition
;
87 aMDPos
= pWindow
->PixelToLogic(rMEvt
.GetPosPixel());
89 if (comphelper::LibreOfficeKit::isActive())
91 ScViewData
& rViewData
= rViewShell
.GetViewData();
92 ScDocument
& rDocument
= rViewData
.GetDocument();
93 if (rDocument
.IsNegativePage(rViewData
.GetTabNo()))
94 aMDPos
.setX(-aMDPos
.X());
99 SdrHdl
* pHdl
= pView
->PickHandle(aMDPos
);
101 if ( pHdl
!=nullptr || pView
->IsMarkedHit(aMDPos
) )
103 // Determine if this is the tail of a SdrCaptionObj i.e.
104 // we need to disable the drag option on the tail of a note
105 // object. Also, disable the ability to use the circular
106 // drag of a note object.
108 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
109 if( rMarkList
.GetMarkCount() == 1 )
111 SdrObject
* pMarkedObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
112 if( ScDrawLayer::IsNoteCaption( pMarkedObj
) )
114 // move using the valid caption handles for note text box.
115 if(pHdl
&& (pHdl
->GetKind() != SdrHdlKind::Poly
&& pHdl
->GetKind() != SdrHdlKind::Circle
))
117 // move the complete note box.
122 bDrag
= true; // different object
125 bDrag
= true; // several objects
130 if (pView
->BegDragObj(aMDPos
, nullptr, pHdl
))
131 pView
->GetDragMethod()->SetShiftPressed( rMEvt
.IsShift() );
137 SdrPageView
* pPV
= nullptr;
138 bool bAlt
= rMEvt
.IsMod2();
139 SdrObject
* pObj
= !bAlt
? pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::PICKMACRO
) : nullptr;
142 pView
->BegMacroObj(aMDPos
, pObj
, pPV
, pWindow
);
147 OUString sURL
, sTarget
;
148 pObj
= !bAlt
? pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::ALSOONMASTER
) : nullptr;
151 // Support for imported Excel docs
152 // Excel is of course not consistent and allows
153 // a hyperlink to be assigned for an object group
154 // and even though the hyperlink is exported in the Escher layer
155 // its never used, when dealing with a group object the link
156 // associated with the clicked object is used only
158 // additionally you can also select a macro in Excel for a grouped
159 // objects and this *usually* results in the macro being set
160 // for the elements in the group and no macro is exported
161 // for the group itself ( this however is not always true )
162 // if a macro and hlink are defined favour the hlink
163 // If a group object has no hyperlink use the hyperlink of the
166 if ( pObj
->IsGroupObject() )
168 ScMacroInfo
* pTmpInfo
= ScDrawLayer::GetMacroInfo( pObj
);
169 if ( !pTmpInfo
|| pTmpInfo
->GetMacro().isEmpty() )
171 SdrObject
* pHit
= pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::DEEP
);
177 ScMacroInfo
* pInfo
= ScDrawLayer::GetMacroInfo( pObj
, true );
178 // For interoperability favour links over macros if both are defined
179 if ( !pObj
->getHyperlink().isEmpty() )
181 sURL
= pObj
->getHyperlink();
183 else if ( !pInfo
->GetMacro().isEmpty() )
185 SfxObjectShell
* pObjSh
= SfxObjectShell::Current();
186 if ( pObjSh
&& SfxApplication::IsXScriptURL( pInfo
->GetMacro() ) )
188 uno::Reference
< beans::XPropertySet
> xProps( pObj
->getUnoShape(), uno::UNO_QUERY
);
194 aCaller
= xProps
->getPropertyValue(u
"Name"_ustr
);
196 catch( uno::Exception
& ) {}
199 uno::Sequence
< sal_Int16
> aOutArgsIndex
;
200 uno::Sequence
< uno::Any
> aOutArgs
;
201 uno::Sequence
< uno::Any
> aInArgs
;
202 pObjSh
->CallXScript( pInfo
->GetMacro(),
203 aInArgs
, aRet
, aOutArgsIndex
, aOutArgs
, true, &aCaller
);
204 rViewShell
.FakeButtonUp( rViewShell
.GetViewData().GetActivePart() );
205 return true; // no CaptureMouse etc.
214 pView
->PickAnything( rMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
) != SdrHitKind::NONE
&&
215 aVEvt
.mpObj
!= nullptr )
217 if ( SvxIMapInfo::GetIMapInfo( aVEvt
.mpObj
) ) // ImageMap
219 const IMapObject
* pIMapObj
=
220 SvxIMapInfo::GetHitIMapObject( aVEvt
.mpObj
, aMDPos
, pWindow
->GetOutDev() );
221 if ( pIMapObj
&& !pIMapObj
->GetURL().isEmpty() )
223 sURL
= pIMapObj
->GetURL();
224 sTarget
= pIMapObj
->GetTarget();
227 if ( aVEvt
.meEvent
== SdrEventKind::ExecuteUrl
&& aVEvt
.mpURLField
) // URL
229 sURL
= aVEvt
.mpURLField
->GetURL();
230 sTarget
= aVEvt
.mpURLField
->GetTargetFrame();
234 // open hyperlink, if found at object or in object's text
235 // Fragments pointing into the current document should be always opened.
236 if ( !sURL
.isEmpty() && (ScGlobal::ShouldOpenURL() || sURL
.startsWith("#")) )
238 ScGlobal::OpenURL( sURL
, sTarget
);
239 rViewShell
.FakeButtonUp( rViewShell
.GetViewData().GetActivePart() );
240 return true; // no CaptureMouse etc.
243 // Is another object being edited in this view?
244 // (Editing is ended in MarkListHasChanged - test before UnmarkAll)
245 SfxInPlaceClient
* pClient
= rViewShell
.GetIPClient();
246 bool bWasOleActive
= ( pClient
&& pClient
->IsObjectInPlaceActive() );
250 // do not allow multiselection with note caption
251 bool bCaptionClicked
= IsNoteCaptionClicked( aMDPos
);
252 if ( !rMEvt
.IsShift() || bCaptionClicked
|| IsNoteCaptionMarked() )
255 /* Unlock internal layer, if a note caption is clicked. The
256 layer will be relocked in ScDrawView::MarkListHasChanged(). */
257 if( bCaptionClicked
)
258 pView
->UnlockInternalLayer();
260 // try to select the clicked object
261 if ( pView
->MarkObj( aMDPos
, -2, false, rMEvt
.IsMod1() ) )
266 if (pView
->IsMarkedHit(aMDPos
))
268 // Don't start drag timer if inplace editing of an OLE object
269 // was just ended with this mouse click - the view will be moved
270 // (different tool bars) and the object that was clicked on would
271 // be moved unintentionally.
272 if ( !bWasOleActive
)
275 pHdl
=pView
->PickHandle(aMDPos
);
276 pView
->BegDragObj(aMDPos
, nullptr, pHdl
);
279 else // object at the edge
280 if (rViewShell
.IsDrawSelMode())
285 if (rViewShell
.IsDrawSelMode())
290 pView
->BegMarkObj(aMDPos
);
301 // VC calls CaptureMouse itself
302 pWindow
->CaptureMouse();
303 ForcePointer(&rMEvt
);
309 bool FuSelection::MouseMove(const MouseEvent
& rMEvt
)
311 bool bReturn
= FuDraw::MouseMove(rMEvt
);
313 if (aDragTimer
.IsActive() )
315 Point aOldPixel
= pWindow
->LogicToPixel( aMDPos
);
316 Point aNewPixel
= rMEvt
.GetPosPixel();
317 if ( std::abs( aOldPixel
.X() - aNewPixel
.X() ) > SC_MAXDRAGMOVE
||
318 std::abs( aOldPixel
.Y() - aNewPixel
.Y() ) > SC_MAXDRAGMOVE
)
322 if ( pView
->IsAction() )
324 Point
aPix(rMEvt
.GetPosPixel());
325 Point
aPnt(pWindow
->PixelToLogic(aPix
));
328 pView
->MovAction(aPnt
);
332 ForcePointer(&rMEvt
);
337 bool FuSelection::MouseButtonUp(const MouseEvent
& rMEvt
)
339 // remember button state for creation of own MouseEvents
340 SetMouseButtonCode(rMEvt
.GetButtons());
342 bool bReturn
= FuDraw::MouseButtonUp(rMEvt
);
343 bool bOle
= rViewShell
.GetViewFrame().GetFrame().IsInPlace();
345 SdrObject
* pObj
= nullptr;
346 if (aDragTimer
.IsActive() )
351 sal_uInt16 nDrgLog
= sal_uInt16 ( pWindow
->PixelToLogic(Size(SC_MINDRAGMOVE
,0)).Width() );
352 auto aLogicPosition
= rMEvt
.getLogicPosition();
353 Point
aPnt(aLogicPosition
? *aLogicPosition
: pWindow
->PixelToLogic(rMEvt
.GetPosPixel()));
356 ScViewData
& rViewData
= rViewShell
.GetViewData();
357 ScDocument
& rDocument
= rViewData
.GetDocument();
358 SdrPageView
* pPageView
= ( pView
? pView
->GetSdrPageView() : nullptr );
359 SdrPage
* pPage
= ( pPageView
? pPageView
->GetPage() : nullptr );
360 ::std::vector
< OUString
> aExcludedChartNames
;
361 ScRangeListVector aProtectedChartRangesVector
;
363 if (comphelper::LibreOfficeKit::isActive() && rDocument
.IsNegativePage(rViewData
.GetTabNo()))
364 aPnt
.setX(-aPnt
.X());
366 if (pView
&& rMEvt
.IsLeft())
368 if ( pView
->IsDragObj() )
371 if ( rMEvt
.IsMod1() )
375 ScChartHelper::GetChartNames( aExcludedChartNames
, pPage
);
379 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
380 const size_t nMarkCount
= rMarkList
.GetMarkCount();
381 for ( size_t i
= 0; i
< nMarkCount
; ++i
)
383 SdrMark
* pMark
= rMarkList
.GetMark( i
);
384 pObj
= ( pMark
? pMark
->GetMarkedSdrObj() : nullptr );
387 ScChartHelper::AddRangesIfProtectedChart( aProtectedChartRangesVector
, rDocument
, pObj
);
394 if (!rMEvt
.IsShift() && !rMEvt
.IsMod1() && !rMEvt
.IsMod2() &&
395 std::abs(aPnt
.X() - aMDPos
.X()) < nDrgLog
&&
396 std::abs(aPnt
.Y() - aMDPos
.Y()) < nDrgLog
)
398 /* If a user wants to click on an object in front of a marked
399 one, he releases the mouse button immediately */
400 SdrPageView
* pPV
= nullptr;
401 pObj
= pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pPV
, SdrSearchOptions::ALSOONMASTER
| SdrSearchOptions::BEFOREMARK
);
404 pView
->UnmarkAllObj();
405 pView
->MarkObj(pObj
,pPV
);
409 pView
->EndDragObj( rMEvt
.IsMod1() );
410 pView
->ForceMarkedToAnotherPage();
414 else if (pView
->IsAction() )
416 // unlock internal layer to include note captions
417 pView
->UnlockInternalLayer();
419 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
420 if ( rMarkList
.GetMarkCount() != 0 )
424 /* if multi-selection contains a note caption object, remove
425 all other objects from selection. */
426 const size_t nCount
= rMarkList
.GetMarkCount();
430 for( size_t nIdx
= 0; !bFound
&& (nIdx
< nCount
); ++nIdx
)
432 pObj
= rMarkList
.GetMark( nIdx
)->GetMarkedSdrObj();
433 bFound
= ScDrawLayer::IsNoteCaption( pObj
);
437 pView
->MarkObj( pObj
, pView
->GetSdrPageView() );
444 if (ScModule::get()->GetIsWaterCan())
446 auto pStyleSheet
= rViewData
.GetDocument().GetStyleSheetPool()->GetActualStyleSheet();
447 if (pStyleSheet
&& pStyleSheet
->GetFamily() == SfxStyleFamily::Frame
)
448 pView
->SetStyleSheet(static_cast<SfxStyleSheet
*>(pStyleSheet
), false);
452 // maybe consider OLE object
453 SfxInPlaceClient
* pIPClient
= rViewShell
.GetIPClient();
457 ScModule
* pScMod
= ScModule::get();
458 bool bUnoRefDialog
= pScMod
->IsRefDialogOpen() && pScMod
->GetCurRefDlgId() == WID_SIMPLE_REF
;
460 if ( pIPClient
->IsObjectInPlaceActive() && !bUnoRefDialog
)
461 pIPClient
->DeactivateObject();
464 sal_uInt16 nClicks
= rMEvt
.GetClicks();
465 if (pView
&& nClicks
== 2 && rMEvt
.IsLeft())
467 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
468 if ( rMarkList
.GetMarkCount() != 0 )
470 if (rMarkList
.GetMarkCount() == 1)
472 SdrMark
* pMark
= rMarkList
.GetMark(0);
473 pObj
= pMark
->GetMarkedSdrObj();
475 // only activate, when the mouse also is over the selected object
478 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
);
479 if (eHit
!= SdrHitKind::NONE
&& aVEvt
.mpObj
== pObj
)
483 SdrObjKind nSdrObjKind
= pObj
->GetObjIdentifier();
487 if (nSdrObjKind
== SdrObjKind::OLE2
)
491 if (static_cast<SdrOle2Obj
*>(pObj
)->GetObjRef().is())
493 // release so if ActivateObject launches a warning dialog, then that dialog
494 // can get mouse events
495 if (pWindow
->IsMouseCaptured())
496 pWindow
->ReleaseMouse();
497 rViewShell
.ActivateObject(static_cast<SdrOle2Obj
*>(pObj
), css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY
);
503 // not in UNO controls
504 // #i32352# not in media objects
506 else if ( DynCastSdrTextObj( pObj
) != nullptr && dynamic_cast<const SdrUnoObj
*>( pObj
) == nullptr && dynamic_cast<const SdrMediaObj
*>( pObj
) == nullptr )
508 OutlinerParaObject
* pOPO
= pObj
->GetOutlinerParaObject();
509 bool bVertical
= ( pOPO
&& pOPO
->IsEffectivelyVertical() );
510 sal_uInt16 nTextSlotId
= bVertical
? SID_DRAW_TEXT_VERTICAL
: SID_DRAW_TEXT
;
512 rViewShell
.GetViewData().GetDispatcher().
513 Execute(nTextSlotId
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
515 // Get the created FuText now and change into EditMode
516 FuPoor
* pPoor
= rViewShell
.GetViewData().GetView()->GetDrawFuncPtr();
517 if ( pPoor
&& pPoor
->GetSlotID() == nTextSlotId
) // has no RTTI
519 FuText
* pText
= static_cast<FuText
*>(pPoor
);
520 Point aMousePixel
= rMEvt
.GetPosPixel();
521 pText
->SetInEditMode( pObj
, &aMousePixel
);
528 else if ( TestDetective( pView
->GetSdrPageView(), aPnt
) )
532 ForcePointer(&rMEvt
);
534 if (pWindow
->IsMouseCaptured())
535 pWindow
->ReleaseMouse();
537 // command handler for context menu follows after MouseButtonUp,
538 // therefore here the hard IsLeft call
539 if ( !bReturn
&& rMEvt
.IsLeft() )
540 if (rViewShell
.IsDrawSelMode())
541 rViewShell
.GetViewData().GetDispatcher().
542 Execute(SID_OBJECT_SELECT
, SfxCallMode::SLOT
| SfxCallMode::RECORD
);
544 if ( bCopy
&& pPage
)
546 ScDocShell
* pDocShell
= rViewData
.GetDocShell();
547 ScModelObj
* pModelObj
= ( pDocShell
? pDocShell
->GetModel() : nullptr );
550 SCTAB nTab
= rViewData
.GetTabNo();
551 ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument
, pPage
, pModelObj
, nTab
,
552 aProtectedChartRangesVector
, aExcludedChartNames
);
559 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */