basic/source/inc/runtime.hxx             |    3 ++
 basic/source/runtime/runtime.cxx         |   33 ++++++++++++++++++++++++++++++-
 sc/qa/extras/macros-test.cxx             |   28 ++++++++++++++++++++++++++
 sc/qa/extras/testdocuments/tdf130307.ods |binary
 4 files changed, 63 insertions(+), 1 deletion(-)

New commits:
commit 5c502a100476c6b57a1a9f4305195c7e2d5d5608
Author:     Andreas Heinisch <andreas.heini...@yahoo.de>
AuthorDate: Mon Oct 4 21:32:20 2021 +0200
Commit:     Andreas Heinisch <andreas.heini...@yahoo.de>
CommitDate: Tue Oct 12 21:11:10 2021 +0200

    tdf#130307 - Support for each loop for objects exposing XIndexAccess
    
    Change-Id: Ib94c642e6d2a52ac7c60a8f7ae3c79d611b41614
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123072
    Tested-by: Jenkins
    Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de>

diff --git a/basic/source/inc/runtime.hxx b/basic/source/inc/runtime.hxx
index 73e56838e2aa..d09db071a1a9 100644
--- a/basic/source/inc/runtime.hxx
+++ b/basic/source/inc/runtime.hxx
@@ -34,6 +34,7 @@
 #include <memory>
 #include <com/sun/star/lang/XComponent.hpp>
 #include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
 #include <unotools/localedatawrapper.hxx>
 #include <o3tl/deleter.hxx>
 #include <o3tl/typed_flags_set.hxx>
@@ -55,6 +56,7 @@ enum class ForType {
     EachArray,
     EachCollection,
     EachXEnumeration,
+    EachXIndexAccess,
     Error,
 };
 
@@ -74,6 +76,7 @@ struct SbiForStack {                // for/next stack:
     std::unique_ptr<sal_Int32[]>
                         pArrayUpperBounds;
     css::uno::Reference< css::container::XEnumeration > xEnumeration;
+    css::uno::Reference<css::container::XIndexAccess> xIndexAccess;
 
     SbiForStack()
         : pNext(nullptr)
diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx
index 9a2a79e349b5..5c27b84223f7 100644
--- a/basic/source/runtime/runtime.cxx
+++ b/basic/source/runtime/runtime.cxx
@@ -1196,14 +1196,22 @@ void SbiRuntime::PushForEach()
     }
     else if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
     {
-        // XEnumerationAccess?
+        // XEnumerationAccess or XIndexAccess?
         Any aAny = pUnoObj->getUnoAny();
+        Reference<XIndexAccess> xIndexAccess;
         Reference< XEnumerationAccess > xEnumerationAccess;
         if( aAny >>= xEnumerationAccess )
         {
             p->xEnumeration = xEnumerationAccess->createEnumeration();
             p->eForType = ForType::EachXEnumeration;
         }
+        // tdf#130307 - support for each loop for objects exposing XIndexAccess
+        else if (aAny >>= xIndexAccess)
+        {
+            p->eForType = ForType::EachXIndexAccess;
+            p->xIndexAccess = xIndexAccess;
+            p->nCurCollectionIndex = 0;
+        }
         else if ( isVBAEnabled() && pUnoObj->isNativeCOMObject() )
         {
             uno::Reference< script::XInvocation > xInvocation;
@@ -3204,6 +3212,29 @@ void SbiRuntime::StepTESTFOR( sal_uInt32 nOp1 )
             }
             break;
         }
+        // tdf#130307 - support for each loop for objects exposing XIndexAccess
+        case ForType::EachXIndexAccess:
+        {
+            SbiForStack* p = pForStk;
+            if (!p->xIndexAccess)
+            {
+                SbxBase::SetError(ERRCODE_BASIC_CONVERSION);
+                pForStk->eForType = ForType::Error; // terminate loop at the 
next iteration
+            }
+            else if (pForStk->nCurCollectionIndex < 
p->xIndexAccess->getCount())
+            {
+                Any aElem = 
p->xIndexAccess->getByIndex(pForStk->nCurCollectionIndex);
+                pForStk->nCurCollectionIndex++;
+                SbxVariableRef xVar = new SbxVariable(SbxVARIANT);
+                unoToSbxValue(xVar.get(), aElem);
+                (*pForStk->refVar) = *xVar;
+            }
+            else
+            {
+                bEndLoop = true;
+            }
+            break;
+        }
         case ForType::Error:
         {
             // We are in Resume Next mode after failed loop initialization
diff --git a/sc/qa/extras/macros-test.cxx b/sc/qa/extras/macros-test.cxx
index 6c4c9e185521..759f416ae490 100644
--- a/sc/qa/extras/macros-test.cxx
+++ b/sc/qa/extras/macros-test.cxx
@@ -68,6 +68,7 @@ public:
     void testTdf90278();
     void testTdf143582();
     void testTdf144085();
+    void testTdf130307();
     void testMacroButtonFormControlXlsxExport();
 
     CPPUNIT_TEST_SUITE(ScMacrosTest);
@@ -97,6 +98,7 @@ public:
     CPPUNIT_TEST(testTdf90278);
     CPPUNIT_TEST(testTdf143582);
     CPPUNIT_TEST(testTdf144085);
+    CPPUNIT_TEST(testTdf130307);
     CPPUNIT_TEST(testMacroButtonFormControlXlsxExport);
 
     CPPUNIT_TEST_SUITE_END();
@@ -1057,6 +1059,32 @@ void ScMacrosTest::testTdf144085()
     xCloseable->close(true);
 }
 
+void ScMacrosTest::testTdf130307()
+{
+    OUString aFileName;
+    createFileURL(u"tdf130307.ods", aFileName);
+    auto xComponent = loadFromDesktop(aFileName, 
"com.sun.star.sheet.SpreadsheetDocument");
+
+    css::uno::Any aRet;
+    css::uno::Sequence<css::uno::Any> aParams;
+    css::uno::Sequence<css::uno::Any> aOutParam;
+    css::uno::Sequence<sal_Int16> aOutParamIndex;
+
+    SfxObjectShell::CallXScript(
+        xComponent,
+        
"vnd.sun.Star.script:Standard.Module1.ForEachSheets?language=Basic&location=document",
+        aParams, aRet, aOutParamIndex, aOutParam);
+
+    OUString aReturnValue;
+    aRet >>= aReturnValue;
+
+    // Without the fix in place, this test would have crashed here
+    CPPUNIT_ASSERT_EQUAL(OUString("Sheet1Sheet2"), aReturnValue);
+
+    css::uno::Reference<css::util::XCloseable> xCloseable(xComponent, 
css::uno::UNO_QUERY_THROW);
+    xCloseable->close(true);
+}
+
 void ScMacrosTest::testTdf144970()
 {
     OUString aFileName;
diff --git a/sc/qa/extras/testdocuments/tdf130307.ods 
b/sc/qa/extras/testdocuments/tdf130307.ods
new file mode 100644
index 000000000000..fc354cf2cb1e
Binary files /dev/null and b/sc/qa/extras/testdocuments/tdf130307.ods differ

Reply via email to