[Libreoffice-commits] core.git: 2 commits - bin/benchmark-document-loading sfx2/source sw/source xmloff/qa xmloff/source

Tor Lillqvist tml at collabora.com
Mon Sep 30 08:04:01 PDT 2013


 bin/benchmark-document-loading   |    1 
 sfx2/source/doc/Metadatable.cxx  |   29 +++-
 sw/source/core/crsr/bookmrk.cxx  |   32 +++--
 sw/source/core/doc/doc.cxx       |   17 +-
 sw/source/core/doc/docnew.cxx    |   21 ++-
 sw/source/core/doc/docnum.cxx    |   26 +++-
 xmloff/qa/unit/uxmloff.cxx       |    6 -
 xmloff/source/style/impastpl.cxx |  230 +++++++++++++++++++++++++++++++++++----
 xmloff/source/style/impastpl.hxx |    4 
 xmloff/source/text/txtlists.cxx  |   24 ++--
 10 files changed, 323 insertions(+), 67 deletions(-)

New commits:
commit dbd6ae7dfdd292f049bbed5beb659f99e963c47b
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Sep 30 16:46:16 2013 +0300

    Set LIBO_ONEWAY_STABLE_ODF_EXPORT
    
    Change-Id: I97ef9ba6a3082403a76612cf99e46a0d19c9643e

diff --git a/bin/benchmark-document-loading b/bin/benchmark-document-loading
index feb3a4a..25f354e 100644
--- a/bin/benchmark-document-loading
+++ b/bin/benchmark-document-loading
@@ -156,6 +156,7 @@ class OfficeConnection:
         if "--valgrind" in self.args:
             argv.append("--valgrind")
         os.putenv("SAL_LOG", "-INFO-WARN")
+        os.putenv("LIBO_ONEWAY_STABLE_ODF_EXPORT", "YES")
         self.pro = subprocess.Popen(argv)
 #        print(self.pro.pid)
 
commit c1015fdd51909495cefdc0258c3899cd73d4d2df
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Sep 30 15:23:35 2013 +0300

    Add hack to optionally get stable ODF output from the same input
    
    To be used in regression testing and similar scenarios, where the output ODF
    is *not* intended to be further manipulated in LibreOffice. An environment
    variable LIBO_ONEWAY_STABLE_ODF_EXPORT is used to toggle this behaviour. I am
    not 100% sure whether the generated ODF with the hack toggled on is even fully
    correct, but correctness is not the purpose of the hack anyway.
    
    Two classes of issues handled: 1) Automatic style names and 2) use of
    randomness.
    
    For class 1), when the hack toggle is in effect, we generate the names at
    first as strings based on all the properties of the style, and sort them based
    on those, and then rename them (for brevity in the output) to the "normal"
    form of a short prefix plus a number (like "P12").
    
    Sure, it would have been better to just figure out *why* the automatic style
    naming currently is not stable in the first place, but outputs the styles in
    different order (with some styles being assigned different numbers) in
    separate invokations of LibreOffice), but I was unable to understand that.
    
    Possibly this code could be used in all cases, except that it does break some
    unit test (can't recall which right now). I don't know whether that is simply
    because the unit test assumes too much knowledge of the internal workings of
    the automatic style name generation, or whether the generated ODF is actually
    invalid.
    
    For 2), I found a handful of places where randomness was used to generated
    various kinds of identifiers in ODF output. I changed those to just use large
    (64-bit) non-overlapping integers instead. I assume there *is* a point in the
    original code in each case that explains why randomness is needed, so the hack
    definitely needs to be optional and used only for the above mentioned
    scenarios.
    
    Change-Id: I17b657197e38bcf24abdfe61ad4a277f4339eeae

diff --git a/sfx2/source/doc/Metadatable.cxx b/sfx2/source/doc/Metadatable.cxx
index d7528f6..ae4a723 100644
--- a/sfx2/source/doc/Metadatable.cxx
+++ b/sfx2/source/doc/Metadatable.cxx
@@ -394,19 +394,34 @@ template< typename T >
 /*static*/ OUString create_id(const
     ::boost::unordered_map< OUString, T, OUStringHash > & i_rXmlIdMap)
 {
-    static rtlRandomPool s_Pool( rtl_random_createPool() );
+    static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
     const OUString prefix(s_prefix);
     typename ::boost::unordered_map< OUString, T, OUStringHash >
         ::const_iterator iter;
     OUString id;
-    do
+
+    if (bHack)
+    {
+        static sal_Int64 nIdCounter = SAL_CONST_INT64(4000000000);
+        do
+        {
+            id = prefix + OUString::number(nIdCounter++);
+            iter = i_rXmlIdMap.find(id);
+        }
+        while (iter != i_rXmlIdMap.end());
+    }
+    else
     {
-        sal_Int32 n;
-        rtl_random_getBytes(s_Pool, & n, sizeof(n));
-        id = prefix + OUString::number(abs(n));
-        iter = i_rXmlIdMap.find(id);
+        static rtlRandomPool s_Pool( rtl_random_createPool() );
+        do
+        {
+            sal_Int32 n;
+            rtl_random_getBytes(s_Pool, & n, sizeof(n));
+            id = prefix + OUString::number(abs(n));
+            iter = i_rXmlIdMap.find(id);
+        }
+        while (iter != i_rXmlIdMap.end());
     }
-    while (iter != i_rXmlIdMap.end());
     return id;
 }
 
diff --git a/sw/source/core/crsr/bookmrk.cxx b/sw/source/core/crsr/bookmrk.cxx
index 11e6210..3a4ba43 100644
--- a/sw/source/core/crsr/bookmrk.cxx
+++ b/sw/source/core/crsr/bookmrk.cxx
@@ -172,19 +172,29 @@ namespace sw { namespace mark
 
     OUString MarkBase::GenerateNewName(const OUString& rPrefix)
     {
-        static rtlRandomPool aPool = rtl_random_createPool();
-        static OUString sUniquePostfix;
-        static sal_Int32 nCount = SAL_MAX_INT32;
-        OUStringBuffer aResult(rPrefix);
-        if(nCount == SAL_MAX_INT32)
+        static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
+
+        if (bHack)
+        {
+            static sal_Int64 nIdCounter = SAL_CONST_INT64(6000000000);
+            return rPrefix + OUString::number(nIdCounter++);
+        }
+        else
         {
-            sal_Int32 nRandom;
-            rtl_random_getBytes(aPool, &nRandom, sizeof(nRandom));
-            sUniquePostfix = OUStringBuffer(13).append('_').append(static_cast<sal_Int32>(abs(nRandom))).makeStringAndClear();
-            nCount = 0;
+            static rtlRandomPool aPool = rtl_random_createPool();
+            static OUString sUniquePostfix;
+            static sal_Int32 nCount = SAL_MAX_INT32;
+            OUStringBuffer aResult(rPrefix);
+            if(nCount == SAL_MAX_INT32)
+            {
+                sal_Int32 nRandom;
+                rtl_random_getBytes(aPool, &nRandom, sizeof(nRandom));
+                sUniquePostfix = OUStringBuffer(13).append('_').append(static_cast<sal_Int32>(abs(nRandom))).makeStringAndClear();
+                nCount = 0;
+            }
+            // putting the counter in front of the random parts will speed up string comparisons
+            return aResult.append(nCount++).append(sUniquePostfix).makeStringAndClear();
         }
-        // putting the counter in front of the random parts will speed up string comparisons
-        return aResult.append(nCount++).append(sUniquePostfix).makeStringAndClear();
     }
 
     void MarkBase::Modify( const SfxPoolItem *pOld, const SfxPoolItem *pNew )
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index a4eef0e..e4bdbca 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -476,13 +476,18 @@ sal_uInt32 SwDoc::getRsid() const
 
 void SwDoc::setRsid( sal_uInt32 nVal )
 {
-    // Increase the rsid with a random number smaller than 2^17. This way we
-    // expect to be able to edit a document 2^12 times before rsid overflows.
+    static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
+
     sal_uInt32 nIncrease = 0;
-    static rtlRandomPool aPool = rtl_random_createPool();
-    rtl_random_getBytes( aPool, &nIncrease, sizeof ( nIncrease ) );
-    nIncrease &= ( 1<<17 ) - 1;
-    nIncrease++; // make sure the new rsid is not the same
+    if (!bHack)
+    {
+        // Increase the rsid with a random number smaller than 2^17. This way we
+        // expect to be able to edit a document 2^12 times before rsid overflows.
+        static rtlRandomPool aPool = rtl_random_createPool();
+        rtl_random_getBytes( aPool, &nIncrease, sizeof ( nIncrease ) );
+        nIncrease &= ( 1<<17 ) - 1;
+        nIncrease++; // make sure the new rsid is not the same
+    }
     mnRsid = nVal + nIncrease;
 }
 
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 7c3b3c8..1a2fb44 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -407,12 +407,21 @@ SwDoc::SwDoc()
         mpStyleAccess = createStyleManager( &aIgnorableParagraphItems );
     }
 
-    // Initialize the session id of the current document to a random number
-    // smaller than 2^21.
-    static rtlRandomPool aPool = rtl_random_createPool();
-    rtl_random_getBytes( aPool, &mnRsid, sizeof ( mnRsid ) );
-    mnRsid &= ( 1<<21 ) - 1;
-    mnRsid++;
+    static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
+
+    if (bHack)
+    {
+        mnRsid = 0;
+    }
+    else
+    {
+        // Initialize the session id of the current document to a random number
+        // smaller than 2^21.
+        static rtlRandomPool aPool = rtl_random_createPool();
+        rtl_random_getBytes( aPool, &mnRsid, sizeof ( mnRsid ) );
+        mnRsid &= ( 1<<21 ) - 1;
+        mnRsid++;
+    }
     mnRsidRoot = mnRsid;
 
     ResetModified();
diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx
index 5df1a80..8057764 100644
--- a/sw/source/core/doc/docnum.cxx
+++ b/sw/source/core/doc/docnum.cxx
@@ -2596,15 +2596,25 @@ namespace listfunc
     }
     const String CreateUniqueListId( const SwDoc& rDoc )
     {
-        // #i92478#
-        OUString aNewListId( "list" );
-        // #o12311627#
-        static rtlRandomPool s_RandomPool( rtl_random_createPool() );
-        sal_Int64 n;
-        rtl_random_getBytes( s_RandomPool, &n, sizeof(n) );
-        aNewListId += OUString::number( (n < 0 ? -n : n) );
+        static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
 
-        return MakeListIdUnique( rDoc, aNewListId );
+        if (bHack)
+        {
+            static sal_Int64 nIdCounter = SAL_CONST_INT64(7000000000);
+            return MakeListIdUnique( rDoc, OUString( "list" + OUString::number(nIdCounter++) ) );
+        }
+        else
+        {
+            // #i92478#
+            OUString aNewListId( "list" );
+            // #o12311627#
+            static rtlRandomPool s_RandomPool( rtl_random_createPool() );
+            sal_Int64 n;
+            rtl_random_getBytes( s_RandomPool, &n, sizeof(n) );
+            aNewListId += OUString::number( (n < 0 ? -n : n) );
+
+            return MakeListIdUnique( rDoc, aNewListId );
+        }
     }
 }
 
diff --git a/xmloff/qa/unit/uxmloff.cxx b/xmloff/qa/unit/uxmloff.cxx
index a0bd430..8dfa502 100644
--- a/xmloff/qa/unit/uxmloff.cxx
+++ b/xmloff/qa/unit/uxmloff.cxx
@@ -75,7 +75,11 @@ void Test::testAutoStylePool()
     OUString aName = xPool->Add( XML_STYLE_FAMILY_TEXT_PARAGRAPH, "", aProperties );
 
     // not that interesting but worth checking
-    CPPUNIT_ASSERT_MESSAGE( "style / naming changed", aName == "Bob1" );
+    bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
+    if (bHack)
+        CPPUNIT_ASSERT_MESSAGE( "style / naming changed", aName == "Bob" );
+    else
+        CPPUNIT_ASSERT_MESSAGE( "style / naming changed", aName == "Bob1" );
 
     // find ourselves again:
     OUString aSameName = xPool->Find( XML_STYLE_FAMILY_TEXT_PARAGRAPH, "", aProperties );
diff --git a/xmloff/source/style/impastpl.cxx b/xmloff/source/style/impastpl.cxx
index 9b54e94..8aca0b1 100644
--- a/xmloff/source/style/impastpl.cxx
+++ b/xmloff/source/style/impastpl.cxx
@@ -60,24 +60,190 @@ void XMLAutoStyleFamily::ClearEntries()
     maParentSet.clear();
 }
 
+static OUString
+data2string(void *data,
+            const typelib_TypeDescriptionReference *type);
+
+static OUString
+struct2string(void *data,
+              const typelib_TypeDescription *type)
+{
+    assert(type->eTypeClass == typelib_TypeClass_STRUCT);
+
+    OUStringBuffer result;
+
+    result.append("{");
+
+    const typelib_CompoundTypeDescription *compoundType =
+        &((const typelib_StructTypeDescription*) type)->aBase;
+
+    for (int i = 0; i < compoundType->nMembers; i++)
+    {
+        if (i > 0)
+            result.append(":");
+        result.append(compoundType->ppMemberNames[i]);
+        result.append("=");
+        result.append(data2string(((char *)data)+compoundType->pMemberOffsets[i],
+                                  compoundType->ppTypeRefs[i]));
+    }
+
+    result.append("}");
+
+    return result.makeStringAndClear();
+}
+
+static OUString
+data2string(void *data,
+            const typelib_TypeDescriptionReference *type)
+{
+    OUStringBuffer result;
+
+    switch (type->eTypeClass)
+    {
+    case typelib_TypeClass_VOID:
+        break;
+    case typelib_TypeClass_BOOLEAN:
+        result.append((*reinterpret_cast<const sal_Bool*>(data) == sal_False ) ? OUString("false") : OUString("true"));
+        break;
+    case typelib_TypeClass_BYTE:
+        result.append(OUString::number((*reinterpret_cast<const sal_Int8*>(data))));
+        break;
+    case typelib_TypeClass_SHORT:
+        result.append(OUString::number((*reinterpret_cast<const sal_Int16*>(data))));
+        break;
+    case typelib_TypeClass_LONG:
+        result.append(OUString::number((*reinterpret_cast<const sal_Int32*>(data))));
+        break;
+    case typelib_TypeClass_HYPER:
+        result.append(OUString::number((*reinterpret_cast<const sal_Int64*>(data))));
+        break;
+    case typelib_TypeClass_UNSIGNED_SHORT:
+        result.append(OUString::number((*reinterpret_cast<const sal_uInt16*>(data))));
+        break;
+    case typelib_TypeClass_UNSIGNED_LONG:
+        result.append(OUString::number((*reinterpret_cast<const sal_uInt32*>(data)), 16));
+        break;
+    case typelib_TypeClass_UNSIGNED_HYPER:
+        result.append(OUString::number((*reinterpret_cast<const sal_uInt64*>(data)), 16));
+        break;
+    case typelib_TypeClass_FLOAT:
+        result.append(OUString::number((*reinterpret_cast<const float*>(data))));
+        break;
+    case typelib_TypeClass_DOUBLE:
+        result.append(OUString::number((*reinterpret_cast<const double*>(data))));
+        break;
+    case typelib_TypeClass_CHAR:
+        result.append("U+");
+        result.append(OUString::number((*reinterpret_cast<const sal_uInt16*>(data))));
+        break;
+    case typelib_TypeClass_STRING:
+        result.append(*reinterpret_cast<OUString*>(data));
+        break;
+    case typelib_TypeClass_TYPE:
+    case typelib_TypeClass_SEQUENCE:
+    case typelib_TypeClass_EXCEPTION:
+    case typelib_TypeClass_INTERFACE:
+        result.append("wtf");
+        break;
+    case typelib_TypeClass_STRUCT:
+        result.append(struct2string(data, type->pType));
+        break;
+    case typelib_TypeClass_ENUM:
+        result.append(OUString::number((*reinterpret_cast<const sal_Int32*>(data))));
+        break;
+    default:
+        assert(false); // this cannot happen I hope
+        break;
+    }
+
+    return result.makeStringAndClear();
+}
+
+static OUString
+any2string(uno::Any any)
+{
+    return data2string((void*)any.getValue(), any.pType);
+}
+
 // Class SvXMLAutoStylePoolProperties_Impl
 // ctor class SvXMLAutoStylePoolProperties_Impl
 
-XMLAutoStylePoolProperties::XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, const vector< XMLPropertyState >& rProperties )
+XMLAutoStylePoolProperties::XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, const vector< XMLPropertyState >& rProperties, OUString& rParentName )
 : maProperties( rProperties ),
   mnPos       ( rFamilyData.mnCount )
 {
-    // create a name that hasn't been used before. The created name has not
-    // to be added to the array, because it will never tried again
-    OUStringBuffer sBuffer( 7 );
-    do
+    static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
+
+    if (bHack)
     {
-        rFamilyData.mnName++;
-        sBuffer.append( rFamilyData.maStrPrefix );
-        sBuffer.append( OUString::number( rFamilyData.mnName ) );
-        msName = sBuffer.makeStringAndClear();
+        OUStringBuffer aStemBuffer(32);
+        aStemBuffer.append( rFamilyData.maStrPrefix );
+
+        if (rParentName != "")
+            {
+                aStemBuffer.append("-");
+                aStemBuffer.append(rParentName);
+            }
+
+        // Create a name based on the properties used
+        for( size_t i = 0, n = maProperties.size(); i < n; ++i )
+            {
+                XMLPropertyState& rState = maProperties[i];
+                if (rState.mnIndex == -1)
+                    continue;
+                OUString sXMLName(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryXMLName(rState.mnIndex));
+                if (sXMLName == "")
+                    continue;
+                aStemBuffer.append("-");
+                aStemBuffer.append(OUString::number(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryNameSpace(rState.mnIndex)));
+                aStemBuffer.append(":");
+                aStemBuffer.append(sXMLName);
+                aStemBuffer.append("=");
+                aStemBuffer.append(any2string(rState.maValue));
+            }
+
+#if 0
+        // Finally append an incremental counter in an attempt to make identical
+        // styles always come out in the same order. Will see if this works.
+        aStemBuffer.append("-z");
+        static sal_Int32 nCounter = 0;
+        aStemBuffer.append(OUString::number(nCounter++));
+#endif
+
+        // create a name that hasn't been used before. The created name has not
+        // to be added to the array, because it will never tried again
+        OUStringBuffer aTry( aStemBuffer );
+
+        msName = aTry.makeStringAndClear();
+        bool bWarned = false;
+        while (rFamilyData.maNameSet.find(msName) !=
+               rFamilyData.maNameSet.end())
+        {
+            if (!bWarned)
+                SAL_WARN("xmloff", "Overlapping style name for " << msName);
+            bWarned = true;
+            rFamilyData.mnName++;
+            aTry.append( aStemBuffer );
+            aTry.append( "-" );
+            aTry.append( OUString::number( rFamilyData.mnName ) );
+            msName = aTry.makeStringAndClear();
+        }
+        rFamilyData.maNameSet.insert(msName);
+    }
+    else
+    {
+        // create a name that hasn't been used before. The created name has not
+        // to be added to the array, because it will never tried again
+        OUStringBuffer sBuffer( 7 );
+        do
+        {
+            rFamilyData.mnName++;
+            sBuffer.append( rFamilyData.maStrPrefix );
+            sBuffer.append( OUString::number( rFamilyData.mnName ) );
+            msName = sBuffer.makeStringAndClear();
+        }
+        while (rFamilyData.maNameSet.find(msName) != rFamilyData.maNameSet.end());
     }
-    while (rFamilyData.maNameSet.find(msName) != rFamilyData.maNameSet.end());
 }
 
 bool operator<( const XMLAutoStyleFamily& r1, const XMLAutoStyleFamily& r2)
@@ -119,7 +285,7 @@ sal_Bool XMLAutoStylePoolParent::Add( XMLAutoStyleFamily& rFamilyData, const vec
 
     if( !pProperties )
     {
-        pProperties = new XMLAutoStylePoolProperties( rFamilyData, rProperties );
+        pProperties = new XMLAutoStylePoolProperties( rFamilyData, rProperties, msParent );
         PropertiesListType::iterator it = maPropertiesList.begin();
         ::std::advance( it, i );
         maPropertiesList.insert( it, pProperties );
@@ -158,7 +324,7 @@ sal_Bool XMLAutoStylePoolParent::AddNamed( XMLAutoStyleFamily& rFamilyData, cons
     if (rFamilyData.maNameSet.find(rName) == rFamilyData.maNameSet.end())
     {
         XMLAutoStylePoolProperties* pProperties =
-                new XMLAutoStylePoolProperties( rFamilyData, rProperties );
+                new XMLAutoStylePoolProperties( rFamilyData, rProperties, msParent );
         // ignore the generated name
         pProperties->SetName( rName );
         PropertiesListType::iterator it = maPropertiesList.begin();
@@ -274,7 +440,10 @@ void SvXMLAutoStylePoolP_Impl::RegisterName( sal_Int32 nFamily, const OUString&
     DBG_ASSERT( aFind != maFamilySet.end(),
                 "SvXMLAutoStylePool_Impl::RegisterName: unknown family" );
     if (aFind != maFamilySet.end())
+    {
+        // SAL_DEBUG("SvXMLAutoStylePoolP_Impl::RegisterName: " << nFamily << ", '" << rName << "'");
         aFind->maNameSet.insert(rName);
+    }
 }
 
 //
@@ -418,7 +587,7 @@ namespace {
 struct AutoStylePoolExport
 {
     const OUString* mpParent;
-    const XMLAutoStylePoolProperties* mpProperties;
+    XMLAutoStylePoolProperties* mpProperties;
 
     AutoStylePoolExport() : mpParent(NULL), mpProperties(NULL) {}
 };
@@ -450,21 +619,20 @@ void SvXMLAutoStylePoolP_Impl::exportXML(
     // which contains a parent-name and a SvXMLAutoStylePoolProperties_Impl
     std::vector<AutoStylePoolExport> aExpStyles(nCount);
 
-    sal_uInt32 i;
-    for( i=0; i < nCount; i++ )
+    for( size_t i=0; i < nCount; i++ )
     {
         aExpStyles[i].mpParent = 0;
         aExpStyles[i].mpProperties = 0;
     }
 
-    XMLAutoStyleFamily::ParentSetType::const_iterator it = rFamily.maParentSet.begin(), itEnd = rFamily.maParentSet.end();
+    XMLAutoStyleFamily::ParentSetType::iterator it = rFamily.maParentSet.begin(), itEnd = rFamily.maParentSet.end();
     for (; it != itEnd; ++it)
     {
-        const XMLAutoStylePoolParent& rParent = *it;
+        XMLAutoStylePoolParent& rParent = *it;
         size_t nProperties = rParent.GetPropertiesList().size();
         for( size_t j = 0; j < nProperties; j++ )
         {
-            const XMLAutoStylePoolProperties* pProperties =
+            XMLAutoStylePoolProperties* pProperties =
                 &rParent.GetPropertiesList()[j];
             sal_uLong nPos = pProperties->GetPos();
             DBG_ASSERT( nPos < nCount,
@@ -479,12 +647,36 @@ void SvXMLAutoStylePoolP_Impl::exportXML(
         }
     }
 
+    static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
+
+    if (bHack)
+    {
+        struct {
+            bool operator() (AutoStylePoolExport a, AutoStylePoolExport b)
+            {
+                return (a.mpProperties->GetName() < b.mpProperties->GetName() ||
+                        (a.mpProperties->GetName() == b.mpProperties->GetName() && *a.mpParent < *b.mpParent));
+            }
+        } aComparator;
+
+        std::sort(aExpStyles.begin(), aExpStyles.end(), aComparator);
+
+        for (size_t i = 0; i < nCount; i++)
+        {
+            OUString oldName = aExpStyles[i].mpProperties->GetName();
+            sal_Int32 dashIx = oldName.indexOf('-');
+            OUString newName = (dashIx > 0 ? oldName.copy(0, dashIx) : oldName) + OUString::number(i);
+            // SAL_DEBUG("renaming '" << oldName << "' -> '" << newName << "'");
+            aExpStyles[i].mpProperties->SetName(newName);
+        }
+    }
+
     //
     // create string to export for each XML-style. That means for each property-list
     //
     OUString aStrFamilyName = rFamily.maStrFamilyName;
 
-    for( i=0; i<nCount; i++ )
+    for( size_t i = 0; i < nCount; i++ )
     {
         DBG_ASSERT( aExpStyles[i].mpProperties,
                     "SvXMLAutoStylePool_Impl::exportXML: empty position" );
diff --git a/xmloff/source/style/impastpl.hxx b/xmloff/source/style/impastpl.hxx
index f8e2e28..409ac0c 100644
--- a/xmloff/source/style/impastpl.hxx
+++ b/xmloff/source/style/impastpl.hxx
@@ -80,7 +80,7 @@ class XMLAutoStylePoolProperties
 
 public:
 
-    XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, const ::std::vector< XMLPropertyState >& rProperties );
+    XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, const ::std::vector< XMLPropertyState >& rProperties, OUString& rParentname );
 
     ~XMLAutoStylePoolProperties()
     {
@@ -120,7 +120,7 @@ public:
 
     const OUString& GetParent() const { return msParent; }
 
-    const PropertiesListType& GetPropertiesList() const
+    PropertiesListType& GetPropertiesList()
     {
         return maPropertiesList;
     }
diff --git a/xmloff/source/text/txtlists.cxx b/xmloff/source/text/txtlists.cxx
index 1c35a54f..853286f 100644
--- a/xmloff/source/text/txtlists.cxx
+++ b/xmloff/source/text/txtlists.cxx
@@ -228,13 +228,23 @@ const OUString& XMLTextListsHelper::GetListStyleOfLastProcessedList() const
 
 OUString XMLTextListsHelper::GenerateNewListId() const
 {
-    // Value of xml:id in element <text:list> has to be a valid ID type (#i92478#)
-    OUString sTmpStr( "list"  );
-    sal_Int64 n = Time( Time::SYSTEM ).GetTime();
-    n += Date( Date::SYSTEM ).GetDate();
-    n += rand();
-    // Value of xml:id in element <text:list> has to be a valid ID type (#i92478#)
-    sTmpStr += OUString::number( n );
+    static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
+    OUString sTmpStr( "list" );
+
+    if (bHack)
+    {
+        static sal_Int64 nIdCounter = SAL_CONST_INT64(5000000000);
+        sTmpStr += OUString::number(nIdCounter++);
+    }
+    else
+    {
+        // Value of xml:id in element <text:list> has to be a valid ID type (#i92478#)
+        sal_Int64 n = Time( Time::SYSTEM ).GetTime();
+        n += Date( Date::SYSTEM ).GetDate();
+        n += rand();
+        // Value of xml:id in element <text:list> has to be a valid ID type (#i92478#)
+        sTmpStr += OUString::number( n );
+    }
 
     OUString sNewListId( sTmpStr );
     if ( mpProcessedLists != 0 )


More information about the Libreoffice-commits mailing list