include/oox/drawingml/shape.hxx                |    6 +++
 include/oox/ppt/slidepersist.hxx               |    4 ++
 oox/source/ppt/pptshape.cxx                    |   23 ++----------
 oox/source/ppt/presentationfragmenthandler.cxx |   46 +++++++++++++++++++++++++
 oox/source/ppt/slidepersist.cxx                |    2 +
 sd/qa/unit/data/pptx/tdf148965.pptx            |binary
 sd/qa/unit/import-tests.cxx                    |   37 ++++++++++++++++++++
 7 files changed, 100 insertions(+), 18 deletions(-)

New commits:
commit 855a56fea4561135a63cb729d7a625a950b210e7
Author:     Tibor Nagy <nagy.tib...@nisz.hu>
AuthorDate: Fri May 13 08:12:17 2022 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Fri May 27 18:32:38 2022 +0200

    tdf#148965 PPTX import: fix internal hyperlinks on shapes
    
    Locale dependent code path resulted broken hyperlinks
    on shapes in a non-English build.
    
    Change-Id: I045bbe4246ab5336e2b967bf252b5fbca5b17706
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134266
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx
index 4318c1e24d2d..e845b399f5f8 100644
--- a/include/oox/drawingml/shape.hxx
+++ b/include/oox/drawingml/shape.hxx
@@ -140,6 +140,9 @@ public:
     void                            setConnectorShape(bool bConnector) { 
mbConnector = bConnector; }
     bool                            isConnectorShape() const { return 
mbConnector; }
 
+    void                            setBookmark(bool bBookmark) { 
mbHasBookmark = bBookmark; }
+    bool                            hasBookmark() const { return 
mbHasBookmark; }
+
     Shape3DProperties&              get3DProperties() { return 
*mp3DPropertiesPtr; }
     const Shape3DProperties&        get3DProperties() const { return 
*mp3DPropertiesPtr; }
 
@@ -410,6 +413,9 @@ private:
     // Is this a connector shape?
     bool mbConnector = false;
 
+    // Is shape has bookmark?
+    bool mbHasBookmark = false;
+
     // temporary space for DiagramHelper in preparation for collecting data
     // Note: I tried to use a unique_ptr here, but existing constructor func 
does not allow that
     svx::diagram::IDiagramHelper* mpDiagramHelper;
diff --git a/include/oox/ppt/slidepersist.hxx b/include/oox/ppt/slidepersist.hxx
index 1b0a92c70783..4ba48637c66a 100644
--- a/include/oox/ppt/slidepersist.hxx
+++ b/include/oox/ppt/slidepersist.hxx
@@ -127,6 +127,9 @@ public:
 
     void createConnectorShapeConnection();
 
+    void  addURLShapeId(const OUString& rShapeId) { 
maURLShapeId.push_back(rShapeId); }
+    std::vector<OUString>& getURLShapeId() { return maURLShapeId; }
+
 private:
     OUString                                                                
maPath;
     OUString                                                                
maLayoutPath;
@@ -160,6 +163,7 @@ private:
     CommentAuthorList                                                       
maCommentAuthors;
 
     std::vector<OUString>                                                   
maConnectorShapeId;
+    std::vector<OUString>                                                   
maURLShapeId;
 };
 
 }
diff --git a/oox/source/ppt/pptshape.cxx b/oox/source/ppt/pptshape.cxx
index d83737250550..2ec4a3fbe327 100644
--- a/oox/source/ppt/pptshape.cxx
+++ b/oox/source/ppt/pptshape.cxx
@@ -613,27 +613,14 @@ void PPTShape::addShape(
                     // so check here if it's a bookmark or a document
                     if (meClickAction == ClickAction_BOOKMARK)
                     {
+                        sal_Int32 nSplitPos;
                         if (!sURL.startsWith("#"))
                             meClickAction = ClickAction_DOCUMENT;
-                        else
+                        else if (-1 != (nSplitPos = sURL.indexOf( ' ' )))
                         {
-                            sURL = sURL.copy(1);
-                            sal_Int32 nPageNumber = 0;
-                            static const OUStringLiteral sSlide = u"Slide ";
-                            if (sURL.match(sSlide))
-                                nPageNumber = 
o3tl::toInt32(sURL.subView(sSlide.getLength()));
-                            Reference<drawing::XDrawPagesSupplier> 
xDPS(rFilterBase.getModel(),
-                                                                        
uno::UNO_QUERY_THROW);
-                            Reference<drawing::XDrawPages> 
xDrawPages(xDPS->getDrawPages(),
-                                                                      
uno::UNO_SET_THROW);
-                            sal_Int32 nMaxPages = xDrawPages->getCount();
-                            if (nPageNumber && nPageNumber <= nMaxPages)
-                            {
-                                Reference<XDrawPage> xDrawPage;
-                                xDrawPages->getByIndex(nPageNumber - 1) >>= 
xDrawPage;
-                                Reference<container::XNamed> xNamed(xDrawPage, 
UNO_QUERY);
-                                sURL = xNamed->getName();
-                            }
+                            setBookmark(true);
+                            // reuse slide number from '#Slide [Num]' or 
"#Notes [Num]"
+                            sURL = OUString::Concat("#page") + 
sURL.subView(nSplitPos);
                         }
                         nPropertyCount += 1;
                     }
diff --git a/oox/source/ppt/presentationfragmenthandler.cxx 
b/oox/source/ppt/presentationfragmenthandler.cxx
index 64aaf62f9a71..c9deec076edc 100644
--- a/oox/source/ppt/presentationfragmenthandler.cxx
+++ b/oox/source/ppt/presentationfragmenthandler.cxx
@@ -106,6 +106,51 @@ 
PresentationFragmentHandler::~PresentationFragmentHandler() noexcept
 {
 }
 
+static void lcl_setBookmark(uno::Reference<drawing::XShape>& rShape,
+                            std::vector<SlidePersistPtr>& rSlidePersist)
+{
+    OUString aBookmark;
+    sal_Int32 nPageNumber;
+    static const OUStringLiteral sSlideName = u"#page";
+    uno::Reference<beans::XPropertySet> xPropSet(rShape, uno::UNO_QUERY);
+    xPropSet->getPropertyValue("Bookmark") >>= aBookmark;
+    nPageNumber = o3tl::toInt32(aBookmark.subView(sSlideName.getLength()));
+    Reference<XDrawPage> xDrawPage(rSlidePersist[nPageNumber - 1]->getPage());
+    Reference<container::XNamed> xNamed(xDrawPage, UNO_QUERY_THROW);
+    aBookmark = xNamed->getName();
+    xPropSet->setPropertyValue("Bookmark", Any(aBookmark));
+}
+
+static void ResolveShapeBookmark(std::vector<SlidePersistPtr>& rSlidePersist)
+{
+    sal_Int32 nPageCount = rSlidePersist.size();
+    for (sal_Int32 nPage = 0; nPage < nPageCount; ++nPage)
+    {
+        if (!rSlidePersist[nPage]->getURLShapeId().empty())
+        {
+            auto aShapeMap = rSlidePersist[nPage]->getShapeMap();
+            sal_Int32 nCount = rSlidePersist[nPage]->getURLShapeId().size();
+            for (sal_Int32 i = 0; i < nCount; i++)
+            {
+                OUString sId = rSlidePersist[nPage]->getURLShapeId()[i];
+                uno::Reference<drawing::XShape> 
xShape(aShapeMap[sId]->getXShape(), uno::UNO_QUERY);
+                Reference<XShapes> xShapes(xShape, UNO_QUERY);
+                if (xShapes.is()) // group shape
+                {
+                    for (sal_Int32 j = 0; j < xShapes->getCount(); j++)
+                    {
+                        uno::Reference<drawing::XShape> 
xGroupedShape(xShapes->getByIndex(j),
+                                                                      
uno::UNO_QUERY);
+                        lcl_setBookmark(xGroupedShape, rSlidePersist);
+                    }
+                }
+                else
+                    lcl_setBookmark(xShape, rSlidePersist);
+            }
+        }
+    }
+}
+
 static void ResolveTextFields( XmlFilterBase const & rFilter )
 {
     const oox::core::TextFieldStack& rTextFields = rFilter.getTextFieldStack();
@@ -551,6 +596,7 @@ void PresentationFragmentHandler::finalizeImport()
                 nPagesImported++;
             }
             ResolveTextFields( rFilter );
+            ResolveShapeBookmark(rFilter.getDrawPages());
             if (!maCustomShowList.empty())
                 importCustomSlideShow(maCustomShowList);
         }
diff --git a/oox/source/ppt/slidepersist.cxx b/oox/source/ppt/slidepersist.cxx
index 24ce2f9da464..8d45bcdb7947 100644
--- a/oox/source/ppt/slidepersist.cxx
+++ b/oox/source/ppt/slidepersist.cxx
@@ -158,6 +158,8 @@ void SlidePersist::createXShapes( XmlFilterBase& 
rFilterBase )
                             
maConnectorShapeId.push_back(pPPTShape->getChildren()[i]->getId());
                     }
                 }
+                if (pPPTShape->hasBookmark())
+                    addURLShapeId(pPPTShape->getId());
             }
             else
                 child->addShape( rFilterBase, getTheme().get(), xShapes, 
aTransformation, maShapesPtr->getFillProperties(), &getShapeMap() );
diff --git a/sd/qa/unit/data/pptx/tdf148965.pptx 
b/sd/qa/unit/data/pptx/tdf148965.pptx
new file mode 100644
index 000000000000..5b7b9f098d0b
Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf148965.pptx differ
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index 9e60c8886dec..aa329dfddec6 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -55,6 +55,8 @@
 #include <com/sun/star/drawing/ConnectorType.hpp>
 
 #include <stlpool.hxx>
+#include <unotools/syslocaleoptions.hxx>
+#include <comphelper/scopeguard.hxx>
 #include <comphelper/sequenceashashmap.hxx>
 #include <comphelper/lok.hxx>
 #include <svx/svdograf.hxx>
@@ -82,6 +84,7 @@ public:
 
     void testDocumentLayout();
     void testTdf149124();
+    void testTdf148965();
     void testTdf89449();
     void testTdf147459();
     void testTdf146223();
@@ -151,6 +154,7 @@ public:
 
     CPPUNIT_TEST(testDocumentLayout);
     CPPUNIT_TEST(testTdf149124);
+    CPPUNIT_TEST(testTdf148965);
     CPPUNIT_TEST(testTdf89449);
     CPPUNIT_TEST(testTdf147459);
     CPPUNIT_TEST(testTdf146223);
@@ -309,7 +313,40 @@ void SdImportTest::testTdf149124()
     CPPUNIT_ASSERT_EQUAL(sal_Int32(2), nStartGlueId);
     sal_Int32 nEndGlueId = 
xStandardConnector->getPropertyValue("EndGluePointIndex").get<sal_Int32>();
     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nEndGlueId);
+}
+
+void SdImportTest::testTdf148965()
+{
+    // Set the system user interface to Hungarian
+    SvtSysLocaleOptions aOptions;
+    OUString sUIConfigString = aOptions.GetLanguageTag().getBcp47();
+    aOptions.SetUILocaleConfigString("hu-HU");
+    aOptions.Commit();
+    comphelper::ScopeGuard g([&aOptions, &sUIConfigString] {
+        aOptions.SetUILocaleConfigString(sUIConfigString);
+        aOptions.Commit();
+        });
+
+    sd::DrawDocShellRef xDocShRef
+        = 
loadURL(m_directories.getURLFromSrc(u"sd/qa/unit/data/pptx/tdf148965.pptx"), 
PPTX);
 
+    uno::Reference<beans::XPropertySet> xShape1(getShapeFromPage(0, 1, 
xDocShRef));
+    uno::Reference<document::XEventsSupplier> xEventsSupplier1(xShape1, 
uno::UNO_QUERY);
+    uno::Reference<container::XNameAccess> 
xEvents1(xEventsSupplier1->getEvents());
+    uno::Sequence<beans::PropertyValue> props1;
+    xEvents1->getByName("OnClick") >>= props1;
+    comphelper::SequenceAsHashMap map1(props1);
+    auto iter1(map1.find("Bookmark"));
+    CPPUNIT_ASSERT_EQUAL(OUString("page1"), iter1->second.get<OUString>());
+
+    uno::Reference<beans::XPropertySet> xShape2(getShapeFromPage(1, 1, 
xDocShRef));
+    uno::Reference<document::XEventsSupplier> xEventsSupplier2(xShape2, 
uno::UNO_QUERY);
+    uno::Reference<container::XNameAccess> 
xEvents2(xEventsSupplier2->getEvents());
+    uno::Sequence<beans::PropertyValue> props2;
+    xEvents2->getByName("OnClick") >>= props2;
+    comphelper::SequenceAsHashMap map2(props2);
+    auto iter2(map2.find("Bookmark"));
+    CPPUNIT_ASSERT_EQUAL(OUString("page3"), iter2->second.get<OUString>());
     xDocShRef->DoClose();
 }
 

Reply via email to