Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / ui / drawfunc / fusel.cxx
blobcaffb9c1410b91ebefc62225e16bee9a679d6ec1
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 <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>
35 #include <fusel.hxx>
36 #include <sc.hrc>
37 #include <fudraw.hxx>
38 #include <futext.hxx>
39 #include <drawview.hxx>
40 #include <tabvwsh.hxx>
41 #include <drwlayer.hxx>
42 #include <userdat.hxx>
43 #include <scmod.hxx>
44 #include <charthelper.hxx>
45 #include <docuno.hxx>
46 #include <docsh.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() )
73 if ( bSelectionOnly )
74 pView->BckAction();
75 return true;
78 bIsInDragMode = false; // somewhere it has to be reset (#50033#)
80 bool bReturn = FuDraw::MouseButtonDown(rMEvt);
82 aMDPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
84 if ( rMEvt.IsLeft() )
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.
94 bool bDrag = false;
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))
103 bDrag = true;
104 // move the complete note box.
105 else if(!pHdl)
106 bDrag = true;
108 else
109 bDrag = true; // different object
111 else
112 bDrag = true; // several objects
114 if ( bDrag )
116 aDragTimer.Start();
117 if (pView->BegDragObj(aMDPos, nullptr, pHdl))
118 pView->GetDragMethod()->SetShiftPressed( rMEvt.IsShift() );
119 bReturn = true;
122 else
124 SdrPageView* pPV = nullptr;
125 bool bAlt = rMEvt.IsMod2();
126 SdrObject* pObj = !bAlt ? pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) : nullptr;
127 if (pObj)
129 pView->BegMacroObj(aMDPos, pObj, pPV, pWindow);
130 bReturn = true;
132 else
134 OUString sURL, sTarget;
135 pObj = !bAlt ? pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER) : nullptr;
136 if (pObj)
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
151 // object clicked
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);
159 if (pHit)
160 pObj = pHit;
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 );
176 uno::Any aCaller;
177 if ( xProps.is() )
181 aCaller = xProps->getPropertyValue("Name");
183 catch( uno::Exception& ) {}
185 uno::Any aRet;
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.
197 // URL / ImageMap
199 SdrViewEvent aVEvt;
200 if ( !bAlt &&
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() );
234 // Selection
236 // do not allow multiselection with note caption
237 bool bCaptionClicked = IsNoteCaptionClicked( aMDPos );
238 if ( !rMEvt.IsShift() || bCaptionClicked || IsNoteCaptionMarked() )
239 pView->UnmarkAll();
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() ) )
250 // move object
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 )
259 aDragTimer.Start();
261 pHdl=pView->PickHandle(aMDPos);
262 pView->BegDragObj(aMDPos, nullptr, pHdl);
263 bReturn = true;
265 else // object at the edge
266 if (rViewShell.IsDrawSelMode())
267 bReturn = true;
269 else
271 if (rViewShell.IsDrawSelMode())
274 // select object
276 pView->BegMarkObj(aMDPos);
277 bReturn = true;
285 if (!bIsInDragMode)
287 // VC calls CaptureMouse itself
288 pWindow->CaptureMouse();
289 ForcePointer(&rMEvt);
292 return bReturn;
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 )
305 aDragTimer.Stop();
308 if ( pView->IsAction() )
310 Point aPix(rMEvt.GetPosPixel());
311 Point aPnt(pWindow->PixelToLogic(aPix));
313 ForceScroll(aPix);
314 pView->MovAction(aPnt);
315 bReturn = true;
318 ForcePointer(&rMEvt);
320 return bReturn;
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() )
334 aDragTimer.Stop();
337 sal_uInt16 nDrgLog = sal_uInt16 ( pWindow->PixelToLogic(Size(SC_MINDRAGMOVE,0)).Width() );
338 Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
340 bool bCopy = false;
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() )
352 // object was moved
353 if ( rMEvt.IsMod1() )
355 if ( pPage )
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 );
367 if ( pObj )
369 ScChartHelper::AddRangesIfProtectedChart( aProtectedChartRangesVector, pDocument, pObj );
373 bCopy = true;
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);
384 if (pObj)
386 pView->UnmarkAllObj();
387 pView->MarkObj(pObj,pPV);
388 return true;
391 pView->EndDragObj( rMEvt.IsMod1() );
392 pView->ForceMarkedToAnotherPage();
394 bReturn = true;
396 else if (pView->IsAction() )
398 // unlock internal layer to include note captions
399 pView->UnlockInternalLayer();
400 pView->EndAction();
401 if ( pView->AreObjectsMarked() )
403 bReturn = true;
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();
409 if( nCount > 1 )
411 bool bFound = false;
412 for( size_t nIdx = 0; !bFound && (nIdx < nCount); ++nIdx )
414 pObj = rMarkList.GetMark( nIdx )->GetMarkedSdrObj();
415 bFound = ScDrawLayer::IsNoteCaption( pObj );
416 if( bFound )
418 pView->UnMarkAll();
419 pView->MarkObj( pObj, pView->GetSdrPageView() );
427 // maybe consider OLE object
428 SfxInPlaceClient* pIPClient = rViewShell.GetIPClient();
430 if (pIPClient)
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
452 SdrViewEvent aVEvt;
453 SdrHitKind eHit = pView->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
454 if (eHit != SdrHitKind::NONE && aVEvt.pObj == pObj)
456 sal_uInt16 nSdrObjKind = pObj->GetObjIdentifier();
458 // OLE: activate
460 if (nSdrObjKind == OBJ_OLE2)
462 if (!bOle)
464 if (static_cast<SdrOle2Obj*>(pObj)->GetObjRef().is())
466 rViewShell.ActivateObject( static_cast<SdrOle2Obj*>(pObj), 0 );
471 // Edit text
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 );
492 bReturn = true;
497 else if ( TestDetective( pView->GetSdrPageView(), aPnt ) )
498 bReturn = true;
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 );
517 if ( pModelObj )
519 SCTAB nTab = rViewData.GetTabNo();
520 ScChartHelper::CreateProtectedChartListenersAndNotify( pDocument, pPage, pModelObj, nTab,
521 aProtectedChartRangesVector, aExcludedChartNames );
525 return bReturn;
528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */