[Libreoffice-commits] core.git: sd/source

Samuel Mehrbrodt (via logerrit) logerrit at kemper.freedesktop.org
Fri Jun 28 12:22:21 UTC 2019


 sd/source/ui/func/fudraw.cxx |  174 +++++++++++++++++++++++++++++--------------
 sd/source/ui/func/fusel.cxx  |  120 ++++++++++++++++++++++++++---
 sd/source/ui/inc/fudraw.hxx  |    1 
 sd/source/ui/inc/fusel.hxx   |    2 
 4 files changed, 233 insertions(+), 64 deletions(-)

New commits:
commit 58f0144ae2136e07f6a6b9c22b6c0059fc4cb0c6
Author:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
AuthorDate: Fri Jun 28 07:53:59 2019 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Fri Jun 28 14:21:31 2019 +0200

    Related tdf#125748 Reintroduce clickable image maps in sd
    
    Clicking on image maps had been inadvertently removed in 41a1a91b6ec08d78449a199ec300ff73c85dd148.
    The context menu solution used for interactions doesn't quite work here,
    since only parts of an image are clickable.
    
    So we make those parts clickable again, but additionally we respect the
    setting whether Ctrl-Click is required to follow hyperlinks.
    Also the tooltip now indicates whether Ctrl-Click is required to follow hyperlinks.
    This is now consistent with sc and sw.
    
    Change-Id: I04030ef0c2b1350afbc349176a3e1e87f3187393
    Reviewed-on: https://gerrit.libreoffice.org/74830
    Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
    Tested-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>

diff --git a/sd/source/ui/func/fudraw.cxx b/sd/source/ui/func/fudraw.cxx
index a1aabd63cd2c..64bef1f58aac 100644
--- a/sd/source/ui/func/fudraw.cxx
+++ b/sd/source/ui/func/fudraw.cxx
@@ -504,6 +504,8 @@ void FuDraw::ForcePointer(const MouseEvent* pMEvt)
         }
         else if (!mpView->IsAction())
         {
+            SdrObject* pObj = nullptr;
+            SdrPageView* pPV = nullptr;
             SdrViewEvent aVEvt;
             SdrHitKind eHit = SdrHitKind::NONE;
             SdrDragMode eDragMode = mpView->GetDragMode();
@@ -528,7 +530,16 @@ void FuDraw::ForcePointer(const MouseEvent* pMEvt)
                 }
             }
 
-            if (eHit == SdrHitKind::TextEditObj && dynamic_cast< const FuSelection *>( this ) !=  nullptr)
+            if (eHit == SdrHitKind::NONE)
+            {
+                // found nothing -> look after at the masterpage
+                pObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
+            }
+            else if (eHit == SdrHitKind::UnmarkedObject)
+            {
+                pObj = aVEvt.pObj;
+            }
+            else if (eHit == SdrHitKind::TextEditObj && dynamic_cast< const FuSelection *>( this ) !=  nullptr)
             {
                 sal_uInt16 nSdrObjKind = aVEvt.pObj->GetObjIdentifier();
 
@@ -537,10 +548,29 @@ void FuDraw::ForcePointer(const MouseEvent* pMEvt)
                      nSdrObjKind != OBJ_OUTLINETEXT &&
                      aVEvt.pObj->IsEmptyPresObj() )
                 {
+                    pObj = nullptr;
                     bDefPointer = false;
                     mpWindow->SetPointer(PointerStyle::Arrow);
                 }
             }
+
+            if (pObj && pMEvt && !pMEvt->IsMod2()
+                && dynamic_cast<const FuSelection*>(this) != nullptr)
+            {
+                // test for ImageMap
+                bDefPointer = !SetPointer(pObj, aPnt);
+
+                if (bDefPointer
+                    && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr
+                        || dynamic_cast<const E3dScene*>(pObj) != nullptr))
+                {
+                    // take a glance into the group
+                    pObj = mpView->PickObj(aPnt, mpView->getHitTolLog(), pPV,
+                                           SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::DEEP);
+                    if (pObj)
+                        bDefPointer = !SetPointer(pObj, aPnt);
+                }
+            }
         }
     }
 
@@ -552,6 +582,52 @@ void FuDraw::ForcePointer(const MouseEvent* pMEvt)
 }
 
 /**
+ * Set cursor to pointer when in clickable area of an ImageMap
+ *
+ * @return True when pointer was set
+ */
+bool FuDraw::SetPointer(SdrObject* pObj, const Point& rPos)
+{
+    bool bImageMapInfo = SdDrawDocument::GetIMapInfo(pObj) != nullptr;
+
+    if (!bImageMapInfo)
+        return false;
+
+    const SdrLayerIDSet* pVisiLayer = &mpView->GetSdrPageView()->GetVisibleLayers();
+    sal_uInt16 nHitLog(sal_uInt16(mpWindow->PixelToLogic(Size(HITPIX, 0)).Width()));
+    long n2HitLog(nHitLog * 2);
+    Point aHitPosR(rPos);
+    Point aHitPosL(rPos);
+    Point aHitPosT(rPos);
+    Point aHitPosB(rPos);
+
+    aHitPosR.AdjustX(n2HitLog);
+    aHitPosL.AdjustX(-n2HitLog);
+    aHitPosT.AdjustY(n2HitLog);
+    aHitPosB.AdjustY(-n2HitLog);
+
+    if (!pObj->IsClosedObj()
+        || (SdrObjectPrimitiveHit(*pObj, aHitPosR, nHitLog, *mpView->GetSdrPageView(), pVisiLayer,
+                                  false)
+            && SdrObjectPrimitiveHit(*pObj, aHitPosL, nHitLog, *mpView->GetSdrPageView(),
+                                     pVisiLayer, false)
+            && SdrObjectPrimitiveHit(*pObj, aHitPosT, nHitLog, *mpView->GetSdrPageView(),
+                                     pVisiLayer, false)
+            && SdrObjectPrimitiveHit(*pObj, aHitPosB, nHitLog, *mpView->GetSdrPageView(),
+                                     pVisiLayer, false)))
+    {
+        // hit inside the object (without margin) or open object
+        if (SdDrawDocument::GetHitIMapObject(pObj, rPos))
+        {
+            mpWindow->SetPointer(PointerStyle::RefHand);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
  * Response of doubleclick
  */
 void FuDraw::DoubleClick(const MouseEvent& rMEvt)
@@ -658,71 +734,63 @@ bool FuDraw::RequestHelp(const HelpEvent& rHEvt)
 
 bool FuDraw::SetHelpText(SdrObject* pObj, const Point& rPosPixel, const SdrViewEvent& rVEvt)
 {
-    bool bSet = false;
     OUString aHelpText;
     Point aPos(mpWindow->PixelToLogic(mpWindow->ScreenToOutputPixel(rPosPixel)));
+    IMapObject* pIMapObj = SdDrawDocument::GetHitIMapObject(pObj, aPos);
 
-    // URL for IMapObject underneath pointer is help text
-    if ( SdDrawDocument::GetIMapInfo(pObj) )
-    {
-        IMapObject* pIMapObj = SdDrawDocument::GetHitIMapObject(pObj, aPos);
-
-        if ( pIMapObj )
-        {
-            // show name
-            aHelpText = pIMapObj->GetAltText();
+    if (!rVEvt.pURLField && !pIMapObj)
+        return false;
 
-            if (aHelpText.isEmpty())
-            {
-                // show url if no name is available
-                aHelpText = INetURLObject::decode( pIMapObj->GetURL(), INetURLObject::DecodeMechanism::WithCharset );
-            }
-        }
-    }
-    else if (rVEvt.pURLField)
+    OUString aURL;
+    if (rVEvt.pURLField)
+        aURL = INetURLObject::decode(rVEvt.pURLField->GetURL(),
+                                     INetURLObject::DecodeMechanism::WithCharset);
+    else if (pIMapObj)
     {
-        /**************************************************************
-        * URL-Field
-        **************************************************************/
-        OUString aURL = INetURLObject::decode(rVEvt.pURLField->GetURL(), INetURLObject::DecodeMechanism::WithCharset);
+        aURL = pIMapObj->GetAltText();
+        aURL += " ("
+                + INetURLObject::decode(pIMapObj->GetURL(),
+                                        INetURLObject::DecodeMechanism::WithCharset)
+                + ")";
+    }
+    else
+        return false;
 
-        SvtSecurityOptions aSecOpt;
-        if (aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
-        {
-            // Hint about Ctrl-click to open hyperlink, but need to detect "Ctrl" key for MacOs
-            vcl::KeyCode aCode(KEY_SPACE);
-            vcl::KeyCode aModifiedCode(KEY_SPACE, KEY_MOD1);
-            OUString aModStr(aModifiedCode.GetName());
-            aModStr = aModStr.replaceFirst(aCode.GetName(), "");
-            aModStr = aModStr.replaceAll("+", "");
+    SvtSecurityOptions aSecOpt;
+    if (aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
+    {
+        // Hint about Ctrl-click to open hyperlink, but need to detect "Ctrl" key for MacOs
+        vcl::KeyCode aCode(KEY_SPACE);
+        vcl::KeyCode aModifiedCode(KEY_SPACE, KEY_MOD1);
+        OUString aModStr(aModifiedCode.GetName());
+        aModStr = aModStr.replaceFirst(aCode.GetName(), "");
+        aModStr = aModStr.replaceAll("+", "");
 
-            OUString aCtrlClickHlinkStr = SdResId(STR_CTRLCLICKHYPERLINK);
+        OUString aCtrlClickHlinkStr = SdResId(STR_CTRLCLICKHYPERLINK);
 
-            aCtrlClickHlinkStr = aCtrlClickHlinkStr.replaceAll("%s", aModStr);
+        aCtrlClickHlinkStr = aCtrlClickHlinkStr.replaceAll("%s", aModStr);
 
-            aHelpText = aCtrlClickHlinkStr + aURL;
-        }
-        else
-        {
-            // Hint about just clicking hyperlink
-            aHelpText = SdResId(STR_CLICKHYPERLINK) + aURL;
-        }
+        aHelpText = aCtrlClickHlinkStr + aURL;
     }
-
-    if (!aHelpText.isEmpty())
+    else
     {
-        bSet = true;
-        ::tools::Rectangle aLogicPix = mpWindow->LogicToPixel(pObj->GetLogicRect());
-        ::tools::Rectangle aScreenRect(mpWindow->OutputToScreenPixel(aLogicPix.TopLeft()),
-                              mpWindow->OutputToScreenPixel(aLogicPix.BottomRight()));
-
-        if (Help::IsBalloonHelpEnabled())
-            Help::ShowBalloon( static_cast<vcl::Window*>(mpWindow), rPosPixel, aScreenRect, aHelpText);
-        else if (Help::IsQuickHelpEnabled())
-            Help::ShowQuickHelp( static_cast<vcl::Window*>(mpWindow), aScreenRect, aHelpText);
+        // Hint about just clicking hyperlink
+        aHelpText = SdResId(STR_CLICKHYPERLINK) + aURL;
     }
 
-    return bSet;
+    if (aHelpText.isEmpty())
+        return false;
+
+    ::tools::Rectangle aLogicPix = mpWindow->LogicToPixel(pObj->GetLogicRect());
+    ::tools::Rectangle aScreenRect(mpWindow->OutputToScreenPixel(aLogicPix.TopLeft()),
+                            mpWindow->OutputToScreenPixel(aLogicPix.BottomRight()));
+
+    if (Help::IsBalloonHelpEnabled())
+        Help::ShowBalloon( static_cast<vcl::Window*>(mpWindow), rPosPixel, aScreenRect, aHelpText);
+    else if (Help::IsQuickHelpEnabled())
+        Help::ShowQuickHelp( static_cast<vcl::Window*>(mpWindow), aScreenRect, aHelpText);
+
+    return true;
 }
 
 /** is called when the current function should be aborted. <p>
diff --git a/sd/source/ui/func/fusel.cxx b/sd/source/ui/func/fusel.cxx
index 0a8bd4452dfe..c083bd3c6556 100644
--- a/sd/source/ui/func/fusel.cxx
+++ b/sd/source/ui/func/fusel.cxx
@@ -124,6 +124,17 @@ FuSelection::~FuSelection()
     }
 }
 
+namespace {
+    bool lcl_followHyperlinkAllowed(const MouseEvent& rMEvt) {
+        SvtSecurityOptions aSecOpt;
+        if (!rMEvt.IsMod1() && aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
+            return false;
+        if (rMEvt.IsMod1() && !aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
+            return false;
+        return true;
+    }
+}
+
 bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt)
 {
     pHdl = nullptr;
@@ -264,10 +275,7 @@ bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt)
              {
                 mpWindow->ReleaseMouse();
 
-                SvtSecurityOptions aSecOpt;
-                if (!rMEvt.IsMod1() && aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
-                    return true;
-                if (rMEvt.IsMod1() && !aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
+                if (!lcl_followHyperlinkAllowed(rMEvt))
                     return true;
 
                 SfxStringItem aStrItem(SID_FILE_NAME, aVEvt.pURLField->GetURL());
@@ -307,14 +315,37 @@ bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt)
                 )
             {
                 pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
-                if (pObj && !bReturn && !bReadOnly && rMEvt.GetClicks() == 2
-                    && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr
-                        || dynamic_cast<const E3dScene*>(pObj) != nullptr))
+                if (pObj)
                 {
-                    // New: double click on selected Group object
-                    // enter group
-                    if (!bSelectionOnly && pObj->getSdrPageFromSdrObject() == pPV->GetPage())
-                        bReturn = pPV->EnterGroup(pObj);
+                    // Handle ImageMap click when not just selecting
+                    if (!bSelectionOnly)
+                    {
+                        if (lcl_followHyperlinkAllowed(rMEvt))
+                            bReturn = HandleImageMapClick(pObj, aMDPos);
+                    }
+
+                    if (!bReturn
+                        && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr
+                            || dynamic_cast<const E3dScene*>(pObj) != nullptr))
+                    {
+                        if (rMEvt.GetClicks() == 1)
+                        {
+                            // Look into the group
+                            pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV,
+                                                   SdrSearchOptions::ALSOONMASTER
+                                                       | SdrSearchOptions::DEEP);
+                            if (pObj && lcl_followHyperlinkAllowed(rMEvt))
+                                bReturn = HandleImageMapClick(pObj, aMDPos);
+                        }
+                        else if (!bReadOnly && rMEvt.GetClicks() == 2)
+                        {
+                            // New: double click on selected Group object
+                            // enter group
+                            if (!bSelectionOnly
+                                && pObj->getSdrPageFromSdrObject() == pPV->GetPage())
+                                bReturn = pPV->EnterGroup(pObj);
+                        }
+                    }
                 }
 
                 // #i71727# replaced else here with two possibilities, once the original else (!pObj)
@@ -1168,6 +1199,73 @@ void FuSelection::SetEditMode(sal_uInt16 nMode)
     rBindings.Invalidate(SID_BEZIER_INSERT);
 }
 
+/**
+ * Execute ImageMap interaction
+ */
+bool FuSelection::HandleImageMapClick(SdrObject* pObj, const Point& rPos)
+{
+    bool bClosed = pObj->IsClosedObj();
+    bool bFilled = false;
+
+    if (bClosed)
+    {
+        SfxItemSet aSet(mpDoc->GetPool());
+
+        aSet.Put(pObj->GetMergedItemSet());
+
+        const XFillStyleItem& rFillStyle = aSet.Get(XATTR_FILLSTYLE);
+        bFilled = rFillStyle.GetValue() != drawing::FillStyle_NONE;
+    }
+
+    const SdrLayerIDSet* pVisiLayer = &mpView->GetSdrPageView()->GetVisibleLayers();
+    sal_uInt16 nHitLog = sal_uInt16(mpWindow->PixelToLogic(Size(HITPIX, 0)).Width());
+    const long n2HitLog = nHitLog * 2;
+    Point aHitPosR(rPos);
+    Point aHitPosL(rPos);
+    Point aHitPosT(rPos);
+    Point aHitPosB(rPos);
+
+    aHitPosR.AdjustX(n2HitLog);
+    aHitPosL.AdjustX(-n2HitLog);
+    aHitPosT.AdjustY(n2HitLog);
+    aHitPosB.AdjustY(-n2HitLog);
+
+    if (!bClosed || !bFilled
+        || (SdrObjectPrimitiveHit(*pObj, aHitPosR, nHitLog, *mpView->GetSdrPageView(), pVisiLayer,
+                                  false)
+            && SdrObjectPrimitiveHit(*pObj, aHitPosL, nHitLog, *mpView->GetSdrPageView(),
+                                     pVisiLayer, false)
+            && SdrObjectPrimitiveHit(*pObj, aHitPosT, nHitLog, *mpView->GetSdrPageView(),
+                                     pVisiLayer, false)
+            && SdrObjectPrimitiveHit(*pObj, aHitPosB, nHitLog, *mpView->GetSdrPageView(),
+                                     pVisiLayer, false)))
+    {
+        if (SdDrawDocument::GetIMapInfo(pObj))
+        {
+            const IMapObject* pIMapObj = SdDrawDocument::GetHitIMapObject(pObj, rPos);
+
+            if (pIMapObj && !pIMapObj->GetURL().isEmpty())
+            {
+                // Jump to Document
+                mpWindow->ReleaseMouse();
+                SfxStringItem aStrItem(SID_FILE_NAME, pIMapObj->GetURL());
+                SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
+                SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+                SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
+                SfxBoolItem aBrowseItem(SID_BROWSE, true);
+                mpWindow->ReleaseMouse();
+                pFrame->GetDispatcher()->ExecuteList(
+                    SID_OPENDOC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+                    { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
+
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
 /** is called when the current function should be aborted. <p>
     This is used when a function gets a KEY_ESCAPE but can also
     be called directly.
diff --git a/sd/source/ui/inc/fudraw.hxx b/sd/source/ui/inc/fudraw.hxx
index 9e64300928a6..11158738ff82 100644
--- a/sd/source/ui/inc/fudraw.hxx
+++ b/sd/source/ui/inc/fudraw.hxx
@@ -47,6 +47,7 @@ public:
 
     virtual void DoubleClick(const MouseEvent& rMEvt);
 
+    bool    SetPointer(SdrObject* pObj, const Point& rPos);
     bool    SetHelpText(SdrObject* pObj, const Point& rPos, const SdrViewEvent& rVEvt);
 
     void    SetPermanent(bool bSet) { bPermanent = bSet; }
diff --git a/sd/source/ui/inc/fusel.hxx b/sd/source/ui/inc/fusel.hxx
index 5806cb2e8d66..6f48ed9a4860 100644
--- a/sd/source/ui/inc/fusel.hxx
+++ b/sd/source/ui/inc/fusel.hxx
@@ -50,6 +50,8 @@ public:
     void    SetEditMode(sal_uInt16 nMode);
     sal_uInt16  GetEditMode() { return nEditMode; }
 
+    bool HandleImageMapClick(SdrObject* pObj, const Point& rPos);
+
     /** is called when the current function should be aborted. <p>
         This is used when a function gets a KEY_ESCAPE but can also
         be called directly.


More information about the Libreoffice-commits mailing list