1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <sal/config.h>
21
22 #include <vcl/svapp.hxx>
23 #include <vcl/ptrstyle.hxx>
24 #include <editeng/flditem.hxx>
25 #include <svx/svdogrp.hxx>
26 #include <tools/urlobj.hxx>
27 #include <vcl/help.hxx>
28 #include <svx/bmpmask.hxx>
29 #include <svx/svdotext.hxx>
30 #include <svx/ImageMapInfo.hxx>
31 #include <sfx2/dispatch.hxx>
32 #include <sfx2/bindings.hxx>
33 #include <sfx2/sfxhelp.hxx>
34 #include <svx/svdpagv.hxx>
35 #include <vcl/imapobj.hxx>
36 #include <svx/svxids.hrc>
37 #include <svx/obj3d.hxx>
38 #include <svx/scene3d.hxx>
39 #include <sfx2/viewfrm.hxx>
40
41 #include <strings.hrc>
42
43
44 #include <sdmod.hxx>
45 #include <fudraw.hxx>
46 #include <ViewShell.hxx>
47 #include <FrameView.hxx>
48 #include <View.hxx>
49 #include <Window.hxx>
50 #include <drawdoc.hxx>
51 #include <DrawDocShell.hxx>
52 #include <sdresid.hxx>
53 #include <fusel.hxx>
54 #include <vcl/weld.hxx>
55 #include <svx/sdrhittesthelper.hxx>
56
57 using namespace ::com::sun::star;
58
59 namespace sd {
60
61
62 /**
63 * Base-class for all drawmodul-specific functions
64 */
FuDraw(ViewShell * pViewSh,::sd::Window * pWin,::sd::View * pView,SdDrawDocument * pDoc,SfxRequest & rReq)65 FuDraw::FuDraw(ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView,
66 SdDrawDocument* pDoc, SfxRequest& rReq)
67 : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
68 , aNewPointer(PointerStyle::Arrow)
69 , aOldPointer(PointerStyle::Arrow)
70 , bMBDown(false)
71 , bDragHelpLine(false)
72 , nHelpLine(0)
73 , bPermanent(false)
74 {
75 }
76
~FuDraw()77 FuDraw::~FuDraw()
78 {
79 mpView->BrkAction();
80 }
81
82
83 /**
84 * Code shared by MouseButtonDown and MouseMove
85 */
DoModifiers(const MouseEvent & rMEvt,bool bSnapModPressed)86 void FuDraw::DoModifiers(const MouseEvent& rMEvt, bool bSnapModPressed)
87 {
88 FrameView* pFrameView = mpViewShell->GetFrameView();
89 bool bGridSnap = pFrameView->IsGridSnap();
90 bGridSnap = (bSnapModPressed != bGridSnap);
91
92 if (mpView->IsGridSnap() != bGridSnap)
93 mpView->SetGridSnap(bGridSnap);
94
95 bool bBordSnap = pFrameView->IsBordSnap();
96 bBordSnap = (bSnapModPressed != bBordSnap);
97
98 if (mpView->IsBordSnap() != bBordSnap)
99 mpView->SetBordSnap(bBordSnap);
100
101 bool bHlplSnap = pFrameView->IsHlplSnap();
102 bHlplSnap = (bSnapModPressed != bHlplSnap);
103
104 if (mpView->IsHlplSnap() != bHlplSnap)
105 mpView->SetHlplSnap(bHlplSnap);
106
107 bool bOFrmSnap = pFrameView->IsOFrmSnap();
108 bOFrmSnap = (bSnapModPressed != bOFrmSnap);
109
110 if (mpView->IsOFrmSnap() != bOFrmSnap)
111 mpView->SetOFrmSnap(bOFrmSnap);
112
113 bool bOPntSnap = pFrameView->IsOPntSnap();
114 bOPntSnap = (bSnapModPressed != bOPntSnap);
115
116 if (mpView->IsOPntSnap() != bOPntSnap)
117 mpView->SetOPntSnap(bOPntSnap);
118
119 bool bOConSnap = pFrameView->IsOConSnap();
120 bOConSnap = (bSnapModPressed != bOConSnap);
121
122 if (mpView->IsOConSnap() != bOConSnap)
123 mpView->SetOConSnap(bOConSnap);
124
125 bool bAngleSnap = rMEvt.IsShift() == !pFrameView->IsAngleSnapEnabled();
126
127 if (mpView->IsAngleSnapEnabled() != bAngleSnap)
128 mpView->SetAngleSnapEnabled(bAngleSnap);
129
130 bool bCenter = rMEvt.IsMod2();
131
132 if ( mpView->IsCreate1stPointAsCenter() != bCenter ||
133 mpView->IsResizeAtCenter() != bCenter )
134 {
135 mpView->SetCreate1stPointAsCenter(bCenter);
136 mpView->SetResizeAtCenter(bCenter);
137 }
138 }
139
140
MouseButtonDown(const MouseEvent & rMEvt)141 bool FuDraw::MouseButtonDown(const MouseEvent& rMEvt)
142 {
143 // remember button state for creation of own MouseEvents
144 SetMouseButtonCode(rMEvt.GetButtons());
145
146 bool bReturn = false;
147 bDragHelpLine = false;
148 aMDPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
149
150 if ( rMEvt.IsLeft() )
151 {
152 FrameView* pFrameView = mpViewShell->GetFrameView();
153
154 bool bOrtho = false;
155
156 bool bRestricted = true;
157
158 if (mpView->IsDragObj())
159 {
160 // object is dragged (move, resize,...)
161 const SdrHdl* pHdl = mpView->GetDragStat().GetHdl();
162
163 if (!pHdl || (!pHdl->IsCornerHdl() && !pHdl->IsVertexHdl()))
164 {
165 // Move
166 bRestricted = false;
167 }
168 }
169
170 // #i33136#
171 if(bRestricted && doConstructOrthogonal())
172 {
173 // Restrict movement:
174 // rectangle->square, ellipse->circle, etc.
175 bOrtho = !rMEvt.IsShift();
176 }
177 else
178 {
179 bOrtho = rMEvt.IsShift() != pFrameView->IsOrtho();
180 }
181 if (!mpView->IsSnapEnabled())
182 mpView->SetSnapEnabled(true);
183
184 bool bSnapModPressed = rMEvt.IsMod1();
185 if (mpView->IsOrtho() != bOrtho)
186 mpView->SetOrtho(bOrtho);
187
188 DoModifiers(rMEvt, bSnapModPressed);
189
190 SdrPageView* pPV = nullptr;
191 sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
192
193 // look only for HelpLines when they are visible (!)
194 bool bHelpLine(false);
195 if(mpView->IsHlplVisible())
196 bHelpLine = mpView->PickHelpLine(aMDPos, nHitLog, *mpWindow->GetOutDev(), nHelpLine, pPV);
197 bool bHitHdl = (mpView->PickHandle(aMDPos) != nullptr);
198
199 if ( bHelpLine
200 && !mpView->IsCreateObj()
201 && ((mpView->GetEditMode() == SdrViewEditMode::Edit && !bHitHdl) || (rMEvt.IsShift() && bSnapModPressed)) )
202 {
203 mpWindow->CaptureMouse();
204 mpView->BegDragHelpLine(nHelpLine, pPV);
205 bDragHelpLine = mpView->IsDragHelpLine();
206 bReturn = true;
207 }
208 }
209 ForcePointer(&rMEvt);
210
211 return bReturn;
212 }
213
MouseMove(const MouseEvent & rMEvt)214 bool FuDraw::MouseMove(const MouseEvent& rMEvt)
215 {
216 FrameView* pFrameView = mpViewShell->GetFrameView();
217 Point aPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );
218
219 bool bOrtho = false;
220 bool bRestricted = true;
221
222 if (mpView->IsDragObj())
223 {
224 // object is dragged (move, resize, ...)
225 const SdrHdl* pHdl = mpView->GetDragStat().GetHdl();
226
227 if (!pHdl || (!pHdl->IsCornerHdl() && !pHdl->IsVertexHdl()))
228 {
229 // Move
230 bRestricted = false;
231 }
232 }
233
234 if (mpView->IsAction())
235 {
236 // #i33136# and fdo#88339
237 if(bRestricted && doConstructOrthogonal())
238 {
239 // Scale proportionally by default:
240 // rectangle->square, ellipse->circle, images, etc.
241 bOrtho = !rMEvt.IsShift();
242 }
243 else
244 {
245 bOrtho = rMEvt.IsShift() != pFrameView->IsOrtho();
246 }
247
248 bool bSnapModPressed = rMEvt.IsMod2();
249 mpView->SetDragWithCopy(rMEvt.IsMod1() && pFrameView->IsDragWithCopy());
250
251 if (mpView->IsOrtho() != bOrtho)
252 mpView->SetOrtho(bOrtho);
253 DoModifiers(rMEvt, bSnapModPressed);
254
255
256 if ( mpView->IsDragHelpLine() )
257 mpView->MovDragHelpLine(aPos);
258 }
259
260 bool bReturn = mpView->MouseMove(rMEvt, mpWindow->GetOutDev());
261
262 if (mpView->IsAction())
263 {
264 // Because the flag set back if necessary in MouseMove
265 if (mpView->IsOrtho() != bOrtho)
266 mpView->SetOrtho(bOrtho);
267 }
268
269 ForcePointer(&rMEvt);
270
271 return bReturn;
272 }
273
MouseButtonUp(const MouseEvent & rMEvt)274 bool FuDraw::MouseButtonUp(const MouseEvent& rMEvt)
275 {
276 if (mpView && mpView->IsDragHelpLine())
277 mpView->EndDragHelpLine();
278
279 if ( bDragHelpLine )
280 {
281 ::tools::Rectangle aOutputArea(Point(0,0), mpWindow->GetOutputSizePixel());
282
283 if (mpView && !aOutputArea.Contains(rMEvt.GetPosPixel()))
284 mpView->GetSdrPageView()->DeleteHelpLine(nHelpLine);
285
286 mpWindow->ReleaseMouse();
287 }
288
289 if (mpView)
290 {
291 FrameView* pFrameView = mpViewShell->GetFrameView();
292 mpView->SetOrtho( pFrameView->IsOrtho() );
293 mpView->SetAngleSnapEnabled( pFrameView->IsAngleSnapEnabled() );
294 mpView->SetSnapEnabled(true);
295 mpView->SetCreate1stPointAsCenter(false);
296 mpView->SetResizeAtCenter(false);
297 mpView->SetDragWithCopy(pFrameView->IsDragWithCopy());
298 mpView->SetGridSnap(pFrameView->IsGridSnap());
299 mpView->SetBordSnap(pFrameView->IsBordSnap());
300 mpView->SetHlplSnap(pFrameView->IsHlplSnap());
301 mpView->SetOFrmSnap(pFrameView->IsOFrmSnap());
302 mpView->SetOPntSnap(pFrameView->IsOPntSnap());
303 mpView->SetOConSnap(pFrameView->IsOConSnap());
304 }
305
306 bIsInDragMode = false;
307 ForcePointer(&rMEvt);
308 FuPoor::MouseButtonUp(rMEvt);
309
310 return false;
311 }
312
313 /**
314 * Process keyboard input
315 * @returns sal_True if a KeyEvent is being processed, sal_False otherwise
316 */
KeyInput(const KeyEvent & rKEvt)317 bool FuDraw::KeyInput(const KeyEvent& rKEvt)
318 {
319 bool bReturn = false;
320 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
321
322 switch ( rKEvt.GetKeyCode().GetCode() )
323 {
324 case KEY_ESCAPE:
325 {
326 bReturn = FuDraw::cancel();
327 }
328 break;
329
330 case KEY_DELETE:
331 case KEY_BACKSPACE:
332 {
333 if (!mpDocSh->IsReadOnly())
334 {
335 if (mpView->IsPresObjSelected(false, true, false, true))
336 {
337 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(mpWindow->GetFrameWeld(),
338 VclMessageType::Info, VclButtonsType::Ok,
339 SdResId(STR_ACTION_NOTPOSSIBLE)));
340 xInfoBox->run();
341 }
342 else
343 {
344 // wait-mousepointer while deleting object
345 weld::WaitObject aWait(mpViewShell->GetFrameWeld());
346 // delete object
347 mpView->DeleteMarked();
348 }
349 }
350 bReturn = true;
351 }
352 break;
353
354 case KEY_TAB:
355 {
356 vcl::KeyCode aCode = rKEvt.GetKeyCode();
357
358 if ( !aCode.IsMod1() && !aCode.IsMod2() )
359 {
360 // Moved next line which was a bugfix itself into
361 // the scope which really does the object selection travel
362 // and thus is allowed to call SelectionHasChanged().
363
364 // Switch to FuSelect.
365 mpViewShell->GetViewFrame()->GetDispatcher()->Execute(
366 SID_OBJECT_SELECT,
367 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
368
369 // changeover to the next object
370 if(!mpView->MarkNextObj( !aCode.IsShift() ))
371 {
372 //If there is only one object, don't do the UnmarkAllObj() & MarkNextObj().
373 if ( mpView->HasMultipleMarkableObjects() && rMarkList.GetMarkCount() != 0 )
374 {
375 // No next object: go over open end and get first from
376 // the other side
377 mpView->UnmarkAllObj();
378 mpView->MarkNextObj(!aCode.IsShift());
379 }
380 }
381
382 if(rMarkList.GetMarkCount() != 0)
383 mpView->MakeVisible(mpView->GetAllMarkedRect(), *mpWindow);
384
385 bReturn = true;
386 }
387 }
388 break;
389
390 case KEY_END:
391 {
392 vcl::KeyCode aCode = rKEvt.GetKeyCode();
393
394 if ( aCode.IsMod1() )
395 {
396 // mark last object
397 mpView->UnmarkAllObj();
398 mpView->MarkNextObj();
399
400 if(rMarkList.GetMarkCount() != 0)
401 mpView->MakeVisible(mpView->GetAllMarkedRect(), *mpWindow);
402
403 bReturn = true;
404 }
405 }
406 break;
407
408 case KEY_HOME:
409 {
410 vcl::KeyCode aCode = rKEvt.GetKeyCode();
411
412 if ( aCode.IsMod1() )
413 {
414 // mark first object
415 mpView->UnmarkAllObj();
416 mpView->MarkNextObj(true);
417
418 if(rMarkList.GetMarkCount() != 0)
419 mpView->MakeVisible(mpView->GetAllMarkedRect(), *mpWindow);
420
421 bReturn = true;
422 }
423 }
424 break;
425
426 default:
427 break;
428 }
429
430 if (!bReturn)
431 {
432 bReturn = FuPoor::KeyInput(rKEvt);
433 }
434 else
435 {
436 mpWindow->ReleaseMouse();
437 }
438
439 return bReturn;
440 }
441
Activate()442 void FuDraw::Activate()
443 {
444 FuPoor::Activate();
445 ForcePointer();
446 }
447
448 /**
449 * Toggle mouse-pointer
450 */
ForcePointer(const MouseEvent * pMEvt)451 void FuDraw::ForcePointer(const MouseEvent* pMEvt)
452 {
453 Point aPnt;
454 sal_uInt16 nModifier = 0;
455 bool bLeftDown = false;
456 bool bDefPointer = true;
457
458 if (pMEvt)
459 {
460 aPnt = mpWindow->PixelToLogic(pMEvt->GetPosPixel());
461 nModifier = pMEvt->GetModifier();
462 bLeftDown = pMEvt->IsLeft();
463 }
464 else
465 {
466 aPnt = mpWindow->PixelToLogic(mpWindow->GetPointerPosPixel());
467 }
468
469 if (mpView->IsDragObj())
470 {
471 if (SD_MOD()->GetWaterCan() && !mpView->PickHandle(aPnt))
472 {
473 // water can mode
474 bDefPointer = false;
475 mpWindow->SetPointer(PointerStyle::Fill);
476 }
477 }
478 else
479 {
480 SdrHdl* pHdl = mpView->PickHandle(aPnt);
481
482 if (SD_MOD()->GetWaterCan() && !pHdl)
483 {
484 // water can mode
485 bDefPointer = false;
486 mpWindow->SetPointer(PointerStyle::Fill);
487 }
488 else if (!pHdl &&
489 mpViewShell->GetViewFrame()->HasChildWindow(SvxBmpMaskChildWindow::GetChildWindowId()))
490 {
491 // pipette mode
492 SfxChildWindow* pWnd = mpViewShell->GetViewFrame()->GetChildWindow(SvxBmpMaskChildWindow::GetChildWindowId());
493 SvxBmpMask* pMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr;
494 if (pMask && pMask->IsEyedropping())
495 {
496 bDefPointer = false;
497 mpWindow->SetPointer(PointerStyle::RefHand);
498 }
499 }
500 else if (!mpView->IsAction())
501 {
502 SdrObject* pObj = nullptr;
503 SdrPageView* pPV = nullptr;
504 SdrViewEvent aVEvt;
505 SdrHitKind eHit = SdrHitKind::NONE;
506 SdrDragMode eDragMode = mpView->GetDragMode();
507
508 if (pMEvt)
509 {
510 eHit = mpView->PickAnything(*pMEvt, SdrMouseEventKind::MOVE, aVEvt);
511 }
512
513 if ((eDragMode == SdrDragMode::Rotate) && (eHit == SdrHitKind::MarkedObject))
514 {
515 // The goal of this request is show always the rotation arrow for 3D-objects at rotation mode
516 // Independent of the settings at Tools->Options->Draw "Objects always moveable"
517 // 2D-objects acquit in another way. Otherwise, the rotation of 3d-objects around any axes
518 // wouldn't be possible per default.
519 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
520 SdrObject* pObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
521 if (DynCastE3dObject(pObject) && (rMarkList.GetMarkCount() == 1))
522 {
523 mpWindow->SetPointer(PointerStyle::Rotate);
524 bDefPointer = false; // Otherwise it'll be called Joe's routine and the mousepointer will reconfigurate again
525 }
526 }
527
528 if (eHit == SdrHitKind::NONE)
529 {
530 // found nothing -> look after at the masterpage
531 pObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
532 }
533 else if (eHit == SdrHitKind::UnmarkedObject)
534 {
535 pObj = aVEvt.mpObj;
536 }
537 else if (eHit == SdrHitKind::TextEditObj && dynamic_cast< const FuSelection *>( this ) != nullptr)
538 {
539 SdrObjKind nSdrObjKind = aVEvt.mpObj->GetObjIdentifier();
540
541 if ( nSdrObjKind != SdrObjKind::Text &&
542 nSdrObjKind != SdrObjKind::TitleText &&
543 nSdrObjKind != SdrObjKind::OutlineText &&
544 aVEvt.mpObj->IsEmptyPresObj() )
545 {
546 pObj = nullptr;
547 bDefPointer = false;
548 mpWindow->SetPointer(PointerStyle::Arrow);
549 }
550 }
551
552 if (pObj && pMEvt && !pMEvt->IsMod2()
553 && dynamic_cast<const FuSelection*>(this) != nullptr)
554 {
555 // test for ImageMap
556 bDefPointer = !SetPointer(pObj, aPnt);
557
558 if (bDefPointer
559 && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr
560 || DynCastE3dScene(pObj)))
561 {
562 // take a glance into the group
563 pObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV,
564 SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::DEEP);
565 if (pObj)
566 bDefPointer = !SetPointer(pObj, aPnt);
567 }
568 }
569 }
570 }
571
572 if (bDefPointer)
573 {
574 mpWindow->SetPointer(mpView->GetPreferredPointer(
575 aPnt, mpWindow->GetOutDev(), nModifier, bLeftDown));
576 }
577 }
578
579 /**
580 * Set cursor to pointer when in clickable area of an ImageMap
581 *
582 * @return True when pointer was set
583 */
SetPointer(const SdrObject * pObj,const Point & rPos)584 bool FuDraw::SetPointer(const SdrObject* pObj, const Point& rPos)
585 {
586 bool bImageMapInfo = SvxIMapInfo::GetIMapInfo(pObj) != nullptr;
587
588 if (!bImageMapInfo)
589 return false;
590
591 const SdrLayerIDSet* pVisiLayer = &mpView->GetSdrPageView()->GetVisibleLayers();
592 double fHitLog(mpWindow->PixelToLogic(Size(HITPIX, 0)).Width());
593 ::tools::Long n2HitLog(fHitLog * 2);
594 Point aHitPosR(rPos);
595 Point aHitPosL(rPos);
596 Point aHitPosT(rPos);
597 Point aHitPosB(rPos);
598
599 aHitPosR.AdjustX(n2HitLog);
600 aHitPosL.AdjustX(-n2HitLog);
601 aHitPosT.AdjustY(n2HitLog);
602 aHitPosB.AdjustY(-n2HitLog);
603
604 if (!pObj->IsClosedObj()
605 || (SdrObjectPrimitiveHit(*pObj, aHitPosR, {fHitLog, fHitLog}, *mpView->GetSdrPageView(), pVisiLayer,
606 false)
607 && SdrObjectPrimitiveHit(*pObj, aHitPosL, {fHitLog, fHitLog}, *mpView->GetSdrPageView(),
608 pVisiLayer, false)
609 && SdrObjectPrimitiveHit(*pObj, aHitPosT, {fHitLog, fHitLog}, *mpView->GetSdrPageView(),
610 pVisiLayer, false)
611 && SdrObjectPrimitiveHit(*pObj, aHitPosB, {fHitLog, fHitLog}, *mpView->GetSdrPageView(),
612 pVisiLayer, false)))
613 {
614 // hit inside the object (without margin) or open object
615 if (SvxIMapInfo::GetHitIMapObject(pObj, rPos))
616 {
617 mpWindow->SetPointer(PointerStyle::RefHand);
618 return true;
619 }
620 }
621
622 return false;
623 }
624
625 /**
626 * Response of doubleclick
627 */
DoubleClick(const MouseEvent & rMEvt)628 void FuDraw::DoubleClick(const MouseEvent& rMEvt)
629 {
630 sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
631
632 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
633 if ( rMarkList.GetMarkCount() != 0 )
634 {
635 if (rMarkList.GetMarkCount() == 1)
636 {
637 SdrMark* pMark = rMarkList.GetMark(0);
638 SdrObject* pObj = pMark->GetMarkedSdrObj();
639
640 SdrInventor nInv = pObj->GetObjInventor();
641 SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
642
643 if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::OLE2)
644 {
645 // activate OLE-object
646 SfxInt16Item aItem(SID_OBJECT, 0);
647 mpViewShell->GetViewFrame()->
648 GetDispatcher()->ExecuteList(SID_OBJECT,
649 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
650 { &aItem });
651 }
652 else if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::Graphic && pObj->IsEmptyPresObj() )
653 {
654 mpViewShell->GetViewFrame()->
655 GetDispatcher()->Execute( SID_INSERT_GRAPHIC,
656 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
657 }
658 else if ( ( DynCastSdrTextObj( pObj ) != nullptr || dynamic_cast< const SdrObjGroup *>( pObj ) != nullptr ) &&
659 !SD_MOD()->GetWaterCan() &&
660 mpViewShell->GetFrameView()->IsDoubleClickTextEdit() &&
661 !mpDocSh->IsReadOnly())
662 {
663 SfxUInt16Item aItem(SID_TEXTEDIT, 2);
664 mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
665 SID_TEXTEDIT,
666 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
667 { &aItem });
668 }
669 else if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::Group)
670 {
671 // hit group -> select subobject
672 mpView->UnMarkAll();
673 mpView->MarkObj(aMDPos, nHitLog, rMEvt.IsShift(), true);
674 }
675 }
676 }
677 else
678 mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
679 }
680
RequestHelp(const HelpEvent & rHEvt)681 bool FuDraw::RequestHelp(const HelpEvent& rHEvt)
682 {
683 bool bReturn = false;
684
685 if (Help::IsBalloonHelpEnabled() || Help::IsQuickHelpEnabled())
686 {
687 SdrViewEvent aVEvt;
688
689 MouseEvent aMEvt(mpWindow->GetPointerPosPixel(), 1, MouseEventModifiers::NONE, MOUSE_LEFT);
690
691 SdrHitKind eHit = mpView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
692
693 SdrObject* pObj = aVEvt.mpObj;
694
695 if (eHit != SdrHitKind::NONE && pObj != nullptr)
696 {
697 Point aPosPixel = rHEvt.GetMousePosPixel();
698
699 bReturn = SetHelpText(pObj, aPosPixel, aVEvt);
700
701 if (!bReturn && (dynamic_cast< const SdrObjGroup *>( pObj ) != nullptr || DynCastE3dScene(pObj)))
702 {
703 // take a glance into the group
704 SdrPageView* pPV = nullptr;
705
706 Point aPos(mpWindow->PixelToLogic(mpWindow->ScreenToOutputPixel(aPosPixel)));
707
708 pObj = mpView->PickObj(aPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::DEEP);
709 if (pObj)
710 bReturn = SetHelpText(pObj, aPosPixel, aVEvt);
711 }
712 }
713 }
714
715 if (!bReturn)
716 {
717 bReturn = FuPoor::RequestHelp(rHEvt);
718 }
719
720 if (!bReturn)
721 bReturn = mpView->RequestHelp(rHEvt);
722
723 return bReturn;
724 }
725
SetHelpText(const SdrObject * pObj,const Point & rPosPixel,const SdrViewEvent & rVEvt)726 bool FuDraw::SetHelpText(const SdrObject* pObj, const Point& rPosPixel, const SdrViewEvent& rVEvt)
727 {
728 OUString aHelpText;
729 Point aPos(mpWindow->PixelToLogic(mpWindow->ScreenToOutputPixel(rPosPixel)));
730 IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(pObj, aPos);
731
732 if (!rVEvt.mpURLField && !pIMapObj)
733 return false;
734
735 OUString aURL;
736 if (rVEvt.mpURLField)
737 aURL = INetURLObject::decode(rVEvt.mpURLField->GetURL(),
738 INetURLObject::DecodeMechanism::WithCharset);
739 else if (pIMapObj)
740 {
741 aURL = pIMapObj->GetAltText() +
742 " (" +
743 INetURLObject::decode(pIMapObj->GetURL(),
744 INetURLObject::DecodeMechanism::WithCharset) +
745 ")";
746 }
747 else
748 return false;
749
750 aHelpText = SfxHelp::GetURLHelpText(aURL);
751
752 if (aHelpText.isEmpty())
753 return false;
754
755 ::tools::Rectangle aLogicPix = mpWindow->LogicToPixel(pObj->GetLogicRect());
756 ::tools::Rectangle aScreenRect(mpWindow->OutputToScreenPixel(aLogicPix.TopLeft()),
757 mpWindow->OutputToScreenPixel(aLogicPix.BottomRight()));
758
759 if (Help::IsBalloonHelpEnabled())
760 Help::ShowBalloon( static_cast<vcl::Window*>(mpWindow), rPosPixel, aScreenRect, aHelpText);
761 else if (Help::IsQuickHelpEnabled())
762 Help::ShowQuickHelp( static_cast<vcl::Window*>(mpWindow), aScreenRect, aHelpText);
763
764 return true;
765 }
766
767 /** is called when the current function should be aborted. <p>
768 This is used when a function gets a KEY_ESCAPE but can also
769 be called directly.
770
771 @returns true if an active function was aborted
772 */
cancel()773 bool FuDraw::cancel()
774 {
775 bool bReturn = false;
776 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
777
778 if ( mpView->IsAction() )
779 {
780 mpView->BrkAction();
781 bReturn = true;
782 }
783 else if ( mpView->IsTextEdit() )
784 {
785 mpView->SdrEndTextEdit();
786 bReturn = true;
787
788 SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
789 rBindings.Invalidate( SID_DEC_INDENT );
790 rBindings.Invalidate( SID_INC_INDENT );
791 rBindings.Invalidate( SID_PARASPACE_INCREASE );
792 rBindings.Invalidate( SID_PARASPACE_DECREASE );
793 }
794 else if ( rMarkList.GetMarkCount() != 0 )
795 {
796 const SdrHdlList& rHdlList = mpView->GetHdlList();
797 SdrHdl* pHdl = rHdlList.GetFocusHdl();
798
799 if(pHdl)
800 {
801 const_cast<SdrHdlList&>(rHdlList).ResetFocusHdl();
802 }
803 else
804 {
805 mpView->UnmarkAll();
806 }
807
808 // Switch to FuSelect.
809 mpViewShell->GetViewFrame()->GetDispatcher()->Execute(
810 SID_OBJECT_SELECT,
811 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
812
813 bReturn = true;
814 }
815
816 return bReturn;
817 }
818
819 } // end of namespace sd
820
821 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
822