[Libreoffice-commits] core.git: include/oox oox/source sw/qa sw/source writerfilter/source

umeshkadam umesh.kadam at synerzip.com
Tue Apr 22 03:10:10 PDT 2014


 include/oox/drawingml/shape.hxx                       |   16 ++
 oox/source/drawingml/shape.cxx                        |   19 +++
 oox/source/shape/WpsContext.cxx                       |   35 +++++-
 oox/source/token/tokens.txt                           |    1 
 sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx    |binary
 sw/qa/extras/ooxmlexport/ooxmlexport.cxx              |   10 +
 sw/source/filter/ww8/docxsdrexport.cxx                |   75 +++++++++++--
 writerfilter/source/dmapper/DomainMapper_Impl.cxx     |  103 +++++++++++++++++-
 writerfilter/source/dmapper/DomainMapper_Impl.hxx     |    2 
 writerfilter/source/ooxml/OOXMLFastContextHandler.cxx |    3 
 10 files changed, 250 insertions(+), 14 deletions(-)

New commits:
commit 255194801e9eb8e3aaede56837450af35f8313e0
Author: umeshkadam <umesh.kadam at synerzip.com>
Date:   Fri Apr 18 13:12:53 2014 +0530

    fod#77122 DOCX filter: link between textboxes is not being preserved
    
    Added support for linked textboxes for docx interoperability.
    
    Reviewed on:
    	https://gerrit.libreoffice.org/9092
    
    Change-Id: I7db4f5a1783afff53c64908d182788b262f5e863

diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx
index a7232fa..926f223 100644
--- a/include/oox/drawingml/shape.hxx
+++ b/include/oox/drawingml/shape.hxx
@@ -63,6 +63,15 @@ struct ChartShapeInfo
     explicit     ChartShapeInfo( bool bEmbedShapes ) : mbEmbedShapes( bEmbedShapes ) {}
 };
 
+/// Attributes for a linked textbox.
+struct LinkedTxbxAttr
+{
+    sal_Int32 id;
+    sal_Int32 seq;
+    LinkedTxbxAttr(): id(0),seq(0){};
+    ~LinkedTxbxAttr(){};
+};
+
 class OOX_DLLPUBLIC Shape
     : public boost::enable_shared_from_this< Shape >
 {
@@ -176,6 +185,11 @@ public:
     void                setDiagramDoms(const com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& rDiagramDoms) { maDiagramDoms = rDiagramDoms; }
     com::sun::star::uno::Sequence< com::sun::star::uno::Sequence< com::sun::star::uno::Any > >resolveRelationshipsOfTypeFromOfficeDoc(
                                                                           core::XmlFilterBase& rFilter, const OUString& sFragment, const OUString& sType );
+    void                setLinkedTxbxAttributes(const LinkedTxbxAttr& rhs){ maLinkedTxbxAttr = rhs; };
+    void                setTxbxHasLinkedTxtBox( const bool rhs){ mbHasLinkedTxbx = rhs; };
+    const LinkedTxbxAttr&     getLinkedTxbxAttributes() { return maLinkedTxbxAttr; };
+    bool                isLinkedTxbx() { return mbHasLinkedTxbx; };
+
 protected:
 
     ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
@@ -279,6 +293,8 @@ private:
                                                          // to propagate it when applying reference shape
     bool mbLockedCanvas; ///< Is this shape part of a locked canvas?
     bool mbWps; ///< Is this a wps shape?
+    LinkedTxbxAttr                  maLinkedTxbxAttr;
+    bool                            mbHasLinkedTxbx; // this text box has linked text box ?
 
     com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> maDiagramDoms;
 };
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index f7150db..1d0d452 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -139,6 +139,8 @@ Shape::Shape( const ShapePtr& pSourceShape )
 , mbHiddenMasterShape( pSourceShape->mbHiddenMasterShape )
 , mbLockedCanvas( pSourceShape->mbLockedCanvas )
 , mbWps( pSourceShape->mbWps )
+, maLinkedTxbxAttr()
+, mbHasLinkedTxbx(false)
 , maDiagramDoms( pSourceShape->maDiagramDoms )
 {}
 
@@ -677,6 +679,23 @@ Reference< XShape > Shape::createAndInsert(
                     aGrabBag[length].Value = uno::makeAny(mpCustomShapePropertiesPtr->getShapePresetTypeName());
                     propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag));
                 }
+                //If the text box has links then save the link information so that
+                //it can be accessed in DomainMapper_Impl.cxx while chaining the text frames.
+                if (this->isLinkedTxbx())
+                {
+                    uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
+                    uno::Sequence<beans::PropertyValue> aGrabBag;
+                    propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
+                    sal_Int32 length = aGrabBag.getLength();
+                    aGrabBag.realloc( length + 3 );
+                    aGrabBag[length].Name = "TxbxHasLink";
+                    aGrabBag[length].Value = uno::makeAny(this->isLinkedTxbx());
+                    aGrabBag[length + 1 ].Name = "Txbx-Id";
+                    aGrabBag[length + 1 ].Value = uno::makeAny(this->getLinkedTxbxAttributes().id);
+                    aGrabBag[length + 2 ].Name = "Txbx-Seq";
+                    aGrabBag[length + 2 ].Value = uno::makeAny(this->getLinkedTxbxAttributes().seq);
+                    propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag));
+                }
 
                 // TextFrames have BackColor, not FillColor
                 if (aShapeProps.hasProperty(PROP_FillColor))
diff --git a/oox/source/shape/WpsContext.cxx b/oox/source/shape/WpsContext.cxx
index c30992d..5723709 100644
--- a/oox/source/shape/WpsContext.cxx
+++ b/oox/source/shape/WpsContext.cxx
@@ -109,9 +109,42 @@ oox::core::ContextHandlerRef WpsContext::onCreateContext(sal_Int32 nElementToken
     }
     break;
     case XML_txbx:
+    {
         mpShape->getCustomShapeProperties()->setShapeTypeOverride(true);
         mpShape->setServiceName("com.sun.star.text.TextFrame");
-        break;
+        //in case if the textbox is linked, save the attributes
+        //for further processing.
+        if (rAttribs.hasAttribute(XML_id))
+        {
+            OptValue<OUString> id = rAttribs.getString(XML_id);
+            if (id.has())
+            {
+                oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr ;
+                linkedTxtBoxAttr.id = id.get().toInt32();
+                mpShape->setTxbxHasLinkedTxtBox(true);
+                mpShape->setLinkedTxbxAttributes(linkedTxtBoxAttr);
+            }
+        }
+    }
+    break;
+    case XML_linkedTxbx:
+    {
+        //in case if the textbox is linked, save the attributes
+        //for further processing.
+        mpShape->getCustomShapeProperties()->setShapeTypeOverride(true);
+        mpShape->setServiceName("com.sun.star.text.TextFrame");
+        OptValue<OUString> id  = rAttribs.getString(XML_id);
+        OptValue<OUString> seq = rAttribs.getString(XML_seq);
+        if (id.has() && seq.has())
+        {
+            oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr ;
+            linkedTxtBoxAttr.id  = id.get().toInt32();
+            linkedTxtBoxAttr.seq = seq.get().toInt32();
+            mpShape->setTxbxHasLinkedTxtBox(true);
+            mpShape->setLinkedTxbxAttributes(linkedTxtBoxAttr);
+        }
+    }
+    break;
     default:
         SAL_WARN("oox", "WpsContext::createFastChildContext: unhandled element: " << getBaseToken(nElementToken));
         break;
diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt
index e274001..bab7cf1 100644
--- a/oox/source/token/tokens.txt
+++ b/oox/source/token/tokens.txt
@@ -3074,6 +3074,7 @@ lines
 linesAndChars
 linestyle
 link
+linkedTxbx
 linkStyles
 linkTarget
 linkToQuery
diff --git a/sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx b/sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx
new file mode 100644
index 0000000..1c953c2
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index a7ad9b7..00122ea 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -3087,6 +3087,16 @@ DECLARE_OOXMLEXPORT_TEST(testAuthorPropertySdt, "author-property.docx")
     //            "xmlns:ns0='http://purl.org/dc/elements/1.1/' xmlns:ns1='http://schemas.openxmlformats.org/package/2006/metadata/core-properties'");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testFDO77122, "LinkedTextBoxes.docx")
+{
+    xmlDocPtr pXmlDoc = parseExport("word/document.xml");
+    if (!pXmlDoc)
+        return;
+    //ensure that the text box links are preserved.
+    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData[1]/wps:wsp[1]/wps:txbx[1]", "id", "1");
+    assertXPath(pXmlDoc, "/w:document[1]/w:body[1]/w:p[1]/w:r[3]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:linkedTxbx[1]", "id", "1");
+}
+
 DECLARE_OOXMLEXPORT_TEST(testFDO76586, "fdo76586.docx")
 {
     /*
diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx
index a2cb109..da3c9e9 100644
--- a/sw/source/filter/ww8/docxsdrexport.cxx
+++ b/sw/source/filter/ww8/docxsdrexport.cxx
@@ -148,6 +148,8 @@ struct DocxSdrExport::Impl
     sax_fastparser::FastAttributeList* m_pBodyPrAttrList;
     sax_fastparser::FastAttributeList* m_pDashLineStyleAttr;
     bool m_bIsInDMLTextFrame;
+    sal_Int32 m_nId ;
+    sal_Int32 m_nSeq ;
 
     Impl(DocxSdrExport& rSdrExport, DocxExport& rExport, sax_fastparser::FSHelperPtr pSerializer, oox::drawingml::DrawingML* pDrawingML)
         : m_rSdrExport(rSdrExport),
@@ -165,7 +167,9 @@ struct DocxSdrExport::Impl
           m_pFlyWrapAttrList(0),
           m_pBodyPrAttrList(0),
           m_pDashLineStyleAttr(0),
-          m_bIsInDMLTextFrame(false)
+          m_bIsInDMLTextFrame(false),
+          m_nId(0),
+          m_nSeq(0)
     {
     }
 
@@ -1176,17 +1180,68 @@ void DocxSdrExport::writeDMLTextFrame(sw::Frame* pParentFrame, int nAnchorId)
     pFS->endElementNS(XML_wps, XML_spPr);
 
     m_pImpl->m_rExport.mpParentFrame = NULL;
-    pFS->startElementNS(XML_wps, XML_txbx, FSEND);
-    pFS->startElementNS(XML_w, XML_txbxContent, FSEND);
+    bool skipTxBxContent = false ;
+    bool isTxbxLinked = false ;
+
+    /* Check if the text box is linked and then decides whether
+       to write the tag txbx or linkedTxbx
+    */
+    if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("ChainPrevName") &&
+            xPropSetInfo->hasPropertyByName("ChainNextName"))
+    {
+        OUString sChainPrevName;
+        OUString sChainNextName;
 
-    m_pImpl->m_bFrameBtLr = checkFrameBtlr(m_pImpl->m_rExport.pDoc->GetNodes()[nStt], 0);
-    m_pImpl->m_bFlyFrameGraphic = true;
-    m_pImpl->m_rExport.WriteText();
-    m_pImpl->m_bFlyFrameGraphic = false;
-    m_pImpl->m_bFrameBtLr = false;
+        xPropertySet->getPropertyValue("ChainPrevName") >>= sChainPrevName ;
+        xPropertySet->getPropertyValue("ChainNextName") >>= sChainNextName ;
 
-    pFS->endElementNS(XML_w, XML_txbxContent);
-    pFS->endElementNS(XML_wps, XML_txbx);
+        if (!sChainPrevName.isEmpty())
+        {
+            /* no text content should be added to this tag,
+               since the textbox is linked, the entire content
+               is written in txbx block
+            */
+            ++m_pImpl->m_nSeq ;
+            pFS->singleElementNS(XML_wps, XML_linkedTxbx,
+                                 XML_id,  I32S(m_pImpl->m_nId),
+                                 XML_seq, I32S(m_pImpl->m_nSeq),
+                                 FSEND);
+            skipTxBxContent = true ;
+
+            //Text box chaining for a group of textboxes ends here,
+            //therefore reset the seq.
+            if (sChainNextName.isEmpty())
+                m_pImpl->m_nSeq = 0 ;
+        }
+        else if (sChainPrevName.isEmpty() && !sChainNextName.isEmpty())
+        {
+            /* this is the first textbox in the chaining, we add the text content
+               to this block*/
+            ++m_pImpl->m_nId ;
+            //since the text box is linked, it needs an id.
+            pFS->startElementNS(XML_wps, XML_txbx,
+                                XML_id, I32S(m_pImpl->m_nId),
+                                FSEND);
+            isTxbxLinked = true ;
+        }
+    }
+
+    if (!skipTxBxContent)
+    {
+        if (!isTxbxLinked)
+            pFS->startElementNS(XML_wps, XML_txbx, FSEND);//text box is not linked, therefore no id.
+
+        pFS->startElementNS(XML_w, XML_txbxContent, FSEND);
+
+        m_pImpl->m_bFrameBtLr = checkFrameBtlr(m_pImpl->m_rExport.pDoc->GetNodes()[nStt], 0);
+        m_pImpl->m_bFlyFrameGraphic = true;
+        m_pImpl->m_rExport.WriteText();
+        m_pImpl->m_bFlyFrameGraphic = false;
+        m_pImpl->m_bFrameBtLr = false;
+
+        pFS->endElementNS(XML_w, XML_txbxContent);
+        pFS->endElementNS(XML_wps, XML_txbx);
+    }
     sax_fastparser::XFastAttributeListRef xBodyPrAttrList(m_pImpl->m_pBodyPrAttrList);
     m_pImpl->m_pBodyPrAttrList = NULL;
     pFS->startElementNS(XML_wps, XML_bodyPr, xBodyPrAttrList);
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 88bcabd..434e9b0 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -59,7 +59,7 @@
 #include <com/sun/star/text/ControlCharacter.hpp>
 #include <com/sun/star/text/XTextColumns.hpp>
 #include <oox/mathml/import.hxx>
- #include <GraphicHelpers.hxx>
+#include <GraphicHelpers.hxx>
 
 #ifdef DEBUG_DOMAINMAPPER
 #include <resourcemodel/QNameToString.hxx>
@@ -195,7 +195,8 @@ DomainMapper_Impl::DomainMapper_Impl(
         m_bHasFtnSep(false),
         m_bIgnoreNextPara(false),
         m_bIgnoreNextTab(false),
-        m_bFrameBtLr(false)
+        m_bFrameBtLr(false),
+        m_vTextFramesForChaining()
 
 {
     appendTableManager( );
@@ -221,6 +222,7 @@ DomainMapper_Impl::DomainMapper_Impl(
 
 DomainMapper_Impl::~DomainMapper_Impl()
 {
+    ChainTextFrames();
     RemoveLastParagraph( );
     getTableManager( ).endLevel();
     popTableManager( );
@@ -1775,6 +1777,15 @@ void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape
                     }
                     if(checkBtLrStatus && checkZOredrStatus)
                         break;
+
+                    if ( aGrabBag[i].Name == "TxbxHasLink" )
+                    {
+                        //Chaining of textboxes will happen in ~DomainMapper_Impl
+                        //i.e when all the textboxes are read and all its attributes
+                        //have been set ( basically the Name/LinkedDisplayName )
+                        //which is set in Graphic Import.
+                        m_vTextFramesForChaining.push_back(xShape);
+                    }
                 }
 
                 uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY_THROW);
@@ -2219,7 +2230,95 @@ void DomainMapper_Impl::SetNumberFormat( const OUString& rCommand,
     }
 }
 
+static uno::Any lcl_getGrabBagValue( const uno::Sequence<beans::PropertyValue>& grabBag, OUString name )
+{
+    for (int i = 0; i < grabBag.getLength(); ++i)
+    {
+        if (grabBag[i].Name == name )
+            return grabBag[i].Value ;
+    }
+    return uno::Any();
+}
+
+//Link the text frames.
+void DomainMapper_Impl::ChainTextFrames()
+{
+    if( 0 == m_vTextFramesForChaining.size() )
+        return ;
+
+    try
+    {
+        bool bIsTxbxChained = false ;
+        sal_Int32 nTxbxId1  = 0 ; //holds id for the shape in outer loop
+        sal_Int32 nTxbxId2  = 0 ; //holds id for the shape in inner loop
+        sal_Int32 nTxbxSeq1 = 0 ; //holds seq number for the shape in outer loop
+        sal_Int32 nTxbxSeq2 = 0 ; //holds seq number for the shape in inner loop
+        OUString sName1 ; //holds the text box Name for the shape in outer loop
+        OUString sName2 ; //holds the text box Name for the shape in outer loop
+        OUString sChainNextName("ChainNextName");
+        OUString sChainPrevName("ChainPrevName");
+
+        for( std::vector<uno::Reference< drawing::XShape > >::iterator outer_itr = m_vTextFramesForChaining.begin();
+             outer_itr != m_vTextFramesForChaining.end(); )
+        {
+            bIsTxbxChained = false ;
+            uno::Reference<text::XTextContent>  xTextContent1(*outer_itr, uno::UNO_QUERY_THROW);
+            uno::Reference<beans::XPropertySet> xPropertySet1(xTextContent1, uno::UNO_QUERY);
+            uno::Sequence<beans::PropertyValue> aGrabBag1;
+            xPropertySet1->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag1;
+            xPropertySet1->getPropertyValue("LinkDisplayName") >>= sName1;
+
+            lcl_getGrabBagValue( aGrabBag1, "Txbx-Id")  >>= nTxbxId1;
+            lcl_getGrabBagValue( aGrabBag1, "Txbx-Seq") >>= nTxbxSeq1;
+
+            //Check which text box in the document links/(is a link) to this one.
+            std::vector<uno::Reference< drawing::XShape > >::iterator inner_itr = ( outer_itr + 1 );
+            for( ; inner_itr != m_vTextFramesForChaining.end(); ++inner_itr )
+            {
+                uno::Reference<text::XTextContent>  xTextContent2(*inner_itr, uno::UNO_QUERY_THROW);
+                uno::Reference<beans::XPropertySet> xPropertySet2(xTextContent2, uno::UNO_QUERY);
+                uno::Sequence<beans::PropertyValue> aGrabBag2;
+                xPropertySet2->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag2;
+                xPropertySet2->getPropertyValue("LinkDisplayName") >>= sName2;
+
+                lcl_getGrabBagValue( aGrabBag2, "Txbx-Id")  >>= nTxbxId2;
+                lcl_getGrabBagValue( aGrabBag2, "Txbx-Seq") >>= nTxbxSeq2;
 
+                if ( nTxbxId1 == nTxbxId2 )
+                {
+                    //who connects whom ??
+                    if ( ( nTxbxSeq1 == ( nTxbxSeq2 + 1 ) ) )
+                    {
+                        xPropertySet2->setPropertyValue(sChainNextName, uno::makeAny(sName1));
+                        xPropertySet1->setPropertyValue(sChainPrevName, uno::makeAny(sName2));
+                        bIsTxbxChained = true ;
+                        break ; //there cannot be more than one previous/next frames
+                    }
+                    else if(  (nTxbxSeq2 == ( nTxbxSeq1 + 1 ) ))
+                    {
+                        xPropertySet1->setPropertyValue(sChainNextName, uno::makeAny(sName2));
+                        xPropertySet2->setPropertyValue(sChainPrevName, uno::makeAny(sName1));
+                        bIsTxbxChained = true ;
+                        break ; //there cannot be more than one previous/next frames
+                    }
+                }
+            }
+            if( bIsTxbxChained )
+            {
+                //This txt box is no longer needed for chaining since
+                //there cannot be more than one previous/next frames
+                outer_itr = m_vTextFramesForChaining.erase(outer_itr);
+            }
+            else
+                ++outer_itr ;
+        }
+        m_vTextFramesForChaining.clear(); //clear the vector
+    }
+    catch (const uno::Exception& rException)
+    {
+        SAL_WARN("writerfilter", "failed. message: " << rException.Message);
+    }
+}
 
 uno::Reference< beans::XPropertySet > DomainMapper_Impl::FindOrCreateFieldMaster(
         const sal_Char* pFieldMasterService, const OUString& rFieldMasterName )
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index a28636b..842a13b 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -449,6 +449,7 @@ public:
 
     void StartParaMarkerChange( );
     void EndParaMarkerChange( );
+    void ChainTextFrames();
 
     void RemoveLastParagraph( );
     void SetIsLastParagraphInSection( bool bIsLast );
@@ -777,6 +778,7 @@ public:
 
 private:
     void PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType);
+    std::vector<uno::Reference< drawing::XShape > > m_vTextFramesForChaining ;
 };
 } //namespace dmapper
 } //namespace writerfilter
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
index 4f73da5..a8ecda3 100644
--- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
@@ -2193,7 +2193,8 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext
     // OOXMLFastContextHandlerWrapper::lcl_createFastChildContext(), here we
     // handle the WPS import of shape text, as there the parent context is a
     // Shape one, so a different situation.
-    if (Element == static_cast<sal_Int32>(NS_wps | OOXML_txbx))
+    if (Element == static_cast<sal_Int32>(NS_wps | OOXML_txbx) ||
+        Element == static_cast<sal_Int32>(NS_wps | OOXML_linkedTxbx) )
         sendShape(Element);
 
     return xContextHandler;


More information about the Libreoffice-commits mailing list